This guide is intended to help users migrate from Spring Security 3.x to Spring Security 4.x when using XML based configuration.
If you are looking to migrate from Spring Security 3.x to Spring Security 4.x when using Java Based configuration, click here
1. Introduction
As exploits against applications evolve, so must Spring Security. As a major release version, the Spring Security team took the opportunity to make some non-passive changes which focus on: lo * Ensuring Spring Security is more secure by default * Minimizing Information Leakage * Removing deprecated APIs
A complete listing of non-passive changes between 3.x and 4.x can be found in JIRA
2. Sample Migration
A sample illustrating all of the changes in a migration can be found on github. The sample demonstrates migrating spring-security-3-xml to Spring Security 4. The completed migration can be found in spring-security-4-xml
You can find a diff of the changes on github.
3. Updating to Spring 4.1.x
Spring Security 4 now requires Spring 4. Conveniently, Spring Security 3.2.x works with Spring 3.2.x and Spring 4. This means your first step is to update to Spring 4.1.x.
For detailed instructions refer to:
4. Deprecations
A number of deprecations were removed in Spring Security 4 to clean up clutter. The following section describes how to migrate each deprecation.
If you are using the XML Namespace configuration, there are many instances where you will be shielded from deprecation. If you (or a non-spring library you use) do NOT use an API directly, then you will NOT be impacted. This means typically a quick search in your workspace should allow you to find all the deprecations.
4.1. Related Links
For thoroughness we have include the related links in the table below.
JIRA | Commits |
---|---|
4.2. spring-security-acl
This section describes all of the deprecated APIs within the spring-security-acl module. If you are not using the spring-security-acl module, you can safely skip to spring-security-cas.
4.2.1. AclImpl
AclImpl had a deprecated constructor removed.
Specifically, the constructor that defaults the PermissionGrantingStrategy
was removed:
@Deprecated
public AclImpl(ObjectIdentity objectIdentity, Serializable id,
AclAuthorizationStrategy aclAuthorizationStrategy,
AuditLogger auditLogger, Acl parentAcl,
...
List<Sid> loadedSids, boolean entriesInheriting, Sid owner) {
}
This means that an AclImpl was being created with this constructor:
new AclImpl(objectIdentity, id, aclAuthorizationStrategy, auditLogger,
parentAcl, loadedSids, entriesInheriting, owner);
it needs to be updated to pass in the PermissionGrantingStrategy
instead of the AuditLogger
PermissionGrantingStrategy permissionGrantingStrategy =
new DefaultPermissionGrantingStrategy(auditLogger);
new AclImpl(objectIdentity, id, aclAuthorizationStrategy, permissionGrantingStrategy,
parentAcl, loadedSids, entriesInheriting, owner);
4.2.2. EhCacheBasedAclCache
EhCacheBasedAclCache
had a deprecated constructor removed.
Specifically, the constructor that defaults the PermissionGrantingStrategy
was removed:
@Deprecated
public EhCacheBasedAclCache(Ehcache cache) {
...
}
This means that an EhCacheBasedAclCache
was being created with this constructor:
new EhCacheBasedAclCache(ehCache);
it needs to be updated to pass in the PermissionGrantingStrategy
and AclAuthorizationStrategy
too:
PermissionGrantingStrategy permissionGrantingStrategy =
new DefaultPermissionGrantingStrategy(auditLogger);
AclAuthorizationStrategy aclAuthorizationStrategy =
new AclAuthorizationStrategyImpl(new SimpleGrantedAuthority("ROLE_ACL_ADMIN"));
new EhCacheBasedAclCache(ehCache, permissionGrantingStrategy, aclAuthorizationStrategy);
and
<bean id="aclCache" class="org.springframework.security.acls.domain.EhCacheBasedAclCache">
<constructor-arg>
<bean class="org.springframework.cache.ehcache.EhCacheFactoryBean">
<property name="cacheManager">
<bean class="org.springframework.cache.ehcache.EhCacheManagerFactoryBean"/>
</property>
<property name="cacheName" value="aclCache"/>
</bean>
</constructor-arg>
</bean>
needs to be update to
<bean id="aclCache" class="org.springframework.security.acls.domain.EhCacheBasedAclCache">
<constructor-arg>
<bean class="org.springframework.cache.ehcache.EhCacheFactoryBean">
<property name="cacheManager">
<bean class="org.springframework.cache.ehcache.EhCacheManagerFactoryBean"/>
</property>
<property name="cacheName" value="aclCache"/>
</bean>
</constructor-arg>
<constructor-arg>
<bean class="org.springframework.security.acls.domain.DefaultPermissionGrantingStrategy">
<constructor-arg>
<bean class="org.springframework.security.acls.domain.ConsoleAuditLogger"/>
</constructor-arg>
</bean>
</constructor-arg>
<constructor-arg>
<bean class="org.springframework.security.acls.domain.AclAuthorizationStrategyImpl">
<constructor-arg>
<list>
<bean class="org.springframework.security.core.authority.SimpleGrantedAuthority">
<constructor-arg value="ROLE_ACL_ADMIN"/>
</bean>
</list>
</constructor-arg>
</bean>
</constructor-arg>
</bean>
4.3. spring-security-cas
This section describes all of the deprecated APIs within the spring-security-cas module. If you are not using the spring-security-cas module, you can safely skip to spring-security-config.
4.3.1. ServiceAuthenticationDetailsSource
ServiceAuthenticationDetailsSource
removed the deprecated construtors that defaulted the ServiceProperties
.
@Deprecated
public ServiceAuthenticationDetailsSource() {
...
}
@Deprecated
public ServiceAuthenticationDetailsSource(final String artifactParameterName) {
...
}
This means that an ServiceAuthenticationDetailsSource
was being created with these constructors:
new ServiceAuthenticationDetailsSource();
new ServiceAuthenticationDetailsSource(artifactId);
it needs to be updated to pass in the ServiceProperties
as shown below:
new ServiceAuthenticationDetailsSource(serviceProperties);
new ServiceAuthenticationDetailsSource(serviceProperties, artifactId);
and
<b:bean class="org.springframework.security.cas.web.authentication.ServiceAuthenticationDetailsSource"/>
<b:bean class="org.springframework.security.cas.web.authentication.ServiceAuthenticationDetailsSource">
<b:constructor-arg value="TICKET"/>
</b:bean>
needs to be updated to
<b:bean class="org.springframework.security.cas.web.authentication.ServiceAuthenticationDetailsSource">
<b:constructor-arg ref="serviceProperties"/>
</b:bean>
<b:bean class="org.springframework.security.cas.web.authentication.ServiceAuthenticationDetailsSource">
<b:constructor-arg ref="serviceProperties"/>
<b:constructor-arg value="TICKET"/>
</b:bean>
4.4. spring-security-config
This section describes all of the deprecated APIs within the spring-security-config module. If you are not using the spring-security-config module or have already completed this task, you can safely skip to spring-security-core.
4.4.1. filter-invocation-definition-source
The XML element filter-invocation-definition-source
was removed in favor of filter-security-metadata-source.
This means if you have something like this:
<filter-invocation-definition-source ...>
...
</filter-invocation-definition-source>
it needs to be replaced with:
<filter-security-metadata-source ...>
...
</filter-security-metadata-source>
4.4.2. http@access-denied-page
The XML attribute http@access-denied-page
was removed in favor of access-denied-handler@error-page.
This means if you have something like this:
<http ... access-denied-page="/denied">
...
</http>
it needs to be replaced with:
<http ...>
<access-denied-handler error-page="/denied"/>
</http>
4.4.3. http@path-type
The XML attribute http@path-type
was removed in favor of http@request-matcher.
This means if you have something like this:
<http ... path-type="regex">
...
</http>
it needs to be replaced with:
<http ... request-matcher="regex">
...
</http>
4.4.4. filter-chain-map@path-type
The XML attribute filter-chain-map@path-type
was removed in favor of filter-chain-map@request-matcher.
This means if you have something like this:
<filter-chain-map ... path-type="regex">
...
</filter-chain-map>
it needs to be replaced with:
<filter-chain-map ... request-matcher="regex">
...
</filter-chain-map>
4.4.5. filter-security-metadata-source@path-type
The XML attribute filter-security-metadata-source@path-type
was removed in favor of filter-security-metadata-source@request-matcher.
This means if you have something like this:
<filter-security-metadata-source ... path-type="regex">
...
</filter-security-metadata-source>
it needs to be replaced with:
<filter-security-metadata-source ... request-matcher="regex">
...
</filter-security-metadata-source>
4.5. spring-security-core
This section describes all of the deprecated APIs within the spring-security-core module. If you are not using the spring-security-core module or have already completed this task, you can safely skip to spring-security-openid.
4.5.1. SecurityConfig
SecurityConfig.createSingleAttributeList(String)
was removed in favor of using SecurityConfig.createList(String…)
.
This means if you have something like this:
List<ConfigAttribute> attrs =
SecurityConfig.createSingleAttributeList("ROLE_USER");
needs to be replaced with:
List<ConfigAttribute> attrs =
SecurityConfig.createList("ROLE_USER");
4.5.2. UserDetailsServiceWrapper
UserDetailsServiceWrapper
was deprecated in favor of using RoleHierarchyAuthoritiesMapper
.
For example, if you have something like this:
<authentication-manager>
<authentication-provider user-service-ref="userDetailsServiceWrapper"/>
</authentication-manager>
<b:bean id="userDetailsServiceWrapper" class="org.springframework.security.access.hierarchicalroles.UserDetailsServiceWrapper">
<b:property name="userDetailsService" ref="userDetailsService"/>
<b:property name="roleHierarchy" ref="roleHierarchy"/>
</b:bean>
<b:bean id="roleHierarchy" class="org.springframework.security.access.hierarchicalroles.RoleHierarchyImpl">
<b:property name="hierarchy">
<b:value>
ROLE_ADMIN > ROLE_USER
</b:value>
</b:property>
</b:bean>
then it needs to be migrated with something like this:
<authentication-manager>
<authentication-provider ref="authenticationProvider"/>
</authentication-manager>
<b:bean id="authenticationProvider" class="org.springframework.security.authentication.dao.DaoAuthenticationProvider">
<b:property name="userDetailsService" ref="userDetailsService"/>
<b:property name="authoritiesMapper" ref="authoritiesMapper"/>
</b:bean>
<b:bean id="authoritiesMapper" class="org.springframework.security.access.hierarchicalroles.RoleHierarchyAuthoritiesMapper">
<b:constructor-arg ref="roleHierarchy"/>
</b:bean>
<b:bean id="roleHierarchy" class="org.springframework.security.access.hierarchicalroles.RoleHierarchyImpl">
<b:property name="hierarchy">
<b:value>
ROLE_ADMIN > ROLE_USER
</b:value>
</b:property>
</b:bean>
4.5.3. UserDetailsWrapper
UserDetailsWrapper
was deprecated in favor of using RoleHierarchyAuthoritiesMapper
.
Typically users would not use the UserDetailsWrapper
directly. However, if they are they can use RoleHierarchyAuthoritiesMapper
For example, if the following code is present:
UserDetailsWrapper authenticate = new UserDetailsWrapper(userDetails, roleHiearchy);
then it needs to be replaced by:
Collection<GrantedAuthority> allAuthorities =
roleHiearchy.getReachableGrantedAuthorities(userDetails.getAuthorities());
UserDetails authenticate =
new User(userDetails.getUsername(), userDetails.getPassword(), allAuthorities);
4.5.4. AbstractAccessDecisionManager
The default constructor for AbstractAccessDecisionManager
has been deprecated along with the setDecisionVoters
method.
Naturally, this impacts the subclasses AffirmativeBased
, ConsensusBased
, and UnanimousBased
.
For example, this means that if you are using the following:
AffirmativeBased adm = new AffirmativeBased();
adm.setDecisionVoters(voters);
it needs to be migrated to:
AffirmativeBased adm = new AffirmativeBased(voters);
This type of migration also applies to XML based configuration. For example, if you are using the following:
<b:bean class="org.springframework.security.access.vote.UnanimousBased">
<b:property name="decisionVoters" ref="voters"/>
</b:bean>
then it needs to be migrated to:
<b:bean class="org.springframework.security.access.vote.UnanimousBased">
<b:constructor-arg ref="voters"/>
</b:bean>
4.5.5. AuthenticationException
The constructor that accepts extraInformation within AuthenticationException
was removed to prevent accidental leaking of the UserDetails
.
Specifically, the following we removed.
public AccountExpiredException(String msg, Object extraInformation) {
...
}
This impacts the subclasses AccountStatusException
, AccountExpiredException
, BadCredentialsException
, CredentialsExpiredException
, DisabledException
, LockedException
, and UsernameNotFoundException
.
If use are using any of these constructors, simply remove the additional argument.
For example, the following is changed from:
new LockedException("Message", userDetails);
to:
new LockedException("Message");
4.5.6. AnonymousAuthenticationProvider
AnonymousAuthenticationProvider
default constructor and setKey
method was deprecated in favor of using constructor injection.
For example, if you have the following:
AnonymousAuthenticationProvider provider = new AnonymousAuthenticationProvider();
provider.setKey(key);
it should be changed to:
AnonymousAuthenticationProvider provider = new AnonymousAuthenticationProvider(key);
4.5.7. AuthenticationDetailsSourceImpl
AuthenticationDetailsSourceImpl
was deprecated in favor of writing a custom AuthenticationDetailsSource
.
For example, if you have the following:
AuthenticationDetailsSourceImpl source = new AuthenticationDetailsSourceImpl();
source.setClazz(CustomWebAuthenticationDetails.class);
You should implement AuthenticationDetailsSource
directly to return CustomSource
:
public class CustomWebAuthenticationDetailsSource implements AuthenticationDetailsSource<HttpServletRequest, WebAuthenticationDetails> {
public WebAuthenticationDetails buildDetails(HttpServletRequest context) {
return new CustomWebAuthenticationDetails(context);
}
}
4.5.8. ProviderManager
ProviderManager
has removed the deprecated default constructor and the correspdonding setter methods in favor of using constructor injection.
It has also removed the clearExtraInformation property since the AuthenticationException
had the extra information property removed.
For example, if you have something like the following:
ProviderManager provider = new ProviderManager();
provider.setParent(parent);
provider.setProviders(providers);
provider.setClearExtraInformation(true);
then it should be changed to:
ProviderManager provider = new ProviderManager(providers, parent);
The clearExtraInformation property was removed since the AuthenticationException had the extra information property removed. So there is no replacement for this.
|
and
<b:bean class="org.springframework.security.authentication.ProviderManager">
<b:property name="parent" ref="parent"/>
<b:property name="providers">
<b:list>
<b:ref bean="authenticationProvider"/>
</b:list>
</b:property>
<b:property name="clearExtraInformation" value="true"/>
</b:bean>
should be changed to
<b:bean class="org.springframework.security.authentication.ProviderManager">
<b:constructor-arg>
<b:list>
<b:ref bean="authenticationProvider"/>
</b:list>
</b:constructor-arg>
<b:constructor-arg ref="parent"/>
</b:bean>
4.5.9. RememberMeAuthenticationProvider
RememberMeAuthenticationProvider
had the default constructor and the setKey
method removed in favor of constructor injection.
For example:
RememberMeAuthenticationProvider provider = new RememberMeAuthenticationProvider();
provider.setKey(key);
should be migrated to:
RememberMeAuthenticationProvider provider = new RememberMeAuthenticationProvider(key);
and
<b:bean class="org.springframework.security.authentication.RememberMeAuthenticationProvider">
<b:property name="key" value="key"/>
</b:bean>
should be migrated to
<b:bean class="org.springframework.security.authentication.RememberMeAuthenticationProvider">
<b:constructor-arg value="key"/>
</b:bean>
4.5.10. GrantedAuthorityImpl
GrantedAuthorityImpl
was removed in favor of SimpleGrantedAuthority
or implementing your own.
For example:
new GrantedAuthorityImpl(role);
should be replaced with
new SimpleGrantedAuthority(role);
4.5.11. InMemoryDaoImpl
InMemoryDaoImpl
was replaced in favor of InMemoryUserDetailsManager
For example the following:
InMemoryDaoImpl uds = new InMemoryDaoImpl();
uds.setUserProperties(properties);
should be replaced with
InMemoryUserDetailsManager uds = new InMemoryUserDetailsManager(properties);
and
<b:bean class="org.springframework.security.core.userdetails.memory.InMemoryDaoImpl">
<b:property name="userProperties">
<b:value>
user=password,ROLE_USER
</b:value>
</b:property>
</b:bean>
should be replaced with
<b:bean class="org.springframework.security.provisioning.InMemoryUserDetailsManager">
<b:constructor-arg>
<b:value>
user=password,ROLE_USER
</b:value>
</b:constructor-arg>
</b:bean>
4.5.12. spring-security-openid
This section describes all of the deprecated APIs within the spring-security-openid module. If you are not using the spring-security-openid module or have already completed this task, you can safely skip to spring-security-taglibs.
4.5.13. OpenID4JavaConsumer
The OpenID4JavaConsumer
constructors that accept List<OpenIDAttribute>
have been removed in favor of using an AxFetchListFactory
.
For example:
new OpenID4JavaConsumer(attributes);
should be replaced with:
Map<String, List<OpenIDAttribute>> regexMap = new HashMap<String,List<OpenIDAttribute>>();
regexMap.put(".*", attributes);
RegexBasedAxFetchListFactory factory = new RegexBasedAxFetchListFactory(regexMap);
new OpenID4JavaConsumer(factory);
and
<b:bean class="org.springframework.security.openid.OpenID4JavaConsumer">
<b:constructor-arg>
<b:list>
<b:bean class="org.springframework.security.openid.OpenIDAttribute">
<b:constructor-arg value="email"/>
<b:constructor-arg value="http://axschema.org/contact/email"/>
</b:bean>
</b:list>
</b:constructor-arg>
</b:bean>
should be replaced with:
<b:bean class="org.springframework.security.openid.OpenID4JavaConsumer">
<b:constructor-arg>
<b:bean class="org.springframework.security.openid.RegexBasedAxFetchListFactory">
<b:constructor-arg>
<b:map>
<b:entry key=".*">
<b:list>
<b:bean class="org.springframework.security.openid.OpenIDAttribute">
<b:constructor-arg value="email"/>
<b:constructor-arg value="http://axschema.org/contact/email"/>
</b:bean>
</b:list>
</b:entry>
</b:map>
</b:constructor-arg>
</b:bean>
</b:constructor-arg>
</b:bean>
4.6. spring-security-taglibs
This section describes all of the deprecated APIs within the spring-security-taglibs module. If you are not using the spring-security-taglibs module or have already completed this task, you can safely skip to spring-security-web.
Spring Security’s authorize JSP tag deprecated the properties ifAllGranted
, ifAnyGranted
, and ifNotGranted
in favor of using expressions.
For example:
<sec:authorize ifAllGranted="ROLE_ADMIN,ROLE_USER">
<p>Must have ROLE_ADMIN and ROLE_USER</p>
</sec:authorize>
<sec:authorize ifAnyGranted="ROLE_ADMIN,ROLE_USER">
<p>Must have ROLE_ADMIN or ROLE_USER</p>
</sec:authorize>
<sec:authorize ifNotGranted="ROLE_ADMIN,ROLE_USER">
<p>Must not have ROLE_ADMIN or ROLE_USER</p>
</sec:authorize>
can be replaced with:
<sec:authorize access="hasRole('ROLE_ADMIN') and hasRole('ROLE_USER')">
<p>Must have ROLE_ADMIN and ROLE_USER</p>
</sec:authorize>
<sec:authorize access="hasAnyRole('ROLE_ADMIN','ROLE_USER')">
<p>Must have ROLE_ADMIN or ROLE_USER</p>
</sec:authorize>
<sec:authorize access="!hasAnyRole('ROLE_ADMIN','ROLE_USER')">
<p>Must not have ROLE_ADMIN or ROLE_USER</p>
</sec:authorize>
4.7. spring-security-web
This section describes all of the deprecated APIs within the spring-security-web module. If you are not using the spring-security-web module or have already completed this task, you can safely skip to [m3to4-xml -defaults].
4.7.1. FilterChainProxy
FilterChainProxy
removed the setFilterChainMap
method in favor of constructor injection.
For example, if you have the following:
FilterChainProxy filter = new FilterChainProxy();
filter.setFilterChainMap(filterChainMap);
it should be replaced with:
FilterChainProxy filter = new FilterChainProxy(securityFilterChains);
FilterChainProxy
also removed getFilterChainMap
in favor of using getFilterChains
for example:
FilterChainProxy securityFilterChain = ...
Map<RequestMatcher,List<Filter>> mappings = securityFilterChain.getFilterChainMap();
for(Map.Entry<RequestMatcher, List<Filter>> entry : mappings.entrySet()) {
RequestMatcher matcher = entry.getKey();
boolean matches = matcher.matches(request);
List<Filter> filters = entry.getValue();
}
should be replaced with
FilterChainProxy securityFilterChain = ...
List<SecurityFilterChain> mappings = securityFilterChain.getFilterChains();
for(SecurityFilterChain entry : mappings) {
boolean matches = entry.matches(request);
List<Filter> filters = entry.getFilters();
}
and
<b:bean class="org.springframework.security.web.FilterChainProxy">
<b:property name="filterChainMap">
<b:map>
<b:entry key="#{T(org.springframework.security.web.util.matcher.AnyRequestMatcher).INSTANCE}">
<b:ref bean="mockFilter"/>
</b:entry>
</b:map>
</b:property>
</b:bean>
should be replaced with
<b:bean class="org.springframework.security.web.FilterChainProxy">
<b:constructor-arg>
<b:bean class="org.springframework.security.web.DefaultSecurityFilterChain">
<b:constructor-arg value="#{T(org.springframework.security.web.util.matcher.AnyRequestMatcher).INSTANCE}"/>
<b:constructor-arg ref="mockFilter"/>
</b:bean>
</b:constructor-arg>
</b:bean>
4.7.2. ExceptionTranslationFilter
The default constructor for ExceptionTranslationFilter
and the setAuthenticationEntryPoint
method was removed in favor of using constructor injection.
ExceptionTranslationFilter filter = new ExceptionTranslationFilter();
filter.setAuthenticationEntryPoint(entryPoint);
filter.setRequestCache(requestCache);
can be replaced with
ExceptionTranslationFilter filter = new ExceptionTranslationFilter(entryPoint, requestCache);
and
<b:bean class="org.springframework.security.web.access.ExceptionTranslationFilter">
<b:property name="authenticationEntryPoint" ref="entryPoint"/>
<b:property name="requestCache" ref="requestCache"/>
</b:bean>
can be replaced with
<b:bean class="org.springframework.security.web.access.ExceptionTranslationFilter">
<b:constructor-arg ref="entryPoint"/>
<b:constructor-arg ref="requestCache"/>
</b:bean>
4.7.3. AbstractAuthenticationProcessingFilter
AbstractAuthenticationProcessingFilter
had its successfulAuthentication(HttpServletRequest,HttpServletResponse,Authentication)
method removed.
So if your application overrides the following method:
protected void successfulAuthentication(HttpServletRequest request, HttpServletResponse response,
Authentication authResult) throws IOException, ServletException {
}
it should be replaced with:
protected void successfulAuthentication(HttpServletRequest request, HttpServletResponse response,
FilterChain chain, Authentication authResult) throws IOException, ServletException {
}
4.7.4. AnonymousAuthenticationFilter
AnonymousAuthenticationFilter
had the default constructor and the setKey
and setPrincipal
methods removed in favor of constructor injection.
For example:
AnonymousAuthenticationFilter filter = new AnonymousAuthenticationFilter();
filter.setKey(key);
filter.setUserAttribute(attrs);
should be replaced with:
AnonymousAuthenticationFilter filter =
new AnonymousAuthenticationFilter(key,attrs.getPassword(),attrs.getAuthorities());
and
<b:bean class="org.springframework.security.web.authentication.AnonymousAuthenticationFilter">
<b:property name="key" value="key"/>
<b:property name="userAttribute" ref="userAttribute"/>
</b:bean>
can be replaced with
<b:bean class="org.springframework.security.web.authentication.AnonymousAuthenticationFilter">
<b:constructor-arg value="key"/>
<b:constructor-arg value="#{userAttribute.password}"/>
<b:constructor-arg value="#{userAttribute.authorities}"/>
</b:bean>
4.7.5. LoginUrlAuthenticationEntryPoint
The LoginUrlAuthenticationEntryPoint
default constructor and the setLoginFormUrl
method was removed in favor of constructor injection.
For example:
LoginUrlAuthenticationEntryPoint entryPoint = new LoginUrlAuthenticationEntryPoint();
entryPoint.setLoginFormUrl("/login");
should be replaced with
LoginUrlAuthenticationEntryPoint entryPoint = new LoginUrlAuthenticationEntryPoint(loginFormUrl);
and
<b:bean class="org.springframework.security.web.authentication.LoginUrlAuthenticationEntryPoint">
<b:property name="loginFormUrl" value="/login"/>
</b:bean>
should be replaced with:
<b:bean class="org.springframework.security.web.authentication.LoginUrlAuthenticationEntryPoint">
<b:constructor-arg value="/login"/>
</b:bean>
4.7.6. PreAuthenticatedGrantedAuthoritiesUserDetailsService
PreAuthenticatedGrantedAuthoritiesUserDetailsService
removed createuserDetails
in favor of createUserDetails
.
The new method has a correction in the case (i.e. U instead of u). |
This means if you have a subclass of PreAuthenticatedGrantedAuthoritiesUserDetailsService
that overrides createuserDetails
public class SubclassPreAuthenticatedGrantedAuthoritiesUserDetailsService extends PreAuthenticatedGrantedAuthoritiesUserDetailsService {
@Override
protected UserDetails createuserDetails(Authentication token,
Collection<? extends GrantedAuthority> authorities) {
// customize
}
}
it should be changed to override createUserDetails
public class SubclassPreAuthenticatedGrantedAuthoritiesUserDetailsService extends PreAuthenticatedGrantedAuthoritiesUserDetailsService {
@Override
protected UserDetails createUserDetails(Authentication token,
Collection<? extends GrantedAuthority> authorities) {
// customize
}
}
4.7.7. AbstractRememberMeServices
AbstractRememberMeServices
and its subclasses PersistentTokenBasedRememberMeServices
and TokenBasedRememberMeServices
removed the default constructor and the setKey
and setUserDetailsService
methods in favor of constructor injection.
4.7.8. PersistentTokenBasedRememberMeServices
AbstractRememberMeServices
and its subclasses PersistentTokenBasedRememberMeServices
and TokenBasedRememberMeServices
removed the default constructor and the setKey
and setUserDetailsService
methods in favor of constructor injection.
For example:
PersistentTokenBasedRememberMeServices services = new PersistentTokenBasedRememberMeServices();
services.setKey(key);
services.setUserDetailsService(userDetailsService);
services.setTokenRepository(tokenRepository);
should be replaced with
PersistentTokenBasedRememberMeServices services =
new PersistentTokenBasedRememberMeServices(key, userDetailsService, tokenRepository);
and
<b:bean class="org.springframework.security.web.authentication.rememberme.PersistentTokenBasedRememberMeServices">
<b:property name="key" value="key"/>
<b:property name="userDetailsService" ref="userDetailsService"/>
<b:property name="tokenRepository" ref="tokenRepository"/>
</b:bean>
should be replaced with:
<b:bean class="org.springframework.security.web.authentication.rememberme.PersistentTokenBasedRememberMeServices">
<b:constructor-arg value="key"/>
<b:constructor-arg ref="userDetailsService"/>
<b:constructor-arg ref="tokenRepository"/>
</b:bean>
4.7.9. RememberMeAuthenticationFilter
RememberMeAuthenticationFilter
default constructor and the setAuthenticationManager
and setRememberMeServices
methods were removed in favor of constructor injection.
RememberMeAuthenticationFilter filter = new RememberMeAuthenticationFilter();
filter.setAuthenticationManager(authenticationManager);
filter.setRememberMeServices(rememberMeServices);
should be replaced with
RememberMeAuthenticationFilter filter =
new RememberMeAuthenticationFilter(authenticationManager,rememberMeServices);
and
<b:bean class="org.springframework.security.web.authentication.rememberme.RememberMeAuthenticationFilter">
<b:property name="authenticationManager" ref="authenticationManager"/>
<b:property name="rememberMeServices" ref="rememberMeServices"/>
</b:bean>
should be replaced with
<b:bean class="org.springframework.security.web.authentication.rememberme.RememberMeAuthenticationFilter">
<b:constructor-arg ref="authenticationManager"/>
<b:constructor-arg ref="rememberMeServices"/>
</b:bean>
4.7.10. TokenBasedRememberMeServices
AbstractRememberMeServices
and its subclasses PersistentTokenBasedRememberMeServices
and TokenBasedRememberMeServices
removed the default constructor and the setKey
and setUserDetailsService
methods in favor of constructor injection.
For example:
TokenBasedRememberMeServices services = new TokenBasedRememberMeServices();
services.setKey(key);
services.setUserDetailsService(userDetailsService);
should be replaced with
TokenBasedRememberMeServices services =
new TokenBasedRememberMeServices(key, userDetailsService);
and
<b:bean class="org.springframework.security.web.authentication.rememberme.TokenBasedRememberMeServices">
<b:property name="key" value="key"/>
<b:property name="userDetailsService" ref="userDetailsService"/>
</b:bean>
should be replaced with
<b:bean class="org.springframework.security.web.authentication.rememberme.TokenBasedRememberMeServices">
<b:constructor-arg value="key"/>
<b:constructor-arg ref="userDetailsService"/>
</b:bean>
4.7.11. ConcurrentSessionControlStrategy
ConcurrentSessionControlStrategy
was replaced with ConcurrentSessionControlAuthenticationStrategy
.
Previously ConcurrentSessionControlStrategy
could not be decoupled from SessionFixationProtectionStrategy
.
Now it is completely decoupled.
For example, the following:
ConcurrentSessionControlStrategy strategy = new ConcurrentSessionControlStrategy(sessionRegistry);
can be replaced with
List<SessionAuthenticationStrategy> delegates = new ArrayList<SessionAuthenticationStrategy>();
delegates.add(new ConcurrentSessionControlAuthenticationStrategy(sessionRegistry));
delegates.add(new SessionFixationProtectionStrategy());
delegates.add(new RegisterSessionAuthenticationStrategy(sessionRegistry));
CompositeSessionAuthenticationStrategy strategy = new CompositeSessionAuthenticationStrategy(delegates);
and
<b:bean class="org.springframework.security.web.authentication.session.ConcurrentSessionControlStrategy">
<b:constructor-arg ref="sessionRegistry"/>
</b:bean>
can be replaced with
<b:bean class="org.springframework.security.web.authentication.session.CompositeSessionAuthenticationStrategy">
<b:constructor-arg>
<b:list>
<b:bean class="org.springframework.security.web.authentication.session.ConcurrentSessionControlAuthenticationStrategy">
<b:constructor-arg ref="sessionRegistry"/>
</b:bean>
<b:bean class="org.springframework.security.web.authentication.session.SessionFixationProtectionStrategy"/>
<b:bean class="org.springframework.security.web.authentication.session.RegisterSessionAuthenticationStrategy">
<b:constructor-arg ref="sessionRegistry"/>
</b:bean>
</b:list>
</b:constructor-arg>
</b:bean>
4.7.12. SessionFixationProtectionStrategy
SessionFixationProtectionStrategy
removed setRetainedAttributes
method in favor of users subclassing SessionFixationProtectionStrategy
and overriding extractAttributes
method.
This means the following:
SessionFixationProtectionStrategy strategy = new SessionFixationProtectionStrategy();
strategy.setRetainedAttributes(attrsToRetain);
should be replaced with
public class AttrsSessionFixationProtectionStrategy extends SessionFixationProtectionStrategy {
private final Collection<String> attrsToRetain;
public AttrsSessionFixationProtectionStrategy(
Collection<String> attrsToRetain) {
this.attrsToRetain = attrsToRetain;
}
@Override
protected Map<String, Object> extractAttributes(HttpSession session) {
Map<String,Object> attrs = new HashMap<String, Object>();
for(String attr : attrsToRetain) {
attrs.put(attr, session.getAttribute(attr));
}
return attrs;
}
}
SessionFixationProtectionStrategy strategy = new AttrsSessionFixationProtectionStrategy(attrsToRetain);
4.7.13. BasicAuthenticationFilter
BasicAuthenticationFilter
default constructor and the setAuthenticationManager
and setRememberMeServices
methods were removed in favor of constructor injection.
BasicAuthenticationFilter filter = new BasicAuthenticationFilter();
filter.setAuthenticationManager(authenticationManager);
filter.setAuthenticationEntryPoint(entryPoint);
filter.setIgnoreFailure(true);
should be replaced with
BasicAuthenticationFilter filter =
new BasicAuthenticationFilter(authenticationManager,entryPoint);
Using this constructor automatically sets ignoreFalure to true |
and
<b:bean class="org.springframework.security.web.authentication.www.BasicAuthenticationFilter">
<b:property name="authenticationManager" ref="authenticationManager"/>
<b:property name="authenticationEntryPoint" ref="entryPoint"/>
</b:bean>
should be replaced with
<b:bean class="org.springframework.security.web.authentication.www.BasicAuthenticationFilter">
<b:constructor-arg ref="authenticationManager"/>
<b:constructor-arg ref="entryPoint"/>
</b:bean>
4.7.14. SecurityContextPersistenceFilter
SecurityContextPersistenceFilter
removed the setSecurityContextRepository
in favor of constructor injection.
For example:
SecurityContextPersistenceFilter filter = new SecurityContextPersistenceFilter();
filter.setSecurityContextRepository(securityContextRepository);
should be replaced with
SecurityContextPersistenceFilter filter = new SecurityContextPersistenceFilter(securityContextRepository);
and
<b:bean class="org.springframework.security.web.context.SecurityContextPersistenceFilter">
<b:property name="securityContextRepository" ref="securityContextRepository"/>
</b:bean>
should be replaced with
<b:bean class="org.springframework.security.web.context.SecurityContextPersistenceFilter">
<b:constructor-arg ref="securityContextRepository"/>
</b:bean>
4.7.15. RequestCacheAwareFilter
RequestCacheAwareFilter
removed the setRequestCache
in favor of constructor injection.
For example:
RequestCacheAwareFilter filter = new RequestCacheAwareFilter();
filter.setRequestCache(requestCache);
should be replaced with
RequestCacheAwareFilter filter = new RequestCacheAwareFilter(requestCache);
and
<b:bean class="org.springframework.security.web.savedrequest.RequestCacheAwareFilter">
<b:property name="requestCache" ref="requestCache"/>
</b:bean>
should be replaced with
<b:bean class="org.springframework.security.web.savedrequest.RequestCacheAwareFilter">
<b:constructor-arg ref="requestCache"/>
</b:bean>
4.7.16. ConcurrentSessionFilter
ConcurrentSessionFilter
removed the default constructor and the setExpiredUrl
and setSessionRegistry
methods in favor of constructor injection.
For example:
ConcurrentSessionFilter filter = new ConcurrentSessionFilter();
filter.setSessionRegistry(sessionRegistry);
filter.setExpiredUrl("/expired");
should be replaced with
ConcurrentSessionFilter filter = new ConcurrentSessionFilter(sessionRegistry,"/expired");
and
<b:bean class="org.springframework.security.web.session.ConcurrentSessionFilter">
<b:property name="sessionRegistry" ref="sessionRegistry"/>
</b:bean>
should be replaced with
<b:bean class="org.springframework.security.web.session.ConcurrentSessionFilter">
<b:constructor-arg ref="sessionRegistry"/>
</b:bean>
4.7.17. SessionManagementFilter
SessionManagementFilter
removed the setSessionAuthenticationStrategy
method in favor of constructor injection.
For example:
SessionManagementFilter filter = new SessionManagementFilter(securityContextRepository);
filter.setSessionAuthenticationStrategy(sessionAuthenticationStrategy);
should be replaced with
SessionManagementFilter filter = new SessionManagementFilter(securityContextRepository, sessionAuthenticationStrategy);
and
<b:bean class="org.springframework.security.web.session.SessionManagementFilter">
<b:constructor-arg ref="securityContextRepository"/>
<b:property name="sessionAuthenticationStrategy" ref="sessionAuthenticationStrategy"/>
</b:bean>
should be replaced with
<b:bean class="org.springframework.security.web.session.SessionManagementFilter">
<b:constructor-arg ref="securityContextRepository"/>
<b:constructor-arg ref="sessionAuthenticationStrategy"/>
</b:bean>
4.7.18. RequestMatcher
The RequestMatcher
and its implementations have moved from the package org.springframework.security.web.util
to org.springframework.security.web.util.matcher
.
Specifically
-
org.springframework.security.web.util.RequestMatcher
→org.springframework.security.web.util.matcher.RequestMatcher
-
org.springframework.security.web.util.AntPathRequestMatcher
→org.springframework.security.web.util.matcher.AntPathRequestMatcher
-
org.springframework.security.web.util.AnyRequestMatcher
→org.springframework.security.web.util.matcher.AnyRequestMatcher.INSTANCE
-
org.springframework.security.web.util.ELRequestMatcher
→org.springframework.security.web.util.matcher.ELRequestMatcher
-
org.springframework.security.web.util.IpAddressMatcher
→org.springframework.security.web.util.matcher.IpAddressMatcher
-
org.springframework.security.web.util.RequestMatcherEditor
→org.springframework.security.web.util.matcher.RequestMatcherEditor
-
org.springframework.security.web.util.RegexRequestMatcher
→org.springframework.security.web.util.matcher.RegexRequestMatcher
4.7.19. WebSecurityExpressionHandler
WebSecurityExpressionHandler
was removed in favor of using SecurityExpressionHandler<FilterInvocation>
.
This means if you are using:
WebSecurityExpressionHandler handler = ...
it needs to be updated to
SecurityExpressionHandler<FilterInvocation> handler = ...
If you implement WebSecurityExpressionHandler:
public class CustomWebSecurityExpressionHandler implements WebSecurityExpressionHandler {
...
}
then it must be updated to:
public class CustomWebSecurityExpressionHandler implements SecurityExpressionHandler<FilterInvocation> {
...
}
4.7.20. @AuthenticationPrincipal
org.springframework.security.web.bind.annotation.AuthenticationPrincipal
has been deprecated in favor of org.springframework.security.core.annotation.AuthenticationPrincipal
.
For example:
import org.springframework.security.web.bind.annotation.AuthenticationPrincipal;
// ...
@RequestMapping("/messages/inbox")
public ModelAndView findMessagesForUser(@AuthenticationPrincipal CustomUser customUser) {
// .. find messags for this user and return them ...
}
should be replaced with
import org.springframework.security.core.annotation.AuthenticationPrincipal;
// ...
@RequestMapping("/messages/inbox")
public ModelAndView findMessagesForUser(@AuthenticationPrincipal CustomUser customUser) {
// .. find messags for this user and return them ...
}
and
<mvc:annotation-driven>
<mvc:argument-resolvers>
<b:bean class="org.springframework.security.web.bind.support.AuthenticationPrincipalArgumentResolver" />
</mvc:argument-resolvers>
</mvc:annotation-driven>
should be replaced with
<mvc:annotation-driven>
<mvc:argument-resolvers>
<b:bean class="org.springframework.security.web.method.annotation.AuthenticationPrincipalArgumentResolver" />
</mvc:argument-resolvers>
</mvc:annotation-driven>
5. Update Spring Security
Now you can update to Spring Security 4.x. If you are using Maven and Spring Security’s BOM, you can do something like this:
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-bom</artifactId>
<version>4.0.0.RELEASE</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
Now all of the Spring Security dependencies that do not specify a version will use the updated Spring Security version.
Alternatively, you can update each of the Spring Security dependencies within your pom. For example, the following would update spring-security-core to use version 4.0.0.RELEASE
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-core</artifactId>
<version>4.0.0.RELEASE</version>
</dependency>
6. Migrate XML Namespace Defaults
We updated the default values for many of the Spring Security XML Namespace Elements. You can find a detailed list of changes and how to address them below.
If you do not use XML based configuration, you may safely skip this section and proceed to Migrate Default Filter URLs |
6.1. Related Links
For thoroughness we have include the related links in the table below.
JIRA | Commits |
---|---|
6.2. Migrate <http>
The http@use-expressions attribute’s default value changed from false to true. This means if the use-expression attribute is not explicitly configured, then the configuration will need updated. For example, if an application using Spring Security 3.2.x contains a configuration similar to the following:
<http> (1)
<intercept-url pattern="/login" access="ROLE_ANONYMOUS"/>
<intercept-url pattern="/**" access="ROLE_USER"/>
...
</http>
1 | Observe that the use-expressions attribute is not provided. If it were provided, then nothing needs to be done. |
The configuration will need to be updated to something similar to the following when Spring Security 4.x:
<http use-expressions="false"> (1)
<intercept-url pattern="/login" access="ROLE_ANONYMOUS"/>
<intercept-url pattern="/**" access="ROLE_USER"/>
...
</http>
1 | We explicitly provide the use-expressions attribute. Again, if the attribute was already provided, then nothing needs to be done. |
Alternatively, the application can omit the the use-expressions attribute and switch to using expressions. For example, something similar to the following:
<http>
<intercept-url pattern="/login" access="permitAll"/>
<intercept-url pattern="/**" access="hasRole('USER')"/>
...
</http>
The http@disable-url-rewriting attribute’s default value changed from false to true.
It is recommended to disable url rewriting to prevent the JSESSIONID from being included in URLs. If your application does not use url rewriting, then it is preferrable to leave this attribute set to the default value. |
This means if the disable-url-rewriting attribute is not explicitly configured and you are relying on url rewriting, then the configuration will need updated. For example, if an application using Spring Security 3.2.x contains a configuration similar to the following:
<http> (1)
...
</http>
1 | Observe that the disable-url-rewriting attribute is not provided. If it were provided, then nothing needs to be done. |
The configuration will need to be updated to something similar to the following when Spring Security 4.x:
<http disable-url-rewriting="false"> (1)
...
</http>
1 | We explicitly provide the disable-url-rewriting attribute. Again, if the attribute was already provided, then nothing needs to be done. |
6.3. Migrating <form-login>
If the <form-login>
is being used within an application, then some of the default attributes have changed.
Below are detailed description of the changes and how to migrate:
-
The form-login@username-parameter attribute default value changed from j_username to username. If an application explicitly provides the attribute, no action is required for the migration.
-
The form-login@password-parameter attribute default value changed from j_password to password. If an application explicitly provides the attribute, no action is required for the migration.
-
The form-login@login-processing-url attribute default value changed from /j_spring_security_check to POST /login. If an application explicitly provides the attribute, no action is required for the migration.
-
The form-login@authentication-failure-url attribute default value changed from appending ?login_error to the login-page to appending ?error to the login-page. If an application explicitly provides the attribute, no action is required for the migration.
These changes mean if you have the following configuration within your XML configuration when using Spring Security 3.2.x:
<http>
...
<form-login login-page="/login"/>
</http>
You will need to migrate by explicitly configuring the attributes that have new default values when migrating to Spring Security 4.x:
Any attribute that is already explicitly provided will not be impacted and requires no action. |
<http>
...
<form-login login-page="/login"
username-parameter="j_username" (1)
password-parameter="j_password" (2)
login-processing-url="/j_spring_security_check" (3)
authentication-failure-url="/login?login_error=1" (4)
/>
</http>
1 | If the configuration does not specify the username-parameter, then it should be explicitly stated |
2 | If the configuration does not specify the password-parameter, then it should be explicitly stated |
3 | If the configuration does not specify the login-processing-url, then it should be explicitly stated |
4 | If the configuration does not specify the authentication-failure-url, then it should be explicitly stated |
Alternatively, the application can be updated to use the new defaults. For example, one might update their log in form to look like the following:
<c:if test="${param.error != null}"> (1)
<p>Invalid username / password</p>
</c:if>
<c:url var="loginUrl" value="/login"/> (2)
<form action="${loginUrl}" method="post">
<p><label for="username">User:</label></p>
<input type="text" id="username" name="username"/> (3)
<p><label for="password">Password:</label></p>
<input type="password" id="password" name="password"> (4)
<div>
<input name="submit" type="submit"/>
</div>
</form>
1 | If the configuration does not specify the authentication-failure-url, then detect that an invalid log in check to see if the HTTP parameter error is not null. |
2 | If the configuration does not specify the login-processing-url, then modify the URL to submit to be "/login" |
3 | If the configuration does not specify the username-parameter, then modify the username HTTP parameter to be "username" |
4 | If the configuration does not specify the password-parameter, then modify the password HTTP parameter to be "password" |
6.4. Migrating <logout>
If the <logout>
is being used within an application, then some of the default attributes have changed.
Below are detailed description of the changes and how to migrate:
-
The logout@logout-url attribute default value changed from "/j_spring_security_logout" to "/logout". If an application explicitly provides the attribute, no action is required for the migration.
These changes mean if you have the following configuration within your XML configuration when using Spring Security 3.2.x:
<http>
...
<logout/>
</http>
You will need to migrate by explicitly configuring the logout-url attribute when migrating to Spring Security 4.x:
If the logout-url attribute is already explicitly provided the application will not be impacted and no action is required. |
<http>
...
<logout logout-url="/j_spring_security_logout"/> (1)
/>
</http>
1 | If the configuration does not specify the logout-url attribute, then it should be explicitly stated |
Alternatively, the application can be updated to use the new defaults.
-
The logout@logout-success-url attribute default value changed from "/" to the log in page + "?logout". For example, if the log in page is "/login", then the log out success page is "/login?logout". If an application explicitly provides the attribute, no action is required for the migration.
These changes mean if you have the following configuration within your XML configuration when using Spring Security 3.2.x:
<http>
...
<logout/>
</http>
You will need to migrate by explicitly configuring the logout-success-url attribute when migrating to Spring Security 4.x:
If the logout-success-url attribute is already explicitly provided the application will not be impacted and no action is required. |
<http>
...
<logout logout-success-url="/"/> (1)
/>
</http>
1 | If the configuration does not specify the logout-success-url attribute, then it should be explicitly stated |
Alternatively, the application can be updated to use the new defaults.
6.5. Migrating <openid-login>
The openid-login@login-processing-url attribute default value changed from /j_spring_openid_security_check to /login/openid.
This means if the login-processing-url attribute is not explicitly configured, then the configuration will need updated. For example, if an application using Spring Security 3.2.x contains a configuration similar to the following:
<http>
<openid-login /> (1)
...
</http>
1 | Observe that the login-processing-url attribute is not provided. If it were provided, then nothing needs to be done. |
The configuration will need to be updated to something similar to the following when Spring Security 4.x:
<http>
<openid-login login-processing-url="/j_spring_openid_security_check"/> (1)
...
</http>
1 | We explicitly provide the login-processing-url attribute. Again, if the attribute was already provided, then nothing needs to be done. |
Alternatively, the application can omit the the login-processing-url attribute and update the log in form. For example, something similar to the following:
<c:url var="openidLoginUrl" value="/login/openid"/> (1)
<form action="${openidLoginUrl}" method="post">
<div>
<input name="openid_identifier" type="text" value="http://" />
<input type="submit" value="Sign-In"/>
</div>
</form>
1 | If the configuration does not specify the login-processing-url attribute, then update the log in action to "/login/openid". |
6.6. Migrating <headers>
As Spring Security 4.0+ Security HTTP Response Headers is now enabled by default. This means if an application did not provide the headers element, then the configuration will need updated. For example, if an application using Spring Security 3.2.x contains a configuration similar to the following:
<http>
...
<!-- no headers element -->
</http>
The application will need updated. The quickest, but not ideal, solution is to explicitly disable the headers protection using headers@disabled. For example:
<http>
...
<headers disabled="true"/>
</http>
Alternatively, the application would enable Security HTTP Response Headers. In many instances, leaving the Security HTTP Response Headers enabled will not have a negative impact on an application.
Strict Transport Security will cause infinite redirects if anywhere within your domain forcefully redirects from HTTPS to HTTP for a subset of pages. If your domain forcfully redirects to HTTP when HTTPS is requested, you will need to ensure to remove the redirect (recommended) or disable Strict Transport Security. |
Developers are encouraged to read Security HTTP Response Headers for details on using this feature.
6.7. Migrating <csrf>
As Spring Security 4.0+ CSRF Protection is now enabled by default. This means if an application did not provide the csrf element, then the configuration will need updated. For example, if an application using Spring Security 3.2.x contains a configuration similar to the following:
<http>
...
<!-- no csrf element -->
</http>
The application will need updated. The quickest, but not ideal, solution is to explicitly disable the csrf protection using csrf@disabled. For example:
<http>
...
<csrf disabled="true"/>
</http>
Alternatively, the application would enable CSRF. For more details refer to Using Spring Security CSRF Protection
6.8. Migrating <remember-me>
If the <remember-me>
element is being used within an application, then some of the default attributes have changed.
Below are detailed description of the changes and how to migrate:
-
The remember-me@remember-me-parameter attribute default value changed from "_spring_security_remember_me" to "remember-me". If an application explicitly provides the attribute, no action is required for the migration.
-
The remember-me@remember-me-cookie attribute default value changed from "SPRING_SECURITY_REMEMBER_ME_COOKIE" to "remember-me". If an application explicitly provides the attribute, no action is required for the migration.
These changes mean if you have the following configuration within your XML configuration when using Spring Security 3.2.x:
<http>
...
<remember-me />
</http>
You will need to migrate by explicitly configuring the attributes that have new default values when migrating to Spring Security 4.x:
Any attribute that is already explicitly provided will not be impacted and requires no action. |
<http>
...
<remember-me
remember-me-parameter="_spring_security_remember_me" (1)
remember-me-cookie="SPRING_SECURITY_REMEMBER_ME_COOKIE" (2)
/>
</http>
1 | If the configuration does not specify the remember-me-parameter, then it should be explicitly stated |
2 | If the configuration does not specify the remember-me-cookie, then it should be explicitly stated |
Alternatively, the application can be updated to use the new defaults. For example, one might update their log in form to look like the following:
<c:url var="loginUrl" value="/login"/>
<form action="${loginUrl}" method="post">
...
<p><label for="remember-me">Remember Me</label></p>
<input type="checkbox" id="remember-me" name="remember-me"/> (1)
<div>
<input name="submit" type="submit"/>
</div>
</form>
1 | If the configuration does not specify the remember-me-parameter, then update the HTTP parameter name to be remember-me |
This approach means that previously remembered users will be forgotten since the remember me cookie name will change. If you are fine with users needing to authenticate again, then nothing is required. If you do not want users to authenticate, then the cookie name must be set to SPRING_SECURITY_REMEMBER_ME_COOKIE as illustrated above. |
6.9. Migrating <filter-security-metadata-source>
The filter-security-metadata-source@use-expressions attribute’s default value changed from false to true. This means if the use-expression attribute is not explicitly configured, then the configuration will need updated. For example, if an application using Spring Security 3.2.x contains a configuration similar to the following:
<filter-security-metadata-source> (1)
<intercept-url pattern="/login" access="ROLE_ANONYMOUS"/>
<intercept-url pattern="/**" access="ROLE_USER"/>
...
</filter-security-metadata-source>
1 | Observe that the use-expressions attribute is not provided. If it were provided, then nothing needs to be done. |
The configuration will need to be updated to something similar to the following when Spring Security 4.x:
<filter-security-metadata-source use-expressions="false"> (1)
<intercept-url pattern="/login" access="ROLE_ANONYMOUS"/>
<intercept-url pattern="/**" access="ROLE_USER"/>
...
</filter-security-metadata-source>
1 | We explicitly provide the use-expressions attribute. Again, if the attribute was already provided, then nothing needs to be done. |
Alternatively, the application can omit the the use-expressions attribute and switch to using expressions. For example, something similar to the following:
<filter-security-metadata-source>
<intercept-url pattern="/login" access="permitAll"/>
<intercept-url pattern="/**" access="hasRole('USER')"/>
...
</filter-security-metadata-source>
7. Migrate Default Filter URLs
A number of servlet Filter’s had their default URLs switched to help guard against information leakage.
7.1. Related Links
For thoroughness we have include the related links in the table below.
JIRA | Commits |
---|---|
7.2. CasAuthenticationFilter
The CasAuthenticationFilter
filterProcessesUrl property default value changed from "/j_spring_cas_security_check" to "/login/cas".
This means if the filterProcessesUrl property is not explicitly specified, then the configuration will need updated.
For example, if an application using Spring Security 3.2.x contains a configuration similar to the following:
<b:bean id="casFilter"
class="org.springframework.security.cas.web.CasAuthenticationFilter">
<b:property name="authenticationManager" ref="authenticationManager"/>
</b:bean>
The configuration will need to be updated to something similar to the following when Spring Security 4.x:
<b:bean id="casFilter"
class="org.springframework.security.cas.web.CasAuthenticationFilter">
<b:property name="authenticationManager" ref="authenticationManager"/>
<b:property name="filterProcessesUrl" value="/j_spring_cas_security_check"/>
</b:bean>
Alternatively, the ServiceProperties
can be updated to use the new default:
<bean id="serviceProperties"
class="org.springframework.security.cas.ServiceProperties">
<property name="service"
value="https://example.com/cas-sample/login/cas"/>
</bean>
7.3. SwitchUserFilter
-
The
SwitchUserFilter
switchUserUrl property default value changed from "/j_spring_security_switch_user" to "/login/impersonate". This means if the switchUserUrl property is not explicitly specified, then the configuration will need updated. -
The
SwitchUserFilter
exitUserUrl property default value changed from "/j_spring_security_exit_user" to "/logout/impersonate". This means if the exitUserUrl property is not explicitly specified, then the configuration will need updated.
For example, if an application using Spring Security 3.2.x contains a configuration similar to the following:
<b:bean id="switchUserProcessingFilter" class="org.springframework.security.web.authentication.switchuser.SwitchUserFilter">
<b:property name="userDetailsService" ref="userDetailsService" />
<b:property name="targetUrl" value="/" />
</b:bean>
The configuration will need to be updated to something similar to the following when Spring Security 4.x:
<b:bean id="switchUserProcessingFilter" class="org.springframework.security.web.authentication.switchuser.SwitchUserFilter">
<b:property name="switchUserUrl" value="/j_spring_security_switch_user" />
<b:property name="exitUserUrl" value="/j_spring_security_exit_user" />
<b:property name="userDetailsService" ref="userDetailsService" />
<b:property name="targetUrl" value="/" />
</bean>
Alternatively, the URL’s within the application can be updated from:
-
"/j_spring_security_switch_user" to "/login/impersonate"
-
"/j_spring_security_exit_user" to "/logout/impersonate"
7.4. LogoutFilter
The LogoutFilter
filterProcessesUrl property default value changed from "/j_spring_security_logout" to "/logout".
This means if the filterProcessesUrl property is not explicitly specified, then the configuration will need updated.
For example, if an application using Spring Security 3.2.x contains a configuration similar to the following:
<b:bean id="logoutFilter" class="org.springframework.security.web.authentication.logout.LogoutFilter">
<b:constructor-arg value="/logout-success"/>
<b:constructor-arg>
<b:bean class="org.springframework.security.web.authentication.logout.SecurityContextLogoutHandler"/>
</b:constructor-arg>
</b:bean>
The configuration will need to be updated to something similar to the following when Spring Security 4.x:
<b:bean id="logoutFilter" class="org.springframework.security.web.authentication.logout.LogoutFilter">
<b:constructor-arg value="/logout-success"/>
<b:constructor-arg>
<b:bean class="org.springframework.security.web.authentication.logout.SecurityContextLogoutHandler"/>
</b:constructor-arg>
<b:property name="filterProcessesUrl" value="/j_spring_security_logout"/>
</b:bean>
Alternatively, the URL’s within the application can be updated from "/j_spring_security_logout" to "/logout".
8. Header Configuration Changes
In Spring Security 3.x the HTTP Response Header configuration was difficult to customize. If an application overrode a single default, then all of the other defaults would be disabled. This was unintuitive, error prone, and most importantly not very secure.
Spring Security 4.x has changed both the Java Configuration and XML Configuration to require explicit disabling of defaults. Additionally, it has made customizing a single default much easier.
If an application has customized the HTTP Response Header Configuration in any way, they are impacted by this change. If the application used the defaults, then they are not impacted by this change.
A detailed description of how to configure Security HTTP Response Headers can be found in the reference. Below we highlight the changes in configuring the Security HTTP Response Headers between 3.x and 4.x.
8.1. Related Links
For thoroughness we have include the related links in the table below.
JIRA | Commits |
---|---|
8.2. Header Samples
In Spring Security 3.x, the following configuration
<http>
<headers>
<frame-options policy="SAMEORIGIN"/>
</headers>
...
</http>
would add the following header:
X-Frame-Options: SAMEORIGIN
In Spring Security 4.x, the same configuration would add
Cache-Control: no-cache, no-store, max-age=0, must-revalidate
Pragma: no-cache
Expires: 0
X-Content-Type-Options: nosniff
Strict-Transport-Security: max-age=31536000 ; includeSubDomains
X-Frame-Options: SAMEORIGIN
X-XSS-Protection: 1; mode=block
If we want to the configuration the same, we must explicitly disable the other defaults.
<http>
...
<headers defaults-disabled="true">
<frame-options policy="SAMEORIGIN"/>
</headers>
would add the following header:
X-Frame-Options: SAMEORIGIN
9. Automatic ROLE_ prefixing
Spring Security 4 automatically prefixes any role with ROLE_. The changes were made as part of SEC-2758
9.1. Related Links
For thoroughness we have include the related links in the table below.
JIRA | Commits |
---|---|
9.2. ROLE_ Prefixing Passivity
Passivity is impacted if the application’s users' roles are not prefixed with ROLE_. If all of the application’s users' roles are prefixed with ROLE_ then it is NOT impacted.
9.3. Disable ROLE_ Prefixing
One can disable automatic ROLE_ prefixing using a BeanPostProcessor
similar to the following:
package sample.role_;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.core.PriorityOrdered;
import org.springframework.security.access.annotation.Jsr250MethodSecurityMetadataSource;
import org.springframework.security.access.expression.method.DefaultMethodSecurityExpressionHandler;
import org.springframework.security.web.access.expression.DefaultWebSecurityExpressionHandler;
import org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter;
public class DefaultRolesPrefixPostProcessor implements BeanPostProcessor, PriorityOrdered {
@Override
public Object postProcessAfterInitialization(Object bean, String beanName)
throws BeansException {
// remove this if you are not using JSR-250
if(bean instanceof Jsr250MethodSecurityMetadataSource) {
((Jsr250MethodSecurityMetadataSource) bean).setDefaultRolePrefix(null);
}
if(bean instanceof DefaultMethodSecurityExpressionHandler) {
((DefaultMethodSecurityExpressionHandler) bean).setDefaultRolePrefix(null);
}
if(bean instanceof DefaultWebSecurityExpressionHandler) {
((DefaultWebSecurityExpressionHandler) bean).setDefaultRolePrefix(null);
}
if(bean instanceof SecurityContextHolderAwareRequestFilter) {
((SecurityContextHolderAwareRequestFilter)bean).setRolePrefix("");
}
return bean;
}
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName)
throws BeansException {
return bean;
}
@Override
public int getOrder() {
return PriorityOrdered.HIGHEST_PRECEDENCE;
}
}
and then defining it as a Bean:
<b:bean class="sample.role_.DefaultRolesPrefixPostProcessor"/>