mardi 21 juin 2016

Spring security 3.2.3 concurrent login issue

Hello I am not very familiar with spring security session management, but have tried preventing concurrent login using sample example as mentioned in http://docs.spring.io/spring-security/site/docs/3.2.5.RELEASE/reference/htmlsingle/#concurrent-sessions.

I do not get any errors in console, but at the same time when i login with a username from one machine and then on another machine it does not prevent the login or do not logout the 1st user.

I have kept log4j.logger.org.springframework.security=DEBUG in log4j.properties file but do not see any obvious error.

UserDetailsImpl class

   public class UserDetailsImpl implements UserDetails {
    private Collection<GrantedAuthority> authorities = null;
    private String username;
    private String email;
    private String password;
    private String userFirstName;
    private String userLastName;
    private boolean accountNonExpired = false;
    private boolean accountNonLocked = false;
    private boolean credentialsNonExpired = false;
    private boolean enabled = false;


    public UserDetailsImpl(Collection<GrantedAuthority> authorities, String email, String password, String userFirstName, String userLastName, boolean accountNonExpired, boolean accountNonLocked, boolean credentialsNonExpired, boolean enabled) {
        this.authorities = authorities;
        this.username = email;
        this.email=email; //basically same as username, but username kept since Spring might need for DAO authentication
        this.password = password;
        this.userFirstName = userFirstName;
        this.userLastName = userLastName;
        this.accountNonExpired = accountNonExpired;
        this.accountNonLocked = accountNonLocked;
        this.credentialsNonExpired = credentialsNonExpired;
        this.enabled = enabled;
    }


    public Collection<GrantedAuthority> getAuthorities() {
        return authorities;
    }


    public void setAuthorities(Collection<GrantedAuthority> authorities) {
        this.authorities = authorities;
    }


    public String getPassword() {
        return password;
    }


    public void setPassword(String password) {
        this.password = password;
    }


    public String getUsername() {
        return username;
    }


    public void setUsername(String username) {
        this.username = username;
    }

    public String getEmail() {
        return email;
    }


    public void setEmail(String email) {
        this.email = email;
    }


    public String getUserFirstName() {
        return userFirstName;
    }


    public void setUserFirstName(String userFirstName) {
        this.userFirstName = userFirstName;
    }


    public String getUserLastName() {
        return userLastName;
    }


    public void setUserLastName(String userLastName) {
        this.userLastName = userLastName;
    }

    public boolean isAccountNonExpired() {
        return accountNonExpired;
    }


    public void setAccountNonExpired(boolean accountNonExpired) {
        this.accountNonExpired = accountNonExpired;
    }


    public boolean isAccountNonLocked() {
        return accountNonLocked;
    }


    public void setAccountNonLocked(boolean accountNonLocked) {
        this.accountNonLocked = accountNonLocked;
    }


    public boolean isCredentialsNonExpired() {
        return credentialsNonExpired;
    }


    public void setCredentialsNonExpired(boolean credentialsNonExpired) {
        this.credentialsNonExpired = credentialsNonExpired;
    }


    public boolean isEnabled() {
        return enabled;
    }


    public void setEnabled(boolean enabled) {
        this.enabled = enabled;
    }



    /**
     * Returns {@code true} if the supplied object is a {@code User} instance with the
     * same {@code username} value.
     * <p>
     * In other words, the objects are equal if they have the same username, representing the
     * same principal.
     */
    @Override
    public boolean equals(Object rhs) {
        if (rhs instanceof UserDetailsImpl) {
            return username.equals(((UserDetailsImpl) rhs).username);
        }
        return false;
    }

    /**
     * Returns the hashcode of the {@code username}.
     */
    @Override
    public int hashCode() {
        return username.hashCode();
    }

    @Override
    public String toString() {
        StringBuilder sb = new StringBuilder();
        sb.append(super.toString()).append(": ");
        sb.append("Username: ").append(this.username).append("; ");
        sb.append("Password: [PROTECTED]; ");
        sb.append("Enabled: ").append(this.enabled).append("; ");
        sb.append("AccountNonExpired: ").append(this.accountNonExpired).append("; ");
        sb.append("credentialsNonExpired: ").append(this.credentialsNonExpired).append("; ");
        sb.append("AccountNonLocked: ").append(this.accountNonLocked).append("; ");

        if (!authorities.isEmpty()) {
            sb.append("Granted Authorities: ");

            boolean first = true;
            for (GrantedAuthority auth : authorities) {
                if (!first) {
                    sb.append(",");
                }
                first = false;

                sb.append(auth);
            }
        } else {
            sb.append("Not granted any authorities");
        }

        return sb.toString();
    }




    }

applicationContext-security.xml

 <http auto-config="true" use-expressions="true" disable-url-rewriting="true"  access-decision-manager-ref="accessDecisionManager">
            <intercept-url pattern="/MDS/hemoncCBC/hemoncCBCHome.html" access="permitAll"/>   

            <!--  
            <form-login login-page="/MDSHome.html" always-use-default-target="true" />
            <intercept-url pattern="/caseSubmission.html" access="hasAnyRole('Admin','Moderator')" />
            <intercept-url pattern="/**" access="permitAll"/>               
            <intercept-url pattern="/home.html" access="hasAnyRole('Admin','Moderator')"/> 
            <intercept-url pattern="/MDSHome.html/login.html" access="hasRole('Admin')"  requires-channel='https'/> -->

            <form-login login-page="/loginPage.html"
                        default-target-url="/MDSHome.html"
                        always-use-default-target="true" 
                        authentication-failure-url= "/redirectToMDSLogin.html?error=true"/>
                        <!--   authentication-failure-url= "/redirectToMDSLogin.html?error=true" /> -->


            <intercept-url pattern="/**" access="permitAll"/>  

            <!--
            <intercept-url pattern="/**" access="ROLE_USER" />      
            <intercept-url pattern="/anonymous*" access="isAnonymous()" />
            <intercept-url pattern="/login*" access="permitAll" />
            <intercept-url pattern="/**" access="isAuthenticated()" /> -->

            <access-denied-handler error-page="/WEB-INF/jsp/access_denied.jsp"/>

            <logout invalidate-session="true"  
                logout-url="/j_spring_security_logout" 
                success-handler-ref="mySimpleUrlLogoutSuccessHandler" 
                delete-cookies="JSESSIONID,COOKIE-MDS" />

            <remember-me token-validity-seconds="1209600"  data-source-ref="dataSource" user-service-ref="userDetailsService"/>

            <!--  
            <session-management  session-authentication-error-url="/WEB-INF/jsp/access_denied.jsp">
                <concurrency-control max-sessions="1" error-if-maximum-exceeded="true" />
            </session-management> -->


             <custom-filter before="CONCURRENT_SESSION_FILTER" ref="concurrencyFilter" />
             <custom-filter before="FORM_LOGIN_FILTER" ref="authenticationFilter" />

             <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="/sessionExpired.html" />
    </beans:bean>

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

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



    <beans:bean id="mySimpleUrlLogoutSuccessHandler" class="com.medicalsingularity.app.MDS.security.MySimpleUrlLogoutSuccessHandler" />


    <beans:bean id="authenticationFilter" class="org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter">
        <beans:property name="sessionAuthenticationStrategy" ref="sas" />
        <beans:property name="authenticationManager" ref="authenticationManager"/>
        <beans:property name="filterProcessesUrl" value="/j_spring_security_check"/>
    </beans:bean> 



</beans:beans>  

DEBUG log

DEBUG HttpSessionSecurityContextRepository2016-06-18 01:06:25,249 Obtained a valid SecurityContext from SPRING_SECURITY_CONTEXT: 'org.springframework.security.core.context.SecurityContextImpl@adbe30d5: Authentication: org.springframework.security.authentication.UsernamePasswordAuthenticationToken@adbe30d5: Principal: com.medicalsingularity.app.MDS.security.UserDetailsImpl@a90fa6c6: Username: pms_priti@yahoo.com; Password: [PROTECTED]; Enabled: true; AccountNonExpired: true; credentialsNonExpired: true; AccountNonLocked: true; Granted Authorities: Admin,PaidOQ,LoggedInUser,PaidHQ,PaidHOC,PaidHOCQ; Credentials: [PROTECTED]; Authenticated: true; Details: null; Granted Authorities: Admin, PaidOQ, LoggedInUser, PaidHQ, PaidHOC, PaidHOCQ' DEBUG FilterChainProxy 2016-06-18 01:06:25,249 /FreeWheels.mp3 at position 2 of 13 in additional filter chain; firing Filter: 'ConcurrentSessionFilter' DEBUG FilterChainProxy 2016-06-18 01:06:25,249 /FreeWheels.mp3 at position 3 of 13 in additional filter chain; firing Filter: 'WebAsyncManagerIntegrationFilter' DEBUG FilterChainProxy 2016-06-18 01:06:25,264 /FreeWheels.mp3 at position 4 of 13 in additional filter chain; firing Filter: 'LogoutFilter' DEBUG FilterChainProxy 2016-06-18 01:06:25,264 /FreeWheels.mp3 at position 5 of 13 in additional filter chain; firing Filter: 'UsernamePasswordAuthenticationFilter' DEBUG FilterChainProxy 2016-06-18 01:06:25,264 /FreeWheels.mp3 at position 6 of 13 in additional filter chain; firing Filter: 'BasicAuthenticationFilter' DEBUG FilterChainProxy 2016-06-18 01:06:25,264 /FreeWheels.mp3 at position 7 of 13 in additional filter chain; firing Filter: 'RequestCacheAwareFilter' DEBUG FilterChainProxy 2016-06-18 01:06:25,264 /FreeWheels.mp3 at position 8 of 13 in additional filter chain; firing Filter: 'SecurityContextHolderAwareRequestFilter' DEBUG FilterChainProxy 2016-06-18 01:06:25,264 /FreeWheels.mp3 at position 9 of 13 in additional filter chain; firing Filter: 'RememberMeAuthenticationFilter' DEBUG RememberMeAuthenticationFilter2016-06-18 01:06:25,265 SecurityContextHolder not populated with remember-me token, as it already contained: 'org.springframework.security.authentication.UsernamePasswordAuthenticationToken@adbe30d5: Principal: com.medicalsingularity.app.MDS.security.UserDetailsImpl@a90fa6c6: Username: pms_priti@yahoo.com; Password: [PROTECTED]; Enabled: true; AccountNonExpired: true; credentialsNonExpired: true; AccountNonLocked: true; Granted Authorities: Admin,PaidOQ,LoggedInUser,PaidHQ,PaidHOC,PaidHOCQ; Credentials: [PROTECTED]; Authenticated: true; Details: null; Granted Authorities: Admin, PaidOQ, LoggedInUser, PaidHQ, PaidHOC, PaidHOCQ' DEBUG FilterChainProxy 2016-06-18 01:06:25,265 /FreeWheels.mp3 at position 10 of 13 in additional filter chain; firing Filter: 'AnonymousAuthenticationFilter' DEBUG AnonymousAuthenticationFilter2016-06-18 01:06:25,265 SecurityContextHolder not populated with anonymous token, as it already contained: 'org.springframework.security.authentication.UsernamePasswordAuthenticationToken@adbe30d5: Principal: com.medicalsingularity.app.MDS.security.UserDetailsImpl@a90fa6c6: Username: pms_priti@yahoo.com; Password: [PROTECTED]; Enabled: true; AccountNonExpired: true; credentialsNonExpired: true; AccountNonLocked: true; Granted Authorities: Admin,PaidOQ,LoggedInUser,PaidHQ,PaidHOC,PaidHOCQ; Credentials: [PROTECTED]; Authenticated: true; Details: null; Granted Authorities: Admin, PaidOQ, LoggedInUser, PaidHQ, PaidHOC, PaidHOCQ' DEBUG FilterChainProxy 2016-06-18 01:06:25,265 /FreeWheels.mp3 at position 11 of 13 in additional filter chain; firing Filter: 'SessionManagementFilter' DEBUG FilterChainProxy 2016-06-18 01:06:25,265 /FreeWheels.mp3 at position 12 of 13 in additional filter chain; firing Filter: 'ExceptionTranslationFilter' DEBUG FilterChainProxy 2016-06-18 01:06:25,265 /FreeWheels.mp3 at position 13 of 13 in additional filter chain; firing Filter: 'FilterSecurityInterceptor' DEBUG AntPathRequestMatcher 2016-06-18 01:06:25,265 Checking match of request : '/freewheels.mp3'; against '/mds/hemonccbc/hemonccbchome.html' DEBUG FilterSecurityInterceptor2016-06-18 01:06:25,265 Secure object: FilterInvocation: URL: /FreeWheels.mp3; Attributes: [permitAll] DEBUG FilterSecurityInterceptor2016-06-18 01:06:25,265 Previously Authenticated: org.springframework.security.authentication.UsernamePasswordAuthenticationToken@adbe30d5: Principal: com.medicalsingularity.app.MDS.security.UserDetailsImpl@a90fa6c6: Username: pms_priti@yahoo.com; Password: [PROTECTED]; Enabled: true; AccountNonExpired: true; credentialsNonExpired: true; AccountNonLocked: true; Granted Authorities: Admin,PaidOQ,LoggedInUser,PaidHQ,PaidHOC,PaidHOCQ; Credentials: [PROTECTED]; Authenticated: true; Details: null; Granted Authorities: Admin, PaidOQ, LoggedInUser, PaidHQ, PaidHOC, PaidHOCQ DEBUG AffirmativeBased 2016-06-18 01:06:25,265 Voter: org.springframework.security.web.access.expression.WebExpressionVoter@249c441b, returned: 1 DEBUG FilterSecurityInterceptor2016-06-18 01:06:25,265 Authorization successful DEBUG FilterSecurityInterceptor2016-06-18 01:06:25,265 RunAsManager did not change Authentication object DEBUG FilterChainProxy 2016-06-18 01:06:25,265 /FreeWheels.mp3 reached end of additional filter chain; proceeding with original chain DEBUG ExceptionTranslationFilter2016-06-18 01:06:25,265 Chain processed normally DEBUG SecurityContextPersistenceFilter2016-06-18 01:06:25,265 SecurityContextHolder now cleared, as request processing completed

How do I prevent concurrent multiple login with same username/pwd login in from different machines. Would greatly appreciate any help.

Thank you.

Aucun commentaire:

Enregistrer un commentaire