/*
* Copyright 2002-2012 the original author or authors.
*
* 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 org.springframework.security.config.http;
import static org.springframework.security.config.http.SecurityFilters.*;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.BeanMetadataElement;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.BeanReference;
import org.springframework.beans.factory.config.RuntimeBeanReference;
import org.springframework.beans.factory.parsing.BeanComponentDefinition;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.ManagedList;
import org.springframework.beans.factory.support.ManagedMap;
import org.springframework.beans.factory.support.RootBeanDefinition;
import org.springframework.beans.factory.xml.ParserContext;
import org.springframework.security.authentication.AnonymousAuthenticationProvider;
import org.springframework.security.authentication.RememberMeAuthenticationProvider;
import org.springframework.security.config.BeanIds;
import org.springframework.security.config.Elements;
import org.springframework.security.core.authority.AuthorityUtils;
import org.springframework.security.core.authority.mapping.SimpleAttributes2GrantedAuthoritiesMapper;
import org.springframework.security.core.authority.mapping.SimpleMappableAttributesRetriever;
import org.springframework.security.web.access.AccessDeniedHandlerImpl;
import org.springframework.security.web.access.ExceptionTranslationFilter;
import org.springframework.security.web.authentication.AnonymousAuthenticationFilter;
import org.springframework.security.web.authentication.Http403ForbiddenEntryPoint;
import org.springframework.security.web.authentication.logout.SecurityContextLogoutHandler;
import org.springframework.security.web.authentication.preauth.PreAuthenticatedAuthenticationProvider;
import org.springframework.security.web.authentication.preauth.PreAuthenticatedGrantedAuthoritiesUserDetailsService;
import org.springframework.security.web.authentication.preauth.j2ee.J2eeBasedPreAuthenticatedWebAuthenticationDetailsSource;
import org.springframework.security.web.authentication.preauth.j2ee.J2eePreAuthenticatedProcessingFilter;
import org.springframework.security.web.authentication.preauth.x509.SubjectDnX509PrincipalExtractor;
import org.springframework.security.web.authentication.preauth.x509.X509AuthenticationFilter;
import org.springframework.security.web.authentication.ui.DefaultLoginPageGeneratingFilter;
import org.springframework.security.web.authentication.www.BasicAuthenticationEntryPoint;
import org.springframework.security.web.authentication.www.BasicAuthenticationFilter;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;
import org.springframework.util.xml.DomUtils;
import org.w3c.dom.Element;
import java.security.SecureRandom;
import java.util.*;
/**
* Handles creation of authentication mechanism filters and related beans for <http>
* parsing.
*
* @author Luke Taylor
* @author Rob Winch
* @since 3.0
*/
final class AuthenticationConfigBuilder {
private final Log logger = LogFactory.getLog(getClass());
private static final String ATT_REALM = "realm";
private static final String DEF_REALM = "Spring Security Application";
static final String OPEN_ID_AUTHENTICATION_PROCESSING_FILTER_CLASS = "org.springframework.security.openid.OpenIDAuthenticationFilter";
static final String OPEN_ID_AUTHENTICATION_PROVIDER_CLASS = "org.springframework.security.openid.OpenIDAuthenticationProvider";
private static final String OPEN_ID_CONSUMER_CLASS = "org.springframework.security.openid.OpenID4JavaConsumer";
static final String OPEN_ID_ATTRIBUTE_CLASS = "org.springframework.security.openid.OpenIDAttribute";
private static final String OPEN_ID_ATTRIBUTE_FACTORY_CLASS = "org.springframework.security.openid.RegexBasedAxFetchListFactory";
static final String AUTHENTICATION_PROCESSING_FILTER_CLASS = "org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter";
static final String ATT_AUTH_DETAILS_SOURCE_REF = "authentication-details-source-ref";
private static final String ATT_AUTO_CONFIG = "auto-config";
private static final String ATT_ACCESS_DENIED_ERROR_PAGE = "error-page";
private static final String ATT_ENTRY_POINT_REF = "entry-point-ref";
private static final String ATT_USER_SERVICE_REF = "user-service-ref";
private static final String ATT_KEY = "key";
private final Element httpElt;
private final ParserContext pc;
private final boolean autoConfig;
private final boolean allowSessionCreation;
private RootBeanDefinition anonymousFilter;
private BeanReference anonymousProviderRef;
private BeanDefinition rememberMeFilter;
private String rememberMeServicesId;
private BeanReference rememberMeProviderRef;
private BeanDefinition basicFilter;
private RuntimeBeanReference basicEntryPoint;
private BeanDefinition formEntryPoint;
private BeanDefinition openIDEntryPoint;
private BeanReference openIDProviderRef;
private String formFilterId = null;
private String openIDFilterId = null;
private BeanDefinition x509Filter;
private BeanReference x509ProviderRef;
private BeanDefinition jeeFilter;
private BeanReference jeeProviderRef;
private RootBeanDefinition preAuthEntryPoint;
private BeanMetadataElement mainEntryPoint;
private BeanMetadataElement accessDeniedHandler;
private BeanDefinition logoutFilter;
@SuppressWarnings("rawtypes")
private ManagedList logoutHandlers;
private BeanDefinition loginPageGenerationFilter;
private BeanDefinition etf;
private final BeanReference requestCache;
private final BeanReference portMapper;
private final BeanReference portResolver;
private final BeanMetadataElement csrfLogoutHandler;
private String loginProcessingUrl;
private String openidLoginProcessingUrl;
private String formLoginPage;
private String openIDLoginPage;
public AuthenticationConfigBuilder(Element element, boolean forceAutoConfig,
ParserContext pc, SessionCreationPolicy sessionPolicy,
BeanReference requestCache, BeanReference authenticationManager,
BeanReference sessionStrategy, BeanReference portMapper,
BeanReference portResolver, BeanMetadataElement csrfLogoutHandler) {
this.httpElt = element;
this.pc = pc;
this.requestCache = requestCache;
autoConfig = forceAutoConfig
| "true".equals(element.getAttribute(ATT_AUTO_CONFIG));
this.allowSessionCreation = sessionPolicy != SessionCreationPolicy.NEVER
&& sessionPolicy != SessionCreationPolicy.STATELESS;
this.portMapper = portMapper;
this.portResolver = portResolver;
this.csrfLogoutHandler = csrfLogoutHandler;
createAnonymousFilter();
createRememberMeFilter(authenticationManager);
createBasicFilter(authenticationManager);
createFormLoginFilter(sessionStrategy, authenticationManager);
createOpenIDLoginFilter(sessionStrategy, authenticationManager);
createX509Filter(authenticationManager);
createJeeFilter(authenticationManager);
createLogoutFilter();
createLoginPageFilterIfNeeded();
createUserDetailsServiceFactory();
createExceptionTranslationFilter();
}
void createRememberMeFilter(BeanReference authenticationManager) {
// Parse remember me before logout as RememberMeServices is also a LogoutHandler
// implementation.
Element rememberMeElt = DomUtils.getChildElementByTagName(httpElt,
Elements.REMEMBER_ME);
if (rememberMeElt != null) {
String key = rememberMeElt.getAttribute(ATT_KEY);
if (!StringUtils.hasText(key)) {
key = createKey();
}
RememberMeBeanDefinitionParser rememberMeParser = new RememberMeBeanDefinitionParser(
key, authenticationManager);
rememberMeFilter = rememberMeParser.parse(rememberMeElt, pc);
rememberMeServicesId = rememberMeParser.getRememberMeServicesId();
createRememberMeProvider(key);
}
}
private void createRememberMeProvider(String key) {
RootBeanDefinition provider = new RootBeanDefinition(
RememberMeAuthenticationProvider.class);
provider.setSource(rememberMeFilter.getSource());
provider.getConstructorArgumentValues().addGenericArgumentValue(key);
String id = pc.getReaderContext().generateBeanName(provider);
pc.registerBeanComponent(new BeanComponentDefinition(provider, id));
rememberMeProviderRef = new RuntimeBeanReference(id);
}
void createFormLoginFilter(BeanReference sessionStrategy, BeanReference authManager) {
Element formLoginElt = DomUtils.getChildElementByTagName(httpElt,
Elements.FORM_LOGIN);
RootBeanDefinition formFilter = null;
if (formLoginElt != null || autoConfig) {
FormLoginBeanDefinitionParser parser = new FormLoginBeanDefinitionParser(
"/login", "POST", AUTHENTICATION_PROCESSING_FILTER_CLASS,
requestCache, sessionStrategy, allowSessionCreation, portMapper,
portResolver);
parser.parse(formLoginElt, pc);
formFilter = parser.getFilterBean();
formEntryPoint = parser.getEntryPointBean();
loginProcessingUrl = parser.getLoginProcessingUrl();
formLoginPage = parser.getLoginPage();
}
if (formFilter != null) {
formFilter.getPropertyValues().addPropertyValue("allowSessionCreation",
allowSessionCreation);
formFilter.getPropertyValues().addPropertyValue("authenticationManager",
authManager);
// Id is required by login page filter
formFilterId = pc.getReaderContext().generateBeanName(formFilter);
pc.registerBeanComponent(new BeanComponentDefinition(formFilter, formFilterId));
injectRememberMeServicesRef(formFilter, rememberMeServicesId);
}
}
void createOpenIDLoginFilter(BeanReference sessionStrategy, BeanReference authManager) {
Element openIDLoginElt = DomUtils.getChildElementByTagName(httpElt,
Elements.OPENID_LOGIN);
RootBeanDefinition openIDFilter = null;
if (openIDLoginElt != null) {
FormLoginBeanDefinitionParser parser = new FormLoginBeanDefinitionParser(
"/login/openid", null,
OPEN_ID_AUTHENTICATION_PROCESSING_FILTER_CLASS, requestCache,
sessionStrategy, allowSessionCreation, portMapper, portResolver);
parser.parse(openIDLoginElt, pc);
openIDFilter = parser.getFilterBean();
openIDEntryPoint = parser.getEntryPointBean();
openidLoginProcessingUrl = parser.getLoginProcessingUrl();
openIDLoginPage = parser.getLoginPage();
List<Element> attrExElts = DomUtils.getChildElementsByTagName(openIDLoginElt,
Elements.OPENID_ATTRIBUTE_EXCHANGE);
if (!attrExElts.isEmpty()) {
// Set up the consumer with the required attribute list
BeanDefinitionBuilder consumerBldr = BeanDefinitionBuilder
.rootBeanDefinition(OPEN_ID_CONSUMER_CLASS);
BeanDefinitionBuilder axFactory = BeanDefinitionBuilder
.rootBeanDefinition(OPEN_ID_ATTRIBUTE_FACTORY_CLASS);
ManagedMap<String, ManagedList<BeanDefinition>> axMap = new ManagedMap<String, ManagedList<BeanDefinition>>();
for (Element attrExElt : attrExElts) {
String identifierMatch = attrExElt.getAttribute("identifier-match");
if (!StringUtils.hasText(identifierMatch)) {
if (attrExElts.size() > 1) {
pc.getReaderContext().error(
"You must supply an identifier-match attribute if using more"
+ " than one "
+ Elements.OPENID_ATTRIBUTE_EXCHANGE
+ " element", attrExElt);
}
// Match anything
identifierMatch = ".*";
}
axMap.put(identifierMatch, parseOpenIDAttributes(attrExElt));
}
axFactory.addConstructorArgValue(axMap);
consumerBldr.addConstructorArgValue(axFactory.getBeanDefinition());
openIDFilter.getPropertyValues().addPropertyValue("consumer",
consumerBldr.getBeanDefinition());
}
}
if (openIDFilter != null) {
openIDFilter.getPropertyValues().addPropertyValue("allowSessionCreation",
allowSessionCreation);
openIDFilter.getPropertyValues().addPropertyValue("authenticationManager",
authManager);
// Required by login page filter
openIDFilterId = pc.getReaderContext().generateBeanName(openIDFilter);
pc.registerBeanComponent(new BeanComponentDefinition(openIDFilter,
openIDFilterId));
injectRememberMeServicesRef(openIDFilter, rememberMeServicesId);
createOpenIDProvider();
}
}
private ManagedList<BeanDefinition> parseOpenIDAttributes(Element attrExElt) {
ManagedList<BeanDefinition> attributes = new ManagedList<BeanDefinition>();
for (Element attElt : DomUtils.getChildElementsByTagName(attrExElt,
Elements.OPENID_ATTRIBUTE)) {
String name = attElt.getAttribute("name");
String type = attElt.getAttribute("type");
String required = attElt.getAttribute("required");
String count = attElt.getAttribute("count");
BeanDefinitionBuilder attrBldr = BeanDefinitionBuilder
.rootBeanDefinition(OPEN_ID_ATTRIBUTE_CLASS);
attrBldr.addConstructorArgValue(name);
attrBldr.addConstructorArgValue(type);
if (StringUtils.hasLength(required)) {
attrBldr.addPropertyValue("required", Boolean.valueOf(required));
}
if (StringUtils.hasLength(count)) {
attrBldr.addPropertyValue("count", Integer.parseInt(count));
}
attributes.add(attrBldr.getBeanDefinition());
}
return attributes;
}
private void createOpenIDProvider() {
Element openIDLoginElt = DomUtils.getChildElementByTagName(httpElt,
Elements.OPENID_LOGIN);
BeanDefinitionBuilder openIDProviderBuilder = BeanDefinitionBuilder
.rootBeanDefinition(OPEN_ID_AUTHENTICATION_PROVIDER_CLASS);
RootBeanDefinition uds = new RootBeanDefinition();
uds.setFactoryBeanName(BeanIds.USER_DETAILS_SERVICE_FACTORY);
uds.setFactoryMethodName("authenticationUserDetailsService");
uds.getConstructorArgumentValues().addGenericArgumentValue(
openIDLoginElt.getAttribute(ATT_USER_SERVICE_REF));
openIDProviderBuilder.addPropertyValue("authenticationUserDetailsService", uds);
BeanDefinition openIDProvider = openIDProviderBuilder.getBeanDefinition();
openIDProviderRef = new RuntimeBeanReference(pc.getReaderContext()
.registerWithGeneratedName(openIDProvider));
}
private void injectRememberMeServicesRef(RootBeanDefinition bean,
String rememberMeServicesId) {
if (rememberMeServicesId != null) {
bean.getPropertyValues().addPropertyValue("rememberMeServices",
new RuntimeBeanReference(rememberMeServicesId));
}
}
void createBasicFilter(BeanReference authManager) {
Element basicAuthElt = DomUtils.getChildElementByTagName(httpElt,
Elements.BASIC_AUTH);
if (basicAuthElt == null && !autoConfig) {
// No basic auth, do nothing
return;
}
String realm = httpElt.getAttribute(ATT_REALM);
if (!StringUtils.hasText(realm)) {
realm = DEF_REALM;
}
BeanDefinitionBuilder filterBuilder = BeanDefinitionBuilder
.rootBeanDefinition(BasicAuthenticationFilter.class);
String entryPointId;
if (basicAuthElt != null) {
if (StringUtils.hasText(basicAuthElt.getAttribute(ATT_ENTRY_POINT_REF))) {
basicEntryPoint = new RuntimeBeanReference(
basicAuthElt.getAttribute(ATT_ENTRY_POINT_REF));
}
injectAuthenticationDetailsSource(basicAuthElt, filterBuilder);
}
if (basicEntryPoint == null) {
RootBeanDefinition entryPoint = new RootBeanDefinition(
BasicAuthenticationEntryPoint.class);
entryPoint.setSource(pc.extractSource(httpElt));
entryPoint.getPropertyValues().addPropertyValue("realmName", realm);
entryPointId = pc.getReaderContext().generateBeanName(entryPoint);
pc.registerBeanComponent(new BeanComponentDefinition(entryPoint, entryPointId));
basicEntryPoint = new RuntimeBeanReference(entryPointId);
}
filterBuilder.addConstructorArgValue(authManager);
filterBuilder.addConstructorArgValue(basicEntryPoint);
basicFilter = filterBuilder.getBeanDefinition();
}
void createX509Filter(BeanReference authManager) {
Element x509Elt = DomUtils.getChildElementByTagName(httpElt, Elements.X509);
RootBeanDefinition filter = null;
if (x509Elt != null) {
BeanDefinitionBuilder filterBuilder = BeanDefinitionBuilder
.rootBeanDefinition(X509AuthenticationFilter.class);
filterBuilder.getRawBeanDefinition().setSource(pc.extractSource(x509Elt));
filterBuilder.addPropertyValue("authenticationManager", authManager);
String regex = x509Elt.getAttribute("subject-principal-regex");
if (StringUtils.hasText(regex)) {
BeanDefinitionBuilder extractor = BeanDefinitionBuilder
.rootBeanDefinition(SubjectDnX509PrincipalExtractor.class);
extractor.addPropertyValue("subjectDnRegex", regex);
filterBuilder.addPropertyValue("principalExtractor",
extractor.getBeanDefinition());
}
injectAuthenticationDetailsSource(x509Elt, filterBuilder);
filter = (RootBeanDefinition) filterBuilder.getBeanDefinition();
createPrauthEntryPoint(x509Elt);
createX509Provider();
}
x509Filter = filter;
}
private void injectAuthenticationDetailsSource(Element elt,
BeanDefinitionBuilder filterBuilder) {
String authDetailsSourceRef = elt
.getAttribute(AuthenticationConfigBuilder.ATT_AUTH_DETAILS_SOURCE_REF);
if (StringUtils.hasText(authDetailsSourceRef)) {
filterBuilder.addPropertyReference("authenticationDetailsSource",
authDetailsSourceRef);
}
}
private void createX509Provider() {
Element x509Elt = DomUtils.getChildElementByTagName(httpElt, Elements.X509);
BeanDefinition provider = new RootBeanDefinition(
PreAuthenticatedAuthenticationProvider.class);
RootBeanDefinition uds = new RootBeanDefinition();
uds.setFactoryBeanName(BeanIds.USER_DETAILS_SERVICE_FACTORY);
uds.setFactoryMethodName("authenticationUserDetailsService");
uds.getConstructorArgumentValues().addGenericArgumentValue(
x509Elt.getAttribute(ATT_USER_SERVICE_REF));
provider.getPropertyValues().addPropertyValue(
"preAuthenticatedUserDetailsService", uds);
x509ProviderRef = new RuntimeBeanReference(pc.getReaderContext()
.registerWithGeneratedName(provider));
}
private void createPrauthEntryPoint(Element source) {
if (preAuthEntryPoint == null) {
preAuthEntryPoint = new RootBeanDefinition(Http403ForbiddenEntryPoint.class);
preAuthEntryPoint.setSource(pc.extractSource(source));
}
}
void createJeeFilter(BeanReference authManager) {
final String ATT_MAPPABLE_ROLES = "mappable-roles";
Element jeeElt = DomUtils.getChildElementByTagName(httpElt, Elements.JEE);
RootBeanDefinition filter = null;
if (jeeElt != null) {
BeanDefinitionBuilder filterBuilder = BeanDefinitionBuilder
.rootBeanDefinition(J2eePreAuthenticatedProcessingFilter.class);
filterBuilder.getRawBeanDefinition().setSource(pc.extractSource(jeeElt));
filterBuilder.addPropertyValue("authenticationManager", authManager);
BeanDefinitionBuilder adsBldr = BeanDefinitionBuilder
.rootBeanDefinition(J2eeBasedPreAuthenticatedWebAuthenticationDetailsSource.class);
adsBldr.addPropertyValue("userRoles2GrantedAuthoritiesMapper",
new RootBeanDefinition(
SimpleAttributes2GrantedAuthoritiesMapper.class));
String roles = jeeElt.getAttribute(ATT_MAPPABLE_ROLES);
Assert.hasLength(roles, "roles is expected to have length");
BeanDefinitionBuilder rolesBuilder = BeanDefinitionBuilder
.rootBeanDefinition(StringUtils.class);
rolesBuilder.addConstructorArgValue(roles);
rolesBuilder.setFactoryMethod("commaDelimitedListToSet");
RootBeanDefinition mappableRolesRetriever = new RootBeanDefinition(
SimpleMappableAttributesRetriever.class);
mappableRolesRetriever.getPropertyValues().addPropertyValue(
"mappableAttributes", rolesBuilder.getBeanDefinition());
adsBldr.addPropertyValue("mappableRolesRetriever", mappableRolesRetriever);
filterBuilder.addPropertyValue("authenticationDetailsSource",
adsBldr.getBeanDefinition());
filter = (RootBeanDefinition) filterBuilder.getBeanDefinition();
createPrauthEntryPoint(jeeElt);
createJeeProvider();
}
jeeFilter = filter;
}
private void createJeeProvider() {
Element jeeElt = DomUtils.getChildElementByTagName(httpElt, Elements.JEE);
BeanDefinition provider = new RootBeanDefinition(
PreAuthenticatedAuthenticationProvider.class);
RootBeanDefinition uds;
if (StringUtils.hasText(jeeElt.getAttribute(ATT_USER_SERVICE_REF))) {
uds = new RootBeanDefinition();
uds.setFactoryBeanName(BeanIds.USER_DETAILS_SERVICE_FACTORY);
uds.setFactoryMethodName("authenticationUserDetailsService");
uds.getConstructorArgumentValues().addGenericArgumentValue(
jeeElt.getAttribute(ATT_USER_SERVICE_REF));
}
else {
uds = new RootBeanDefinition(
PreAuthenticatedGrantedAuthoritiesUserDetailsService.class);
}
provider.getPropertyValues().addPropertyValue(
"preAuthenticatedUserDetailsService", uds);
jeeProviderRef = new RuntimeBeanReference(pc.getReaderContext()
.registerWithGeneratedName(provider));
}
void createLoginPageFilterIfNeeded() {
boolean needLoginPage = formFilterId != null || openIDFilterId != null;
// If no login page has been defined, add in the default page generator.
if (needLoginPage && formLoginPage == null && openIDLoginPage == null) {
logger.info("No login page configured. The default internal one will be used. Use the '"
+ FormLoginBeanDefinitionParser.ATT_LOGIN_PAGE
+ "' attribute to set the URL of the login page.");
BeanDefinitionBuilder loginPageFilter = BeanDefinitionBuilder
.rootBeanDefinition(DefaultLoginPageGeneratingFilter.class);
if (formFilterId != null) {
loginPageFilter.addConstructorArgReference(formFilterId);
loginPageFilter.addPropertyValue("authenticationUrl", loginProcessingUrl);
}
if (openIDFilterId != null) {
loginPageFilter.addConstructorArgReference(openIDFilterId);
loginPageFilter.addPropertyValue("openIDauthenticationUrl",
openidLoginProcessingUrl);
}
loginPageGenerationFilter = loginPageFilter.getBeanDefinition();
}
}
void createLogoutFilter() {
Element logoutElt = DomUtils.getChildElementByTagName(httpElt, Elements.LOGOUT);
if (logoutElt != null || autoConfig) {
String formLoginPage = this.formLoginPage;
if (formLoginPage == null) {
formLoginPage = DefaultLoginPageGeneratingFilter.DEFAULT_LOGIN_PAGE_URL;
}
LogoutBeanDefinitionParser logoutParser = new LogoutBeanDefinitionParser(
formLoginPage, rememberMeServicesId, csrfLogoutHandler);
logoutFilter = logoutParser.parse(logoutElt, pc);
logoutHandlers = logoutParser.getLogoutHandlers();
}
}
@SuppressWarnings({ "rawtypes", "unchecked" })
ManagedList getLogoutHandlers() {
if (logoutHandlers == null && rememberMeProviderRef != null) {
logoutHandlers = new ManagedList();
if (csrfLogoutHandler != null) {
logoutHandlers.add(csrfLogoutHandler);
}
logoutHandlers.add(new RuntimeBeanReference(rememberMeServicesId));
logoutHandlers
.add(new RootBeanDefinition(SecurityContextLogoutHandler.class));
}
return logoutHandlers;
}
BeanMetadataElement getEntryPointBean() {
return mainEntryPoint;
}
BeanMetadataElement getAccessDeniedHandlerBean() {
return accessDeniedHandler;
}
void createAnonymousFilter() {
Element anonymousElt = DomUtils.getChildElementByTagName(httpElt,
Elements.ANONYMOUS);
if (anonymousElt != null && "false".equals(anonymousElt.getAttribute("enabled"))) {
return;
}
String grantedAuthority = null;
String username = null;
String key = null;
Object source = pc.extractSource(httpElt);
if (anonymousElt != null) {
grantedAuthority = anonymousElt.getAttribute("granted-authority");
username = anonymousElt.getAttribute("username");
key = anonymousElt.getAttribute(ATT_KEY);
source = pc.extractSource(anonymousElt);
}
if (!StringUtils.hasText(grantedAuthority)) {
grantedAuthority = "ROLE_ANONYMOUS";
}
if (!StringUtils.hasText(username)) {
username = "anonymousUser";
}
if (!StringUtils.hasText(key)) {
// Generate a random key for the Anonymous provider
key = createKey();
}
anonymousFilter = new RootBeanDefinition(AnonymousAuthenticationFilter.class);
anonymousFilter.getConstructorArgumentValues().addIndexedArgumentValue(0, key);
anonymousFilter.getConstructorArgumentValues().addIndexedArgumentValue(1,
username);
anonymousFilter.getConstructorArgumentValues().addIndexedArgumentValue(2,
AuthorityUtils.commaSeparatedStringToAuthorityList(grantedAuthority));
anonymousFilter.setSource(source);
RootBeanDefinition anonymousProviderBean = new RootBeanDefinition(
AnonymousAuthenticationProvider.class);
anonymousProviderBean.getConstructorArgumentValues().addIndexedArgumentValue(0,
key);
anonymousProviderBean.setSource(anonymousFilter.getSource());
String id = pc.getReaderContext().generateBeanName(anonymousProviderBean);
pc.registerBeanComponent(new BeanComponentDefinition(anonymousProviderBean, id));
anonymousProviderRef = new RuntimeBeanReference(id);
}
private String createKey() {
SecureRandom random = new SecureRandom();
return Long.toString(random.nextLong());
}
void createExceptionTranslationFilter() {
BeanDefinitionBuilder etfBuilder = BeanDefinitionBuilder
.rootBeanDefinition(ExceptionTranslationFilter.class);
accessDeniedHandler = createAccessDeniedHandler(httpElt, pc);
etfBuilder.addPropertyValue("accessDeniedHandler", accessDeniedHandler);
assert requestCache != null;
mainEntryPoint = selectEntryPoint();
etfBuilder.addConstructorArgValue(mainEntryPoint);
etfBuilder.addConstructorArgValue(requestCache);
etf = etfBuilder.getBeanDefinition();
}
private BeanMetadataElement createAccessDeniedHandler(Element element,
ParserContext pc) {
Element accessDeniedElt = DomUtils.getChildElementByTagName(element,
Elements.ACCESS_DENIED_HANDLER);
BeanDefinitionBuilder accessDeniedHandler = BeanDefinitionBuilder
.rootBeanDefinition(AccessDeniedHandlerImpl.class);
if (accessDeniedElt != null) {
String errorPage = accessDeniedElt.getAttribute("error-page");
String ref = accessDeniedElt.getAttribute("ref");
if (StringUtils.hasText(errorPage)) {
if (StringUtils.hasText(ref)) {
pc.getReaderContext()
.error("The attribute "
+ ATT_ACCESS_DENIED_ERROR_PAGE
+ " cannot be used together with the 'ref' attribute within <"
+ Elements.ACCESS_DENIED_HANDLER + ">",
pc.extractSource(accessDeniedElt));
}
accessDeniedHandler.addPropertyValue("errorPage", errorPage);
}
else if (StringUtils.hasText(ref)) {
return new RuntimeBeanReference(ref);
}
}
return accessDeniedHandler.getBeanDefinition();
}
private BeanMetadataElement selectEntryPoint() {
// We need to establish the main entry point.
// First check if a custom entry point bean is set
String customEntryPoint = httpElt.getAttribute(ATT_ENTRY_POINT_REF);
if (StringUtils.hasText(customEntryPoint)) {
return new RuntimeBeanReference(customEntryPoint);
}
Element basicAuthElt = DomUtils.getChildElementByTagName(httpElt,
Elements.BASIC_AUTH);
Element formLoginElt = DomUtils.getChildElementByTagName(httpElt,
Elements.FORM_LOGIN);
Element openIDLoginElt = DomUtils.getChildElementByTagName(httpElt,
Elements.OPENID_LOGIN);
// Basic takes precedence if explicit element is used and no others are configured
if (basicAuthElt != null && formLoginElt == null && openIDLoginElt == null) {
return basicEntryPoint;
}
// If formLogin has been enabled either through an element or auto-config, then it
// is used if no openID login page
// has been set.
if (formLoginPage != null && openIDLoginPage != null) {
pc.getReaderContext().error(
"Only one login-page can be defined, either for OpenID or form-login, "
+ "but not both.", pc.extractSource(openIDLoginElt));
}
if (formFilterId != null && openIDLoginPage == null) {
return formEntryPoint;
}
// Otherwise use OpenID if enabled
if (openIDFilterId != null) {
return openIDEntryPoint;
}
// If X.509 or JEE have been enabled, use the preauth entry point.
if (preAuthEntryPoint != null) {
return preAuthEntryPoint;
}
pc.getReaderContext()
.error("No AuthenticationEntryPoint could be established. Please "
+ "make sure you have a login mechanism configured through the namespace (such as form-login) or "
+ "specify a custom AuthenticationEntryPoint with the '"
+ ATT_ENTRY_POINT_REF + "' attribute ", pc.extractSource(httpElt));
return null;
}
private void createUserDetailsServiceFactory() {
if (pc.getRegistry().containsBeanDefinition(BeanIds.USER_DETAILS_SERVICE_FACTORY)) {
// Multiple <http> case
return;
}
RootBeanDefinition bean = new RootBeanDefinition(
UserDetailsServiceFactoryBean.class);
bean.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
pc.registerBeanComponent(new BeanComponentDefinition(bean,
BeanIds.USER_DETAILS_SERVICE_FACTORY));
}
List<OrderDecorator> getFilters() {
List<OrderDecorator> filters = new ArrayList<OrderDecorator>();
if (anonymousFilter != null) {
filters.add(new OrderDecorator(anonymousFilter, ANONYMOUS_FILTER));
}
if (rememberMeFilter != null) {
filters.add(new OrderDecorator(rememberMeFilter, REMEMBER_ME_FILTER));
}
if (logoutFilter != null) {
filters.add(new OrderDecorator(logoutFilter, LOGOUT_FILTER));
}
if (x509Filter != null) {
filters.add(new OrderDecorator(x509Filter, X509_FILTER));
}
if (jeeFilter != null) {
filters.add(new OrderDecorator(jeeFilter, PRE_AUTH_FILTER));
}
if (formFilterId != null) {
filters.add(new OrderDecorator(new RuntimeBeanReference(formFilterId),
FORM_LOGIN_FILTER));
}
if (openIDFilterId != null) {
filters.add(new OrderDecorator(new RuntimeBeanReference(openIDFilterId),
OPENID_FILTER));
}
if (loginPageGenerationFilter != null) {
filters.add(new OrderDecorator(loginPageGenerationFilter, LOGIN_PAGE_FILTER));
}
if (basicFilter != null) {
filters.add(new OrderDecorator(basicFilter, BASIC_AUTH_FILTER));
}
filters.add(new OrderDecorator(etf, EXCEPTION_TRANSLATION_FILTER));
return filters;
}
List<BeanReference> getProviders() {
List<BeanReference> providers = new ArrayList<BeanReference>();
if (anonymousProviderRef != null) {
providers.add(anonymousProviderRef);
}
if (rememberMeProviderRef != null) {
providers.add(rememberMeProviderRef);
}
if (openIDProviderRef != null) {
providers.add(openIDProviderRef);
}
if (x509ProviderRef != null) {
providers.add(x509ProviderRef);
}
if (jeeProviderRef != null) {
providers.add(jeeProviderRef);
}
return providers;
}
}