Spring Security 3: Salting password issue
I have got an simple application made in which I am able to register users and authenticate them. I've got the passwords encoded using and successfully able to authenticate them. I am using Spring 3, Spring Security 3 and Hibernate 3 in my application.
Now I want to salt their passwords with the ID of the user but I am not able to achieve this functionality. Could someone help me achieve it? I've been trying to do it for quite some time but ain't able to get it done.
Here is the code I've got for salting users with their ID and authenticating them.
xyz-security.xml
<http auto-config="true" use-expressions="true">
<intercept-url pattern="/welcome.do" access="hasRole('ROLE_USER')" />
<form-login login-page="/login.do" authentication开发者_开发百科-failure-url="/login.do?login_error=1"/>
<logout invalidate-session="true" logout-url="/logout" logout-success-url="/"/>
</http>
<beans:bean id="daoAuthenticationProvider" class="org.springframework.security.authentication.dao.DaoAuthenticationProvider">
<beans:property name="userDetailsService" ref="userDetailsService"/>
</beans:bean>
<beans:bean id="authenticationManager" class="org.springframework.security.authentication.ProviderManager">
<beans:property name="providers">
<beans:list>
<beans:ref local="daoAuthenticationProvider" />
</beans:list>
</beans:property>
</beans:bean>
<authentication-manager>
<authentication-provider user-service-ref="userDetailsService">
<password-encoder ref="passwordEncoder">
<salt-source ref="saltSource"/>
</password-encoder>
</authentication-provider>
</authentication-manager>
<!-- For hashing and salting user passwords -->
<beans:bean id="passwordEncoder" class="org.springframework.security.authentication.encoding.ShaPasswordEncoder"/>
<beans:bean id="saltSource" class="org.springframework.security.authentication.dao.ReflectionSaltSource"
p:userPropertyToUse="id"/>
UserDetailsAdapter.java
@Service("userDetailsAdapter")
public class UserDetailsAdapter {
private Long id;
org.springframework.security.core.userdetails.User buildUserFromUserEntity(User userEntity) {
String username = userEntity.getUsername();
String password = userEntity.getPassword();
boolean enabled = userEntity.isEnabled();
boolean accountNonExpired = true;
boolean credentialsNonExpired = true;
boolean accountNonLocked = true;
Collection<GrantedAuthority> authorities = new ArrayList<GrantedAuthority>();
for (String authority: userEntity.getAuthorities()) {
authorities.add(new GrantedAuthorityImpl(authority));
}
this.id = userEntity.getId();
org.springframework.security.core.userdetails.User user = new org.springframework.security.core.userdetails.User(username, password, enabled, accountNonExpired, credentialsNonExpired, accountNonLocked, authorities);
return user;
}
public Long getId() {
return id;
}
}
UserDetailsServiceImpl
@Service("userDetailsService")
public class UserDetailsServiceImpl implements UserDetailsService {
@Autowired
private UserDao userDao;
@Autowired
private UserDetailsAdapter userDetailsAdapter;
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException, DataAccessException {
UserDetails userDetails = null;
User userEntity = userDao.findByUsername(username);
if (userEntity == null) {
throw new UsernameNotFoundException("user not found");
}
userDetails = userDetailsAdapter.buildUserFromUserEntity(userEntity);
return userDetails;
}
}
UserServiceImpl
@Service
public class UserServiceImpl implements UserService {
@Autowired
private UserDao userDao;
@Autowired
private PasswordEncoder passwordEncoder;
@Autowired
private SaltSource saltSource;
public User getByUsername(String username) {
return userDao.findByUsername(username);
}
public User getByEmail(String email) {
return userDao.findByEmail(email);
}
public void createUser(User user) {
userDao.create(user);
UserDetailsAdapter userDetailsAdapter = new UserDetailsAdapter();
org.springframework.security.core.userdetails.User userDetails = userDetailsAdapter.buildUserFromUserEntity(user);
String password = userDetails.getPassword();
Object salt = saltSource.getSalt(userDetails);
user.setPassword(passwordEncoder.encodePassword(password, salt));
userDao.update(user);
}
public void updateUser(User user) {
userDao.update(user);
}
}
Could someone help me understand what am I missing here? Many thanks.
ReflectionSaltSource
extracts a salt from the instance of UserDetails
. But you use org.springframework.security.core.userdetails.User
as an implementation of UserDetails
, and it doesn't have a property named id
(instead of that you have this property in UserDetailsAdapter
, that doesn't make sense, since UserDetailsAdapter
is a singleton).
So, you need to create a subclass of org.springframework.security.core.userdetails.User
with id
property, and return it from your UserDetailsAdapter
.
Here are the updated files that made it working:
UserDetailsAdapter.java
public class UserDetailsAdapter extends org.springframework.security.core.userdetails.User {
private final Long id;
public UserDetailsAdapter(User userEntity) {
super(userEntity.getUsername(), userEntity.getPassword(), userEntity.isEnabled(), true, true, true, toAuthorities(userEntity.getAuthorities()));
this.id = userEntity.getId();
}
private static Collection<GrantedAuthority> toAuthorities(List<String> authorities) {
Collection<GrantedAuthority> authorityList = new ArrayList<GrantedAuthority>();
for (String authority: authorities) {
authorityList.add(new GrantedAuthorityImpl(authority));
}
return authorityList;
}
public Long getId() {
return id;
}
}
UserDetailsServiceImpl.java
@Service("userDetailsService")
public class UserDetailsServiceImpl implements UserDetailsService {
@Autowired
private UserDao userDao;
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException, DataAccessException {
UserDetails userDetails = null;
User userEntity = userDao.findByUsername(username);
if (userEntity == null) {
throw new UsernameNotFoundException("user not found");
}
userDetails = new UserDetailsAdapter(userEntity);
return userDetails;
}
}
UserServiceImpl.java
@Service
public class UserServiceImpl implements UserService {
...
public void createUser(User user) {
userDao.create(user);
UserDetailsAdapter userDetails = new UserDetailsAdapter(user);
String password = userDetails.getPassword();
Object salt = saltSource.getSalt(userDetails);
user.setPassword(passwordEncoder.encodePassword(password, salt));
userDao.update(user);
}
...
}
Thanks :)
精彩评论