I'm working on a web application that uses Spring Security 3.0.7 to authenticate users either by username/password or using OpenID. Now I need the ability to disable some accounts. At first I couldn't find a relevant documentation for, but finally I found out User.isEnabled():
Indicates whether the user is enabled or disabled. A disabled user cannot be authenticated.
the value for this flag is given in the constructor.
When authenticating using a form it seems to work fine. Unfortunately it seems that Spring's OpenID completely ignores the flag. I logged as much as I could and I can see in the log:
DEBUG o.s.s.o.OpenIDAuthenticationFilter - Authentication success. Updating SecurityContextHolder to contain: [org.springframework.security.openid.OpenIDAuthenticationToken@66348da1: Principal: mypackage.UserInfo@ddd49b1b: Username: cbada36792e42a3be5a5e0f77d14e918186c7e3f; Password: [PROTECTED]; Enabled: false; AccountNonExpired: true; credentialsNonExpired: true; AccountNonLocked: true; Granted Authorities: ROLE_USER; Credentials: [PROTECTED]; Authenticated: true; Details: org.springframework.security.web.authentication.WebAuthenticationDetails@fffd148a: RemoteIpAddress: 127.0.0.1; SessionId: 1arhd8er0sj1yynglq8linpnb; Granted Authorities: ROLE_USER, attributes : []]
How can authentication be successful on a disabled account? (It is the same if I try to lock the account instead.)
Am I missing something important? Or is it just a bug? Any ideas what to look for, what more logging to enable?
My XML configuration:
<?xml version="1.0" encoding="UTF-8"?>
<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.0.xsd
http://www.springframework.org/schema/security
http://www.springframework.org/schema/security/spring-security-3.0.xsd">
<global-method-security secured-annotations="enabled">
</global-method-security>
<http use-expressions="true" auto-config="true">
<intercept-url pattern="/" access="permitAll" />
<!-- ... other pattens -->
<form-login
login-page="/"
authentication-success-handler-ref="loginSuccessHandler"
/>
<remember-me data-source-ref="dataSource" user-service-ref="myUserDetails"/>
<openid-login
user-service-ref="openIdAuth"
authentication-success-handler-ref="loginSuccessHandler"
authentication-failure-handler-ref="openIdFailureHandler"
>
<attribute-exchange>
<openid-attribute name="email" type="http://axschema.org/contact/email" required="true" />
<openid-attribute name="name" type="http://axschema.org/namePerson" />
</attribute-exchange>
</openid-login>
<logout success-handler-ref="logoutSuccessHandler"/>
</http>
<authentication-manager>
<authentication-provider ref="daoAuthenticationProvider"/>
</authentication-manager>
<beans:bean id="daoAuthenticationProvider"
class="org.springframework.security.authentication.dao.DaoAuthenticationProvider">
<beans:property name="userDetailsService" ref="myUserDetails"/>
<beans:property name="saltSource" ref="saltSource"/>
<beans:property name="passwordEncoder" ref="passwordEncoder"/>
<beans:property name="preAuthenticationChecks">
<beans:bean class="org.springframework.security.authentication.AccountStatusUserDetailsChecker"/>
</beans:property>
</beans:bean>
</beans:beans>
Here myUserDetails
is my custom bean that loads a user from a database and returns a simple custom implementation of User
:
public class UserInfo
extends User
{
public UserInfo(UserEntity user)
{
super( user.getUserName(),
user.getPassword(),
!user.isDisabled(), // enabled
true, // non-expired
true, // credentials non-expired
!user.isLocked(), // non-locked
UserInfo.authorities(user) // my static method
);
// store some info for further reference here
// ...
}
// ...
}