I use,
- Spring Framework 4.0.0 RELEASE (GA)
- Spring Security 3.2.0 RELEASE (GA)
- Struts 2.3.16
in which I use,
org.springframework.security.authentication.dao.DaoAuthenticationProvider
for authentication. My spring-security.xml
file looks like the following.
<?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-4.0.xsd
http://www.springframework.org/schema/security
http://www.springframework.org/schema/security/spring-security-3.2.xsd">
<http pattern="/Login.jsp*" security="none"></http>
<http auto-config='true' use-expressions="true" disable-url-rewriting="true" authentication-manager-ref="authenticationManager">
<session-management session-fixation-protection="newSession">
<concurrency-control max-sessions="1" error-if-maximum-exceeded="true" />
</session-management>
<csrf/>
<headers>
<xss-protection />
<frame-options />
<!--<cache-control />-->
<!--<hsts />-->
<content-type-options /> <!--content sniffing-->
</headers>
<intercept-url pattern="/admin_side/**" access="hasRole('ROLE_ADMIN')" requires-channel="any"/>
<form-login login-page="/admin_login/Login.action" authentication-success-handler-ref="loginSuccessHandler" authentication-failure-handler-ref="authenticationFailureHandler"/>
<logout logout-success-url="/admin_login/Login.action" invalidate-session="true" delete-cookies="JSESSIONID"/>
</http>
<beans:bean id="encoder" class="org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder"/>
<beans:bean id="daoAuthenticationProvider" class="org.springframework.security.authentication.dao.DaoAuthenticationProvider">
<beans:property name="userDetailsService" ref="userDetailsService"/>
<beans:property name="passwordEncoder" ref="encoder" />
</beans:bean>
<beans:bean id="authenticationManager" class="org.springframework.security.authentication.ProviderManager">
<beans:property name="providers">
<beans:list>
<beans:ref bean="daoAuthenticationProvider" />
</beans:list>
</beans:property>
</beans:bean>
<authentication-manager>
<authentication-provider user-service-ref="userDetailsService"/>
</authentication-manager>
<beans:bean id="loginSuccessHandler" class="loginsuccesshandler.LoginSuccessHandler"/>
<beans:bean id="authenticationFailureHandler" class="loginsuccesshandler.AuthenticationFailureHandler" />
<global-method-security secured-annotations="enabled" proxy-target-class="false" authentication-manager-ref="authenticationManager">
<protect-pointcut expression="execution(* admin.dao.*.*(..))" access="ROLE_ADMIN"/>
</global-method-security>
</beans:beans>
The implementation of UserDetailsService
is as follows.
@Service(value="userDetailsService")
public final class UserDetailsImpl implements UserDetailsService {
@Autowired
private final transient UserService userService = null;
@Autowired
private final transient AssemblerService assemblerService = null;
@Override
@Transactional(readOnly = true, propagation = Propagation.REQUIRED)
public UserDetails loadUserByUsername(String userName) throws UsernameNotFoundException {
UserTable userTable = userService.findUserByName(userName);
if (userTable == null) {
throw new UsernameNotFoundException("User name not found.");
} else if (!userTable.getEnabled()) {
throw new DisabledException("The user is disabled.");
} else if (!userTable.getVarified()) {
throw new LockedException("The user is locked.");
}
//Password expiration and other things may also be implemented as and when required.
return assemblerService.buildUserFromUserEntity(userTable);
}
}
And the following is just a helper service that converts a user entity which is to be used by a Spring User
object.
@Service(value="assembler")
@Transactional(readOnly = true, propagation=Propagation.REQUIRED)
public final class AssemblerDAO implements AssemblerService {
@Override
public User buildUserFromUserEntity(UserTable userTable) {
String username = userTable.getEmailId();
String password = userTable.getPassword();
boolean active = userTable.getEnabled();
boolean enabled = active;
boolean accountNonExpired = active;
boolean credentialsNonExpired = active;
boolean accountNonLocked = userTable.getVarified();
Collection<GrantedAuthority> authorities = new ArrayList<GrantedAuthority>();
for (UserRoles role : userTable.getUserRolesSet()) {
authorities.add(new SimpleGrantedAuthority(role.getAuthority()));
}
return new User(username, password, enabled, accountNonExpired, credentialsNonExpired, accountNonLocked, authorities);
}
}
There is no need to refer to these classes.
My question is that while using,
org.springframework.security.provisioning.JdbcUserDetailsManager
UserDetailsManager
can be injected into a controller and its
public void changePassword(String oldPassword, String newPassword) throws AuthenticationException {
//...
}
method can be used to change the password. I never tried this but it may roughly be implemented like the following.
<bean id="jdbcUserService" class="org.springframework.security.provisioning.JdbcUserDetailsManager">
<property name="dataSource" ref="datasource" />
<property name="authenticationManager" ref="authenticationManager" />
</bean>
and in a controller, it should be injected as follows.
@Autowired
@Qualifier("jdbcUserService")
public UserDetailsManager userDetailsManager;
Is there any facility provided by Spring security in the approach I'm using or just a simple method of my own in a DAO to change the password of the current logged-in user is sufficient? Kindly suggest, if I'm doing something wrong anywhere!
This contents may be too big to answer this question but I'm asking this because it is something quite experimental.