/* Copyright 2012 Cloudseal Ltd
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.cloudseal.client.spring;
import com.cloudseal.client.saml2.IdentifierGenerator;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.AuthenticationEntryPoint;
import org.springframework.util.Assert;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
/**
* When an AccessDeniedException is thrown by Spring it will be intercepted by the ExceptionTranslationFilter which will then
* call the commence method on the AuthenticationEntryPoint. This entry point will then redirect the user to Cloudseal where he
* will be authenticated.
*/
public class CloudsealEntryPoint implements AuthenticationEntryPoint, InitializingBean {
public static final String AUTH_REQUEST_ID = "cloudseal_entry_point_auth_request_id";
public static final String AUDIENCE = "cloudseal_entry_point_audience";
private CloudsealManager cloudsealManager;
private IdentifierGenerator identityGenerator;
public CloudsealEntryPoint() {
identityGenerator = new IdentifierGenerator();
}
CloudsealEntryPoint(IdentifierGenerator identifierGenerator) {
this.identityGenerator = identifierGenerator;
}
@Override
public void commence(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, AuthenticationException ex)
throws IOException, ServletException {
String id = identityGenerator.generateIdentifier();
String spIssuer = buildSpIssuer(httpServletRequest);
String acsUrl = buildAcsUrl(httpServletRequest);
try {
String samlAuthRequest = cloudsealManager.generateSamlAuthRequest(spIssuer, acsUrl, acsUrl, id);
String redirectUrl = getSsoUrl() + "?" + samlAuthRequest;
httpServletRequest.getSession().setAttribute(AUTH_REQUEST_ID, id);
httpServletRequest.getSession().setAttribute(AUDIENCE, spIssuer);
httpServletResponse.sendRedirect(redirectUrl);
} catch (Exception e) {
throw new IOException(e);
}
}
/**
* This would return the url specified in the idp.xml which would not work for the Admin console
* so we allow subclasses to override this method to add dynamic hostnames
* @return
*/
protected String getSsoUrl() {
return cloudsealManager.getSsoUrl();
}
@Override
public void afterPropertiesSet() throws Exception {
Assert.notNull(this.cloudsealManager, "cloudsealManager must be specified");
}
public void setCloudsealManager(CloudsealManager cloudsealManager) {
this.cloudsealManager = cloudsealManager;
}
String buildAcsUrl(HttpServletRequest request) {
StringBuilder builder = new StringBuilder();
// Needed for ssl offload
if (request.isSecure() || "https".equals(request.getScheme())
|| "https".equals(request.getHeader("X-Forwarded-Proto"))) {
builder.append("https://");
} else {
builder.append("http://");
}
builder.append(request.getHeader("Host"));
builder.append(request.getContextPath());
builder.append("/");
builder.append("cloudseal_acs");
return builder.toString();
}
String buildSpIssuer(HttpServletRequest httpRequest) {
StringBuilder builder = new StringBuilder("http://");
String host = httpRequest.getHeader("Host");
if (host == null || host.length() < 1) {
host = "www.mycompany.com";
}
builder.append(host);
builder.append("/saml/sp");
return builder.toString();
}
}