How to customize Spring Security switch user? - spring-security

I have enabled switch user in my web app. Now I'd like to do something similar on the mobile app however the target URL should be different.
On web app the target URL is /account (returns jsp)
On mobile app I expect the target URL to be rest/member/account (returns json)
I tried the following but it didn't do it
public class MySwitchUserFilter extends SwitchUserFilter {
#Override
public void doFilter(ServletRequest req, ServletResponse res,
FilterChain chain) throws IOException, ServletException {
HttpServletRequest request = (HttpServletRequest) req;
HttpServletResponse response = (HttpServletResponse) res;
if (request.getParameter("android") != null)
this.setTargetUrl("/rest/member/account");
else
this.setTargetUrl("/account");
super.doFilter(request, response, chain);
}
}
My Spring Security context
<beans:bean id="switchUserFilter"
class="com.myapp.auth.MySwitchUserFilter">
<beans:property name="userDetailsService" ref="userDetailsService" />
<beans:property name="switchUserUrl" value="/admin/j_spring_security_switch_user" />
<beans:property name="exitUserUrl" value="/j_spring_security_exit_user" />
<beans:property name="targetUrl" value="/account" />
</beans:bean>
When I execute below URL in browser I get Access is Denied
https://localhost:8443/business/admin/j_spring_security_switch_user?j_username=test&android=1
Log
DEBUG: org.springframework.security.web.FilterChainProxy - /admin/j_spring_security_switch_user?j_username=test&android=1 at position 1 of 12 in additional filter chain; firing Filter: 'ChannelProcessingFilter'
DEBUG: org.springframework.security.web.util.matcher.AntPathRequestMatcher - Checking match of request : '/admin/j_spring_security_switch_user'; against '/login'
DEBUG: org.springframework.security.web.util.matcher.AntPathRequestMatcher - Checking match of request : '/admin/j_spring_security_switch_user'; against '/authentication'
DEBUG: org.springframework.security.web.util.matcher.AntPathRequestMatcher - Checking match of request : '/admin/j_spring_security_switch_user'; against '/forgot'
DEBUG: org.springframework.security.web.util.matcher.AntPathRequestMatcher - Checking match of request : '/admin/j_spring_security_switch_user'; against '/resources/**'
DEBUG: org.springframework.security.web.util.matcher.AntPathRequestMatcher - Checking match of request : '/admin/j_spring_security_switch_user'; against '/admin/**'
DEBUG: org.springframework.security.web.access.channel.ChannelProcessingFilter - Request: FilterInvocation: URL: /admin/j_spring_security_switch_user?j_username=test&android=1; ConfigAttributes: [REQUIRES_SECURE_CHANNEL]
DEBUG: org.springframework.security.web.FilterChainProxy - /admin/j_spring_security_switch_user?j_username=test&android=1 at position 2 of 12 in additional filter chain; firing Filter: 'SecurityContextPersistenceFilter'
DEBUG: org.springframework.security.web.context.HttpSessionSecurityContextRepository - Obtained a valid SecurityContext from SPRING_SECURITY_CONTEXT: 'org.springframework.security.core.context.SecurityContextImpl#fd6ed5da: Authentication: org.springframework.security.authentication.UsernamePasswordAuthenticationToken#fd6ed5da: Principal: com.myapp.auth.AuthenticationUserDetails#1259255; Credentials: [PROTECTED]; Authenticated: true; Details: org.springframework.security.web.authentication.WebAuthenticationDetails#b364: RemoteIpAddress: 0:0:0:0:0:0:0:1; SessionId: EAE58863B5C733E17CDC0DFEEEE131CB; Granted Authorities: ADMIN'
DEBUG: org.springframework.security.web.FilterChainProxy - /admin/j_spring_security_switch_user?j_username=test&android=1 at position 3 of 12 in additional filter chain; firing Filter: 'WebAsyncManagerIntegrationFilter'
DEBUG: org.springframework.security.web.FilterChainProxy - /admin/j_spring_security_switch_user?j_username=test&android=1 at position 4 of 12 in additional filter chain; firing Filter: 'LogoutFilter'
DEBUG: org.springframework.security.web.FilterChainProxy - /admin/j_spring_security_switch_user?j_username=test&android=1 at position 5 of 12 in additional filter chain; firing Filter: 'BrowserAuthenticationFilter'
DEBUG: org.springframework.security.web.FilterChainProxy - /admin/j_spring_security_switch_user?j_username=test&android=1 at position 6 of 12 in additional filter chain; firing Filter: 'RequestCacheAwareFilter'
DEBUG: org.springframework.security.web.FilterChainProxy - /admin/j_spring_security_switch_user?j_username=test&android=1 at position 7 of 12 in additional filter chain; firing Filter: 'SecurityContextHolderAwareRequestFilter'
DEBUG: org.springframework.security.web.FilterChainProxy - /admin/j_spring_security_switch_user?j_username=test&android=1 at position 8 of 12 in additional filter chain; firing Filter: 'AnonymousAuthenticationFilter'
DEBUG: org.springframework.security.web.authentication.AnonymousAuthenticationFilter - SecurityContextHolder not populated with anonymous token, as it already contained: 'org.springframework.security.authentication.UsernamePasswordAuthenticationToken#fd6ed5da: Principal: com.myapp.auth.AuthenticationUserDetails#1259255; Credentials: [PROTECTED]; Authenticated: true; Details: org.springframework.security.web.authentication.WebAuthenticationDetails#b364: RemoteIpAddress: 0:0:0:0:0:0:0:1; SessionId: EAE58863B5C733E17CDC0DFEEEE131CB; Granted Authorities: ADMIN'
DEBUG: org.springframework.security.web.FilterChainProxy - /admin/j_spring_security_switch_user?j_username=test&android=1 at position 9 of 12 in additional filter chain; firing Filter: 'SessionManagementFilter'
DEBUG: org.springframework.security.web.FilterChainProxy - /admin/j_spring_security_switch_user?j_username=test&android=1 at position 10 of 12 in additional filter chain; firing Filter: 'ExceptionTranslationFilter'
DEBUG: org.springframework.security.web.FilterChainProxy - /admin/j_spring_security_switch_user?j_username=test&android=1 at position 11 of 12 in additional filter chain; firing Filter: 'FilterSecurityInterceptor'
DEBUG: org.springframework.security.web.util.matcher.AntPathRequestMatcher - Checking match of request : '/admin/j_spring_security_switch_user'; against '/login'
DEBUG: org.springframework.security.web.util.matcher.AntPathRequestMatcher - Checking match of request : '/admin/j_spring_security_switch_user'; against '/authentication'
DEBUG: org.springframework.security.web.util.matcher.AntPathRequestMatcher - Checking match of request : '/admin/j_spring_security_switch_user'; against '/forgot'
DEBUG: org.springframework.security.web.util.matcher.AntPathRequestMatcher - Checking match of request : '/admin/j_spring_security_switch_user'; against '/resources/**'
DEBUG: org.springframework.security.web.util.matcher.AntPathRequestMatcher - Checking match of request : '/admin/j_spring_security_switch_user'; against '/admin/**'
DEBUG: org.springframework.security.web.access.intercept.FilterSecurityInterceptor - Secure object: FilterInvocation: URL: /admin/j_spring_security_switch_user?j_username=test&android=1; Attributes: [hasAnyRole('ADMIN')]
DEBUG: org.springframework.security.web.access.intercept.FilterSecurityInterceptor - Previously Authenticated: org.springframework.security.authentication.UsernamePasswordAuthenticationToken#fd6ed5da: Principal: com.myapp.auth.AuthenticationUserDetails#1259255; Credentials: [PROTECTED]; Authenticated: true; Details: org.springframework.security.web.authentication.WebAuthenticationDetails#b364: RemoteIpAddress: 0:0:0:0:0:0:0:1; SessionId: EAE58863B5C733E17CDC0DFEEEE131CB; Granted Authorities: ADMIN
DEBUG: org.springframework.security.access.vote.AffirmativeBased - Voter: org.springframework.security.web.access.expression.WebExpressionVoter#1410588, returned: 1
DEBUG: org.springframework.security.web.access.intercept.FilterSecurityInterceptor - Authorization successful
DEBUG: org.springframework.security.web.access.intercept.FilterSecurityInterceptor - RunAsManager did not change Authentication object
DEBUG: org.springframework.security.web.FilterChainProxy - /admin/j_spring_security_switch_user?j_username=test&android=1 at position 12 of 12 in additional filter chain; firing Filter: 'MySwitchUserFilter'
DEBUG: org.springframework.security.web.util.matcher.AntPathRequestMatcher - Checking match of request : '/admin/j_spring_security_switch_user'; against '/rest/**'
DEBUG: org.springframework.security.web.FilterChainProxy - /admin/j_spring_security_switch_user?j_username=test&android=1 at position 1 of 12 in additional filter chain; firing Filter: 'ChannelProcessingFilter'
DEBUG: org.springframework.security.web.util.matcher.AntPathRequestMatcher - Checking match of request : '/admin/j_spring_security_switch_user'; against '/login'
DEBUG: org.springframework.security.web.util.matcher.AntPathRequestMatcher - Checking match of request : '/admin/j_spring_security_switch_user'; against '/authentication'
DEBUG: org.springframework.security.web.util.matcher.AntPathRequestMatcher - Checking match of request : '/admin/j_spring_security_switch_user'; against '/forgot'
DEBUG: org.springframework.security.web.util.matcher.AntPathRequestMatcher - Checking match of request : '/admin/j_spring_security_switch_user'; against '/resources/**'
DEBUG: org.springframework.security.web.util.matcher.AntPathRequestMatcher - Checking match of request : '/admin/j_spring_security_switch_user'; against '/admin/**'
DEBUG: org.springframework.security.web.access.channel.ChannelProcessingFilter - Request: FilterInvocation: URL: /admin/j_spring_security_switch_user?j_username=test&android=1; ConfigAttributes: [REQUIRES_SECURE_CHANNEL]
DEBUG: org.springframework.security.web.FilterChainProxy - /admin/j_spring_security_switch_user?j_username=test&android=1 at position 2 of 12 in additional filter chain; firing Filter: 'SecurityContextPersistenceFilter'
DEBUG: org.springframework.security.web.context.HttpSessionSecurityContextRepository - Obtained a valid SecurityContext from SPRING_SECURITY_CONTEXT: 'org.springframework.security.core.context.SecurityContextImpl#91b8a7a: Authentication: org.springframework.security.authentication.UsernamePasswordAuthenticationToken#91b8a7a: Principal: com.myapp.auth.AuthenticationUserDetails#194a73d; Credentials: [PROTECTED]; Authenticated: true; Details: org.springframework.security.web.authentication.WebAuthenticationDetails#b364: RemoteIpAddress: 0:0:0:0:0:0:0:1; SessionId: EAE58863B5C733E17CDC0DFEEEE131CB; Granted Authorities: MEMBER, Switch User Authority [ROLE_PREVIOUS_ADMINISTRATOR,org.springframework.security.authentication.UsernamePasswordAuthenticationToken#fd6ed5da: Principal: com.myapp.auth.AuthenticationUserDetails#1259255; Credentials: [PROTECTED]; Authenticated: true; Details: org.springframework.security.web.authentication.WebAuthenticationDetails#b364: RemoteIpAddress: 0:0:0:0:0:0:0:1; SessionId: EAE58863B5C733E17CDC0DFEEEE131CB; Granted Authorities: ADMIN]'
DEBUG: org.springframework.security.web.FilterChainProxy - /admin/j_spring_security_switch_user?j_username=test&android=1 at position 3 of 12 in additional filter chain; firing Filter: 'WebAsyncManagerIntegrationFilter'
DEBUG: org.springframework.security.web.FilterChainProxy - /admin/j_spring_security_switch_user?j_username=test&android=1 at position 4 of 12 in additional filter chain; firing Filter: 'LogoutFilter'
DEBUG: org.springframework.security.web.FilterChainProxy - /admin/j_spring_security_switch_user?j_username=test&android=1 at position 5 of 12 in additional filter chain; firing Filter: 'BrowserAuthenticationFilter'
DEBUG: org.springframework.security.web.FilterChainProxy - /admin/j_spring_security_switch_user?j_username=test&android=1 at position 6 of 12 in additional filter chain; firing Filter: 'RequestCacheAwareFilter'
DEBUG: org.springframework.security.web.FilterChainProxy - /admin/j_spring_security_switch_user?j_username=test&android=1 at position 7 of 12 in additional filter chain; firing Filter: 'SecurityContextHolderAwareRequestFilter'
DEBUG: org.springframework.security.web.FilterChainProxy - /admin/j_spring_security_switch_user?j_username=test&android=1 at position 8 of 12 in additional filter chain; firing Filter: 'AnonymousAuthenticationFilter'
DEBUG: org.springframework.security.web.authentication.AnonymousAuthenticationFilter - SecurityContextHolder not populated with anonymous token, as it already contained: 'org.springframework.security.authentication.UsernamePasswordAuthenticationToken#91b8a7a: Principal: com.myapp.auth.AuthenticationUserDetails#194a73d; Credentials: [PROTECTED]; Authenticated: true; Details: org.springframework.security.web.authentication.WebAuthenticationDetails#b364: RemoteIpAddress: 0:0:0:0:0:0:0:1; SessionId: EAE58863B5C733E17CDC0DFEEEE131CB; Granted Authorities: MEMBER, Switch User Authority [ROLE_PREVIOUS_ADMINISTRATOR,org.springframework.security.authentication.UsernamePasswordAuthenticationToken#fd6ed5da: Principal: com.myapp.auth.AuthenticationUserDetails#1259255; Credentials: [PROTECTED]; Authenticated: true; Details: org.springframework.security.web.authentication.WebAuthenticationDetails#b364: RemoteIpAddress: 0:0:0:0:0:0:0:1; SessionId: EAE58863B5C733E17CDC0DFEEEE131CB; Granted Authorities: ADMIN]'
DEBUG: org.springframework.security.web.FilterChainProxy - /admin/j_spring_security_switch_user?j_username=test&android=1 at position 9 of 12 in additional filter chain; firing Filter: 'SessionManagementFilter'
DEBUG: org.springframework.security.web.FilterChainProxy - /admin/j_spring_security_switch_user?j_username=test&android=1 at position 10 of 12 in additional filter chain; firing Filter: 'ExceptionTranslationFilter'
DEBUG: org.springframework.security.web.FilterChainProxy - /admin/j_spring_security_switch_user?j_username=test&android=1 at position 11 of 12 in additional filter chain; firing Filter: 'FilterSecurityInterceptor'
DEBUG: org.springframework.security.web.util.matcher.AntPathRequestMatcher - Checking match of request : '/admin/j_spring_security_switch_user'; against '/login'
DEBUG: org.springframework.security.web.util.matcher.AntPathRequestMatcher - Checking match of request : '/admin/j_spring_security_switch_user'; against '/authentication'
DEBUG: org.springframework.security.web.util.matcher.AntPathRequestMatcher - Checking match of request : '/admin/j_spring_security_switch_user'; against '/forgot'
DEBUG: org.springframework.security.web.util.matcher.AntPathRequestMatcher - Checking match of request : '/admin/j_spring_security_switch_user'; against '/resources/**'
DEBUG: org.springframework.security.web.util.matcher.AntPathRequestMatcher - Checking match of request : '/admin/j_spring_security_switch_user'; against '/admin/**'
DEBUG: org.springframework.security.web.access.intercept.FilterSecurityInterceptor - Secure object: FilterInvocation: URL: /admin/j_spring_security_switch_user?j_username=test&android=1; Attributes: [hasAnyRole('ADMIN')]
DEBUG: org.springframework.security.web.access.intercept.FilterSecurityInterceptor - Previously Authenticated: org.springframework.security.authentication.UsernamePasswordAuthenticationToken#91b8a7a: Principal: com.myapp.auth.AuthenticationUserDetails#194a73d; Credentials: [PROTECTED]; Authenticated: true; Details: org.springframework.security.web.authentication.WebAuthenticationDetails#b364: RemoteIpAddress: 0:0:0:0:0:0:0:1; SessionId: EAE58863B5C733E17CDC0DFEEEE131CB; Granted Authorities: MEMBER, Switch User Authority [ROLE_PREVIOUS_ADMINISTRATOR,org.springframework.security.authentication.UsernamePasswordAuthenticationToken#fd6ed5da: Principal: com.myapp.auth.AuthenticationUserDetails#1259255; Credentials: [PROTECTED]; Authenticated: true; Details: org.springframework.security.web.authentication.WebAuthenticationDetails#b364: RemoteIpAddress: 0:0:0:0:0:0:0:1; SessionId: EAE58863B5C733E17CDC0DFEEEE131CB; Granted Authorities: ADMIN]
DEBUG: org.springframework.security.access.vote.AffirmativeBased - Voter: org.springframework.security.web.access.expression.WebExpressionVoter#1410588, returned: -1
DEBUG: org.springframework.security.web.access.ExceptionTranslationFilter - Access is denied (user is not anonymous); delegating to AccessDeniedHandler
org.springframework.security.access.AccessDeniedException: Access is denied
at org.springframework.security.access.vote.AffirmativeBased.decide(AffirmativeBased.java:83)
at org.springframework.security.access.intercept.AbstractSecurityInterceptor.beforeInvocation(AbstractSecurityInterceptor.java:206)
at org.springframework.security.web.access.intercept.FilterSecurityInterceptor.invoke(FilterSecurityInterceptor.java:115)
at org.springframework.security.web.access.intercept.FilterSecurityInterceptor.doFilter(FilterSecurityInterceptor.java:84)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
at org.springframework.security.web.access.ExceptionTranslationFilter.doFilter(ExceptionTranslationFilter.java:113)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
at org.springframework.security.web.session.SessionManagementFilter.doFilter(SessionManagementFilter.java:103)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
at org.springframework.security.web.authentication.AnonymousAuthenticationFilter.doFilter(AnonymousAuthenticationFilter.java:113)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
at org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter.doFilter(SecurityContextHolderAwareRequestFilter.java:154)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
at org.springframework.security.web.savedrequest.RequestCacheAwareFilter.doFilter(RequestCacheAwareFilter.java:45)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
at org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter.doF
Security Context
<beans:beans xmlns="http://www.springframework.org/schema/security"
xmlns:beans="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.2.xsd
http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-3.2.xsd">
<!-- authentication manager and password hashing -->
<authentication-manager alias="authenticationManager">
<authentication-provider ref="daoAuthenticationProvider" />
</authentication-manager>
<beans:bean id="daoAuthenticationProvider"
class="org.springframework.security.authentication.dao.DaoAuthenticationProvider">
<beans:property name="userDetailsService" ref="userDetailsService" />
<beans:property name="passwordEncoder" ref="passwordEncoder" />
</beans:bean>
<beans:bean id="authenticationSuccessHandler" class="com.myapp.auth.AuthenticationSuccessHandler"/>
<beans:bean id="userDetailsService" name="userAuthenticationProvider"
class="com.myapp.auth.AuthenticationUserDetailsGetter" />
<beans:bean id="passwordEncoder"
class="org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder">
</beans:bean>
<global-method-security pre-post-annotations="enabled" />
<!-- declare the filter bean -->
<beans:bean id="switchUserFilter"
class="com.myapp.auth.MySwitchUserFilter">
<beans:property name="userDetailsService" ref="userDetailsService" />
<beans:property name="switchUserUrl" value="/admin/j_spring_security_switch_user" />
<beans:property name="exitUserUrl" value="/j_spring_security_exit_user" />
<beans:property name="targetUrl" value="/account" />
</beans:bean>
<!-- web services-->
<http use-expressions="true" pattern="/rest/**"
disable-url-rewriting="true" entry-point-ref="restAuthenticationEntryPoint" >
<intercept-url pattern="/rest/admin/**" access="hasAnyRole('ADMIN')"
requires-channel="https" />
<intercept-url pattern="/rest/member/**" access="hasAnyRole('ADMIN,MEMBER')"
requires-channel="https" />
<form-login login-processing-url="/rest/j_spring_security_check"
authentication-success-handler-ref="restSuccessHandler"
authentication-failure-handler-ref="restAuthenticationFailureHandler" />
<logout delete-cookies="JSESSIONID" />
</http>
<!-- browser -->
<http auto-config="false" use-expressions="true"
entry-point-ref="loginUrlAuthenticationEntryPoint"
disable-url-rewriting="true">
<custom-filter ref="switchUserFilter" position="SWITCH_USER_FILTER"/>
<custom-filter ref="jqueryCaptchaProcessingFilter"
position="FORM_LOGIN_FILTER" />
<intercept-url pattern="/login" access="permitAll"
requires-channel="https" />
<intercept-url pattern="/authentication" access="permitAll"
requires-channel="https" />
<intercept-url pattern="/forgot" access="permitAll"
requires-channel="https" />
<intercept-url pattern="/resources/**" access="permitAll"
requires-channel="https" />
<!-- <intercept-url pattern="/site_**" access="permitAll"
requires-channel="https" /> -->
<intercept-url pattern="/admin/**" access="hasAnyRole('ADMIN')"
requires-channel="https" />
<intercept-url pattern="/**" access="hasAnyRole('MEMBER','ADMIN')"
requires-channel="https" />
<session-management invalid-session-url="/login"
session-authentication-error-url="/login">
</session-management>
<logout logout-url="/logout" />
</http>
<beans:bean id="jqueryCaptchaProcessingFilter"
class="com.myapp.auth.BrowserAuthenticationFilter">
<beans:property name="authenticationManager" ref="authenticationManager" />
<beans:property name="filterProcessesUrl" value="/authentication" />
<beans:property name="authenticationSuccessHandler">
<beans:bean class="com.myapp.auth.AuthenticationSuccessHandler">
<beans:property name="alwaysUseDefaultTargetUrl"
value="true" />
<beans:property name="defaultTargetUrl" value="/account" />
</beans:bean>
</beans:property>
<beans:property name="authenticationFailureHandler">
<beans:bean
class="org.springframework.security.web.authentication.SimpleUrlAuthenticationFailureHandler">
<beans:property name="defaultFailureUrl" value="/login" />
</beans:bean>
</beans:property>
</beans:bean>
<beans:bean id="loginUrlAuthenticationEntryPoint"
class="org.springframework.security.web.authentication.LoginUrlAuthenticationEntryPoint">
<beans:property name="loginFormUrl" value="/login" />
</beans:bean>
</beans:beans>

I think you can get the proper device in this way :
Set this on Android client :
DefaultHttpClient httpclient = new DefaultHttpClient();
httpclient.getParams().setParameter(CoreProtocolPNames.USER_AGENT, "android");
This will give you the headers.
And check in the request header rather then parameters to see which device it is.
Plus, telling that access was denied is hardly useful, turn on Spring-Security logger to debug and paste the stacktrace in your post.

Related

How to avoid Spring Security redirect loop when using custom form login?

App security scenario:
Spring MVC app running 3 instances on PaaS
App is split in to 2 security domains. Managed w/ 2 DispatchServlets located at /app and /kmlservice
App must use https on all pages except for any paths within /kmlservice
App must use custom login page to access all paths within /app
App must use persistent remember-me scheme with LDAP auth
When we converted to https, we are getting infinite redirect loops when attempting to navigate to the /app/login page or any other page. In fact even unprotected pages infinitely reroute to themselves.
Here is an example of the redirect logs we are seeing on attempting to navigate to /app/login:
stdout.log: DEBUG: org.springframework.security.web.access.channel.ChannelProcessingFilter - Request: FilterInvocation: URL: /app/login; ConfigAttributes: [REQUIRES_SECURE_CHANNEL]
stdout.log: DEBUG: org.springframework.security.web.access.channel.RetryWithHttpsEntryPoint - Redirecting to: https:/some_url.com/app/login
stdout.log: DEBUG: org.springframework.security.web.DefaultRedirectStrategy - Redirecting to 'https:/some_url.com/app/login'
stdout.log: DEBUG: org.springframework.security.web.util.matcher.AntPathRequestMatcher - Checking match of request : '/app/login'; against '/kmlservice/**'
stdout.log: DEBUG: org.springframework.security.web.util.matcher.AntPathRequestMatcher - Checking match of request : '/app/login'; against '/resources/**'
stdout.log: DEBUG: org.springframework.security.web.util.matcher.AntPathRequestMatcher - Checking match of request : '/app/login'; against '/app/**'
stdout.log: DEBUG: org.springframework.security.web.FilterChainProxy - /app/login at position 1 of 12 in additional filter chain; firing Filter: 'ChannelProcessingFilter'
stdout.log: DEBUG: org.springframework.security.web.util.matcher.AntPathRequestMatcher - Checking match of request : '/app/login'; against '/app/logout'
stdout.log: DEBUG: org.springframework.security.web.util.matcher.AntPathRequestMatcher - Checking match of request : '/app/login'; against '/app/accessdenied'
stdout.log: DEBUG: org.springframework.security.web.util.matcher.AntPathRequestMatcher - Checking match of request : '/app/login'; against '/app/useful_path'
stdout.log: DEBUG: org.springframework.security.web.util.matcher.AntPathRequestMatcher - Checking match of request : '/app/login'; against '/app/help'
stdout.log: DEBUG: org.springframework.security.web.util.matcher.AntPathRequestMatcher - Checking match of request : '/app/login'; against '/app/login'
stdout.log: DEBUG: org.springframework.security.web.access.channel.ChannelProcessingFilter - Request: FilterInvocation: URL: /app/login; ConfigAttributes: [REQUIRES_SECURE_CHANNEL]
stdout.log: DEBUG: org.springframework.security.web.access.channel.RetryWithHttpsEntryPoint - Redirecting to: https:/some_url.com/app/login
stdout.log: DEBUG: org.springframework.security.web.DefaultRedirectStrategy - Redirecting to 'https:/some_url.com/app/login'
Here's what the config looks like:
<http pattern="/kmlservice/**" use-expressions="true" auto-config="true">
<intercept-url pattern="/**" access="isAuthenticated()" />
<http-basic />
</http>
<http pattern="/resources/**" security="none" />
<http pattern="/app/**" use-expressions="true">
<form-login login-page="/app/login"
authentication-failure-url="/app/accessdenied" default-target-url="/app" />
<intercept-url pattern="/app/logout" access="permitAll"
requires-channel="https" />
<intercept-url pattern="/app/accessdenied" access="permitAll"
requires-channel="https" />
<intercept-url pattern="/app/useful_path"
access="hasRole('ROLE_HAS_ACCESS')" requires-channel="https" />
<intercept-url pattern="/app/help" access="permitAll"
requires-channel="https" />
<intercept-url pattern="/app/login" access="IS_AUTHENTICATED_ANONYMOUSLY"
requires-channel="https" />
<intercept-url pattern="/app/**" access="isAuthenticated()"
requires-channel="https" />
<access-denied-handler error-page="/403" />
<logout logout-success-url="/app/logout" delete-cookies="JSESSIONID" />
<remember-me user-service-ref="userDetailsService"
data-source-ref="dataSource" />
</http>
I have tried to remove
<intercept-url pattern="/app/**" access="isAuthenticated()" requires-channel="https" />
which seemed to make no difference
Is there any other useful config I could provide?
Thanks.
If https terminates at your router, as is often the case with PaaS configurations, then your servlet container needs some way to work out whether the incoming request was actually secure or not. Spring Security uses the standard servlet API method isSecure to decide whether it needs to redirect or not. I'd guess that in your case, the servlet container can't tell whether the external request to the router was made over HTTPS or not.
Tomcat, for example, can be configured with the RemoteIpValve to check for particular headers and set the request properties accordingly. I don't know whether you have any control over this, but you there's an equivalent filter which you can use instead. Of course this also requires that you know how your PaaS is setup and whether it forwards headers like X-Forwarded-Proto to your app at all.
It is going in indefinite loop because URL /app/login is secured as it is marked with IS_AUTHENTICATED_ANONYMOUSLY.
Change the access value to permitAll
<intercept-url pattern="/app/login" access="permitAll" requires-channel="https" />

Spring Security url-intercept with regular expressions match failure

Using Spring security 3.2, I am trying to intercept urls as follows:
<security:http use-expressions="true" path-type="regex" >
<security:intercept-url pattern="/jsp/Error_403.jsp" access="hasAnyRole('ROLE_VISITOR','ROLE_ADMIN','ROLE_BRONZE_SUB','ROLE_BRONZE_TEST','ROLE_SILVER_SUB','ROLE_SILVER_TEST','ROLE_GOLD_SUB','ROLE_GOLD_TEST')" />
<security:intercept-url pattern="/jsp/LoggedOut.jsp" access="hasAnyRole('ROLE_VISITOR','ROLE_ADMIN','ROLE_BRONZE_SUB','ROLE_BRONZE_TEST','ROLE_SILVER_SUB','ROLE_SILVER_TEST','ROLE_GOLD_SUB','ROLE_GOLD_TEST')" />
<security:intercept-url pattern="/jsp/home/header.html" access="hasAnyRole('ROLE_VISITOR','ROLE_ADMIN','ROLE_BRONZE_SUB','ROLE_BRONZE_TEST','ROLE_SILVER_SUB','ROLE_SILVER_TEST','ROLE_GOLD_SUB','ROLE_GOLD_TEST')"/>
<security:intercept-url pattern="/unjust?action=statistics" access="hasAnyRole('ROLE_ADMIN','ROLE_GOLD_SUB','ROLE_GOLD_TEST')" />
<security:intercept-url pattern="/unjust?action=browse" access="hasAnyRole('ROLE_ADMIN')" />
<security:intercept-url pattern="/unjust?action=search" access="hasAnyRole('ROLE_ADMIN','ROLE_BRONZE_SUB','ROLE_BRONZE_TEST','ROLE_SILVER_SUB','ROLE_SILVER_TEST','ROLE_GOLD_SUB','ROLE_GOLD_TEST')" />
<security:intercept-url pattern="/unjust?action=home" access="hasAnyRole('ROLE_ADMIN','ROLE_BRONZE_SUB','ROLE_BRONZE_TEST','ROLE_SILVER_SUB','ROLE_SILVER_TEST','ROLE_GOLD_SUB','ROLE_GOLD_TEST')" />
<security:intercept-url pattern="/unjust" access="hasAnyRole('ROLE_VISITOR','ROLE_ADMIN','ROLE_BRONZE_SUB','ROLE_BRONZE_TEST','ROLE_SILVER_SUB','ROLE_SILVER_TEST','ROLE_GOLD_SUB','ROLE_GOLD_TEST')"/>
<security:intercept-url pattern="/**" access="denyAll" />
<access-denied-handler error-page="/jsp/Error_403.jsp"/>
<security:logout />
<security:openid-login login-page="/openidlogin.jsp"
user-service-ref="registeringUserService" authentication-failure-url="/openidlogin.jsp?login_error=true">
<attribute-exchange identifier-match="https://www.google.com/.*">
<openid-attribute name="email"
type="http://axschema.org/contact/email" required="true" count="1" />
<openid-attribute name="firstname"
type="http://axschema.org/namePerson/first" required="true" />
<openid-attribute name="lastname"
type="http://axschema.org/namePerson/last" required="true" />
</attribute-exchange>
<attribute-exchange identifier-match=".*myopenid.com.*">
<openid-attribute name="email"
type="http://schema.openid.net/contact/email" required="true" />
<openid-attribute name="fullname"
type="http://schema.openid.net/namePerson" required="true" />
</attribute-exchange>
</security:openid-login>
<remember-me token-repository-ref="tokenRepo" />
</security:http>
When I try to execute, for example, the browse action, I cannot authenticate, and the log shows this:
12889 [http-bio-8080-exec-14] DEBUG org.springframework.security.web.FilterChainProxy - /unjust?action=statistics at position 11 of 11 in additional filter chain; firing Filter: 'FilterSecurityInterceptor'
12889 [http-bio-8080-exec-14] DEBUG org.springframework.security.web.util.RegexRequestMatcher - Checking match of request : '/unjust?action=statistics'; against '/jsp/Error_403.jsp'
12889 [http-bio-8080-exec-14] DEBUG org.springframework.security.web.util.RegexRequestMatcher - Checking match of request : '/unjust?action=statistics'; against '/jsp/LoggedOut.jsp'
12889 [http-bio-8080-exec-14] DEBUG org.springframework.security.web.util.RegexRequestMatcher - Checking match of request : '/unjust?action=statistics'; against '/jsp/home/header.html'
12889 [http-bio-8080-exec-14] DEBUG org.springframework.security.web.util.RegexRequestMatcher - Checking match of request : '/unjust?action=statistics'; against '/unjust?action=statistics'
12889 [http-bio-8080-exec-14] DEBUG org.springframework.security.web.util.RegexRequestMatcher - Checking match of request : '/unjust?action=statistics'; against '/unjust?action=browse'
12889 [http-bio-8080-exec-14] DEBUG org.springframework.security.web.util.RegexRequestMatcher - Checking match of request : '/unjust?action=statistics'; against '/unjust?action=search$'
12890 [http-bio-8080-exec-14] DEBUG org.springframework.security.web.util.RegexRequestMatcher - Checking match of request : '/unjust?action=statistics'; against '/unjust?action=home'
12890 [http-bio-8080-exec-14] DEBUG org.springframework.security.web.util.RegexRequestMatcher - Checking match of request : '/unjust?action=statistics'; against '/unjust'
12890 [http-bio-8080-exec-14] DEBUG org.springframework.security.web.access.intercept.FilterSecurityInterceptor - Secure object: FilterInvocation: URL: /unjust?action=statistics; Attributes: [denyAll]
12890 [http-bio-8080-exec-14] DEBUG org.springframework.security.web.access.intercept.FilterSecurityInterceptor - Previously Authenticated: [org.springframework.security.openid.OpenIDAuthenticationToken#c8f995e9: Principal: unjust.beans.CustomUserDetails#d66c4fbd: Username: https://www.google.com/accounts/o8/id?xxxxx; Password: [PROTECTED]; Enabled: true; AccountNonExpired: true; credentialsNonExpired: true; AccountNonLocked: true; Granted Authorities: ROLE_BRONZE_SUB; Credentials: [PROTECTED]; Authenticated: true; Details: org.springframework.security.web.authentication.WebAuthenticationDetails#380f4: RemoteIpAddress: 127.0.0.1; SessionId: 6F57A4A404D2BC3CD82391F6973FA715; Granted Authorities: ROLE_BRONZE_SUB, attributes : xxxxxx
12890 [http-bio-8080-exec-14] DEBUG org.springframework.security.access.vote.AffirmativeBased - Voter: org.springframework.security.web.access.expression.WebExpressionVoter#b041b0, returned: -1
12890 [http-bio-8080-exec-14] DEBUG org.springframework.security.web.access.ExceptionTranslationFilter - Access is denied (user is not anonymous); delegating to AccessDeniedHandler
org.springframework.security.access.AccessDeniedException: Access is denied
I have seen a number of posts on StackOverflow that have a number of different formats for the regular expression, ranging from what I have above to
<security:intercept-url pattern="\A^/unjust?action=search.$\Z"
I have been able to generate matches using the ant path matcher, however, things then fail when I have a request like this:
/unjust?action=browseUNDT&sEcho=1&iColumns=7&sColumns=&iDisplayStart=0&iDisplayLength=10&mDataProp_0=caseName&mDataProp_1=caseId&mDataProp_2=judgmentDate&mDataProp_3=judgmentType&mDataProp_4=judgmentNo&mDataProp_5=docId&mDataProp_6=displayCase&sSearch=&bRegex=false&sSearch_0=&bRegex_0=false&bSearchable_0=true&sSearch_1=&bRegex_1=false&bSearchable_1=true&sSearch_2=&bRegex_2=false&bSearchable_2=true&sSearch_3=&bRegex_3=false&bSearchable_3=true&sSearch_4=&bRegex_4=false&bSearchable_4=true&sSearch_5=&bRegex_5=false&bSearchable_5=true&sSearch_6=&bRegex_6=false&bSearchable_6=true&iSortCol_0=0&sSortDir_0=asc&iSortingCols=1&bSortable_0=true&bSortable_1=true&bSortable_2=true&bSortable_3=true&bSortable_4=true&bSortable_5=true&bSortable_6=true&_=1379771161138
And everything in between.
Can someone please steer me towards the correct setup and syntax for this pattern matching?
Spring doesnt support parameter matching in url by default. with regex matcher using request-matcher="regex" or path-type="regex" you can use regex to match urls.
Now in the pattern you provided =/unjust?action=browse "?" means a special symbol in regex One occurence or Zero. You should escape ? in your pattern by using "\\?"

persisted remember-me authentication after using custom filter

I'm using Spring-Security 3.1.RELEASE within a Spring Roo environment. I've changed the login mechanism so that it works with JSON-Response. For that I've created two classes (scala) namely
class JsonSuccessHandler extends SimpleUrlAuthenticationSuccessHandler {
override def onAuthenticationSuccess(request: HttpServletRequest, response: HttpServletResponse, authentication: Authentication) = {
val responseWrapper = new HttpServletResponseWrapper(response);
val out = responseWrapper.getWriter
out.write("{success: true}")
out.close
}
}
#Repository class JsonEntryPoint extends AuthenticationEntryPoint {
def commence(request: HttpServletRequest, response: HttpServletResponse, ae: AuthenticationException) = {
response.sendError(HttpServletResponse.SC_UNAUTHORIZED, "Unauthorized")
}
}
The entries in application-security.xml are as follows:
<http use-expressions="true" entry-point-ref="jsonAuthenticationEntryPoint">
<custom-filter ref="myFilter" position="FORM_LOGIN_FILTER"/>
<custom-filter ref="rememberMeFilter" position="REMEMBER_ME_FILTER"/>
<logout logout-url="/resources/j_spring_security_logout"/>
<intercept-url pattern="/backend/**" access="isAuthenticated()" />
<intercept-url pattern="/resources/**" access="permitAll" />
<intercept-url pattern="/admin/**" access="hasRole('ROLE_ADMIN')" />
<intercept-url pattern="/**" access="permitAll" />
</http>
<beans:bean id="rememberMeFilter" class="org.springframework.security.web.authentication.rememberme.RememberMeAuthenticationFilter">
<beans:property name="rememberMeServices" ref="rememberMeServices"/>
<beans:property name="authenticationManager" ref="authenticationManager" />
</beans:bean>
<beans:bean id="rememberMeServices" class="org.springframework.security.web.authentication.rememberme.JdbcTokenBasedRememberMeServices">
<beans:property name="userDetailsService" ref="userServiceDb"/>
<beans:property name="tokenRepository" ref="tokenRepository"/>
<beans:property name="key" value="reservation" />
</beans:bean>
<beans:bean id="tokenRepository" class="org.springframework.security.web.authentication.rememberme.JdbcTokenRepositoryImpl">
<beans:property name="dataSource" ref="dataSource"/>
</beans:bean>
<beans:bean id="myFilter" class="org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter">
<beans:property name="authenticationManager" ref="authenticationManager" />
<beans:property name="authenticationSuccessHandler" ref="mySuccessHandler" />
<beans:property name="rememberMeServices" ref="rememberMeServices" />
<beans:property name="usernameParameter" value="email" />
<beans:property name="passwordParameter" value="password" />
</beans:bean>
<beans:bean id="mySuccessHandler" class="JsonSuccessHandler"/>
<beans:bean id="jsonAuthenticationEntryPoint" class="JsonEntryPoint" />
Authentication is working fine, so I can successfully login and also concerning remember-me the data is stored successfully into the database (table persistent_logins). But when I restart the server the Session is as expected deleted and the remember me functionality should do its work. Unfortunately it fails with following log data:
[INFO] Started Jetty Server
17:19:15.867 [qtp1943091306-38] DEBUG o.s.security.web.FilterChainProxy - / at position 1 of 10 in additional filter chain; firing Filter: 'SecurityContextPersistenceFilter'
17:19:15.875 [qtp1943091306-38] DEBUG o.s.s.w.c.HttpSessionSecurityContextRepository - No HttpSession currently exists
17:19:15.875 [qtp1943091306-38] DEBUG o.s.s.w.c.HttpSessionSecurityContextRepository - No SecurityContext was available from the HttpSession: null. A new one will be created.
17:19:15.877 [qtp1943091306-38] DEBUG o.s.security.web.FilterChainProxy - / at position 2 of 10 in additional filter chain; firing Filter: 'LogoutFilter'
17:19:15.878 [qtp1943091306-38] DEBUG o.s.security.web.FilterChainProxy - / at position 3 of 10 in additional filter chain; firing Filter: 'UsernamePasswordAuthenticationFilter'
17:19:15.878 [qtp1943091306-38] DEBUG o.s.security.web.FilterChainProxy - / at position 4 of 10 in additional filter chain; firing Filter: 'RequestCacheAwareFilter'
17:19:15.878 [qtp1943091306-38] DEBUG o.s.security.web.FilterChainProxy - / at position 5 of 10 in additional filter chain; firing Filter: 'SecurityContextHolderAwareRequestFilter'
17:19:15.879 [qtp1943091306-38] DEBUG o.s.security.web.FilterChainProxy - / at position 6 of 10 in additional filter chain; firing Filter: 'RememberMeAuthenticationFilter'
17:19:15.879 [qtp1943091306-38] DEBUG o.s.s.w.a.r.PersistentTokenBasedRememberMeServices - Remember-me cookie detected
17:19:15.895 [qtp1943091306-38] DEBUG o.s.jdbc.core.JdbcTemplate - Executing prepared SQL query
17:19:15.895 [qtp1943091306-38] DEBUG o.s.jdbc.core.JdbcTemplate - Executing prepared SQL statement [select username,series,token,last_used from persistent_logins where series = ?]
17:19:15.896 [qtp1943091306-38] DEBUG o.s.jdbc.datasource.DataSourceUtils - Fetching JDBC Connection from DataSource
17:19:15.922 [qtp1943091306-38] DEBUG o.s.jdbc.datasource.DataSourceUtils - Returning JDBC Connection to DataSource
17:19:15.938 [qtp1943091306-38] DEBUG o.s.s.w.a.r.PersistentTokenBasedRememberMeServices - Refreshing persistent login token for user 'physio1#physio-termin.at', series 'oLmZMQbnFsfyTziANriMKw=='
17:19:15.939 [qtp1943091306-38] DEBUG o.s.jdbc.core.JdbcTemplate - Executing prepared SQL update
17:19:15.944 [qtp1943091306-38] DEBUG o.s.jdbc.core.JdbcTemplate - Executing prepared SQL statement [update persistent_logins set token = ?, last_used = ? where series = ?]
17:19:15.944 [qtp1943091306-38] DEBUG o.s.jdbc.datasource.DataSourceUtils - Fetching JDBC Connection from DataSource
17:19:15.984 [qtp1943091306-38] DEBUG o.s.jdbc.core.JdbcTemplate - SQL update affected 1 rows
17:19:15.992 [qtp1943091306-38] DEBUG o.s.jdbc.datasource.DataSourceUtils - Returning JDBC Connection to DataSource
17:19:15.996 [qtp1943091306-38] DEBUG o.s.jdbc.core.JdbcTemplate - Executing prepared SQL query
17:19:15.996 [qtp1943091306-38] DEBUG o.s.jdbc.core.JdbcTemplate - Executing prepared SQL statement [select email username, password, isactive enabled from principal where email = ?]
17:19:15.996 [qtp1943091306-38] DEBUG o.s.jdbc.datasource.DataSourceUtils - Fetching JDBC Connection from DataSource
17:19:16.001 [qtp1943091306-38] DEBUG o.s.jdbc.datasource.DataSourceUtils - Returning JDBC Connection to DataSource
17:19:16.013 [qtp1943091306-38] DEBUG o.s.jdbc.core.JdbcTemplate - Executing prepared SQL query
17:19:16.013 [qtp1943091306-38] DEBUG o.s.jdbc.core.JdbcTemplate - Executing prepared SQL statement [select p.email username, a.authority from principal p inner join principal_authority apa on p.id = apa.principal_id inner join authority a on a.id = apa.authorities_id where p.email = ?]
17:19:16.013 [qtp1943091306-38] DEBUG o.s.jdbc.datasource.DataSourceUtils - Fetching JDBC Connection from DataSource
17:19:16.015 [qtp1943091306-38] DEBUG o.s.jdbc.datasource.DataSourceUtils - Returning JDBC Connection to DataSource
17:19:16.021 [qtp1943091306-38] DEBUG o.s.s.w.a.r.PersistentTokenBasedRememberMeServices - Remember-me cookie accepted
17:19:16.036 [qtp1943091306-38] DEBUG o.s.b.f.s.DefaultListableBeanFactory - Returning cached instance of singleton bean 'org.springframework.context.annotation.internalScheduledAnnotationProcessor'
17:19:16.042 [qtp1943091306-38] DEBUG o.s.s.w.a.r.RememberMeAuthenticationFilter - SecurityContextHolder not populated with remember-me token, as AuthenticationManager rejected Authentication returned by RememberMeServices: 'org.springframework.security.authentication.RememberMeAuthenticationToken#2fb6ff6b: Principal: org.springframework.security.core.userdetails.User#d45302c2: Username: physio1#physio-termin.at; Password: [PROTECTED]; Enabled: true; AccountNonExpired: true; credentialsNonExpired: true; AccountNonLocked: true; Granted Authorities: ROLE_PHYSIOTHERAPEUT; Credentials: [PROTECTED]; Authenticated: true; Details: org.springframework.security.web.authentication.WebAuthenticationDetails#957e: RemoteIpAddress: 127.0.0.1; SessionId: null; Granted Authorities: ROLE_PHYSIOTHERAPEUT'; invalidating remember-me token
org.springframework.security.authentication.ProviderNotFoundException: No AuthenticationProvider found for org.springframework.security.authentication.RememberMeAuthenticationToken
at org.springframework.security.authentication.ProviderManager.authenticate(ProviderManager.java:196) ~[spring-security-core-3.1.0.RELEASE.jar:3.1.0.RELEASE]
at org.springframework.security.web.authentication.rememberme.RememberMeAuthenticationFilter.doFilter(RememberMeAuthenticationFilter.java:102) ~[spring-security-web-3.1.0.RELEASE.jar:3.1.0.RELEASE]
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:323) [spring-security-web-3.1.0.RELEASE.jar:3.1.0.RELEASE]
What am I missing? I dont't understand why the ProviderNotFoundException is thrown.
You're almost done, authentication works OK, you forgot to add RememberMeAuthenticationProvider. If you use security namespace to create AuthenticationManager, just add separate <authentication-provider> like here:
<authentication-manager>
<authentication-provider ref="yourRegularAuthenticationProvider" />
<authentication-provider ref="rememberMeAuthenticationProvider" />
</authentication-manager>
<beans:bean id="rememberMeAuthenticationProvider" class="org.springframework.security.authentication.RememberMeAuthenticationProvider">
<beans:property name="key" value="reservation" />
</beans:bean>

apply security=none to context root and static resources : spring security version 3.1

my application compiles to ROOT.war which basically means I do not have a context root other than /. There are pages which are to be secured; however there are URLs which do not need it; for example my http://localhost:8080/ gives the home page of this application; and there are similar pages like about us, contact us, etc where security is not need. So I add this to the configuration
<security:intercept-url pattern="/" access="permitAll" />
<security:intercept-url pattern="/resources/**" access="permitAll" />
<security:intercept-url pattern="/register/confirm" access="isAuthenticated()" />
<security:intercept-url pattern="/register/accept" access="isAuthenticated()" />
<security:intercept-url pattern="/shopper/**" access="isAuthenticated()" />
but this just says that users are allowed to access these URL "without authentication"if you access these URLs the security filters are all applied, as seen below in the debug logs
DEBUG: org.springframework.security.web.FilterChainProxy - / at position 1 of 12 in additional filter chain; firing Filter: 'ConcurrentSessionFilter'
DEBUG: org.springframework.security.web.FilterChainProxy - / at position 2 of 12 in additional filter chain; firing Filter: 'SecurityContextPersistenceFilter'
DEBUG: org.springframework.security.web.context.HttpSessionSecurityContextRepository - No HttpSession currently exists
DEBUG: org.springframework.security.web.context.HttpSessionSecurityContextRepository - No SecurityContext was available from the HttpSession: null. A new one will be created.
DEBUG: org.springframework.security.web.FilterChainProxy - / at position 3 of 12 in additional filter chain; firing Filter: 'LogoutFilter'
DEBUG: org.springframework.security.web.FilterChainProxy - / at position 4 of 12 in additional filter chain; firing Filter: 'UsernamePasswordAuthenticationFilter'
DEBUG: org.springframework.security.web.FilterChainProxy - / at position 5 of 12 in additional filter chain; firing Filter: 'OpenIDAuthenticationFilter'
DEBUG: org.springframework.security.web.FilterChainProxy - / at position 6 of 12 in additional filter chain; firing Filter: 'BasicAuthenticationFilter'
DEBUG: org.springframework.security.web.FilterChainProxy - / at position 7 of 12 in additional filter chain; firing Filter: 'RequestCacheAwareFilter'
DEBUG: org.springframework.security.web.FilterChainProxy - / at position 8 of 12 in additional filter chain; firing Filter: 'SecurityContextHolderAwareRequestFilter'
DEBUG: org.springframework.security.web.FilterChainProxy - / at position 9 of 12 in additional filter chain; firing Filter: 'AnonymousAuthenticationFilter'
DEBUG: org.springframework.security.web.authentication.AnonymousAuthenticationFilter - Populated SecurityContextHolder with anonymous token: 'org.springframework.security.authentication.AnonymousAuthenticationToken#9055e4a6: Principal: anonymousUser; Credentials: [PROTECTED]; Authenticated: true; Details: org.springframework.security.web.authentication.WebAuthenticationDetails#957e: RemoteIpAddress: 127.0.0.1; SessionId: null; Granted Authorities: ROLE_ANONYMOUS'
DEBUG: org.springframework.security.web.FilterChainProxy - / at position 10 of 12 in additional filter chain; firing Filter: 'SessionManagementFilter'
DEBUG: org.springframework.security.web.FilterChainProxy - / at position 11 of 12 in additional filter chain; firing Filter: 'ExceptionTranslationFilter'
DEBUG: org.springframework.security.web.FilterChainProxy - / at position 12 of 12 in additional filter chain; firing Filter: 'FilterSecurityInterceptor'
DEBUG: org.springframework.security.web.util.AntPathRequestMatcher - Checking match of request : '/'; against '/'
DEBUG: org.springframework.security.web.access.intercept.FilterSecurityInterceptor - Secure object: FilterInvocation: URL: /; Attributes: [permitAll]
DEBUG: org.springframework.security.web.access.intercept.FilterSecurityInterceptor - Previously Authenticated: org.springframework.security.authentication.AnonymousAuthenticationToken#9055e4a6: Principal: anonymousUser; Credentials: [PROTECTED]; Authenticated: true; Details: org.springframework.security.web.authentication.WebAuthenticationDetails#957e: RemoteIpAddress: 127.0.0.1; SessionId: null; Granted Authorities: ROLE_ANONYMOUS
DEBUG: org.springframework.security.access.vote.AffirmativeBased - Voter: org.springframework.security.web.access.expression.WebExpressionVoter#2b06c17b, returned: 1
DEBUG: org.springframework.security.web.access.intercept.FilterSecurityInterceptor - Authorization successful
DEBUG: org.springframework.security.web.access.intercept.FilterSecurityInterceptor - RunAsManager did not change Authentication object
DEBUG: org.springframework.security.web.FilterChainProxy - / reached end of additional filter chain; proceeding with original chain
DEBUG: org.springframework.web.servlet.DispatcherServlet - DispatcherServlet with name 'appServlet' processing GET request for [/
]
When I try using this configuration (in sequence mentioned below):
<!-- No Security required for the ROOT Context -->
<security:http pattern="/**" security="none" />
<!-- Apply secyrity for shopper URLs -->
<security:http auto-config="true" use-expressions="true" access-denied-page="/denied">
<security:intercept-url pattern="/" access="permitAll" />
<security:intercept-url pattern="/resources/**" access="permitAll" />
<security:intercept-url pattern="/register/confirm" access="isAuthenticated()" />
<security:intercept-url pattern="/register/accept" access="isAuthenticated()" />
<security:intercept-url pattern="/shopper/**" access="isAuthenticated()" /
....
</security:http>
<security:http pattern="/resources/**" security="none" />
It breaks down giving the error
DEBUG: org.springframework.security.web.util.AntPathRequestMatcher - Checking match of request : '/auth/login'; against '/'
DEBUG: org.springframework.security.web.util.AntPathRequestMatcher - Checking match of request : '/auth/login'; against '/resources/**'
DEBUG: org.springframework.security.web.util.AntPathRequestMatcher - Checking match of request : '/auth/login'; against '/register/confirm'
DEBUG: org.springframework.security.web.util.AntPathRequestMatcher - Checking match of request : '/auth/login'; against '/register/accept'
DEBUG: org.springframework.security.web.util.AntPathRequestMatcher - Checking match of request : '/auth/login'; against '/shopper/**'
DEBUG: org.springframework.security.config.http.DefaultFilterChainValidator - No access attributes defined for login page URL
INFO : org.springframework.beans.factory.support.DefaultListableBeanFactory - Destroying singletons in org.springframework.beans.factory.support.DefaultListableBeanFactory#5bebacc8: defining beans [placeholderConfig,dataSource,entityManagerFactory,org.springframework.aop.config.internalAutoProxyCreator,org.springframework.transaction.annotation.AnnotationTransactionAttributeSource#0,org.springframework.transaction.interceptor.TransactionInterceptor#0,org.springframework.transaction.config.internalTransactionAdvisor,transactionManager,org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor#0,registrationService,shopperService,org.springframework.context.annotation.internalConfigurationAnnotationProcessor,org.springframework.context.annotation.internalAutowiredAnnotationProcessor,org.springframework.context.annotation.internalRequiredAnnotationProcessor,org.springframework.context.annotation.internalCommonAnnotationProcessor,org.springframework.context.annotation.internalPersistenceAnnotationProcessor,org.springframework.security.filterChains,org.springframework.security.filterChainProxy,org.springframework.security.web.PortMapperImpl#0,org.springframework.security.config.authentication.AuthenticationManagerFactoryBean#0,org.springframework.security.authentication.ProviderManager#0,org.springframework.security.web.context.HttpSessionSecurityContextRepository#0,org.springframework.security.core.session.SessionRegistryImpl#0,org.springframework.security.web.authentication.session.ConcurrentSessionControlStrategy#0,org.springframework.security.web.savedrequest.HttpSessionRequestCache#0,org.springframework.security.web.access.expression.DefaultWebSecurityExpressionHandler#0,org.springframework.security.access.vote.AffirmativeBased#0,org.springframework.security.web.access.intercept.FilterSecurityInterceptor#0,org.springframework.security.web.access.DefaultWebInvocationPrivilegeEvaluator#0,org.springframework.security.authentication.AnonymousAuthenticationProvider#0,org.springframework.security.web.authentication.www.BasicAuthenticationEntryPoint#0,org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter#0,org.springframework.security.openid.OpenIDAuthenticationFilter#0,org.springframework.security.openid.OpenIDAuthenticationProvider#0,org.springframework.security.userDetailsServiceFactory,org.springframework.security.web.DefaultSecurityFilterChain#0,org.springframework.security.web.DefaultSecurityFilterChain#1,org.springframework.security.authentication.dao.DaoAuthenticationProvider#0,org.springframework.security.authentication.DefaultAuthenticationEventPublisher#0,org.springframework.security.authenticationManager,passwordEncoder,registrationAwareUserDetailsService,registrationAwareAuthSuccessHandler,org.springframework.context.annotation.ConfigurationClassPostProcessor$ImportAwareBeanPostProcessor#0]; root of factory hierarchy
INFO : org.hibernate.impl.SessionFactoryImpl - closing
ERROR: org.springframework.web.context.ContextLoader - Context initialization failed
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'org.springframework.security.filterChainProxy': Invocation of init method failed; nested exception is java.lang.IllegalArgumentException: A universal match pattern ('/**') is defined before other patterns in the filter chain, causing them to be ignored. Please check the ordering in your <security:http> namespace or FilterChainProxy bean configuration
I cannot really understand the reason behind this. Do I have to implement my own request pattern matcher?
Solution
<beans:bean id="filterChainProxy" class="org.springframework.security.web.FilterChainProxy" >
<beans:constructor-arg>
<beans:list>
<security:filter-chain pattern="/resources/**"
filters="none" />
<security:filter-chain pattern="/aboutus"
filters="none" />
<security:filter-chain pattern="/contactus"
filters="none" />
<security:filter-chain pattern="/news"
filters="none" />
</beans:list>
</beans:constructor-arg>
</beans:bean>
security="none" with pattern /** captures all URLs, so no other rule could be applied. What's why you receive error in second example.
But it's possible to define different filter-chains for different URL-patterns. I don't have example of this with new syntax, but here is example with old syntax (order of filter-chains is important):
<bean id="springSecurityFilterChain" class="org.springframework.security.web.FilterChainProxy">
<sec:filter-chain-map path-type="ant">
<sec:filter-chain pattern="/dwr/**" filters="securityContextPersistenceFilter,securityContextHolderAwareRequestFilter,rememberMeAuthenticationFilter,anonymousAuthenticationFilter" />
<sec:filter-chain pattern="/**" filters="channelProcessingFilter,securityContextPersistenceFilter,logoutFilter,authenticationFilter,securityContextHolderAwareRequestFilter,rememberMeAuthenticationFilter,anonymousAuthenticationFilter,sessionManagementFilter,exceptionTranslationFilter,filterSecurityInterceptor,switchUserProcessingFilter" />
</sec:filter-chain-map>
</bean>
Here's the syntax I have finally chosen to stick with; for it makes the XML a lot easier to read and comprehend
<!-- Non secure URLs -->
<security:http pattern="/" security='none' />
<security:http pattern="/home" security='none' />
<security:http pattern="/aboutus" security='none' />
...
...
<security:http pattern="/resources/**" security='none' />
<security:http pattern="/favicon.ico" security='none' />
<!-- URLs under security config -->
<security:http auto-config="true" use-expressions="true" pattern="/admin/**" access-denied-page="/denied">
<security:intercept-url pattern="/admin/**" access="ROLE_ADMIN" requires-channel="https" />
</security:http>

Spring Security RememberMeAuthenticationFilter not fired

Im trying to integrate RememberMe functionality inside a Spring 3 webapp.
The app is working good and doesn't show any other problem.
When I enable the "remember me" check, the cookie is correctly created and sent with any request (i've tested it with Firebug and Chrome DevExtensions).
When I close and reopen the browser, the Cookie is still alive and sent, but the RememberMe Filter is not fired, then the next filter in chain is AnonymousFilter, the user is authenticated as anonymous and sent back to the login page.
Any idea why?
The applicationContext relevant part is:
<security:http>
<security:intercept-url pattern="/" access="IS_AUTHENTICATED_ANONYMOUSLY" />
<security:intercept-url pattern="/login.jsp*" access="IS_AUTHENTICATED_ANONYMOUSLY" />
<security:intercept-url pattern="/stylesheets/**" access="IS_AUTHENTICATED_ANONYMOUSLY" />
<security:intercept-url pattern="/javascripts/**" access="IS_AUTHENTICATED_ANONYMOUSLY" />
<security:intercept-url pattern="/images/**" access="IS_AUTHENTICATED_ANONYMOUSLY" />
<security:intercept-url pattern="/impianti/public/**" access="IS_AUTHENTICATED_ANONYMOUSLY" />
<security:intercept-url pattern="/buoni/public/**" access="IS_AUTHENTICATED_ANONYMOUSLY" />
<security:intercept-url pattern="/admin/*" access="ROLE_ADMIN" />
<security:intercept-url pattern="/**" access="ROLE_USER" />
<security:form-login login-page="/login.jsp" authentication-failure-url="/login.jsp" default-target-url="/index.html" />
<security:http-basic />
<security:logout logout-success-url="/login_redirect.jsp" logout-url="/logout" />
<security:remember-me/>
</security:http>
<security:authentication-manager>
<security:authentication-provider>
<security:password-encoder hash="md5" />
<security:jdbc-user-service data-source-ref="dataSource"/>
</security:authentication-provider>
</security:authentication-manager>
The logs are:
Before the browser close & reopen:
DEBUG: org.springframework.security.web.FilterChainProxy - /index.html at position 7 of 11 in additional filter chain; firing Filter: 'org.springframework.security.web.authentication.rememberme.RememberMeAuthenticationFilter#1420fea'
DEBUG: org.springframework.security.web.authentication.rememberme.RememberMeAuthenticationFilter - SecurityContextHolder not populated with remember-me token, as it already contained: (etc)
After the reopen:
DEBUG: org.springframework.security.web.FilterChainProxy - /login.jsp at position 7 of 11 in additional filter chain; firing Filter: 'org.springframework.security.web.authentication.rememberme.RememberMeAuthenticationFilter#1420fea'
DEBUG: org.springframework.security.web.FilterChainProxy - /login.jsp at position 8 of 11 in additional filter chain; firing Filter: 'org.springframework.security.web.authentication.AnonymousAuthenticationFilter#230be4'
DEBUG: org.springframework.security.web.authentication.AnonymousAuthenticationFilter - Populated SecurityContextHolder with anonymous token: 'org.springframework.security.authentication.AnonymousAuthenticationToken#905571d8: Principal: anonymousUser; Password: [PROTECTED]; Authenticated: true; Details: org.springframework.security.web.authentication.WebAuthenticationDetails#0: RemoteIpAddress: 0:0:0:0:0:0:0:1; SessionId: 96789943A570362DE4B0113A5262F0CB; Granted Authorities: ROLE_ANONYMOUS'
Check if you'd missed the remember me auth provider.

Resources