3

I'm new to Spring Security. I have a requirement to do a URL based authentication wherein a user needs to be authenticated based on a unique reference that will be sent every time as a parameter in the URL. I'll pass on this reference to a webservice, get the required data and then authenticate the user (and set the roles). The Authentication & Authorization part is working fine.

However, when i try to access the application again (now with a different reference in the URL), it says "SecurityContextHolder not populated with anonymous token, as it already contained ..." and it showed the details of the previous request. I've tried clearing the security context using SecurityContextHolder.getContext().setAuthentication(null) and SecurityContextHolder.clearContext().

After this, i was able to access the application multiple times. However, if i try to access the application simultaneously from my colleagues machine, i get a blank page. Upon checking the logs, i see a message "SecurityContextHolder not populated with anonymous token ...". I've also tried setting up the sessions but I'm clueless as to where I'm losing the track.

Below is my web.xml (only the spring security part):

<filter>
    <filter-name>springSecurityFilterChain</filter-name>
    <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
</filter>

<filter-mapping>
    <filter-name>springSecurityFilterChain</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>

<listener>
<listener-class>
          org.springframework.web.context.ContextLoaderListener
    </listener-class>
</listener>

<listener>
    <listener-class>
          org.springframework.security.web.session.HttpSessionEventPublisher
    </listener-class>
</listener>

<session-config>
<session-timeout>30</session-timeout>
</session-config>

spring-security.xml:

<http use-expressions="true" auto-config="false" entry-point-                   
                            ref="http403ForbiddenEntryPoint">
<intercept-url pattern="/paymentPortalInternal.*" access="hasRole('Internal')"/>
<intercept-url pattern="/paymentPortalExternal.*" access="hasRole('External')"/>

<custom-filter position="PRE_AUTH_FILTER" ref="customAuthenticationFilter"/>
<custom-filter position="CONCURRENT_SESSION_FILTER" ref="concurrencyFilter" />
<session-management session-authentication-strategy-ref="sas"/>
</http>

<beans:bean id="concurrencyFilter"
class="org.springframework.security.web.session.ConcurrentSessionFilter">
<beans:property name="sessionRegistry" ref="sessionRegistry" />
<beans:property name="expiredUrl" value="/session-expired.htm" />
</beans:bean>

<beans:bean id="http403ForbiddenEntryPoint"
  class="org.springframework.security.web.authentication.Http403ForbiddenEntryPoint"/>
<beans:bean id="customAuthenticationFilter"
  class="com.xxx.xxx.xxxxx.security.CustomAuthenticationFilter">
      <beans:property name="sessionAuthenticationStrategy" ref="sas" />
  <beans:property name="authenticationManager" ref="authenticationManager" />
</beans:bean>

<beans:bean id="sas" 
              class="org.springframework.security.web.authentication.session.
                                               ConcurrentSessionControlStrategy">
<beans:constructor-arg name="sessionRegistry" ref="sessionRegistry" />
<beans:property name="maximumSessions" value="1" />
<beans:property name="exceptionIfMaximumExceeded" value="true" />
</beans:bean>

<beans:bean id="sessionRegistry"    
class="org.springframework.security.core.session.SessionRegistryImpl" />

<authentication-manager alias="authenticationManager">
    <authentication-provider ref="preauthAuthProvider" />
</authentication-manager>

<beans:bean id="preauthAuthProvider" 
                class="org.springframework.security.web.authentication.preauth.
                                       PreAuthenticatedAuthenticationProvider">
<beans:property name="preAuthenticatedUserDetailsService">
    <beans:bean class="com.XXX.XXXX.XXX.UserServiceImpl" />
    </beans:property>
</beans:bean>

Please let me know if I need to provide more information.

EDIT: Adding Logs.

For the first Request:

2013-02-07 17:27:38,834 DEBUG [http-8081-2][org.springframework.security.web.context.HttpSessionSecurityContextRepository.readSecurityContextFromSession(127)] - No HttpSession currently exists 2013-02-07 17:27:38,834 DEBUG [http-8081-2][org.springframework.security.web.context.HttpSessionSecurityContextRepository.loadContext(85)] - No SecurityContext was available from the HttpSession: null. A new one will be created.

For the second request(Please note that the details in the security context are those of the first request):

2013-02-07 17:27:54,272 DEBUG [http-8081-2][org.springframework.security.web.context.HttpSessionSecurityContextRepository.readSecurityContextFromSession(158)] - Obtained a valid SecurityContext from SPRING_SECURITY_CONTEXT: 'org.springframework.security.core.context.SecurityContextImpl@1017293c: Authentication: org.springframework.security.web.authentication.preauth.PreAuthenticatedAuthenticationToken@1017293c: Principal: org.springframework.security.core.userdetails.User@35cd3811: Username: Internal@5581e6e1-7e61-41bb-9257-b3c1acb96519; Password: [PROTECTED]; Enabled: true; AccountNonExpired: true; credentialsNonExpired: true; AccountNonLocked: true; Granted Authorities: Internal; Credentials: [PROTECTED]; Authenticated: true; Details: org.springframework.security.web.authentication.WebAuthenticationDetails@ffffc434: RemoteIpAddress: 10.188.182.107; SessionId: null; Granted Authorities: Internal'

My understanding is that security context holder stores the details of all the users. But in this case, I'm not able to launch the application from a different tab/browser.

Mahesh Kumar
  • 49
  • 1
  • 1
  • 5
  • It sounds like your custom authentication filter is ignoring the change in the URL parameter, perhaps because the user is already authenticated. Also, you should probably remove all the concurrent session stuff until you can get he basics working properly. – Shaun the Sheep Feb 07 '13 at 12:39
  • Thanks for your response Luke. The problem here is, when the second request is fired, my customAuthenticationFilter isn't getting triggered at all. Please see the log trace i've added to the question. – Mahesh Kumar Feb 07 '13 at 17:30
  • @LukeTaylor, Just to add one more point here.. We don't have a proper login mechanism in place. All we have is a unique reference which comes from the URL. So ideally when a second request comes, it is as good as a new user trying to get authenticated. However, the security context is already populated with the token of the first user and i'm clueless at the moment. I'm now trying out the SecurityContextPersistenceFilter filter. Am i going in the right direction? – Mahesh Kumar Feb 07 '13 at 17:48
  • If you are connecting in the same session then it's no surprise that the security context already contains the previous authentication. You really should post the outline of your `CustomAuthenticationFilter`. You say it isn't "triggered". Have you debugged it to find out why? It's a filter, hence its `doFilter` method is called for every request. Put a breakpoint there. And you haven't clarified why you are using all the concurrent session infrastructure. Also, passing authentication parameters in a URL is generally frowned on for security reasons. – Shaun the Sheep Feb 08 '13 at 13:05
  • @LukeTaylor, I found out the reason why my customAuthFilter isn't getting triggered for the second request. It appears that the position that I'm invoking it from is wrong. I used position="PRE_AUTH_FILTER" earlier. I've tried with other positions (like FIRST, BASIC_AUTH_FILTER, etc) and the filter is able to authenticate multiple requests. However, the anonymous filter is getting triggered after my customAuthFilter and it is overriding the security context with an anonymous token. Is there any way to avoid this? I'm now trying to use the filterProxyChain to use only the required filters. – Mahesh Kumar Feb 08 '13 at 13:39
  • No, the anonymous filter won't overwrite the security context if you have already set it. – Shaun the Sheep Feb 08 '13 at 13:43
  • Concurrent sessions really don't matter in my case as every request that comes from a different tab/browser will be treated as a new request and is nowhere related to the previous session. So i've removed all the config related to concurrent sessions. And for the params in the URL, everytime the user tries to access the application, a new reference is generated from a secure database. This reference can be used only once. – Mahesh Kumar Feb 08 '13 at 13:53

2 Answers2

2

If your CustomAuthenticationFilter is extending AbstractPreAuthenticatedProcessingFilter, following 2 properties may give you an insight. 1. checkForPrincipalChanges 2. invalidateSessionOnPrincipalChange

Ketan
  • 982
  • 1
  • 8
  • 16
1

I was able to fix this issue by overriding the default filter chain (used filter chain proxy) and invoking only the required filters. Thanks LukeTaylor and Ketan for your suggestions. Please let me know if some one has the same issue. I can post my XML and other stuff.

Mahesh Kumar
  • 49
  • 1
  • 1
  • 5