JdbcUserDetailsManager handles extra UserDetails attributes
Check ResutSetMetaData to see if extra columns are present in order to also handle the UserDetails attributes: accountNonExpired, accountNonLocked and credentialsNonExpired. Fixes gh-4399
This commit is contained in:
parent
12f320851d
commit
4123d96cd5
|
|
@ -295,7 +295,8 @@ public class JdbcDaoImpl extends JdbcDaoSupport
|
||||||
}
|
}
|
||||||
|
|
||||||
return new User(returnUsername, userFromUserQuery.getPassword(),
|
return new User(returnUsername, userFromUserQuery.getPassword(),
|
||||||
userFromUserQuery.isEnabled(), true, true, true, combinedAuthorities);
|
userFromUserQuery.isEnabled(), userFromUserQuery.isAccountNonExpired(),
|
||||||
|
userFromUserQuery.isCredentialsNonExpired(), userFromUserQuery.isAccountNonLocked(), combinedAuthorities);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright 2002-2016 the original author or authors.
|
* Copyright 2002-2018 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
|
@ -24,6 +24,7 @@ import org.springframework.security.core.GrantedAuthority;
|
||||||
import org.springframework.security.core.authority.AuthorityUtils;
|
import org.springframework.security.core.authority.AuthorityUtils;
|
||||||
import org.springframework.security.core.authority.SimpleGrantedAuthority;
|
import org.springframework.security.core.authority.SimpleGrantedAuthority;
|
||||||
import org.springframework.security.core.context.SecurityContextHolder;
|
import org.springframework.security.core.context.SecurityContextHolder;
|
||||||
|
import org.springframework.security.core.userdetails.User;
|
||||||
import org.springframework.security.core.userdetails.UserCache;
|
import org.springframework.security.core.userdetails.UserCache;
|
||||||
import org.springframework.security.core.userdetails.UserDetails;
|
import org.springframework.security.core.userdetails.UserDetails;
|
||||||
import org.springframework.security.core.userdetails.cache.NullUserCache;
|
import org.springframework.security.core.userdetails.cache.NullUserCache;
|
||||||
|
|
@ -145,15 +146,51 @@ public class JdbcUserDetailsManager extends JdbcDaoImpl implements UserDetailsMa
|
||||||
// ~ UserDetailsManager implementation
|
// ~ UserDetailsManager implementation
|
||||||
// ==============================================================================
|
// ==============================================================================
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Executes the SQL <tt>usersByUsernameQuery</tt> and returns a list of UserDetails
|
||||||
|
* objects. There should normally only be one matching user.
|
||||||
|
*/
|
||||||
|
protected List<UserDetails> loadUsersByUsername(String username) {
|
||||||
|
return getJdbcTemplate().query(getUsersByUsernameQuery(), new String[]{username},
|
||||||
|
(rs, rowNum) -> {
|
||||||
|
|
||||||
|
String userName = rs.getString(1);
|
||||||
|
String password = rs.getString(2);
|
||||||
|
boolean enabled = rs.getBoolean(3);
|
||||||
|
|
||||||
|
boolean accLocked = false;
|
||||||
|
boolean accExpired = false;
|
||||||
|
boolean credsExpired = false;
|
||||||
|
|
||||||
|
if (rs.getMetaData().getColumnCount() > 3) {
|
||||||
|
//NOTE: acc_locked, acc_expired and creds_expired are also to be loaded
|
||||||
|
accLocked = rs.getBoolean(4);
|
||||||
|
accExpired = rs.getBoolean(5);
|
||||||
|
credsExpired = rs.getBoolean(6);
|
||||||
|
}
|
||||||
|
return new User(userName, password, enabled, !accExpired, !credsExpired, !accLocked,
|
||||||
|
AuthorityUtils.NO_AUTHORITIES);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
public void createUser(final UserDetails user) {
|
public void createUser(final UserDetails user) {
|
||||||
validateUserDetails(user);
|
validateUserDetails(user);
|
||||||
|
|
||||||
getJdbcTemplate().update(createUserSql, new PreparedStatementSetter() {
|
getJdbcTemplate().update(createUserSql, new PreparedStatementSetter() {
|
||||||
|
@Override
|
||||||
public void setValues(PreparedStatement ps) throws SQLException {
|
public void setValues(PreparedStatement ps) throws SQLException {
|
||||||
ps.setString(1, user.getUsername());
|
ps.setString(1, user.getUsername());
|
||||||
ps.setString(2, user.getPassword());
|
ps.setString(2, user.getPassword());
|
||||||
ps.setBoolean(3, user.isEnabled());
|
ps.setBoolean(3, user.isEnabled());
|
||||||
}
|
|
||||||
|
|
||||||
|
int paramCount = ps.getParameterMetaData().getParameterCount();
|
||||||
|
if (paramCount > 3) {
|
||||||
|
//NOTE: acc_locked, acc_expired and creds_expired are also to be inserted
|
||||||
|
ps.setBoolean(4, !user.isAccountNonLocked());
|
||||||
|
ps.setBoolean(5, !user.isAccountNonExpired());
|
||||||
|
ps.setBoolean(6, !user.isCredentialsNonExpired());
|
||||||
|
}
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
if (getEnableAuthorities()) {
|
if (getEnableAuthorities()) {
|
||||||
|
|
@ -163,11 +200,25 @@ public class JdbcUserDetailsManager extends JdbcDaoImpl implements UserDetailsMa
|
||||||
|
|
||||||
public void updateUser(final UserDetails user) {
|
public void updateUser(final UserDetails user) {
|
||||||
validateUserDetails(user);
|
validateUserDetails(user);
|
||||||
|
|
||||||
getJdbcTemplate().update(updateUserSql, new PreparedStatementSetter() {
|
getJdbcTemplate().update(updateUserSql, new PreparedStatementSetter() {
|
||||||
|
@Override
|
||||||
public void setValues(PreparedStatement ps) throws SQLException {
|
public void setValues(PreparedStatement ps) throws SQLException {
|
||||||
ps.setString(1, user.getPassword());
|
ps.setString(1, user.getPassword());
|
||||||
ps.setBoolean(2, user.isEnabled());
|
ps.setBoolean(2, user.isEnabled());
|
||||||
ps.setString(3, user.getUsername());
|
|
||||||
|
int paramCount = ps.getParameterMetaData().getParameterCount();
|
||||||
|
if (paramCount == 3) {
|
||||||
|
ps.setString(3, user.getUsername());
|
||||||
|
} else {
|
||||||
|
//NOTE: acc_locked, acc_expired and creds_expired are also updated
|
||||||
|
ps.setBoolean(3, !user.isAccountNonLocked());
|
||||||
|
ps.setBoolean(4, !user.isAccountNonExpired());
|
||||||
|
ps.setBoolean(5, !user.isCredentialsNonExpired());
|
||||||
|
|
||||||
|
ps.setString(6, user.getUsername());
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright 2002-2017 the original author or authors.
|
* Copyright 2002-2018 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
|
@ -106,6 +106,19 @@ public class JdbcUserDetailsManagerTests {
|
||||||
SecurityContextHolder.clearContext();
|
SecurityContextHolder.clearContext();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void setUpAccLockingColumns() {
|
||||||
|
template.execute("alter table users add column acc_locked boolean default false not null");
|
||||||
|
template.execute("alter table users add column acc_expired boolean default false not null");
|
||||||
|
template.execute("alter table users add column creds_expired boolean default false not null");
|
||||||
|
|
||||||
|
manager.setUsersByUsernameQuery(
|
||||||
|
"select username,password,enabled, acc_locked, acc_expired, creds_expired from users where username = ?");
|
||||||
|
manager.setCreateUserSql(
|
||||||
|
"insert into users (username, password, enabled, acc_locked, acc_expired, creds_expired) values (?,?,?,?,?,?)");
|
||||||
|
manager.setUpdateUserSql(
|
||||||
|
"update users set password = ?, enabled = ?, acc_locked=?, acc_expired=?, creds_expired=? where username = ?");
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void createUserInsertsCorrectData() {
|
public void createUserInsertsCorrectData() {
|
||||||
manager.createUser(joe);
|
manager.createUser(joe);
|
||||||
|
|
@ -115,6 +128,19 @@ public class JdbcUserDetailsManagerTests {
|
||||||
assertThat(joe2).isEqualTo(joe);
|
assertThat(joe2).isEqualTo(joe);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void createUserInsertsCorrectDataWithLocking() {
|
||||||
|
setUpAccLockingColumns();
|
||||||
|
|
||||||
|
UserDetails user = new User("joe", "pass", true, false, true, false,
|
||||||
|
AuthorityUtils.createAuthorityList("A", "B"));
|
||||||
|
manager.createUser(user);
|
||||||
|
|
||||||
|
UserDetails user2 = manager.loadUserByUsername(user.getUsername());
|
||||||
|
|
||||||
|
assertThat(user2).isEqualToComparingFieldByField(user);
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void deleteUserRemovesUserDataAndAuthoritiesAndClearsCache() {
|
public void deleteUserRemovesUserDataAndAuthoritiesAndClearsCache() {
|
||||||
insertJoe();
|
insertJoe();
|
||||||
|
|
@ -139,6 +165,24 @@ public class JdbcUserDetailsManagerTests {
|
||||||
assertThat(cache.getUserMap().containsKey("joe")).isFalse();
|
assertThat(cache.getUserMap().containsKey("joe")).isFalse();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void updateUserChangesDataCorrectlyAndClearsCacheWithLocking() {
|
||||||
|
setUpAccLockingColumns();
|
||||||
|
|
||||||
|
insertJoe();
|
||||||
|
|
||||||
|
User newJoe = new User("joe", "newpassword", false, false, false, true,
|
||||||
|
AuthorityUtils.createAuthorityList("D", "F", "E"));
|
||||||
|
|
||||||
|
manager.updateUser(newJoe);
|
||||||
|
|
||||||
|
UserDetails joe = manager.loadUserByUsername(newJoe.getUsername());
|
||||||
|
|
||||||
|
assertThat(joe).isEqualToComparingFieldByField(newJoe);
|
||||||
|
assertThat(cache.getUserMap().containsKey(newJoe.getUsername())).isFalse();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void userExistsReturnsFalseForNonExistentUsername() {
|
public void userExistsReturnsFalseForNonExistentUsername() {
|
||||||
assertThat(manager.userExists("joe")).isFalse();
|
assertThat(manager.userExists("joe")).isFalse();
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue