SEC-582: Namespace configuration implementation for remember-me support.
This commit is contained in:
parent
b868143fb1
commit
9f2bc9a842
|
@ -4,12 +4,13 @@ import org.springframework.beans.factory.config.BeanDefinition;
|
|||
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
|
||||
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
|
||||
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
|
||||
import org.springframework.beans.factory.support.RootBeanDefinition;
|
||||
import org.springframework.beans.factory.support.ManagedList;
|
||||
import org.springframework.beans.factory.support.RootBeanDefinition;
|
||||
import org.springframework.beans.factory.xml.ParserContext;
|
||||
import org.springframework.security.AccessDecisionManager;
|
||||
import org.springframework.security.AuthenticationManager;
|
||||
import org.springframework.security.providers.ProviderManager;
|
||||
import org.springframework.security.userdetails.UserDetailsService;
|
||||
import org.springframework.security.vote.AffirmativeBased;
|
||||
import org.springframework.security.vote.AuthenticatedVoter;
|
||||
import org.springframework.security.vote.RoleVoter;
|
||||
|
@ -93,6 +94,20 @@ public abstract class ConfigUtils {
|
|||
getAuthenticationManager(beanFactory));
|
||||
}
|
||||
|
||||
static UserDetailsService getUserDetailsService(ConfigurableListableBeanFactory bf) {
|
||||
Map services = bf.getBeansOfType(UserDetailsService.class);
|
||||
|
||||
if (services.size() == 0) {
|
||||
throw new IllegalArgumentException("No UserDetailsService registered.");
|
||||
|
||||
} else if (services.size() > 1) {
|
||||
throw new IllegalArgumentException("More than one UserDetailsService registered. Please" +
|
||||
"use a specific Id in yur configuration");
|
||||
}
|
||||
|
||||
return (UserDetailsService) services.values().toArray()[0];
|
||||
}
|
||||
|
||||
private static AuthenticationManager getAuthenticationManager(ConfigurableListableBeanFactory bf) {
|
||||
Map authManagers = bf.getBeansOfType(AuthenticationManager.class);
|
||||
|
||||
|
|
|
@ -29,7 +29,7 @@ public class FormLoginBeanDefinitionParser implements BeanDefinitionParser {
|
|||
private static final String LOGIN_PAGE_ATTRIBUTE = "loginPage";
|
||||
|
||||
private static final String FORM_LOGIN_TARGET_URL_ATTRIBUTE = "defaultTargetUrl";
|
||||
private static final String DEFAULT_FORM_LOGIN_TARGET_URL = "/index";
|
||||
private static final String DEFAULT_FORM_LOGIN_TARGET_URL = "/";
|
||||
|
||||
private static final String FORM_LOGIN_AUTH_FAILURE_URL_ATTRIBUTE = "defaultTargetUrl";
|
||||
// TODO: Change AbstractProcessingFilter to not need a failure URL and just write a failure message
|
||||
|
@ -38,8 +38,13 @@ public class FormLoginBeanDefinitionParser implements BeanDefinitionParser {
|
|||
|
||||
|
||||
public BeanDefinition parse(Element elt, ParserContext parserContext) {
|
||||
ConfigUtils.registerProviderManagerIfNecessary(parserContext);
|
||||
|
||||
BeanDefinition filterBean = createFilterBean(elt);
|
||||
|
||||
filterBean.getPropertyValues().addPropertyValue("authenticationManager",
|
||||
new RuntimeBeanReference(ConfigUtils.DEFAULT_AUTH_MANAGER_ID));
|
||||
|
||||
BeanDefinitionBuilder entryPointBuilder =
|
||||
BeanDefinitionBuilder.rootBeanDefinition(AuthenticationProcessingFilterEntryPoint.class);
|
||||
|
||||
|
@ -90,8 +95,6 @@ public class FormLoginBeanDefinitionParser implements BeanDefinitionParser {
|
|||
}
|
||||
|
||||
filterBuilder.addPropertyValue("authenticationFailureUrl", authenticationFailureUrl);
|
||||
// Set autowire to pick up the authentication manager.
|
||||
filterBuilder.setAutowireMode(RootBeanDefinition.AUTOWIRE_BY_TYPE);
|
||||
|
||||
return filterBuilder.getBeanDefinition();
|
||||
}
|
||||
|
|
|
@ -21,7 +21,6 @@ import org.springframework.util.StringUtils;
|
|||
import org.springframework.util.xml.DomUtils;
|
||||
import org.w3c.dom.Element;
|
||||
|
||||
import javax.servlet.Filter;
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
|
@ -44,6 +43,7 @@ public class HttpSecurityBeanDefinitionParser implements BeanDefinitionParser {
|
|||
public static final String LOGOUT_ELEMENT = "logout";
|
||||
public static final String FORM_LOGIN_ELEMENT = "form-login";
|
||||
public static final String BASIC_AUTH_ELEMENT = "http-basic";
|
||||
public static final String REMEMBER_ME_ELEMENT = "remember-me";
|
||||
|
||||
static final String PATH_PATTERN_ATTRIBUTE = "pattern";
|
||||
static final String PATTERN_TYPE_ATTRIBUTE = "pathType";
|
||||
|
@ -120,6 +120,12 @@ public class HttpSecurityBeanDefinitionParser implements BeanDefinitionParser {
|
|||
new BasicAuthenticationBeanDefinitionParser().parse(basicAuthElt, parserContext);
|
||||
}
|
||||
|
||||
Element rememberMeElt = DomUtils.getChildElementByTagName(element, REMEMBER_ME_ELEMENT);
|
||||
|
||||
if (rememberMeElt != null) {
|
||||
new RememberMeBeanDefinitionParser().parse(rememberMeElt, parserContext);
|
||||
}
|
||||
|
||||
registry.registerBeanDefinition(DEFAULT_FILTER_CHAIN_PROXY_ID, filterChainProxy);
|
||||
registry.registerBeanDefinition(DEFAULT_HTTP_SESSION_FILTER_ID, httpSCIF);
|
||||
registry.registerBeanDefinition(DEFAULT_EXCEPTION_TRANSLATION_FILTER_ID,
|
||||
|
|
|
@ -3,14 +3,17 @@ package org.springframework.security.config;
|
|||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.springframework.beans.BeansException;
|
||||
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
|
||||
import org.springframework.beans.factory.config.BeanDefinition;
|
||||
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
|
||||
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
|
||||
import org.springframework.core.OrderComparator;
|
||||
import org.springframework.core.Ordered;
|
||||
import org.springframework.security.AuthenticationManager;
|
||||
import org.springframework.security.concurrent.ConcurrentSessionFilter;
|
||||
import org.springframework.security.context.HttpSessionContextIntegrationFilter;
|
||||
import org.springframework.security.ui.AbstractProcessingFilter;
|
||||
import org.springframework.security.ui.AuthenticationEntryPoint;
|
||||
import org.springframework.security.ui.rememberme.RememberMeServices;
|
||||
import org.springframework.security.util.FilterChainProxy;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
|
@ -38,11 +41,55 @@ public class HttpSecurityConfigPostProcessor implements BeanFactoryPostProcessor
|
|||
|
||||
ConfigUtils.configureSecurityInterceptor(beanFactory, securityInterceptor);
|
||||
|
||||
configureRememberMeSerices(beanFactory);
|
||||
|
||||
configureAuthenticationEntryPoint(beanFactory);
|
||||
|
||||
configureAuthenticationFilter(beanFactory);
|
||||
|
||||
configureFilterChain(beanFactory);
|
||||
}
|
||||
|
||||
private void configureRememberMeSerices(ConfigurableListableBeanFactory beanFactory) {
|
||||
try {
|
||||
BeanDefinition rememberMeServices =
|
||||
beanFactory.getBeanDefinition(RememberMeBeanDefinitionParser.DEFAULT_REMEMBER_ME_SERVICES_ID);
|
||||
rememberMeServices.getPropertyValues().addPropertyValue("userDetailsService",
|
||||
ConfigUtils.getUserDetailsService(beanFactory));
|
||||
|
||||
BeanDefinition logoutFilter =
|
||||
beanFactory.getBeanDefinition(HttpSecurityBeanDefinitionParser.DEFAULT_FILTER_SECURITY_INTERCEPTOR_ID);
|
||||
|
||||
} catch (NoSuchBeanDefinitionException e) {
|
||||
// ignore
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the authentication manager, (and remember-me services, if required) on any instances of
|
||||
* AbstractProcessingFilter
|
||||
*/
|
||||
private void configureAuthenticationFilter(ConfigurableListableBeanFactory beanFactory) {
|
||||
Map beans = beanFactory.getBeansOfType(RememberMeServices.class);
|
||||
|
||||
RememberMeServices rememberMeServices = null;
|
||||
|
||||
if (beans.size() > 0) {
|
||||
rememberMeServices = (RememberMeServices) beans.values().toArray()[0];
|
||||
}
|
||||
|
||||
Iterator authFilters = beanFactory.getBeansOfType(AbstractProcessingFilter.class).values().iterator();
|
||||
|
||||
while (authFilters.hasNext()) {
|
||||
AbstractProcessingFilter filter = (AbstractProcessingFilter) authFilters.next();
|
||||
|
||||
if (rememberMeServices != null) {
|
||||
logger.info("Using RememberMeServices " + rememberMeServices + " with filter " + filter);
|
||||
filter.setRememberMeServices(rememberMeServices);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Selects the entry point that should be used in ExceptionTranslationFilter. Strategy is
|
||||
*
|
||||
|
@ -52,7 +99,6 @@ public class HttpSecurityConfigPostProcessor implements BeanFactoryPostProcessor
|
|||
* <li>throw an exception (for now). TODO: Examine additional beans and types and make decision</li>
|
||||
* </ol>
|
||||
*
|
||||
* @param beanFactory
|
||||
*/
|
||||
private void configureAuthenticationEntryPoint(ConfigurableListableBeanFactory beanFactory) {
|
||||
logger.info("Selecting AuthenticationEntryPoint for use in ExceptionTranslationFilter");
|
||||
|
@ -90,6 +136,15 @@ public class HttpSecurityConfigPostProcessor implements BeanFactoryPostProcessor
|
|||
filterMap.put(allUrlsMatch, defaultFilterChain);
|
||||
|
||||
filterChainProxy.setFilterChainMap(filterMap);
|
||||
|
||||
Map sessionFilters = beanFactory.getBeansOfType(ConcurrentSessionFilter.class);
|
||||
|
||||
if (!sessionFilters.isEmpty()) {
|
||||
logger.info("Concurrent session filter in use, setting 'forceEagerSessionCreation' to true");
|
||||
HttpSessionContextIntegrationFilter scif = (HttpSessionContextIntegrationFilter)
|
||||
beanFactory.getBean(HttpSecurityBeanDefinitionParser.DEFAULT_HTTP_SESSION_FILTER_ID);
|
||||
scif.setForceEagerSessionCreation(true);
|
||||
}
|
||||
}
|
||||
|
||||
private List orderFilters(ConfigurableListableBeanFactory beanFactory) {
|
||||
|
|
|
@ -0,0 +1,72 @@
|
|||
package org.springframework.security.config;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.springframework.beans.factory.config.BeanDefinition;
|
||||
import org.springframework.beans.factory.config.RuntimeBeanReference;
|
||||
import org.springframework.beans.factory.support.ManagedList;
|
||||
import org.springframework.beans.factory.support.RootBeanDefinition;
|
||||
import org.springframework.beans.factory.xml.BeanDefinitionParser;
|
||||
import org.springframework.beans.factory.xml.ParserContext;
|
||||
import org.springframework.security.ui.rememberme.JdbcTokenRepositoryImpl;
|
||||
import org.springframework.security.ui.rememberme.PersistentTokenBasedRememberMeServices;
|
||||
import org.springframework.security.ui.rememberme.RememberMeProcessingFilter;
|
||||
import org.springframework.security.ui.rememberme.TokenBasedRememberMeServices;
|
||||
import org.springframework.security.providers.rememberme.RememberMeAuthenticationProvider;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.w3c.dom.Element;
|
||||
|
||||
/**
|
||||
* @author Luke Taylor
|
||||
* @version $Id$
|
||||
*/
|
||||
public class RememberMeBeanDefinitionParser implements BeanDefinitionParser {
|
||||
protected final Log logger = LogFactory.getLog(getClass());
|
||||
|
||||
public static final String DEFAULT_REMEMBER_ME_FILTER_ID = "_rememberMeFilter";
|
||||
public static final String DEFAULT_REMEMBER_ME_SERVICES_ID = "_rememberMeServices";
|
||||
|
||||
public BeanDefinition parse(Element element, ParserContext parserContext) {
|
||||
BeanDefinition filter = new RootBeanDefinition(RememberMeProcessingFilter.class);
|
||||
BeanDefinition services = new RootBeanDefinition(PersistentTokenBasedRememberMeServices.class);
|
||||
|
||||
filter.getPropertyValues().addPropertyValue("authenticationManager",
|
||||
new RuntimeBeanReference(ConfigUtils.DEFAULT_AUTH_MANAGER_ID));
|
||||
|
||||
String tokenRepository = element.getAttribute("tokenRepository");
|
||||
String dataSource = element.getAttribute("dataSource");
|
||||
|
||||
if (StringUtils.hasText(tokenRepository)) {
|
||||
if (StringUtils.hasText(dataSource)) {
|
||||
throw new SecurityConfigurationException("Specify tokenRepository or dataSource but not both");
|
||||
}
|
||||
|
||||
services.getPropertyValues().addPropertyValue("tokenRepository", new RuntimeBeanReference(tokenRepository));
|
||||
|
||||
} else if (StringUtils.hasText(dataSource)) {
|
||||
BeanDefinition tokenRepo = new RootBeanDefinition(JdbcTokenRepositoryImpl.class);
|
||||
tokenRepo.getPropertyValues().addPropertyValue("dataSource", new RuntimeBeanReference(dataSource));
|
||||
} else {
|
||||
// Not persistent
|
||||
services = new RootBeanDefinition(TokenBasedRememberMeServices.class);
|
||||
}
|
||||
|
||||
String key = element.getAttribute("key");
|
||||
services.getPropertyValues().addPropertyValue("key", key);
|
||||
|
||||
BeanDefinition authManager = ConfigUtils.registerProviderManagerIfNecessary(parserContext);
|
||||
BeanDefinition provider = new RootBeanDefinition(RememberMeAuthenticationProvider.class);
|
||||
provider.getPropertyValues().addPropertyValue("key", key);
|
||||
|
||||
ManagedList providers = (ManagedList) authManager.getPropertyValues().getPropertyValue("providers").getValue();
|
||||
providers.add(provider);
|
||||
|
||||
filter.getPropertyValues().addPropertyValue("rememberMeServices",
|
||||
new RuntimeBeanReference(DEFAULT_REMEMBER_ME_SERVICES_ID));
|
||||
|
||||
parserContext.getRegistry().registerBeanDefinition(DEFAULT_REMEMBER_ME_SERVICES_ID, services);
|
||||
parserContext.getRegistry().registerBeanDefinition(DEFAULT_REMEMBER_ME_FILTER_ID, filter);
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
|
@ -3,17 +3,20 @@ package org.springframework.security.ui.rememberme;
|
|||
import org.apache.commons.codec.binary.Base64;
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
import org.springframework.context.support.MessageSourceAccessor;
|
||||
import org.springframework.security.Authentication;
|
||||
import org.springframework.security.SpringSecurityMessageSource;
|
||||
import org.springframework.security.providers.rememberme.RememberMeAuthenticationToken;
|
||||
import org.springframework.security.ui.AuthenticationDetailsSource;
|
||||
import org.springframework.security.ui.AuthenticationDetailsSourceImpl;
|
||||
import org.springframework.security.ui.logout.LogoutHandler;
|
||||
import org.springframework.security.userdetails.UserDetails;
|
||||
import org.springframework.security.userdetails.UserDetailsService;
|
||||
import org.springframework.security.userdetails.UsernameNotFoundException;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.springframework.web.bind.ServletRequestUtils;
|
||||
import org.springframework.context.support.MessageSourceAccessor;
|
||||
|
||||
import javax.servlet.http.Cookie;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
|
@ -25,7 +28,7 @@ import javax.servlet.http.HttpServletResponse;
|
|||
* @author Luke Taylor
|
||||
* @version $Id$
|
||||
*/
|
||||
public abstract class AbstractRememberMeServices implements RememberMeServices {
|
||||
public abstract class AbstractRememberMeServices implements RememberMeServices, InitializingBean, LogoutHandler {
|
||||
|
||||
protected final Log logger = LogFactory.getLog(getClass());
|
||||
|
||||
|
@ -42,7 +45,14 @@ public abstract class AbstractRememberMeServices implements RememberMeServices {
|
|||
private String parameter = DEFAULT_PARAMETER;
|
||||
private boolean alwaysRemember;
|
||||
private String key;
|
||||
private long tokenValiditySeconds = 1209600; // 14 days
|
||||
private int tokenValiditySeconds = 1209600; // 14 days
|
||||
|
||||
public void afterPropertiesSet() throws Exception {
|
||||
Assert.hasLength(key);
|
||||
Assert.hasLength(parameter);
|
||||
Assert.hasLength(cookieName);
|
||||
Assert.notNull(userDetailsService);
|
||||
}
|
||||
|
||||
/**
|
||||
* Template implementation which locates the Spring Security cookie, decodes it into
|
||||
|
@ -261,13 +271,21 @@ public abstract class AbstractRememberMeServices implements RememberMeServices {
|
|||
return cookie;
|
||||
}
|
||||
|
||||
protected Cookie makeValidCookie(String value, HttpServletRequest request, long maxAge) {
|
||||
protected Cookie makeValidCookie(String value, HttpServletRequest request, int maxAge) {
|
||||
Cookie cookie = new Cookie(cookieName, value);
|
||||
cookie.setMaxAge(new Long(maxAge).intValue());
|
||||
cookie.setMaxAge(maxAge);
|
||||
cookie.setPath(StringUtils.hasLength(request.getContextPath()) ? request.getContextPath() : "/");
|
||||
|
||||
return cookie;
|
||||
}
|
||||
|
||||
public void logout(HttpServletRequest request, HttpServletResponse response, Authentication authentication) {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug( "Logout of user "
|
||||
+ (authentication == null ? "Unknown" : authentication.getName()));
|
||||
}
|
||||
cancelCookie(request, response);
|
||||
}
|
||||
|
||||
public void setCookieName(String cookieName) {
|
||||
this.cookieName = cookieName;
|
||||
|
@ -281,6 +299,10 @@ public abstract class AbstractRememberMeServices implements RememberMeServices {
|
|||
this.parameter = parameter;
|
||||
}
|
||||
|
||||
public String getParameter() {
|
||||
return parameter;
|
||||
}
|
||||
|
||||
protected UserDetailsService getUserDetailsService() {
|
||||
return userDetailsService;
|
||||
}
|
||||
|
@ -293,11 +315,11 @@ public abstract class AbstractRememberMeServices implements RememberMeServices {
|
|||
this.key = key;
|
||||
}
|
||||
|
||||
public void setTokenValiditySeconds(long tokenValiditySeconds) {
|
||||
public void setTokenValiditySeconds(int tokenValiditySeconds) {
|
||||
this.tokenValiditySeconds = tokenValiditySeconds;
|
||||
}
|
||||
|
||||
public long getTokenValiditySeconds() {
|
||||
public int getTokenValiditySeconds() {
|
||||
return tokenValiditySeconds;
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,34 @@
|
|||
package org.springframework.security.ui.rememberme;
|
||||
|
||||
import org.springframework.jdbc.core.support.JdbcDaoSupport;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Luke Taylor
|
||||
* @version $Id$
|
||||
*/
|
||||
public class JdbcTokenRepositoryImpl extends JdbcDaoSupport implements PersistentTokenRepository {
|
||||
//~ Static fields/initializers =====================================================================================
|
||||
public static final String DEF_TOKEN_BY_SERIES_QUERY =
|
||||
"select username,series,token from persistent_logins where series = ?";
|
||||
public static final String DEF_INSERT_TOKEN_STATEMENT =
|
||||
"insert into persistent_logins (username,series,token) values(?,?,?)";
|
||||
public static final String DEF_REMOVE_USER_TOKENS_STATEMENT =
|
||||
"delete from persistent_logins where username = ?";
|
||||
|
||||
//~ Instance fields ================================================================================================
|
||||
|
||||
private String tokensBySeriesQuery = DEF_TOKEN_BY_SERIES_QUERY;
|
||||
private String insertTokenStatement = DEF_INSERT_TOKEN_STATEMENT;
|
||||
private String removeUserTokensStatement = DEF_REMOVE_USER_TOKENS_STATEMENT;
|
||||
|
||||
public void saveToken(PersistentRememberMeToken token) {
|
||||
}
|
||||
|
||||
public PersistentRememberMeToken getTokenForSeries(String seriesId) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public void removeAllTokens(String username) {
|
||||
}
|
||||
}
|
|
@ -109,7 +109,10 @@ public class PersistentTokenBasedRememberMeServices extends AbstractRememberMeSe
|
|||
}
|
||||
|
||||
private PersistentRememberMeToken createNewToken(String username, String series) {
|
||||
logger.debug("Creating new persistent login token for user " + username);
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug(series == null ? "Creating new" : "Renewing" +
|
||||
" persistent login token for user " + username);
|
||||
}
|
||||
|
||||
if (series == null) {
|
||||
byte[] newSeries = new byte[seriesLength];
|
||||
|
@ -131,8 +134,7 @@ public class PersistentTokenBasedRememberMeServices extends AbstractRememberMeSe
|
|||
|
||||
private void addCookie(PersistentRememberMeToken token, HttpServletRequest request, HttpServletResponse response) {
|
||||
String cookieValue = encodeCookie(new String[] {token.getSeries(), token.getTokenValue()});
|
||||
long maxAge = System.currentTimeMillis() + getTokenValiditySeconds() * 1000;
|
||||
response.addCookie(makeValidCookie(cookieValue, request, maxAge));
|
||||
response.addCookie(makeValidCookie(cookieValue, request, getTokenValiditySeconds()));
|
||||
}
|
||||
|
||||
public void setTokenRepository(PersistentTokenRepository tokenRepository) {
|
||||
|
|
|
@ -4,6 +4,7 @@ import org.springframework.security.AuthenticationException;
|
|||
import org.springframework.security.ui.AbstractProcessingFilter;
|
||||
import org.springframework.security.ui.FilterChainOrderUtils;
|
||||
import org.springframework.security.ui.SpringSecurityFilter;
|
||||
import org.springframework.security.ui.rememberme.AbstractRememberMeServices;
|
||||
import org.springframework.security.ui.rememberme.TokenBasedRememberMeServices;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
|
@ -35,8 +36,8 @@ public class DefaultLoginPageGeneratingFilter extends SpringSecurityFilter {
|
|||
usernameParameter = authFilter.getUsernameParameter();
|
||||
passwordParameter = authFilter.getPasswordParameter();
|
||||
|
||||
if (authFilter.getRememberMeServices() instanceof TokenBasedRememberMeServices) {
|
||||
rememberMeParameter = ((TokenBasedRememberMeServices)authFilter.getRememberMeServices()).getParameter();
|
||||
if (authFilter.getRememberMeServices() instanceof AbstractRememberMeServices) {
|
||||
rememberMeParameter = ((AbstractRememberMeServices)authFilter.getRememberMeServices()).getParameter();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -48,7 +48,7 @@ protect.attlist &=
|
|||
|
||||
http =
|
||||
## Container element for HTTP security configuration
|
||||
element http {http.attlist, intercept-url+, form-login?, http-basic?, logout?, concurrent-session-control? }
|
||||
element http {http.attlist, (intercept-url+ & form-login? & http-basic? & logout? & concurrent-session-control? & remember-me?) }
|
||||
http.attlist &=
|
||||
## Controls the eagerness with which an HTTP session is created.
|
||||
[ a:defaultValue = "ifRequired" ] attribute createSession {"ifRequired" | "always" | "never" }?
|
||||
|
@ -135,6 +135,13 @@ concurrent-sessions.attlist &=
|
|||
concurrent-sessions.attlist &=
|
||||
attribute exceptionIfMaximumExceeded {"true" | "false"}?
|
||||
|
||||
remember-me =
|
||||
element remember-me {remember-me.attlist}
|
||||
remember-me.attlist &=
|
||||
attribute key {xsd:string}
|
||||
remember-me.attlist &=
|
||||
(attribute tokenRepository {xsd:string} | attribute datasource {xsd:string})?
|
||||
|
||||
authentication-provider =
|
||||
element authentication-provider {authentication-provider.attlist, (user-service | jdbc-user-service)}
|
||||
authentication-provider.attlist &= empty
|
||||
|
@ -144,7 +151,6 @@ user-service =
|
|||
user-service.attlist &=
|
||||
attribute properties {xsd:string}*
|
||||
|
||||
|
||||
user =
|
||||
element user {user.attlist, empty}
|
||||
user.attlist &=
|
||||
|
|
|
@ -72,13 +72,14 @@
|
|||
<xs:documentation>Container element for HTTP security configuration</xs:documentation>
|
||||
</xs:annotation>
|
||||
<xs:complexType>
|
||||
<xs:sequence>
|
||||
<xs:element maxOccurs="unbounded" ref="security:intercept-url"/>
|
||||
<xs:element minOccurs="0" ref="security:form-login"/>
|
||||
<xs:element minOccurs="0" ref="security:http-basic"/>
|
||||
<xs:element minOccurs="0" ref="security:logout"/>
|
||||
<xs:element minOccurs="0" ref="security:concurrent-session-control"/>
|
||||
</xs:sequence>
|
||||
<xs:choice minOccurs="0" maxOccurs="unbounded">
|
||||
<xs:element ref="security:intercept-url"/>
|
||||
<xs:element ref="security:form-login"/>
|
||||
<xs:element ref="security:http-basic"/>
|
||||
<xs:element ref="security:logout"/>
|
||||
<xs:element ref="security:concurrent-session-control"/>
|
||||
<xs:element ref="security:remember-me"/>
|
||||
</xs:choice>
|
||||
<xs:attributeGroup ref="security:http.attlist"/>
|
||||
</xs:complexType>
|
||||
</xs:element>
|
||||
|
@ -241,6 +242,16 @@
|
|||
</xs:simpleType>
|
||||
</xs:attribute>
|
||||
</xs:attributeGroup>
|
||||
<xs:element name="remember-me">
|
||||
<xs:complexType>
|
||||
<xs:attributeGroup ref="security:remember-me.attlist"/>
|
||||
</xs:complexType>
|
||||
</xs:element>
|
||||
<xs:attributeGroup name="remember-me.attlist">
|
||||
<xs:attribute name="key" use="required" type="xs:string"/>
|
||||
<xs:attribute name="tokenRepository" type="xs:string"/>
|
||||
<xs:attribute name="datasource" type="xs:string"/>
|
||||
</xs:attributeGroup>
|
||||
<xs:element name="authentication-provider">
|
||||
<xs:complexType>
|
||||
<xs:choice>
|
||||
|
|
|
@ -1,20 +1,22 @@
|
|||
package org.springframework.security.config;
|
||||
|
||||
import org.junit.AfterClass;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import org.junit.BeforeClass;
|
||||
import org.junit.Test;
|
||||
import org.springframework.context.support.ClassPathXmlApplicationContext;
|
||||
import org.springframework.security.concurrent.ConcurrentSessionFilter;
|
||||
import org.springframework.security.context.HttpSessionContextIntegrationFilter;
|
||||
import org.springframework.security.intercept.web.FilterSecurityInterceptor;
|
||||
import org.springframework.security.ui.ExceptionTranslationFilter;
|
||||
import org.springframework.security.ui.rememberme.RememberMeProcessingFilter;
|
||||
import org.springframework.security.ui.basicauth.BasicProcessingFilter;
|
||||
import org.springframework.security.ui.logout.LogoutFilter;
|
||||
import org.springframework.security.ui.webapp.AuthenticationProcessingFilter;
|
||||
import org.springframework.security.ui.webapp.DefaultLoginPageGeneratingFilter;
|
||||
import org.springframework.security.util.FilterChainProxy;
|
||||
|
||||
import org.junit.AfterClass;
|
||||
import static org.junit.Assert.*;
|
||||
import org.junit.BeforeClass;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
|
||||
|
@ -54,7 +56,7 @@ public class HttpSecurityBeanDefinitionParserTests {
|
|||
|
||||
List filterList = filterChainProxy.getFilters("/someurl");
|
||||
|
||||
assertTrue("Expected 8 filters in chain", filterList.size() == 8);
|
||||
assertEquals("Expected 9 filters in chain", 9, filterList.size());
|
||||
|
||||
Iterator filters = filterList.iterator();
|
||||
|
||||
|
@ -64,6 +66,7 @@ public class HttpSecurityBeanDefinitionParserTests {
|
|||
assertTrue(filters.next() instanceof AuthenticationProcessingFilter);
|
||||
assertTrue(filters.next() instanceof DefaultLoginPageGeneratingFilter);
|
||||
assertTrue(filters.next() instanceof BasicProcessingFilter);
|
||||
assertTrue(filters.next() instanceof RememberMeProcessingFilter);
|
||||
assertTrue(filters.next() instanceof ExceptionTranslationFilter);
|
||||
assertTrue(filters.next() instanceof FilterSecurityInterceptor);
|
||||
}
|
||||
|
|
|
@ -7,20 +7,22 @@
|
|||
http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-2.0.xsd">
|
||||
|
||||
<security:http createSession="ifRequired" pathType="ant" lowerCaseComparisons="true">
|
||||
<security:intercept-url pattern="/unprotected" filters="none"/>
|
||||
<security:intercept-url pattern="/unprotected" filters="none" />
|
||||
<security:intercept-url pattern="/somepath" access="ROLE_SPECIAL,ROLE_USER" />
|
||||
<security:intercept-url pattern="/**" access="ROLE_USER" />
|
||||
|
||||
<!-- Default form login configuration. Will create filter and entry point -->
|
||||
<security:form-login loginUrl="/j_spring_security_check" />
|
||||
<security:form-login loginUrl="/j_spring_security_check" />
|
||||
|
||||
<!-- Default basic auth configuration. Will create filter and entry point -->
|
||||
<security:http-basic realm="NamespaceTestRealm" />
|
||||
<security:http-basic realm="NamespaceTestRealm" />
|
||||
|
||||
<!-- Default logout configuration -->
|
||||
<security:logout logoutUrl="/j_spring_security_logout" logoutSuccessUrl="/" invalidateSession="true" />
|
||||
|
||||
<security:concurrent-session-control maxSessions="1"/>
|
||||
|
||||
<security:remember-me key="doesntmatter" tokenRepository="tokenRepo"/>
|
||||
</security:http>
|
||||
|
||||
<security:authentication-provider>
|
||||
|
@ -29,4 +31,9 @@ http://www.springframework.org/schema/security http://www.springframework.org/sc
|
|||
<security:user name="bill" password="billspassword" authorities="ROLE_A,ROLE_B,AUTH_OTHER" />
|
||||
</security:user-service>
|
||||
</security:authentication-provider>
|
||||
|
||||
<bean name="tokenRepo" class="org.springframework.security.ui.rememberme.InMemoryTokenRepositoryImpl"/>
|
||||
|
||||
<!-- bean name="rememberMeServices" class="org.springframework.security.ui.rememberme.NullRememberMeServices"/ -->
|
||||
|
||||
</beans>
|
|
@ -22,8 +22,10 @@ http://www.springframework.org/schema/security http://www.springframework.org/sc
|
|||
<security:logout />
|
||||
<security:concurrent-session-control maxSessions="1" exceptionIfMaximumExceeded="true"/>
|
||||
|
||||
<security:remember-me key="doesntmatter" tokenRepository="tokenRepo"/>
|
||||
</security:http>
|
||||
|
||||
<bean name="tokenRepo" class="org.springframework.security.ui.rememberme.InMemoryTokenRepositoryImpl"/>
|
||||
|
||||
<security:authentication-provider>
|
||||
<security:user-service>
|
||||
|
|
Loading…
Reference in New Issue