mirror of
https://github.com/spring-projects/spring-security.git
synced 2025-06-28 23:02:15 +00:00
SEC-513: Added support for cache flushing after updating or deleting data in JdbcUserDetailsManager.
This commit is contained in:
parent
53fca59301
commit
248d97c9d6
@ -6,6 +6,8 @@ import org.springframework.security.AuthenticationException;
|
|||||||
import org.springframework.security.AuthenticationManager;
|
import org.springframework.security.AuthenticationManager;
|
||||||
import org.springframework.security.context.SecurityContextHolder;
|
import org.springframework.security.context.SecurityContextHolder;
|
||||||
import org.springframework.security.providers.UsernamePasswordAuthenticationToken;
|
import org.springframework.security.providers.UsernamePasswordAuthenticationToken;
|
||||||
|
import org.springframework.security.providers.dao.UserCache;
|
||||||
|
import org.springframework.security.providers.dao.cache.NullUserCache;
|
||||||
import org.springframework.security.userdetails.UserDetails;
|
import org.springframework.security.userdetails.UserDetails;
|
||||||
import org.springframework.security.userdetails.UserDetailsManager;
|
import org.springframework.security.userdetails.UserDetailsManager;
|
||||||
import org.springframework.context.ApplicationContextException;
|
import org.springframework.context.ApplicationContextException;
|
||||||
@ -71,6 +73,8 @@ public class JdbcUserDetailsManager extends JdbcDaoImpl implements UserDetailsMa
|
|||||||
|
|
||||||
private AuthenticationManager authenticationManager;
|
private AuthenticationManager authenticationManager;
|
||||||
|
|
||||||
|
private UserCache userCache = new NullUserCache();
|
||||||
|
|
||||||
//~ Methods ========================================================================================================
|
//~ Methods ========================================================================================================
|
||||||
|
|
||||||
protected void initDao() throws ApplicationContextException {
|
protected void initDao() throws ApplicationContextException {
|
||||||
@ -104,11 +108,14 @@ public class JdbcUserDetailsManager extends JdbcDaoImpl implements UserDetailsMa
|
|||||||
for (int i=0; i < user.getAuthorities().length; i++) {
|
for (int i=0; i < user.getAuthorities().length; i++) {
|
||||||
insertAuthority.update(user.getUsername(), user.getAuthorities()[i].getAuthority());
|
insertAuthority.update(user.getUsername(), user.getAuthorities()[i].getAuthority());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
userCache.removeUserFromCache(user.getUsername());
|
||||||
}
|
}
|
||||||
|
|
||||||
public void deleteUser(String username) {
|
public void deleteUser(String username) {
|
||||||
deleteUserAuthorities.update(username);
|
deleteUserAuthorities.update(username);
|
||||||
deleteUser.update(username);
|
deleteUser.update(username);
|
||||||
|
userCache.removeUserFromCache(username);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void changePassword(String oldPassword, String newPassword) throws AuthenticationException {
|
public void changePassword(String oldPassword, String newPassword) throws AuthenticationException {
|
||||||
@ -136,6 +143,8 @@ public class JdbcUserDetailsManager extends JdbcDaoImpl implements UserDetailsMa
|
|||||||
changePassword.update(new String[] {newPassword, username});
|
changePassword.update(new String[] {newPassword, username});
|
||||||
|
|
||||||
SecurityContextHolder.getContext().setAuthentication(createNewAuthentication(currentUser, newPassword));
|
SecurityContextHolder.getContext().setAuthentication(createNewAuthentication(currentUser, newPassword));
|
||||||
|
|
||||||
|
userCache.removeUserFromCache(username);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected Authentication createNewAuthentication(Authentication currentAuth, String newPassword) {
|
protected Authentication createNewAuthentication(Authentication currentAuth, String newPassword) {
|
||||||
@ -197,6 +206,17 @@ public class JdbcUserDetailsManager extends JdbcDaoImpl implements UserDetailsMa
|
|||||||
this.changePasswordSql = changePasswordSql;
|
this.changePasswordSql = changePasswordSql;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Optionally sets the UserCache if one is in use in the application.
|
||||||
|
* This allows the user to be removed from the cache after updates have taken place to avoid stale data.
|
||||||
|
*
|
||||||
|
* @param userCache the cache used by the AuthenticationManager.
|
||||||
|
*/
|
||||||
|
public void setUserCache(UserCache userCache) {
|
||||||
|
Assert.notNull(userCache, "userCache cannot be null");
|
||||||
|
this.userCache = userCache;
|
||||||
|
}
|
||||||
|
|
||||||
//~ Inner Classes ==================================================================================================
|
//~ Inner Classes ==================================================================================================
|
||||||
|
|
||||||
protected class InsertUser extends SqlUpdate {
|
protected class InsertUser extends SqlUpdate {
|
||||||
|
@ -6,6 +6,7 @@ import org.springframework.security.BadCredentialsException;
|
|||||||
import org.springframework.security.MockAuthenticationManager;
|
import org.springframework.security.MockAuthenticationManager;
|
||||||
import org.springframework.security.context.SecurityContextHolder;
|
import org.springframework.security.context.SecurityContextHolder;
|
||||||
import org.springframework.security.providers.UsernamePasswordAuthenticationToken;
|
import org.springframework.security.providers.UsernamePasswordAuthenticationToken;
|
||||||
|
import org.springframework.security.providers.dao.UserCache;
|
||||||
import org.springframework.security.userdetails.User;
|
import org.springframework.security.userdetails.User;
|
||||||
import org.springframework.security.userdetails.UserDetails;
|
import org.springframework.security.userdetails.UserDetails;
|
||||||
import org.springframework.security.util.AuthorityUtils;
|
import org.springframework.security.util.AuthorityUtils;
|
||||||
@ -19,6 +20,9 @@ import org.junit.Before;
|
|||||||
import org.junit.BeforeClass;
|
import org.junit.BeforeClass;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.HashMap;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Tests for {@link JdbcUserDetailsManager}
|
* Tests for {@link JdbcUserDetailsManager}
|
||||||
*
|
*
|
||||||
@ -34,6 +38,7 @@ public class JdbcUserDetailsManagerTests {
|
|||||||
|
|
||||||
private static DriverManagerDataSource dataSource;
|
private static DriverManagerDataSource dataSource;
|
||||||
private JdbcUserDetailsManager manager;
|
private JdbcUserDetailsManager manager;
|
||||||
|
private MockUserCache cache;
|
||||||
private JdbcTemplate template;
|
private JdbcTemplate template;
|
||||||
|
|
||||||
@BeforeClass
|
@BeforeClass
|
||||||
@ -49,6 +54,8 @@ public class JdbcUserDetailsManagerTests {
|
|||||||
@Before
|
@Before
|
||||||
public void initializeManagerAndCreateTables() {
|
public void initializeManagerAndCreateTables() {
|
||||||
manager = new JdbcUserDetailsManager();
|
manager = new JdbcUserDetailsManager();
|
||||||
|
cache = new MockUserCache();
|
||||||
|
manager.setUserCache(cache);
|
||||||
manager.setDataSource(dataSource);
|
manager.setDataSource(dataSource);
|
||||||
manager.setCreateUserSql(JdbcUserDetailsManager.DEF_CREATE_USER_SQL);
|
manager.setCreateUserSql(JdbcUserDetailsManager.DEF_CREATE_USER_SQL);
|
||||||
manager.setUpdateUserSql(JdbcUserDetailsManager.DEF_UPDATE_USER_SQL);
|
manager.setUpdateUserSql(JdbcUserDetailsManager.DEF_UPDATE_USER_SQL);
|
||||||
@ -83,16 +90,17 @@ public class JdbcUserDetailsManagerTests {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void deleteUserRemovesUserDataAndAuthorities() {
|
public void deleteUserRemovesUserDataAndAuthoritiesAndClearsCache() {
|
||||||
insertJoe();
|
insertJoe();
|
||||||
manager.deleteUser("joe");
|
manager.deleteUser("joe");
|
||||||
|
|
||||||
assertEquals(0, template.queryForList(SELECT_JOE_SQL).size());
|
assertEquals(0, template.queryForList(SELECT_JOE_SQL).size());
|
||||||
assertEquals(0, template.queryForList(SELECT_JOE_AUTHORITIES_SQL).size());
|
assertEquals(0, template.queryForList(SELECT_JOE_AUTHORITIES_SQL).size());
|
||||||
|
assertFalse(cache.getUserMap().containsKey("joe"));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void updateUserChangesDataCorrectly() {
|
public void updateUserChangesDataCorrectlyAndClearsCache() {
|
||||||
insertJoe();
|
insertJoe();
|
||||||
User newJoe = new User("joe","newpassword",false,true,true,true,
|
User newJoe = new User("joe","newpassword",false,true,true,true,
|
||||||
AuthorityUtils.stringArrayToAuthorityArray(new String[]{"D","E","F"}));
|
AuthorityUtils.stringArrayToAuthorityArray(new String[]{"D","E","F"}));
|
||||||
@ -102,6 +110,7 @@ public class JdbcUserDetailsManagerTests {
|
|||||||
UserDetails joe = manager.loadUserByUsername("joe");
|
UserDetails joe = manager.loadUserByUsername("joe");
|
||||||
|
|
||||||
assertEquals(newJoe, joe);
|
assertEquals(newJoe, joe);
|
||||||
|
assertFalse(cache.getUserMap().containsKey("joe"));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@ -113,6 +122,7 @@ public class JdbcUserDetailsManagerTests {
|
|||||||
public void userExistsReturnsTrueForExistingUsername() {
|
public void userExistsReturnsTrueForExistingUsername() {
|
||||||
insertJoe();
|
insertJoe();
|
||||||
assertTrue(manager.userExists("joe"));
|
assertTrue(manager.userExists("joe"));
|
||||||
|
assertTrue(cache.getUserMap().containsKey("joe"));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test(expected = AccessDeniedException.class)
|
@Test(expected = AccessDeniedException.class)
|
||||||
@ -128,6 +138,7 @@ public class JdbcUserDetailsManagerTests {
|
|||||||
UserDetails newJoe = manager.loadUserByUsername("joe");
|
UserDetails newJoe = manager.loadUserByUsername("joe");
|
||||||
|
|
||||||
assertEquals("newPassword", newJoe.getPassword());
|
assertEquals("newPassword", newJoe.getPassword());
|
||||||
|
assertFalse(cache.getUserMap().containsKey("joe"));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@ -144,6 +155,7 @@ public class JdbcUserDetailsManagerTests {
|
|||||||
assertEquals("joe", newAuth.getName());
|
assertEquals("joe", newAuth.getName());
|
||||||
assertEquals(currentAuth.getDetails(), newAuth.getDetails());
|
assertEquals(currentAuth.getDetails(), newAuth.getDetails());
|
||||||
assertEquals("newPassword", newAuth.getCredentials());
|
assertEquals("newPassword", newAuth.getCredentials());
|
||||||
|
assertFalse(cache.getUserMap().containsKey("joe"));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@ -162,6 +174,7 @@ public class JdbcUserDetailsManagerTests {
|
|||||||
UserDetails newJoe = manager.loadUserByUsername("joe");
|
UserDetails newJoe = manager.loadUserByUsername("joe");
|
||||||
assertEquals("password", newJoe.getPassword());
|
assertEquals("password", newJoe.getPassword());
|
||||||
assertEquals("password", SecurityContextHolder.getContext().getAuthentication().getCredentials());
|
assertEquals("password", SecurityContextHolder.getContext().getAuthentication().getCredentials());
|
||||||
|
assertTrue(cache.getUserMap().containsKey("joe"));
|
||||||
}
|
}
|
||||||
|
|
||||||
private Authentication authenticateJoe() {
|
private Authentication authenticateJoe() {
|
||||||
@ -177,5 +190,26 @@ public class JdbcUserDetailsManagerTests {
|
|||||||
template.execute("insert into authorities (username, authority) values ('joe','A')");
|
template.execute("insert into authorities (username, authority) values ('joe','A')");
|
||||||
template.execute("insert into authorities (username, authority) values ('joe','B')");
|
template.execute("insert into authorities (username, authority) values ('joe','B')");
|
||||||
template.execute("insert into authorities (username, authority) values ('joe','C')");
|
template.execute("insert into authorities (username, authority) values ('joe','C')");
|
||||||
|
cache.putUserInCache(joe);
|
||||||
|
}
|
||||||
|
|
||||||
|
private class MockUserCache implements UserCache {
|
||||||
|
private Map cache = new HashMap();
|
||||||
|
|
||||||
|
public UserDetails getUserFromCache(String username) {
|
||||||
|
return (User) cache.get(username);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void putUserInCache(UserDetails user) {
|
||||||
|
cache.put(user.getUsername(), user);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void removeUserFromCache(String username) {
|
||||||
|
cache.remove(username);
|
||||||
|
}
|
||||||
|
|
||||||
|
Map getUserMap() {
|
||||||
|
return cache;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user