keycloak-uncached
Changes
model/invalidation-cache/model-adapters/src/main/java/org/keycloak/models/cache/CacheKeycloakSession.java 2(+2 -0)
model/invalidation-cache/model-adapters/src/main/java/org/keycloak/models/cache/ClientAdapter.java 3(+2 -1)
model/invalidation-cache/model-adapters/src/main/java/org/keycloak/models/cache/DefaultCacheKeycloakSession.java 59(+56 -3)
model/invalidation-cache/model-adapters/src/main/java/org/keycloak/models/cache/entities/CachedUser.java 24(+23 -1)
model/invalidation-cache/model-adapters/src/main/java/org/keycloak/models/cache/KeycloakCache.java 15(+15 -0)
model/invalidation-cache/model-adapters/src/main/java/org/keycloak/models/cache/NoCacheKeycloakSession.java 5(+5 -0)
model/invalidation-cache/model-adapters/src/main/java/org/keycloak/models/cache/SimpleCache.java 127(+120 -7)
model/invalidation-cache/model-adapters/src/main/java/org/keycloak/models/cache/UserAdapter.java 283(+283 -0)
Details
diff --git a/model/invalidation-cache/model-adapters/src/main/java/org/keycloak/models/cache/CacheKeycloakSession.java b/model/invalidation-cache/model-adapters/src/main/java/org/keycloak/models/cache/CacheKeycloakSession.java
index 7ad72b8..0955387 100755
--- a/model/invalidation-cache/model-adapters/src/main/java/org/keycloak/models/cache/CacheKeycloakSession.java
+++ b/model/invalidation-cache/model-adapters/src/main/java/org/keycloak/models/cache/CacheKeycloakSession.java
@@ -16,4 +16,6 @@ public interface CacheKeycloakSession extends KeycloakSession {
void registerRoleInvalidation(String id);
void registerOAuthClientInvalidation(String id);
+
+ void registerUserInvalidation(String id);
}
diff --git a/model/invalidation-cache/model-adapters/src/main/java/org/keycloak/models/cache/ClientAdapter.java b/model/invalidation-cache/model-adapters/src/main/java/org/keycloak/models/cache/ClientAdapter.java
index 82e0332..660c738 100755
--- a/model/invalidation-cache/model-adapters/src/main/java/org/keycloak/models/cache/ClientAdapter.java
+++ b/model/invalidation-cache/model-adapters/src/main/java/org/keycloak/models/cache/ClientAdapter.java
@@ -174,8 +174,9 @@ public abstract class ClientAdapter implements ClientModel {
public boolean hasScope(RoleModel role) {
if (updatedClient != null) return updatedClient.hasScope(role);
+ if (cachedClient.getScope().contains(role.getId())) return true;
+
Set<RoleModel> roles = getScopeMappings();
- if (roles.contains(role)) return true;
for (RoleModel mapping : roles) {
if (mapping.hasRole(role)) return true;
diff --git a/model/invalidation-cache/model-adapters/src/main/java/org/keycloak/models/cache/DefaultCacheKeycloakSession.java b/model/invalidation-cache/model-adapters/src/main/java/org/keycloak/models/cache/DefaultCacheKeycloakSession.java
index b4f6376..1a69c6c 100755
--- a/model/invalidation-cache/model-adapters/src/main/java/org/keycloak/models/cache/DefaultCacheKeycloakSession.java
+++ b/model/invalidation-cache/model-adapters/src/main/java/org/keycloak/models/cache/DefaultCacheKeycloakSession.java
@@ -17,6 +17,7 @@ import org.keycloak.models.cache.entities.CachedOAuthClient;
import org.keycloak.models.cache.entities.CachedRealm;
import org.keycloak.models.cache.entities.CachedRealmRole;
import org.keycloak.models.cache.entities.CachedRole;
+import org.keycloak.models.cache.entities.CachedUser;
import org.keycloak.provider.ProviderSession;
import java.util.HashMap;
@@ -41,10 +42,12 @@ public class DefaultCacheKeycloakSession implements CacheKeycloakSession {
protected Set<String> appInvalidations = new HashSet<String>();
protected Set<String> roleInvalidations = new HashSet<String>();
protected Set<String> clientInvalidations = new HashSet<String>();
+ protected Set<String> userInvalidations = new HashSet<String>();
protected Map<String, RealmModel> managedRealms = new HashMap<String, RealmModel>();
protected Map<String, ApplicationModel> managedApplications = new HashMap<String, ApplicationModel>();
protected Map<String, OAuthClientModel> managedClients = new HashMap<String, OAuthClientModel>();
protected Map<String, RoleModel> managedRoles = new HashMap<String, RoleModel>();
+ protected Map<String, UserModel> managedUsers = new HashMap<String, UserModel>();
protected boolean clearAll;
@@ -88,6 +91,11 @@ public class DefaultCacheKeycloakSession implements CacheKeycloakSession {
clientInvalidations.add(id);
}
+ @Override
+ public void registerUserInvalidation(String id) {
+ userInvalidations.add(id);
+ }
+
protected void runInvalidations() {
for (String id : realmInvalidations) {
cache.invalidateCachedRealmById(id);
@@ -101,6 +109,9 @@ public class DefaultCacheKeycloakSession implements CacheKeycloakSession {
for (String id : clientInvalidations) {
cache.invalidateCachedOAuthClientById(id);
}
+ for (String id : userInvalidations) {
+ cache.invalidateCachedUserById(id);
+ }
}
@@ -210,17 +221,59 @@ public class DefaultCacheKeycloakSession implements CacheKeycloakSession {
@Override
public UserModel getUserById(String id, RealmModel realm) {
- return getDelegate().getUserById(id, realm);
+ CachedUser cached = cache.getCachedUser(id);
+ if (cached == null) {
+ UserModel model = getDelegate().getUserById(id, realm);
+ if (model == null) return null;
+ if (userInvalidations.contains(id)) return model;
+ cached = new CachedUser(realm, model);
+ cache.addCachedUser(cached);
+ } else if (userInvalidations.contains(id)) {
+ return getDelegate().getUserById(id, realm);
+ } else if (managedUsers.containsKey(id)) {
+ return managedUsers.get(id);
+ }
+ UserAdapter adapter = new UserAdapter(cached, cache, this, realm);
+ managedUsers.put(id, adapter);
+ return adapter;
}
@Override
public UserModel getUserByUsername(String username, RealmModel realm) {
- return getDelegate().getUserByUsername(username, realm);
+ CachedUser cached = cache.getCachedUserByUsername(username, realm);
+ if (cached == null) {
+ UserModel model = getDelegate().getUserByUsername(username, realm);
+ if (model == null) return null;
+ if (userInvalidations.contains(model.getId())) return model;
+ cached = new CachedUser(realm, model);
+ cache.addCachedUser(cached);
+ } else if (userInvalidations.contains(cached.getId())) {
+ return getDelegate().getUserById(cached.getId(), realm);
+ } else if (managedUsers.containsKey(cached.getId())) {
+ return managedUsers.get(cached.getId());
+ }
+ UserAdapter adapter = new UserAdapter(cached, cache, this, realm);
+ managedUsers.put(cached.getId(), adapter);
+ return adapter;
}
@Override
public UserModel getUserByEmail(String email, RealmModel realm) {
- return getDelegate().getUserByEmail(email, realm);
+ CachedUser cached = cache.getCachedUserByEmail(email, realm);
+ if (cached == null) {
+ UserModel model = getDelegate().getUserByEmail(email, realm);
+ if (model == null) return null;
+ if (userInvalidations.contains(model.getId())) return model;
+ cached = new CachedUser(realm, model);
+ cache.addCachedUser(cached);
+ } else if (userInvalidations.contains(cached.getId())) {
+ return getDelegate().getUserByEmail(email, realm);
+ } else if (managedUsers.containsKey(cached.getId())) {
+ return managedUsers.get(cached.getId());
+ }
+ UserAdapter adapter = new UserAdapter(cached, cache, this, realm);
+ managedUsers.put(cached.getId(), adapter);
+ return adapter;
}
@Override
diff --git a/model/invalidation-cache/model-adapters/src/main/java/org/keycloak/models/cache/entities/CachedUser.java b/model/invalidation-cache/model-adapters/src/main/java/org/keycloak/models/cache/entities/CachedUser.java
index 557e7e9..465f08f 100755
--- a/model/invalidation-cache/model-adapters/src/main/java/org/keycloak/models/cache/entities/CachedUser.java
+++ b/model/invalidation-cache/model-adapters/src/main/java/org/keycloak/models/cache/entities/CachedUser.java
@@ -1,5 +1,7 @@
package org.keycloak.models.cache.entities;
+import org.keycloak.models.AuthenticationLinkModel;
+import org.keycloak.models.RealmModel;
import org.keycloak.models.RoleModel;
import org.keycloak.models.UserCredentialValueModel;
import org.keycloak.models.UserModel;
@@ -18,32 +20,40 @@ import java.util.Set;
public class CachedUser {
private String id;
private String loginName;
+ private String usernameKey;
private String firstName;
private String lastName;
private String email;
+ private String emailKey;
private boolean emailVerified;
private int notBefore;
private List<UserCredentialValueModel> credentials = new LinkedList<UserCredentialValueModel>();
private boolean enabled;
private boolean totp;
+ private AuthenticationLinkModel authenticationLink;
private Map<String, String> attributes = new HashMap<String, String>();
private Set<UserModel.RequiredAction> requiredActions = new HashSet<UserModel.RequiredAction>();
private Set<String> roleMappings = new HashSet<String>();
- public CachedUser(UserModel user) {
+ public CachedUser(RealmModel realm, UserModel user) {
this.id = user.getId();
this.loginName = user.getLoginName();
+ this.usernameKey = realm.getId() + "." + this.loginName;
this.firstName = user.getFirstName();
this.lastName = user.getLastName();
this.attributes.putAll(user.getAttributes());
this.email = user.getEmail();
+ if (this.email != null) {
+ this.emailKey = realm.getId() + "." + this.email;
+ }
this.emailVerified = user.isEmailVerified();
this.notBefore = user.getNotBefore();
this.credentials.addAll(user.getCredentialsDirectly());
this.enabled = user.isEnabled();
this.totp = user.isTotp();
this.requiredActions.addAll(user.getRequiredActions());
+ this.authenticationLink = user.getAuthenticationLink();
for (RoleModel role : user.getRoleMappings()) {
roleMappings.add(role.getId());
}
@@ -57,6 +67,14 @@ public class CachedUser {
return loginName;
}
+ public String getUsernameKey() {
+ return usernameKey;
+ }
+
+ public String getEmailKey() {
+ return emailKey;
+ }
+
public String getFirstName() {
return firstName;
}
@@ -100,4 +118,8 @@ public class CachedUser {
public Set<String> getRoleMappings() {
return roleMappings;
}
+
+ public AuthenticationLinkModel getAuthenticationLink() {
+ return authenticationLink;
+ }
}
diff --git a/model/invalidation-cache/model-adapters/src/main/java/org/keycloak/models/cache/KeycloakCache.java b/model/invalidation-cache/model-adapters/src/main/java/org/keycloak/models/cache/KeycloakCache.java
index 20ad44b..dca8fa1 100755
--- a/model/invalidation-cache/model-adapters/src/main/java/org/keycloak/models/cache/KeycloakCache.java
+++ b/model/invalidation-cache/model-adapters/src/main/java/org/keycloak/models/cache/KeycloakCache.java
@@ -1,9 +1,11 @@
package org.keycloak.models.cache;
+import org.keycloak.models.RealmModel;
import org.keycloak.models.cache.entities.CachedApplication;
import org.keycloak.models.cache.entities.CachedOAuthClient;
import org.keycloak.models.cache.entities.CachedRealm;
import org.keycloak.models.cache.entities.CachedRole;
+import org.keycloak.models.cache.entities.CachedUser;
/**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
@@ -48,4 +50,17 @@ public interface KeycloakCache {
void invalidateRoleById(String id);
+
+ CachedUser getCachedUser(String id);
+
+ void invalidateCachedUser(CachedUser user);
+
+ void addCachedUser(CachedUser user);
+
+ CachedUser getCachedUserByUsername(String name, RealmModel realm);
+ CachedUser getCachedUserByEmail(String name, RealmModel realm);
+
+ void invalidedCachedUserById(String id);
+
+ void invalidateCachedUserById(String id);
}
diff --git a/model/invalidation-cache/model-adapters/src/main/java/org/keycloak/models/cache/NoCacheKeycloakSession.java b/model/invalidation-cache/model-adapters/src/main/java/org/keycloak/models/cache/NoCacheKeycloakSession.java
index afc35e3..12410e1 100755
--- a/model/invalidation-cache/model-adapters/src/main/java/org/keycloak/models/cache/NoCacheKeycloakSession.java
+++ b/model/invalidation-cache/model-adapters/src/main/java/org/keycloak/models/cache/NoCacheKeycloakSession.java
@@ -278,4 +278,9 @@ public class NoCacheKeycloakSession implements CacheKeycloakSession {
public void removeUserSessions(RealmModel realm) {
getDelegate().removeUserSessions(realm);
}
+
+ @Override
+ public void registerUserInvalidation(String id) {
+ //To change body of implemented methods use File | Settings | File Templates.
+ }
}
diff --git a/model/invalidation-cache/model-adapters/src/main/java/org/keycloak/models/cache/SimpleCache.java b/model/invalidation-cache/model-adapters/src/main/java/org/keycloak/models/cache/SimpleCache.java
index 69bd613..f40723b 100755
--- a/model/invalidation-cache/model-adapters/src/main/java/org/keycloak/models/cache/SimpleCache.java
+++ b/model/invalidation-cache/model-adapters/src/main/java/org/keycloak/models/cache/SimpleCache.java
@@ -1,18 +1,15 @@
package org.keycloak.models.cache;
-import org.keycloak.Config;
-import org.keycloak.models.KeycloakSession;
-import org.keycloak.models.KeycloakSessionFactory;
-import org.keycloak.models.KeycloakTransaction;
import org.keycloak.models.RealmModel;
import org.keycloak.models.cache.entities.CachedApplication;
import org.keycloak.models.cache.entities.CachedOAuthClient;
import org.keycloak.models.cache.entities.CachedRealm;
import org.keycloak.models.cache.entities.CachedRole;
-import org.keycloak.provider.ProviderSession;
-import org.keycloak.provider.ProviderSessionFactory;
+import org.keycloak.models.cache.entities.CachedUser;
-import java.util.List;
+import java.util.Collections;
+import java.util.LinkedHashMap;
+import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
/**
@@ -27,6 +24,121 @@ public class SimpleCache implements KeycloakCache {
protected ConcurrentHashMap<String, CachedOAuthClient> clientCache = new ConcurrentHashMap<String, CachedOAuthClient>();
protected ConcurrentHashMap<String, CachedRole> roleCache = new ConcurrentHashMap<String, CachedRole>();
+ protected int maxUserCacheSize = 10000;
+ protected boolean userCacheEnabled = true;
+
+ protected Map<String, CachedUser> usersById = Collections.synchronizedMap(new LRUCache());
+ protected Map<String, CachedUser> usersByUsername = new ConcurrentHashMap<String, CachedUser>();
+ protected Map<String, CachedUser> usersByEmail = new ConcurrentHashMap<String, CachedUser>();
+
+ protected class LRUCache extends LinkedHashMap<String, CachedUser> {
+ public LRUCache() {
+ super(1000, 1.1F, true);
+ }
+
+ @Override
+ public CachedUser put(String key, CachedUser value) {
+ usersByUsername.put(value.getUsernameKey(), value);
+ if (value.getEmail() != null) {
+ usersByEmail.put(value.getEmailKey(), value);
+ }
+ return super.put(key, value);
+ }
+
+ @Override
+ public CachedUser remove(Object key) {
+ CachedUser user = super.remove(key);
+ if (user == null) return null;
+ removeUser(user);
+ return user;
+ }
+
+ @Override
+ public void clear() {
+ super.clear();
+ usersByUsername.clear();
+ usersByEmail.clear();
+ }
+
+ @Override
+ protected boolean removeEldestEntry(Map.Entry<String, CachedUser> eldest) {
+ boolean evict = size() > maxUserCacheSize;
+ if (evict) {
+ removeUser(eldest.getValue());
+ }
+ return evict;
+ }
+
+ private void removeUser(CachedUser value) {
+ usersByUsername.remove(value.getUsernameKey());
+ if (value.getEmail() != null) usersByEmail.remove(value.getEmailKey());
+ }
+ }
+
+ public int getMaxUserCacheSize() {
+ return maxUserCacheSize;
+ }
+
+ public void setMaxUserCacheSize(int maxUserCacheSize) {
+ this.maxUserCacheSize = maxUserCacheSize;
+ }
+
+ public boolean isUserCacheEnabled() {
+ return userCacheEnabled;
+ }
+
+ public void setUserCacheEnabled(boolean userCacheEnabled) {
+ this.userCacheEnabled = userCacheEnabled;
+ }
+
+ @Override
+ public CachedUser getCachedUser(String id) {
+ if (!userCacheEnabled) return null;
+ return usersById.get(id);
+ }
+
+ @Override
+ public void invalidateCachedUser(CachedUser user) {
+ if (!userCacheEnabled) return;
+ usersById.remove(user.getId());
+ }
+
+ @Override
+ public void invalidateCachedUserById(String id) {
+ if (!userCacheEnabled) return;
+ usersById.remove(id);
+ }
+
+ @Override
+ public void addCachedUser(CachedUser user) {
+ if (!userCacheEnabled) return;
+ usersById.put(user.getId(), user);
+ }
+
+ @Override
+ public CachedUser getCachedUserByUsername(String name, RealmModel realm) {
+ if (!userCacheEnabled) return null;
+ CachedUser user = usersByUsername.get(realm.getId() + "." +name);
+ if (user == null) return null;
+ usersById.get(user.getId()); // refresh cache entry age
+ return user;
+ }
+
+ @Override
+ public CachedUser getCachedUserByEmail(String name, RealmModel realm) {
+ if (!userCacheEnabled) return null;
+ CachedUser user = usersByEmail.get(realm.getId() + "." +name);
+ if (user == null) return null;
+ usersById.get(user.getId()); // refresh cache entry age
+ return user;
+ }
+
+ @Override
+ public void invalidedCachedUserById(String id) {
+ if (!userCacheEnabled) return;
+ usersById.remove(id);
+ }
+
@Override
public void clear() {
realmCache.clear();
@@ -34,6 +146,7 @@ public class SimpleCache implements KeycloakCache {
applicationCache.clear();
clientCache.clear();
roleCache.clear();
+ usersById.clear();
}
@Override
diff --git a/model/invalidation-cache/model-adapters/src/main/java/org/keycloak/models/cache/UserAdapter.java b/model/invalidation-cache/model-adapters/src/main/java/org/keycloak/models/cache/UserAdapter.java
new file mode 100755
index 0000000..a31f3e0
--- /dev/null
+++ b/model/invalidation-cache/model-adapters/src/main/java/org/keycloak/models/cache/UserAdapter.java
@@ -0,0 +1,283 @@
+package org.keycloak.models.cache;
+
+import org.keycloak.models.ApplicationModel;
+import org.keycloak.models.AuthenticationLinkModel;
+import org.keycloak.models.RealmModel;
+import org.keycloak.models.RoleContainerModel;
+import org.keycloak.models.RoleModel;
+import org.keycloak.models.UserCredentialModel;
+import org.keycloak.models.UserCredentialValueModel;
+import org.keycloak.models.UserModel;
+import org.keycloak.models.cache.entities.CachedUser;
+
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
+ * @version $Revision: 1 $
+ */
+public class UserAdapter implements UserModel {
+ protected UserModel updated;
+ protected CachedUser cached;
+ protected KeycloakCache cache;
+ protected CacheKeycloakSession cacheSession;
+ protected RealmModel realm;
+
+ public UserAdapter(CachedUser cached, KeycloakCache cache, CacheKeycloakSession session, RealmModel realm) {
+ this.cached = cached;
+ this.cache = cache;
+ this.cacheSession = session;
+ this.realm = realm;
+ }
+
+ protected void getDelegateForUpdate() {
+ if (updated == null) {
+ cacheSession.registerUserInvalidation(getId());
+ updated = cacheSession.getDelegate().getUserById(getId(), realm);
+ if (updated == null) throw new IllegalStateException("Not found in database");
+ }
+ }
+ @Override
+ public String getId() {
+ if (updated != null) return updated.getId();
+ return cached.getId();
+ }
+
+ @Override
+ public String getLoginName() {
+ if (updated != null) return updated.getLoginName();
+ return cached.getLoginName();
+ }
+
+ @Override
+ public void setLoginName(String loginName) {
+ getDelegateForUpdate();
+ updated.setLoginName(loginName);
+ }
+
+ @Override
+ public boolean isEnabled() {
+ if (updated != null) return updated.isEnabled();
+ return cached.isEnabled();
+ }
+
+ @Override
+ public boolean isTotp() {
+ if (updated != null) return updated.isTotp();
+ return cached.isTotp();
+ }
+
+ @Override
+ public void setEnabled(boolean enabled) {
+ getDelegateForUpdate();
+ updated.setEnabled(enabled);
+ }
+
+ @Override
+ public void setAttribute(String name, String value) {
+ getDelegateForUpdate();
+ updated.setAttribute(name, value);
+ }
+
+ @Override
+ public void removeAttribute(String name) {
+ getDelegateForUpdate();
+ updated.removeAttribute(name);
+ }
+
+ @Override
+ public String getAttribute(String name) {
+ if (updated != null) return updated.getAttribute(name);
+ return cached.getAttributes().get(name);
+ }
+
+ @Override
+ public Map<String, String> getAttributes() {
+ if (updated != null) return updated.getAttributes();
+ return cached.getAttributes();
+ }
+
+ @Override
+ public Set<RequiredAction> getRequiredActions() {
+ if (updated != null) return updated.getRequiredActions();
+ return cached.getRequiredActions();
+ }
+
+ @Override
+ public void addRequiredAction(RequiredAction action) {
+ getDelegateForUpdate();
+ updated.addRequiredAction(action);
+ }
+
+ @Override
+ public void removeRequiredAction(RequiredAction action) {
+ getDelegateForUpdate();
+ updated.removeRequiredAction(action);
+ }
+
+ @Override
+ public String getFirstName() {
+ if (updated != null) return updated.getFirstName();
+ return cached.getFirstName();
+ }
+
+ @Override
+ public void setFirstName(String firstName) {
+ getDelegateForUpdate();
+ updated.setFirstName(firstName);
+ }
+
+ @Override
+ public String getLastName() {
+ if (updated != null) return updated.getLastName();
+ return cached.getLastName();
+ }
+
+ @Override
+ public void setLastName(String lastName) {
+ getDelegateForUpdate();
+ updated.setLastName(lastName);
+ }
+
+ @Override
+ public String getEmail() {
+ if (updated != null) return updated.getEmail();
+ return cached.getEmail();
+ }
+
+ @Override
+ public void setEmail(String email) {
+ getDelegateForUpdate();
+ updated.setEmail(email);
+ }
+
+ @Override
+ public boolean isEmailVerified() {
+ if (updated != null) return updated.isEmailVerified();
+ return cached.isEmailVerified();
+ }
+
+ @Override
+ public void setEmailVerified(boolean verified) {
+ getDelegateForUpdate();
+ updated.setEmailVerified(verified);
+ }
+
+ @Override
+ public void setTotp(boolean totp) {
+ getDelegateForUpdate();
+ updated.setTotp(totp);
+ }
+
+ @Override
+ public int getNotBefore() {
+ if (updated != null) return updated.getNotBefore();
+ return cached.getNotBefore();
+ }
+
+ @Override
+ public void setNotBefore(int notBefore) {
+ getDelegateForUpdate();
+ updated.setNotBefore(notBefore);
+ }
+
+ @Override
+ public void updateCredential(UserCredentialModel cred) {
+ getDelegateForUpdate();
+ updated.updateCredential(cred);
+ }
+
+ @Override
+ public List<UserCredentialValueModel> getCredentialsDirectly() {
+ if (updated != null) return updated.getCredentialsDirectly();
+ return cached.getCredentials();
+ }
+
+ @Override
+ public void updateCredentialDirectly(UserCredentialValueModel cred) {
+ getDelegateForUpdate();
+ updated.updateCredentialDirectly(cred);
+ }
+
+ @Override
+ public AuthenticationLinkModel getAuthenticationLink() {
+ if (updated != null) return updated.getAuthenticationLink();
+ return cached.getAuthenticationLink();
+ }
+
+ @Override
+ public void setAuthenticationLink(AuthenticationLinkModel authenticationLink) {
+ getDelegateForUpdate();
+ updated.setAuthenticationLink(authenticationLink);
+ }
+
+ @Override
+ public Set<RoleModel> getRealmRoleMappings() {
+ if (updated != null) return updated.getRealmRoleMappings();
+ Set<RoleModel> roleMappings = getRoleMappings();
+ Set<RoleModel> realmMappings = new HashSet<RoleModel>();
+ for (RoleModel role : roleMappings) {
+ RoleContainerModel container = role.getContainer();
+ if (container instanceof RealmModel) {
+ if (((RealmModel) container).getId().equals(realm.getId())) {
+ realmMappings.add(role);
+ }
+ }
+ }
+ return realmMappings;
+ }
+
+ @Override
+ public Set<RoleModel> getApplicationRoleMappings(ApplicationModel app) {
+ if (updated != null) return updated.getApplicationRoleMappings(app);
+ Set<RoleModel> roleMappings = getRoleMappings();
+ Set<RoleModel> appMappings = new HashSet<RoleModel>();
+ for (RoleModel role : roleMappings) {
+ RoleContainerModel container = role.getContainer();
+ if (container instanceof ApplicationModel) {
+ if (((ApplicationModel) container).getId().equals(app.getId())) {
+ appMappings.add(role);
+ }
+ }
+ }
+ return appMappings;
+ }
+
+ @Override
+ public boolean hasRole(RoleModel role) {
+ if (updated != null) return updated.hasRole(role);
+ if (cached.getRoleMappings().contains(role.getId())) return true;
+
+ Set<RoleModel> mappings = getRoleMappings();
+ for (RoleModel mapping: mappings) {
+ if (mapping.hasRole(role)) return true;
+ }
+ return false;
+ }
+
+ @Override
+ public void grantRole(RoleModel role) {
+ getDelegateForUpdate();
+ updated.grantRole(role);
+ }
+
+ @Override
+ public Set<RoleModel> getRoleMappings() {
+ if (updated != null) return updated.getRoleMappings();
+ Set<RoleModel> roles = new HashSet<RoleModel>();
+ for (String id : cached.getRoleMappings()) {
+ roles.add(cacheSession.getRoleById(id, realm));
+
+ }
+ return roles;
+ }
+
+ @Override
+ public void deleteRoleMapping(RoleModel role) {
+ getDelegateForUpdate();
+ updated.deleteRoleMapping(role);
+ }
+}
diff --git a/model/mongo/src/main/java/org/keycloak/models/mongo/keycloak/adapters/MongoKeycloakSession.java b/model/mongo/src/main/java/org/keycloak/models/mongo/keycloak/adapters/MongoKeycloakSession.java
index 018e4e6..20d5123 100755
--- a/model/mongo/src/main/java/org/keycloak/models/mongo/keycloak/adapters/MongoKeycloakSession.java
+++ b/model/mongo/src/main/java/org/keycloak/models/mongo/keycloak/adapters/MongoKeycloakSession.java
@@ -254,7 +254,8 @@ public class MongoKeycloakSession implements KeycloakSession {
}
@Override
- public Set<SocialLinkModel> getSocialLinks(UserModel user, RealmModel realm) {
+ public Set<SocialLinkModel> getSocialLinks(UserModel userModel, RealmModel realm) {
+ UserModel user = getUserById(userModel.getId(), realm);
MongoUserEntity userEntity = ((UserAdapter) user).getUser();
List<SocialLinkEntity> linkEntities = userEntity.getSocialLinks();
@@ -271,7 +272,8 @@ public class MongoKeycloakSession implements KeycloakSession {
return result;
}
- private SocialLinkEntity findSocialLink(UserModel user, String socialProvider) {
+ private SocialLinkEntity findSocialLink(UserModel userModel, String socialProvider, RealmModel realm) {
+ UserModel user = getUserById(userModel.getId(), realm);
MongoUserEntity userEntity = ((UserAdapter) user).getUser();
List<SocialLinkEntity> linkEntities = userEntity.getSocialLinks();
if (linkEntities == null) {
@@ -289,7 +291,7 @@ public class MongoKeycloakSession implements KeycloakSession {
@Override
public SocialLinkModel getSocialLink(UserModel user, String socialProvider, RealmModel realm) {
- SocialLinkEntity socialLinkEntity = findSocialLink(user, socialProvider);
+ SocialLinkEntity socialLinkEntity = findSocialLink(user, socialProvider, realm);
return socialLinkEntity != null ? new SocialLinkModel(socialLinkEntity.getSocialProvider(), socialLinkEntity.getSocialUserId(), socialLinkEntity.getSocialUsername()) : null;
}
diff --git a/model/mongo/src/main/java/org/keycloak/models/mongo/keycloak/adapters/RealmAdapter.java b/model/mongo/src/main/java/org/keycloak/models/mongo/keycloak/adapters/RealmAdapter.java
index ecf5b76..2602222 100755
--- a/model/mongo/src/main/java/org/keycloak/models/mongo/keycloak/adapters/RealmAdapter.java
+++ b/model/mongo/src/main/java/org/keycloak/models/mongo/keycloak/adapters/RealmAdapter.java
@@ -857,18 +857,17 @@ public class RealmAdapter extends AbstractMongoAdapter<MongoRealmEntity> impleme
}
@Override
- public boolean removeSocialLink(UserModel user, String socialProvider) {
- SocialLinkEntity socialLinkEntity = findSocialLink(user, socialProvider);
+ public boolean removeSocialLink(UserModel userModel, String socialProvider) {
+ UserModel user = getUserById(userModel.getId());
+ MongoUserEntity userEntity = ((UserAdapter) user).getUser();
+ SocialLinkEntity socialLinkEntity = findSocialLink(userEntity, socialProvider);
if (socialLinkEntity == null) {
return false;
}
- MongoUserEntity userEntity = ((UserAdapter) user).getUser();
-
return getMongoStore().pullItemFromList(userEntity, "socialLinks", socialLinkEntity, invocationContext);
}
- private SocialLinkEntity findSocialLink(UserModel user, String socialProvider) {
- MongoUserEntity userEntity = ((UserAdapter) user).getUser();
+ private SocialLinkEntity findSocialLink(MongoUserEntity userEntity, String socialProvider) {
List<SocialLinkEntity> linkEntities = userEntity.getSocialLinks();
if (linkEntities == null) {
return null;
diff --git a/testsuite/integration/src/main/resources/META-INF/keycloak-server.json b/testsuite/integration/src/main/resources/META-INF/keycloak-server.json
index 65197a4..a1e1ec1 100755
--- a/testsuite/integration/src/main/resources/META-INF/keycloak-server.json
+++ b/testsuite/integration/src/main/resources/META-INF/keycloak-server.json
@@ -24,7 +24,7 @@
},
"modelCache": {
- "provider": "${keycloak.model.cache.provider:none}"
+ "provider": "${keycloak.model.cache.provider:simple}"
},
"timer": {
diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/account/AccountTest.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/account/AccountTest.java
index 1603229..770ef84 100755
--- a/testsuite/integration/src/test/java/org/keycloak/testsuite/account/AccountTest.java
+++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/account/AccountTest.java
@@ -34,6 +34,7 @@ import org.keycloak.models.ApplicationModel;
import org.keycloak.models.PasswordPolicy;
import org.keycloak.models.RealmModel;
import org.keycloak.models.UserCredentialModel;
+import org.keycloak.models.UserCredentialValueModel;
import org.keycloak.models.UserModel;
import org.keycloak.models.utils.TimeBasedOTP;
import org.keycloak.representations.idm.CredentialRepresentation;
@@ -144,7 +145,7 @@ public class AccountTest {
@After
public void after() {
- keycloakRule.configure(new KeycloakSetup() {
+ keycloakRule.update(new KeycloakSetup() {
@Override
public void config(RealmManager manager, RealmModel defaultRealm, RealmModel appRealm) {
UserModel user = appRealm.getUser("test-user@localhost");
@@ -239,7 +240,7 @@ public class AccountTest {
@Test
public void changePasswordWithPasswordPolicy() {
- keycloakRule.configure(new KeycloakRule.KeycloakSetup() {
+ keycloakRule.update(new KeycloakRule.KeycloakSetup() {
@Override
public void config(RealmManager manager, RealmModel adminstrationRealm, RealmModel appRealm) {
appRealm.setPasswordPolicy(new PasswordPolicy("length"));
@@ -263,11 +264,11 @@ public class AccountTest {
events.expectAccount(EventType.UPDATE_PASSWORD).assertEvent();
} finally {
- keycloakRule.configure(new KeycloakRule.KeycloakSetup() {
+ keycloakRule.update(new KeycloakRule.KeycloakSetup() {
@Override
public void config(RealmManager manager, RealmModel adminstrationRealm, RealmModel appRealm) {
appRealm.setPasswordPolicy(new PasswordPolicy(null));
- }
+ }
});
}
}