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