title: Spring Security session concurrency
body: <p>I have an app build with Spring 4.0 and Security 3.2 and I want to implement session concurrency but it does not seems to work. All other aspects of security are working just fine. Here are my xml configs:<br>
  first of all in my web.xml:  </p>
  
  <pre><code>&lt;listener&gt;
      &lt;listener-class&gt;
          org.springframework.security.web.session.HttpSessionEventPublisher
      &lt;/listener-class&gt;
  &lt;/listener&gt; 
  </code></pre>
  
  <p>then in my security.xml  </p>
  
  <pre><code>&lt;security:http  auto-config="false" 
                  use-expressions="true"
                  authentication-manager-ref="authManager"
                  access-decision-manager-ref="webAccessDecisionManager"
                  entry-point-ref="authenticationEntryPoint"&gt;             
  
      &lt;security:intercept-url pattern="/agent/**" access="hasAnyRole('ROLE_AGENT')" /&gt;
      &lt;security:intercept-url pattern="/admin/**" access="hasRole('ROLE_ADMIN')" /&gt;       
      &lt;security:intercept-url pattern="/public/**" access="permitAll" /&gt;
      &lt;security:intercept-url pattern="/**" access="permitAll" /&gt;
  
      &lt;security:session-management session-authentication-strategy-ref="sas"
                                   invalid-session-url="/public/login.xhtml"/&gt;
  
      &lt;security:logout logout-success-url="/public/login.xhtml" 
                       invalidate-session="true" 
                       delete-cookies="true"/&gt;
      &lt;security:expression-handler ref="webExpressionHandler"/&gt;
  
      &lt;security:custom-filter position="FORM_LOGIN_FILTER" ref="myAuthFilter" /&gt;
      &lt;security:custom-filter position="CONCURRENT_SESSION_FILTER" ref="concurrencyFilter" /&gt;
  &lt;/security:http&gt;
  </code></pre>
  
  <p>and </p>
  
  <pre><code>&lt;bean id="authenticationEntryPoint"  class="org.springframework.security.web.authentication.LoginUrlAuthenticationEntryPoint"&gt;
      &lt;constructor-arg index="0" value="/public/login.xhtml" /&gt;
  &lt;/bean&gt;
  
  &lt;bean id="customAuthenticationFailureHandler" class="org.springframework.security.web.authentication.SimpleUrlAuthenticationFailureHandler"
     p:defaultFailureUrl="/public/login.xhtml" /&gt;
  
  &lt;bean id="sessionRegistry" class="org.springframework.security.core.session.SessionRegistryImpl"/&gt;
  
   &lt;bean id="concurrencyFilter" class="org.springframework.security.web.session.ConcurrentSessionFilter"&gt;
      &lt;constructor-arg index="0" ref="sessionRegistry"/&gt;
      &lt;constructor-arg index="1" value="/session-expired.htm"/&gt;       
  &lt;/bean&gt;
  
  &lt;bean id="myAuthFilter" class="org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter"&gt;
      &lt;property name="sessionAuthenticationStrategy" ref="sas" /&gt;
      &lt;property name="authenticationManager" ref="authManager" /&gt;
      &lt;property name="authenticationFailureHandler" ref="customAuthenticationFailureHandler"/&gt;
  &lt;/bean&gt;
  
  &lt;bean id="sas" class="org.springframework.security.web.authentication.session.ConcurrentSessionControlAuthenticationStrategy"&gt;
      &lt;constructor-arg name="sessionRegistry" ref="sessionRegistry" /&gt;
      &lt;property name="maximumSessions" value="1" /&gt;
      &lt;property name="exceptionIfMaximumExceeded" value="true" /&gt;
  &lt;/bean&gt;  
  
  &lt;bean id="authManager" class="org.springframework.security.authentication.ProviderManager"&gt;
      &lt;property name="providers"&gt;
          &lt;list&gt;  
              &lt;ref bean="myCompLdapAuthProvider"/&gt;        
              &lt;ref bean="myCompDBAuthProvider"/&gt;
          &lt;/list&gt;     
      &lt;/property&gt;     
  &lt;/bean&gt;
  </code></pre>
  
  <p>My UserDetails implements hashCode() an equals() and with all this the concurrent session limitation does not work. After a little debug session I have observed that my session is never found in sessionRegistry and I guess that this is the main reason, but I do not know why!?<br>
  Any idea of what I`m doing wrong here ?   </p>
  
  <p>P.S. I have such records in my debug logs:  </p>
  
  <pre><code>(FilterChainProxy.java:337) - /resources/images/icons/connection_on.gif at position 2 of 11 in     additional filter chain; firing Filter: 'ConcurrentSessionFilter'
  (FilterChainProxy.java:337) - /resources/images/icons/connection_on.gif at position 3 of 11 in additional filter chain; firing Filter: 'WebAsyncManagerIntegrationFilter'
  (FilterChainProxy.java:337) - /resources/images/icons/connection_on.gif at position 4 of 11 in additional filter chain; firing Filter: 'LogoutFilter'
  (FilterChainProxy.java:337) - /resources/images/icons/connection_on.gif at position 5 of 11 in additional filter chain; firing Filter: 'UsernamePasswordAuthenticationFilter'
  (FilterChainProxy.java:337) - /resources/images/icons/connection_on.gif at position 6 of 11 in additional filter chain; firing Filter: 'RequestCacheAwareFilter'
  (FilterChainProxy.java:337) - /resources/images/icons/connection_on.gif at position 7 of 11 in additional filter chain; firing Filter: 'SecurityContextHolderAwareRequestFilter'
  (FilterChainProxy.java:337) - /resources/images/icons/connection_on.gif at position 8 of 11 in additional filter chain; firing Filter: 'AnonymousAuthenticationFilter'
  (AnonymousAuthenticationFilter.java:107) - SecurityContextHolder not populated with anonymous token, as it already contained: 'org.springframework.security.authentication.UsernamePasswordAuthenticationToken@96cf68e: Principal: MyUserDetails [username=adrian.videanu, dn=org.springframework.ldap.core.DirContextAdapter: dn=cn=Adrian Videanu,ou=IT,ou=Organization .....
  </code></pre>
  
  <p>so the filters are invoked...  </p>
  
  <p>Updates  </p>
  
  <p>I can see that the session creation event is published because i have this line in logs :  </p>
  
  <pre><code>(HttpSessionEventPublisher.java:66) - Publishing event: org.springframework.security.web.session.HttpSessionCreatedEvent[source=org.apache.catalina.session.StandardSessionFacade@3827a0aa]  
  </code></pre>
  
  <p>but i never hit registerNewSession method from SessionRegistryImpl as I guess it should. Also the HttpSessionEventPublisher is invoked when I initially open the login page because I guess that`s when the session is created, but then after I enter the credentials and push submit HttpSessionEventPublisher is not invoked anymore.</p>
  
  <p>Updates 2<br>
  As a test I have injected SessionRegistryImpl to one of my beans in order to try to access some of its methods:  </p>
  
  <pre><code>@Named
  @Scope("view")
  public class UserDashboardMB  implements Serializable {
  
  private static final long serialVersionUID = 1L;
  
  @Inject
  private SessionRegistry sessionRegistry;
  
  public void init(){
  
      System.out.println("-- START INIT -- ");
      List&lt;Object&gt; principals = sessionRegistry.getAllPrincipals();
  
      System.out.println("Principals = "+principals);
  
      for (Object p:principals){
          System.out.println("Principal = "+p);
      }
  
      System.out.println("-- STOP INIT -- ");
  }   
  }  
  </code></pre>
  
  <p>and the output is :<br>
  INFO: -- START INIT --<br>
  INFO: Principals = []<br>
  INFO: -- STOP INIT --<br>
  so, nothing is populated there.  </p>
  
  <p>Update 3<br>
  I have replaced "sas" bean with the one provided by Serge but it still doesn`t seems to work. I have neabled the debugger again and I thing that the problem is that on class UsernamePasswordAuthenticationFilter at method doFilter() none of my requests are processed as it should.Here is a part of doFilter():  </p>
  
  <pre><code> public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain)
          throws IOException, ServletException {
  
      HttpServletRequest request = (HttpServletRequest) req;
      HttpServletResponse response = (HttpServletResponse) res;
  
      if (!requiresAuthentication(request, response)) {
          chain.doFilter(request, response);
  
          return;
      }
  
      if (logger.isDebugEnabled()) {
          logger.debug("Request is to process authentication");
      }
  
      Authentication authResult;
  // rest of method here
  }
  </code></pre>
  
  <p>From what I see in the debugger my requests doesn't seems to require auth and chain.doFilter(request, response); is invoked.  </p>
  
  <p>Update 4<br>
  I guess i found the issue. The filter is not running as it should because the filterUrl param is not the proper one. As i read in the docs: </p>
  
  <blockquote>
    <p>This filter by default responds to the URL /j_spring_security_check. </p>
  </blockquote>
  
  <p>but my login part is implemented with JSF managed beans and actions. Now, my login form is at /public/login.xhtml and the url that the login info are posted is the same. If I set this as filterUrl I have problems because is called at the intial form rendering also and I have a infinite loop there as no user/password are set up.<br>
  Any idea how to overcome that ?<br>
  This is how my LoginManagedBean looks like:  </p>
  
  <pre><code>@Named
  @Scope("request")
  public class LoginMB implements Serializable {
  
  private static final long serialVersionUID = 1L;
  
  @Autowired
  @Qualifier("authManager")
  private AuthenticationManager authenticationManager;
  
  // setters and getters
  
  public String login(){
  
      FacesContext context = FacesContext.getCurrentInstance();
  
      try {
          Authentication request = new UsernamePasswordAuthenticationToken(this.getUsername(), this.getPassword());
          Authentication result = authenticationManager.authenticate(request);
          SecurityContextHolder.getContext().setAuthentication(result);
  
          // perform some extra logic here and return protected page
          return "/agent/dashboard.xhtml?faces-redirect=true";
  
      } catch (AuthenticationException e) {
          e.printStackTrace();                        
          logger.error("Auth Exception -&gt;"+e.getMessage());
          FacesMessage fm = new FacesMessage("Invalid user/password");
          fm.setSeverity(FacesMessage.SEVERITY_ERROR);
          context.addMessage(null, fm);                   
      }
      return null;
     }
  }
  </code></pre>