KEYCLOAK-5078 ConcurrencyTest fails intermittently

This commit fixes 401 Unauthorized issues
This commit is contained in:
Hynek Mlnarik 2017-06-23 15:16:23 +02:00
parent 58e5f41415
commit 8f9ed32a66
6 changed files with 31 additions and 12 deletions

View file

@ -35,7 +35,7 @@ import java.util.Set;
* @version $Revision: 1 $ * @version $Revision: 1 $
*/ */
public class GroupAdapter implements GroupModel { public class GroupAdapter implements GroupModel {
protected GroupModel updated; protected volatile GroupModel updated;
protected CachedGroup cached; protected CachedGroup cached;
protected RealmCacheSession cacheSession; protected RealmCacheSession cacheSession;
protected KeycloakSession keycloakSession; protected KeycloakSession keycloakSession;
@ -56,7 +56,7 @@ public class GroupAdapter implements GroupModel {
} }
} }
protected boolean invalidated; protected volatile boolean invalidated;
public void invalidate() { public void invalidate() {
invalidated = true; invalidated = true;
} }

View file

@ -55,7 +55,7 @@ import java.util.concurrent.ConcurrentHashMap;
public class RealmAdapter implements CachedRealmModel { public class RealmAdapter implements CachedRealmModel {
protected CachedRealm cached; protected CachedRealm cached;
protected RealmCacheSession cacheSession; protected RealmCacheSession cacheSession;
protected RealmModel updated; protected volatile RealmModel updated;
protected RealmCache cache; protected RealmCache cache;
protected KeycloakSession session; protected KeycloakSession session;
@ -75,7 +75,7 @@ public class RealmAdapter implements CachedRealmModel {
return updated; return updated;
} }
protected boolean invalidated; protected volatile boolean invalidated;
protected void invalidateFlag() { protected void invalidateFlag() {
invalidated = true; invalidated = true;

View file

@ -41,7 +41,7 @@ import java.util.concurrent.ConcurrentHashMap;
* @version $Revision: 1 $ * @version $Revision: 1 $
*/ */
public class UserAdapter implements CachedUserModel { public class UserAdapter implements CachedUserModel {
protected UserModel updated; protected volatile UserModel updated;
protected CachedUser cached; protected CachedUser cached;
protected UserCacheSession userProviderCache; protected UserCacheSession userProviderCache;
protected KeycloakSession keycloakSession; protected KeycloakSession keycloakSession;

View file

@ -56,7 +56,22 @@ public class CredentialModel implements Serializable {
private int period; private int period;
private MultivaluedHashMap<String, String> config; private MultivaluedHashMap<String, String> config;
public CredentialModel shallowClone() {
CredentialModel res = new CredentialModel();
res.id = id;
res.type = type;
res.value = value;
res.device = device;
res.salt = salt;
res.hashIterations = hashIterations;
res.createdDate = createdDate;
res.counter = counter;
res.algorithm = algorithm;
res.digits = digits;
res.period = period;
res.config = config;
return res;
}
public String getId() { public String getId() {
return id; return id;

View file

@ -18,7 +18,7 @@ package org.keycloak.models.cache;
import org.keycloak.models.UserModel; import org.keycloak.models.UserModel;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap;
/** /**
* Cached users will implement this interface * Cached users will implement this interface
@ -55,5 +55,5 @@ public interface CachedUserModel extends UserModel {
* *
* @return * @return
*/ */
ConcurrentHashMap getCachedWith(); ConcurrentMap getCachedWith();
} }

View file

@ -56,12 +56,14 @@ public class PasswordCredentialProvider implements CredentialProvider, Credentia
} }
public CredentialModel getPassword(RealmModel realm, UserModel user) { public CredentialModel getPassword(RealmModel realm, UserModel user) {
List<CredentialModel> passwords; List<CredentialModel> passwords = null;
if (user instanceof CachedUserModel && !((CachedUserModel)user).isMarkedForEviction()) { if (user instanceof CachedUserModel && !((CachedUserModel)user).isMarkedForEviction()) {
CachedUserModel cached = (CachedUserModel)user; CachedUserModel cached = (CachedUserModel)user;
passwords = (List<CredentialModel>)cached.getCachedWith().get(PASSWORD_CACHE_KEY); passwords = (List<CredentialModel>)cached.getCachedWith().get(PASSWORD_CACHE_KEY);
} else { }
// if the model was marked for eviction while passwords were initialized, override it from credentialStore
if (! (user instanceof CachedUserModel) || ((CachedUserModel) user).isMarkedForEviction()) {
passwords = getCredentialStore().getStoredCredentialsByType(realm, user, CredentialModel.PASSWORD); passwords = getCredentialStore().getStoredCredentialsByType(realm, user, CredentialModel.PASSWORD);
} }
if (passwords == null || passwords.isEmpty()) return null; if (passwords == null || passwords.isEmpty()) return null;
@ -207,8 +209,10 @@ public class PasswordCredentialProvider implements CredentialProvider, Credentia
return true; return true;
} }
hash.encode(cred.getValue(), policy.getHashIterations(), password); CredentialModel newPassword = password.shallowClone();
getCredentialStore().updateCredential(realm, user, password); hash.encode(cred.getValue(), policy.getHashIterations(), newPassword);
getCredentialStore().updateCredential(realm, user, newPassword);
UserCache userCache = session.userCache(); UserCache userCache = session.userCache();
if (userCache != null) { if (userCache != null) {
userCache.evict(realm, user); userCache.evict(realm, user);