keycloak-memoizeit

refactor for caching again

6/12/2014 12:11:14 PM

Changes

Details

diff --git a/authentication/authentication-api/src/main/java/org/keycloak/authentication/AuthenticationProviderManager.java b/authentication/authentication-api/src/main/java/org/keycloak/authentication/AuthenticationProviderManager.java
old mode 100644
new mode 100755
index 6b6c56b..b0d485b
--- a/authentication/authentication-api/src/main/java/org/keycloak/authentication/AuthenticationProviderManager.java
+++ b/authentication/authentication-api/src/main/java/org/keycloak/authentication/AuthenticationProviderManager.java
@@ -68,12 +68,12 @@ public class AuthenticationProviderManager {
     }
 
     public AuthProviderStatus validatePassword(UserModel user, String password) {
-        AuthenticationLinkModel authLink = realm.getAuthenticationLink(user);
+        AuthenticationLinkModel authLink = user.getAuthenticationLink();
         if (authLink == null) {
             // User not yet linked with any authenticationProvider. Find provider with biggest priority where he is and link
             AuthUser authUser = getUser(user.getLoginName());
             authLink = new AuthenticationLinkModel(authUser.getProviderName(), authUser.getId());
-            realm.setAuthenticationLink(user, authLink);
+            user.setAuthenticationLink(authLink);
             logger.infof("User '%s' linked with provider '%s'", authUser.getUsername(), authUser.getProviderName());
         }
 
@@ -98,7 +98,7 @@ public class AuthenticationProviderManager {
     }
 
     public boolean updatePassword(UserModel user, String password) throws AuthenticationProviderException {
-        AuthenticationLinkModel authLink = realm.getAuthenticationLink(user);
+        AuthenticationLinkModel authLink = user.getAuthenticationLink();
         if (authLink == null) {
             // Find provider with biggest priority where password update is supported. Then register user here and link him
             List<AuthenticationProviderModel> configuredProviders = getConfiguredProviderModels(realm);
@@ -111,7 +111,7 @@ public class AuthenticationProviderManager {
                             // Linking existing user supported just for "model" provider. In other cases throw exception
                             if (providerModel.getProviderName().equals(AuthenticationProviderModel.DEFAULT_PROVIDER.getProviderName())) {
                                 authLink = new AuthenticationLinkModel(providerModel.getProviderName(), authUser.getId());
-                                realm.setAuthenticationLink(user, authLink);
+                                user.setAuthenticationLink(authLink);
                                 logger.infof("User '%s' linked with provider '%s'", authUser.getUsername(), authUser.getProviderName());
                             } else {
                                 throw new AuthenticationProviderException("User " + authUser.getUsername() + " exists in provider "
@@ -120,7 +120,7 @@ public class AuthenticationProviderManager {
                         } else {
                             String userIdInProvider = delegate.registerUser(realm, providerModel.getConfig(), user.getLoginName());
                             authLink = new AuthenticationLinkModel(providerModel.getProviderName(), userIdInProvider);
-                            realm.setAuthenticationLink(user, authLink);
+                            user.setAuthenticationLink(authLink);
                             logger.infof("User '%s' registered in provider '%s' and linked", user.getLoginName(), providerModel.getProviderName());
                         }
                         break;
diff --git a/export-import/export-import-impl/src/main/java/org/keycloak/exportimport/ExportImportPropertiesManager.java b/export-import/export-import-impl/src/main/java/org/keycloak/exportimport/ExportImportPropertiesManager.java
old mode 100644
new mode 100755
index 87dfa55..4d49b5a
--- a/export-import/export-import-impl/src/main/java/org/keycloak/exportimport/ExportImportPropertiesManager.java
+++ b/export-import/export-import-impl/src/main/java/org/keycloak/exportimport/ExportImportPropertiesManager.java
@@ -132,7 +132,7 @@ public class ExportImportPropertiesManager {
 
     public static class NonEmptyGetterCriteria implements PropertyCriteria {
 
-        private static final List<String> IGNORED_METHODS = Arrays.asList("getPasswordPolicy", "getAuthenticationProviders");
+        private static final List<String> IGNORED_METHODS = Arrays.asList("getPasswordPolicy", "getAuthenticationProviders", "getAuthenticationLink");
 
         @Override
         public boolean methodMatches(Method m) {
diff --git a/export-import/export-import-impl/src/main/java/org/keycloak/exportimport/ModelExporter.java b/export-import/export-import-impl/src/main/java/org/keycloak/exportimport/ModelExporter.java
index 481b8c5..c82d9d2 100755
--- a/export-import/export-import-impl/src/main/java/org/keycloak/exportimport/ModelExporter.java
+++ b/export-import/export-import-impl/src/main/java/org/keycloak/exportimport/ModelExporter.java
@@ -215,7 +215,7 @@ public class ModelExporter {
                 userEntity.setRealmId(realm.getId());
 
                 // authentication links
-                AuthenticationLinkModel authLink = realm.getAuthenticationLink(userModel);
+                AuthenticationLinkModel authLink = userModel.getAuthenticationLink();
                 if (authLink != null) {
                     AuthenticationLinkEntity authLinkEntity = new AuthenticationLinkEntity();
                     this.propertiesManager.setBasicPropertiesFromModel(authLink, authLinkEntity);
diff --git a/export-import/export-import-impl/src/main/java/org/keycloak/exportimport/ModelImporter.java b/export-import/export-import-impl/src/main/java/org/keycloak/exportimport/ModelImporter.java
index a1f8460..7e67c91 100755
--- a/export-import/export-import-impl/src/main/java/org/keycloak/exportimport/ModelImporter.java
+++ b/export-import/export-import-impl/src/main/java/org/keycloak/exportimport/ModelImporter.java
@@ -258,7 +258,7 @@ public class ModelImporter {
                 AuthenticationLinkModel authLinkModel = new AuthenticationLinkModel();
                 this.propertiesManager.setBasicPropertiesToModel(authLinkModel, authLinkEntity);
 
-                realm.setAuthenticationLink(user, authLinkModel);
+                user.setAuthenticationLink(authLinkModel);
             }
 
             // social links
diff --git a/forms/account-freemarker/src/main/java/org/keycloak/account/freemarker/model/AccountSocialBean.java b/forms/account-freemarker/src/main/java/org/keycloak/account/freemarker/model/AccountSocialBean.java
old mode 100644
new mode 100755
index 481f1d9..074174f
--- a/forms/account-freemarker/src/main/java/org/keycloak/account/freemarker/model/AccountSocialBean.java
+++ b/forms/account-freemarker/src/main/java/org/keycloak/account/freemarker/model/AccountSocialBean.java
@@ -50,7 +50,7 @@ public class AccountSocialBean {
         }
 
         // Removing last social provider is not possible if you don't have other possibility to authenticate
-        this.removeLinkPossible = availableLinks > 1 || realm.getAuthenticationLink(user) != null;
+        this.removeLinkPossible = availableLinks > 1 || user.getAuthenticationLink() != null;
     }
 
     private SocialLinkModel getSocialLink(Set<SocialLinkModel> userSocialLinks, String socialProviderId) {
diff --git a/model/api/src/main/java/org/keycloak/models/KeycloakSession.java b/model/api/src/main/java/org/keycloak/models/KeycloakSession.java
index 34746ce..8a708a3 100755
--- a/model/api/src/main/java/org/keycloak/models/KeycloakSession.java
+++ b/model/api/src/main/java/org/keycloak/models/KeycloakSession.java
@@ -38,6 +38,21 @@ public interface KeycloakSession extends Provider {
     List<RealmModel> getRealms();
     boolean removeRealm(String id);
 
+    UsernameLoginFailureModel getUserLoginFailure(String username, RealmModel realm);
+    UsernameLoginFailureModel addUserLoginFailure(String username, RealmModel realm);
+    List<UsernameLoginFailureModel> getAllUserLoginFailures();
+
+    UserSessionModel createUserSession(RealmModel realm, UserModel user, String ipAddress);
+    UserSessionModel getUserSession(String id, RealmModel realm);
+    List<UserSessionModel> getUserSessions(UserModel user, RealmModel realm);
+    Set<UserSessionModel> getUserSessions(RealmModel realm, ClientModel client);
+    int getActiveUserSessions(RealmModel realm, ClientModel client);
+    void removeUserSession(UserSessionModel session);
+    void removeUserSessions(RealmModel realm, UserModel user);
+    void removeExpiredUserSessions(RealmModel realm);
+    void removeUserSessions(RealmModel realm);
+
+
     void removeAllData();
 
     void close();
diff --git a/model/api/src/main/java/org/keycloak/models/RealmModel.java b/model/api/src/main/java/org/keycloak/models/RealmModel.java
index 6438cfa..f669968 100755
--- a/model/api/src/main/java/org/keycloak/models/RealmModel.java
+++ b/model/api/src/main/java/org/keycloak/models/RealmModel.java
@@ -157,10 +157,6 @@ public interface RealmModel extends RoleContainerModel {
 
     boolean removeSocialLink(UserModel user, String socialProvider);
 
-    AuthenticationLinkModel getAuthenticationLink(UserModel user);
-
-    void setAuthenticationLink(UserModel user, AuthenticationLinkModel authenticationLink);
-
     boolean isSocial();
 
     void setSocial(boolean social);
diff --git a/model/api/src/main/java/org/keycloak/models/UserModel.java b/model/api/src/main/java/org/keycloak/models/UserModel.java
index c4bb745..3a7bd0b 100755
--- a/model/api/src/main/java/org/keycloak/models/UserModel.java
+++ b/model/api/src/main/java/org/keycloak/models/UserModel.java
@@ -67,6 +67,12 @@ public interface UserModel {
 
     void updateCredentialDirectly(UserCredentialValueModel cred);
 
+    AuthenticationLinkModel getAuthenticationLink();
+
+    void setAuthenticationLink(AuthenticationLinkModel authenticationLink);
+
+
+
     Set<RoleModel> getRealmRoleMappings();
     Set<RoleModel> getApplicationRoleMappings(ApplicationModel app);
     boolean hasRole(RoleModel role);
diff --git a/model/invalidation-cache/model-adapters/src/main/java/org/keycloak/models/cache/ApplicationAdapter.java b/model/invalidation-cache/model-adapters/src/main/java/org/keycloak/models/cache/ApplicationAdapter.java
new file mode 100755
index 0000000..62de047
--- /dev/null
+++ b/model/invalidation-cache/model-adapters/src/main/java/org/keycloak/models/cache/ApplicationAdapter.java
@@ -0,0 +1,178 @@
+package org.keycloak.models.cache;
+
+import org.keycloak.models.ApplicationModel;
+import org.keycloak.models.ClientModel;
+import org.keycloak.models.RealmModel;
+import org.keycloak.models.RoleContainerModel;
+import org.keycloak.models.RoleModel;
+import org.keycloak.models.UserSessionModel;
+import org.keycloak.models.cache.entities.CachedApplication;
+import org.keycloak.models.cache.entities.CachedClient;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+/**
+ * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
+ * @version $Revision: 1 $
+ */
+public class ApplicationAdapter extends ClientAdapter implements ApplicationModel {
+    protected ApplicationModel updated;
+    protected CachedApplication cached;
+
+    public ApplicationAdapter(RealmModel cachedRealm, CachedApplication cached, CacheKeycloakSession cacheSession, KeycloakCache cache) {
+        super(cachedRealm, cached, cache, cacheSession);
+        this.cached = cached;
+    }
+
+    @Override
+    protected void getDelegateForUpdate() {
+        if (updated == null) {
+            updatedClient = updated = cacheSession.getDelegate().getApplicationById(getId(), cachedRealm);
+            if (updated == null) throw new IllegalStateException("Not found in database");
+        }
+    }
+
+    @Override
+    public void updateApplication() {
+        if (updated != null) updated.updateApplication();
+    }
+
+    @Override
+    public String getName() {
+        return getClientId();
+    }
+
+    @Override
+    public String getClientId() {
+        return getName();
+    }
+
+    @Override
+    public void setName(String name) {
+        getDelegateForUpdate();
+        updated.setName(name);
+    }
+
+    @Override
+    public boolean isSurrogateAuthRequired() {
+        if (updated != null) return updated.isSurrogateAuthRequired();
+        return cached.isSurrogateAuthRequired();
+    }
+
+    @Override
+    public void setSurrogateAuthRequired(boolean surrogateAuthRequired) {
+        getDelegateForUpdate();
+        updated.setSurrogateAuthRequired(surrogateAuthRequired);
+    }
+
+    @Override
+    public String getManagementUrl() {
+        if (updated != null) return updated.getManagementUrl();
+        return cached.getManagementUrl();
+    }
+
+    @Override
+    public void setManagementUrl(String url) {
+        getDelegateForUpdate();
+        updated.setManagementUrl(url);
+    }
+
+    @Override
+    public String getBaseUrl() {
+        if (updated != null) return updated.getBaseUrl();
+        return cached.getBaseUrl();
+    }
+
+    @Override
+    public void setBaseUrl(String url) {
+        getDelegateForUpdate();
+        updated.setBaseUrl(url);
+    }
+
+    @Override
+    public List<String> getDefaultRoles() {
+        if (updated != null) return updated.getDefaultRoles();
+        return cached.getDefaultRoles();
+    }
+
+    @Override
+    public void addDefaultRole(String name) {
+        getDelegateForUpdate();
+        updated.addDefaultRole(name);
+    }
+
+    @Override
+    public void updateDefaultRoles(String[] defaultRoles) {
+        getDelegateForUpdate();
+        updated.updateDefaultRoles(defaultRoles);
+    }
+
+    @Override
+    public Set<RoleModel> getApplicationScopeMappings(ClientModel client) {
+        Set<RoleModel> roleMappings = client.getScopeMappings();
+
+        Set<RoleModel> appRoles = new HashSet<RoleModel>();
+        for (RoleModel role : roleMappings) {
+            RoleContainerModel container = role.getContainer();
+            if (container instanceof RealmModel) {
+            } else {
+                ApplicationModel app = (ApplicationModel)container;
+                if (app.getId().equals(getId())) {
+                    appRoles.add(role);
+                }
+            }
+        }
+
+        return appRoles;
+    }
+
+    @Override
+    public boolean isBearerOnly() {
+        if (updated != null) return updated.isBearerOnly();
+        return cached.isBearerOnly();
+    }
+
+    @Override
+    public void setBearerOnly(boolean only) {
+        getDelegateForUpdate();
+        updated.setBearerOnly(only);
+    }
+
+    @Override
+    public RoleModel getRole(String name) {
+        if (updated != null) return updated.getRole(name);
+        String id = cached.getRoles().get(name);
+        if (id == null) return null;
+        return cacheSession.getRoleById(id, cachedRealm);
+    }
+
+    @Override
+    public RoleModel addRole(String name) {
+        getDelegateForUpdate();
+        return updated.addRole(name);
+    }
+
+    @Override
+    public RoleModel addRole(String id, String name) {
+        getDelegateForUpdate();
+        return updated.addRole(id, name);
+    }
+
+    @Override
+    public boolean removeRole(RoleModel role) {
+        getDelegateForUpdate();
+        return updated.removeRole(role);
+    }
+
+    @Override
+    public Set<RoleModel> getRoles() {
+        if (updated != null) return updated.getRoles();
+
+        Set<RoleModel> roles = new HashSet<RoleModel>();
+        for (String id : cached.getRoles().values()) {
+            roles.add(cacheSession.getRoleById(id, cachedRealm));
+        }
+        return roles;
+    }
+}
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 2ffd4a9..24fe250 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
@@ -2,6 +2,7 @@ package org.keycloak.models.cache;
 
 import org.keycloak.models.ApplicationModel;
 import org.keycloak.models.AuthenticationLinkModel;
+import org.keycloak.models.ClientModel;
 import org.keycloak.models.KeycloakSession;
 import org.keycloak.models.KeycloakTransaction;
 import org.keycloak.models.OAuthClientModel;
@@ -9,6 +10,8 @@ import org.keycloak.models.RealmModel;
 import org.keycloak.models.RoleModel;
 import org.keycloak.models.SocialLinkModel;
 import org.keycloak.models.UserModel;
+import org.keycloak.models.UserSessionModel;
+import org.keycloak.models.UsernameLoginFailureModel;
 import org.keycloak.models.cache.entities.CachedRealm;
 import org.keycloak.models.cache.entities.CachedRole;
 import org.keycloak.provider.ProviderSession;
@@ -235,4 +238,64 @@ public class CacheKeycloakSession implements KeycloakSession {
     public OAuthClientModel getOAuthClientById(String id, RealmModel realm) {
         return null;  //To change body of implemented methods use File | Settings | File Templates.
     }
+
+    @Override
+    public UsernameLoginFailureModel getUserLoginFailure(String username, RealmModel realm) {
+        return null;  //To change body of implemented methods use File | Settings | File Templates.
+    }
+
+    @Override
+    public UsernameLoginFailureModel addUserLoginFailure(String username, RealmModel realm) {
+        return null;  //To change body of implemented methods use File | Settings | File Templates.
+    }
+
+    @Override
+    public List<UsernameLoginFailureModel> getAllUserLoginFailures() {
+        return null;  //To change body of implemented methods use File | Settings | File Templates.
+    }
+
+    @Override
+    public UserSessionModel createUserSession(RealmModel realm, UserModel user, String ipAddress) {
+        return null;  //To change body of implemented methods use File | Settings | File Templates.
+    }
+
+    @Override
+    public UserSessionModel getUserSession(String id, RealmModel realm) {
+        return null;  //To change body of implemented methods use File | Settings | File Templates.
+    }
+
+    @Override
+    public List<UserSessionModel> getUserSessions(UserModel user, RealmModel realm) {
+        return null;  //To change body of implemented methods use File | Settings | File Templates.
+    }
+
+    @Override
+    public Set<UserSessionModel> getUserSessions(RealmModel realm, ClientModel client) {
+        return null;  //To change body of implemented methods use File | Settings | File Templates.
+    }
+
+    @Override
+    public int getActiveUserSessions(RealmModel realm, ClientModel client) {
+        return 0;  //To change body of implemented methods use File | Settings | File Templates.
+    }
+
+    @Override
+    public void removeUserSession(UserSessionModel session) {
+        //To change body of implemented methods use File | Settings | File Templates.
+    }
+
+    @Override
+    public void removeUserSessions(RealmModel realm, UserModel user) {
+        //To change body of implemented methods use File | Settings | File Templates.
+    }
+
+    @Override
+    public void removeExpiredUserSessions(RealmModel realm) {
+        //To change body of implemented methods use File | Settings | File Templates.
+    }
+
+    @Override
+    public void removeUserSessions(RealmModel realm) {
+        //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/ClientAdapter.java b/model/invalidation-cache/model-adapters/src/main/java/org/keycloak/models/cache/ClientAdapter.java
new file mode 100755
index 0000000..82e0332
--- /dev/null
+++ b/model/invalidation-cache/model-adapters/src/main/java/org/keycloak/models/cache/ClientAdapter.java
@@ -0,0 +1,209 @@
+package org.keycloak.models.cache;
+
+import org.keycloak.models.ApplicationModel;
+import org.keycloak.models.ClientModel;
+import org.keycloak.models.RealmModel;
+import org.keycloak.models.RoleContainerModel;
+import org.keycloak.models.RoleModel;
+import org.keycloak.models.UserSessionModel;
+import org.keycloak.models.cache.entities.CachedApplication;
+import org.keycloak.models.cache.entities.CachedClient;
+
+import java.util.HashSet;
+import java.util.Set;
+
+/**
+ * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
+ * @version $Revision: 1 $
+ */
+public abstract class ClientAdapter implements ClientModel {
+    protected CachedClient cachedClient;
+    protected CacheKeycloakSession cacheSession;
+    protected ClientModel updatedClient;
+    protected RealmModel cachedRealm;
+    protected KeycloakCache cache;
+
+    public ClientAdapter(RealmModel cachedRealm, CachedClient cached, KeycloakCache cache, CacheKeycloakSession cacheSession) {
+        this.cachedRealm = cachedRealm;
+        this.cache = cache;
+        this.cacheSession = cacheSession;
+        this.cachedClient = cached;
+    }
+
+    protected abstract void getDelegateForUpdate();
+
+    @Override
+    public String getId() {
+        if (updatedClient != null) return updatedClient.getId();
+        return cachedClient.getId();
+    }
+
+
+    @Override
+    public abstract String getClientId();
+
+    public long getAllowedClaimsMask() {
+        if (updatedClient != null) return updatedClient.getAllowedClaimsMask();
+        return cachedClient.getAllowedClaimsMask();
+    }
+
+    public void setAllowedClaimsMask(long mask) {
+        getDelegateForUpdate();
+        updatedClient.setAllowedClaimsMask(mask);
+    }
+
+    public Set<String> getWebOrigins() {
+        if (updatedClient != null) return updatedClient.getWebOrigins();
+        return cachedClient.getWebOrigins();
+    }
+
+    public void setWebOrigins(Set<String> webOrigins) {
+        getDelegateForUpdate();
+        updatedClient.setWebOrigins(webOrigins);
+    }
+
+    public void addWebOrigin(String webOrigin) {
+        getDelegateForUpdate();
+        updatedClient.addWebOrigin(webOrigin);
+    }
+
+    public void removeWebOrigin(String webOrigin) {
+        getDelegateForUpdate();
+        updatedClient.removeWebOrigin(webOrigin);
+    }
+
+    public Set<String> getRedirectUris() {
+        if (updatedClient != null) return updatedClient.getRedirectUris();
+        return cachedClient.getRedirectUris();
+    }
+
+    public void setRedirectUris(Set<String> redirectUris) {
+        getDelegateForUpdate();
+        updatedClient.setRedirectUris(redirectUris);
+    }
+
+    public void addRedirectUri(String redirectUri) {
+        getDelegateForUpdate();
+        updatedClient.addRedirectUri(redirectUri);
+    }
+
+    public void removeRedirectUri(String redirectUri) {
+        getDelegateForUpdate();
+        updatedClient.removeRedirectUri(redirectUri);
+    }
+
+    public boolean isEnabled() {
+        if (updatedClient != null) return updatedClient.isEnabled();
+        return cachedClient.isEnabled();
+    }
+
+    public void setEnabled(boolean enabled) {
+        getDelegateForUpdate();
+        updatedClient.setEnabled(enabled);
+    }
+
+    public boolean validateSecret(String secret) {
+        return secret.equals(getSecret());
+    }
+
+    public String getSecret() {
+        if (updatedClient != null) return updatedClient.getSecret();
+        return cachedClient.getSecret();
+    }
+
+    public void setSecret(String secret) {
+        getDelegateForUpdate();
+        updatedClient.setSecret(secret);
+    }
+
+    public boolean isPublicClient() {
+        if (updatedClient != null) return updatedClient.isPublicClient();
+        return cachedClient.isPublicClient();
+    }
+
+    public void setPublicClient(boolean flag) {
+        getDelegateForUpdate();
+        updatedClient.setPublicClient(flag);
+    }
+
+    public boolean isDirectGrantsOnly() {
+        if (updatedClient != null) return updatedClient.isDirectGrantsOnly();
+        return cachedClient.isDirectGrantsOnly();
+    }
+
+    public void setDirectGrantsOnly(boolean flag) {
+        getDelegateForUpdate();
+        updatedClient.setDirectGrantsOnly(flag);
+    }
+
+    public Set<RoleModel> getScopeMappings() {
+        if (updatedClient != null) return updatedClient.getScopeMappings();
+        Set<RoleModel> roles = new HashSet<RoleModel>();
+        for (String id : cachedClient.getScope()) {
+            roles.add(cacheSession.getRoleById(id, getRealm()));
+
+        }
+        return roles;
+    }
+
+    public void addScopeMapping(RoleModel role) {
+        getDelegateForUpdate();
+        updatedClient.addScopeMapping(role);
+    }
+
+    public void deleteScopeMapping(RoleModel role) {
+        getDelegateForUpdate();
+        updatedClient.deleteScopeMapping(role);
+    }
+
+    public Set<RoleModel> getRealmScopeMappings() {
+        Set<RoleModel> roleMappings = getScopeMappings();
+
+        Set<RoleModel> appRoles = new HashSet<RoleModel>();
+        for (RoleModel role : roleMappings) {
+            RoleContainerModel container = role.getContainer();
+            if (container instanceof RealmModel) {
+                if (((RealmModel) container).getId().equals(cachedRealm.getId())) {
+                    appRoles.add(role);
+                }
+            }
+        }
+
+        return appRoles;
+    }
+
+    public boolean hasScope(RoleModel role) {
+        if (updatedClient != null) return updatedClient.hasScope(role);
+        Set<RoleModel> roles = getScopeMappings();
+        if (roles.contains(role)) return true;
+
+        for (RoleModel mapping : roles) {
+            if (mapping.hasRole(role)) return true;
+        }
+        return false;
+    }
+
+    public RealmModel getRealm() {
+        return cachedRealm;
+    }
+
+    public int getNotBefore() {
+        if (updatedClient != null) return updatedClient.getNotBefore();
+        return cachedClient.getNotBefore();
+    }
+
+    public void setNotBefore(int notBefore) {
+        getDelegateForUpdate();
+        updatedClient.setNotBefore(notBefore);
+    }
+
+    public Set<UserSessionModel> getUserSessions() {
+        if (updatedClient != null) return updatedClient.getUserSessions();
+        return cacheSession.getUserSessions(cachedRealm, this);
+    }
+
+    public int getActiveUserSessions() {
+        if (updatedClient != null) return updatedClient.getActiveUserSessions();
+        return cacheSession.getActiveUserSessions(cachedRealm, this);
+    }
+}
diff --git a/model/invalidation-cache/model-adapters/src/main/java/org/keycloak/models/cache/entities/CachedRealm.java b/model/invalidation-cache/model-adapters/src/main/java/org/keycloak/models/cache/entities/CachedRealm.java
index 3ee3f77..cd748eb 100755
--- a/model/invalidation-cache/model-adapters/src/main/java/org/keycloak/models/cache/entities/CachedRealm.java
+++ b/model/invalidation-cache/model-adapters/src/main/java/org/keycloak/models/cache/entities/CachedRealm.java
@@ -60,6 +60,7 @@ public class CachedRealm {
     private String accountTheme;
     private String adminTheme;
     private String emailTheme;
+    private String masterAdminApp;
 
     private List<RequiredCredentialModel> requiredCredentials = new ArrayList<RequiredCredentialModel>();
     private List<AuthenticationProviderModel> authenticationProviders = new ArrayList<AuthenticationProviderModel>();
@@ -129,6 +130,7 @@ public class CachedRealm {
         auditExpiration = model.getAuditExpiration();
         auditListeners.addAll(model.getAuditListeners());
         defaultRoles.addAll(model.getDefaultRoles());
+        masterAdminApp = model.getMasterAdminApp().getId();
 
         for (RoleModel role : model.getRoles()) {
             realmRoles.put(role.getName(), role.getId());
@@ -159,6 +161,10 @@ public class CachedRealm {
         return id;
     }
 
+    public String getMasterAdminApp() {
+        return masterAdminApp;
+    }
+
     public String getName() {
         return name;
     }
diff --git a/model/invalidation-cache/model-adapters/src/main/java/org/keycloak/models/cache/OAuthClientAdapter.java b/model/invalidation-cache/model-adapters/src/main/java/org/keycloak/models/cache/OAuthClientAdapter.java
new file mode 100755
index 0000000..73ffa70
--- /dev/null
+++ b/model/invalidation-cache/model-adapters/src/main/java/org/keycloak/models/cache/OAuthClientAdapter.java
@@ -0,0 +1,48 @@
+package org.keycloak.models.cache;
+
+import org.keycloak.models.ApplicationModel;
+import org.keycloak.models.ClientModel;
+import org.keycloak.models.OAuthClientModel;
+import org.keycloak.models.RealmModel;
+import org.keycloak.models.RoleContainerModel;
+import org.keycloak.models.RoleModel;
+import org.keycloak.models.cache.entities.CachedApplication;
+import org.keycloak.models.cache.entities.CachedOAuthClient;
+
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+/**
+ * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
+ * @version $Revision: 1 $
+ */
+public class OAuthClientAdapter extends ClientAdapter implements OAuthClientModel {
+    protected OAuthClientModel updated;
+    protected CachedOAuthClient cached;
+
+    public OAuthClientAdapter(RealmModel cachedRealm, CachedOAuthClient cached, CacheKeycloakSession cacheSession, KeycloakCache cache) {
+        super(cachedRealm, cached, cache, cacheSession);
+        this.cached = cached;
+    }
+
+    @Override
+    protected void getDelegateForUpdate() {
+        if (updated == null) {
+            updatedClient = updated = cacheSession.getDelegate().getOAuthClientById(getId(), cachedRealm);
+            if (updated == null) throw new IllegalStateException("Not found in database");
+        }
+    }
+
+    @Override
+    public String getClientId() {
+        if (updated != null) return updated.getClientId();
+        return cached.getName();
+    }
+
+    @Override
+    public void setClientId(String id) {
+        getDelegateForUpdate();
+        updated.setClientId(id);
+    }
+}
diff --git a/model/invalidation-cache/model-adapters/src/main/java/org/keycloak/models/cache/RealmAdapter.java b/model/invalidation-cache/model-adapters/src/main/java/org/keycloak/models/cache/RealmAdapter.java
index e7fb777..9c1a4b6 100755
--- a/model/invalidation-cache/model-adapters/src/main/java/org/keycloak/models/cache/RealmAdapter.java
+++ b/model/invalidation-cache/model-adapters/src/main/java/org/keycloak/models/cache/RealmAdapter.java
@@ -27,6 +27,7 @@ import java.security.PrivateKey;
 import java.security.PublicKey;
 import java.util.ArrayList;
 import java.util.HashMap;
+import java.util.HashSet;
 import java.util.LinkedList;
 import java.util.List;
 import java.util.Map;
@@ -49,6 +50,13 @@ public class RealmAdapter implements RealmModel {
         this.cacheSession = cacheSession;
     }
 
+    protected void getDelegateForUpdate() {
+        if (updated == null) {
+            updated = cacheSession.getDelegate().getRealm(getId());
+            if (updated == null) throw new IllegalStateException("Not found in database");
+        }
+    }
+
     @Override
     public String getId() {
         if (updated != null) return updated.getId();
@@ -67,13 +75,6 @@ public class RealmAdapter implements RealmModel {
         updated.setName(name);
     }
 
-    protected void getDelegateForUpdate() {
-        if (updated == null) {
-            updated = cacheSession.getDelegate().getRealm(getId());
-            if (updated == null) throw new IllegalStateException("Not found in database");
-        }
-    }
-
     @Override
     public boolean isEnabled() {
         if (updated != null) return updated.isEnabled();
@@ -584,18 +585,6 @@ public class RealmAdapter implements RealmModel {
     }
 
     @Override
-    public AuthenticationLinkModel getAuthenticationLink(UserModel user) {
-        if (updated != null) return updated.getAuthenticationLink(user);
-        return cacheSession.getAuthenticationLink(user, this);
-    }
-
-    @Override
-    public void setAuthenticationLink(UserModel user, AuthenticationLinkModel authenticationLink) {
-        getDelegateForUpdate();
-        updated.setAuthenticationLink(user, authenticationLink);
-    }
-
-    @Override
     public boolean isSocial() {
         if (updated != null) return updated.isSocial();
         return cached.isSocial();
@@ -733,177 +722,250 @@ public class RealmAdapter implements RealmModel {
 
     @Override
     public String getLoginTheme() {
-        return null;  //To change body of implemented methods use File | Settings | File Templates.
+        if (updated != null) return updated.getLoginTheme();
+        return cached.getLoginTheme();
     }
 
     @Override
     public void setLoginTheme(String name) {
-        //To change body of implemented methods use File | Settings | File Templates.
+        getDelegateForUpdate();
+        updated.setLoginTheme(name);
     }
 
     @Override
     public String getAccountTheme() {
-        return null;  //To change body of implemented methods use File | Settings | File Templates.
+        if (updated != null) return updated.getAccountTheme();
+        return cached.getAccountTheme();
     }
 
     @Override
     public void setAccountTheme(String name) {
-        //To change body of implemented methods use File | Settings | File Templates.
+        getDelegateForUpdate();
+        updated.setAccountTheme(name);
     }
 
     @Override
     public String getAdminTheme() {
-        return null;  //To change body of implemented methods use File | Settings | File Templates.
+        if (updated != null) return updated.getAdminTheme();
+        return cached.getAdminTheme();
     }
 
     @Override
     public void setAdminTheme(String name) {
-        //To change body of implemented methods use File | Settings | File Templates.
+        getDelegateForUpdate();
+        updated.setAdminTheme(name);
     }
 
     @Override
     public String getEmailTheme() {
-        return null;  //To change body of implemented methods use File | Settings | File Templates.
+        if (updated != null) return updated.getEmailTheme();
+        return cached.getEmailTheme();
     }
 
     @Override
     public void setEmailTheme(String name) {
-        //To change body of implemented methods use File | Settings | File Templates.
+        getDelegateForUpdate();
+        updated.setEmailTheme(name);
     }
 
     @Override
     public int getNotBefore() {
-        return 0;  //To change body of implemented methods use File | Settings | File Templates.
+        if (updated != null) return updated.getNotBefore();
+        return cached.getNotBefore();
     }
 
     @Override
     public void setNotBefore(int notBefore) {
-        //To change body of implemented methods use File | Settings | File Templates.
+        getDelegateForUpdate();
+        updated.setNotBefore(notBefore);
     }
 
     @Override
     public boolean removeRoleById(String id) {
-        return false;  //To change body of implemented methods use File | Settings | File Templates.
+        getDelegateForUpdate();
+        return updated.removeRoleById(id);
     }
 
     @Override
     public boolean isAuditEnabled() {
-        return false;  //To change body of implemented methods use File | Settings | File Templates.
+        if (updated != null) return updated.isAuditEnabled();
+        return cached.isAuditEnabled();
     }
 
     @Override
     public void setAuditEnabled(boolean enabled) {
-        //To change body of implemented methods use File | Settings | File Templates.
+        getDelegateForUpdate();
+        updated.setAuditEnabled(enabled);
     }
 
     @Override
     public long getAuditExpiration() {
-        return 0;  //To change body of implemented methods use File | Settings | File Templates.
+        if (updated != null) return updated.getAuditExpiration();
+        return cached.getAuditExpiration();
     }
 
     @Override
     public void setAuditExpiration(long expiration) {
-        //To change body of implemented methods use File | Settings | File Templates.
+        getDelegateForUpdate();
+        updated.setAuditExpiration(expiration);
     }
 
     @Override
     public Set<String> getAuditListeners() {
-        return null;  //To change body of implemented methods use File | Settings | File Templates.
+        if (updated != null) return updated.getAuditListeners();
+        return cached.getAuditListeners();
     }
 
     @Override
     public void setAuditListeners(Set<String> listeners) {
-        //To change body of implemented methods use File | Settings | File Templates.
+        getDelegateForUpdate();
+        updated.setAuditListeners(listeners);
     }
 
     @Override
     public ApplicationModel getMasterAdminApp() {
-        return null;  //To change body of implemented methods use File | Settings | File Templates.
+        if (updated != null) return updated.getMasterAdminApp();
+        return getApplicationById(cached.getMasterAdminApp());
     }
 
     @Override
     public void setMasterAdminApp(ApplicationModel app) {
-        //To change body of implemented methods use File | Settings | File Templates.
+        getDelegateForUpdate();
+        updated.setMasterAdminApp(app);
     }
 
     @Override
-    public UsernameLoginFailureModel getUserLoginFailure(String username) {
-        return null;  //To change body of implemented methods use File | Settings | File Templates.
+    public RoleModel getRole(String name) {
+        if (updated != null) return updated.getRole(name);
+        String id = cached.getRealmRoles().get(name);
+        if (id == null) return null;
+        return cacheSession.getRoleById(id, this);
     }
 
     @Override
-    public UsernameLoginFailureModel addUserLoginFailure(String username) {
-        return null;  //To change body of implemented methods use File | Settings | File Templates.
+    public RoleModel addRole(String name) {
+        getDelegateForUpdate();
+        return updated.addRole(name);
     }
 
     @Override
-    public List<UsernameLoginFailureModel> getAllUserLoginFailures() {
-        return null;  //To change body of implemented methods use File | Settings | File Templates.
+    public RoleModel addRole(String id, String name) {
+        getDelegateForUpdate();
+        return updated.addRole(id, name);
     }
 
     @Override
-    public UserSessionModel createUserSession(UserModel user, String ipAddress) {
-        return null;  //To change body of implemented methods use File | Settings | File Templates.
+    public boolean removeRole(RoleModel role) {
+        getDelegateForUpdate();
+        return updated.removeRole(role);
     }
 
     @Override
-    public UserSessionModel getUserSession(String id) {
-        return null;  //To change body of implemented methods use File | Settings | File Templates.
+    public Set<RoleModel> getRoles() {
+        if (updated != null) return updated.getRoles();
+
+        Set<RoleModel> roles = new HashSet<RoleModel>();
+        for (String id : cached.getRealmRoles().values()) {
+            roles.add(cacheSession.getRoleById(id, this));
+        }
+        return roles;
     }
 
     @Override
-    public List<UserSessionModel> getUserSessions(UserModel user) {
-        return null;  //To change body of implemented methods use File | Settings | File Templates.
+    public ClientModel findClientById(String id) {
+        ClientModel model = getApplicationById(id);
+        if (model != null) return model;
+        return getOAuthClientById(id);
     }
 
+
     @Override
-    public void removeUserSession(UserSessionModel session) {
-        //To change body of implemented methods use File | Settings | File Templates.
+    public UsernameLoginFailureModel getUserLoginFailure(String username) {
+        if (updated != null) return updated.getUserLoginFailure(username);
+        return cacheSession.getUserLoginFailure(username, this);
     }
 
     @Override
-    public void removeUserSessions(UserModel user) {
-        //To change body of implemented methods use File | Settings | File Templates.
+    public UsernameLoginFailureModel addUserLoginFailure(String username) {
+        if (updated != null) return updated.addUserLoginFailure(username);
+        return cacheSession.addUserLoginFailure(username, this);
     }
 
     @Override
-    public void removeExpiredUserSessions() {
-        //To change body of implemented methods use File | Settings | File Templates.
+    public List<UsernameLoginFailureModel> getAllUserLoginFailures() {
+        if (updated != null) return updated.getAllUserLoginFailures();
+        return cacheSession.getAllUserLoginFailures();
     }
 
     @Override
-    public ClientModel findClientById(String id) {
-        return null;  //To change body of implemented methods use File | Settings | File Templates.
+    public UserSessionModel createUserSession(UserModel user, String ipAddress) {
+        if (updated != null) return updated.createUserSession(user, ipAddress);
+        return cacheSession.createUserSession(this, user, ipAddress);
     }
 
     @Override
-    public void removeUserSessions() {
-        //To change body of implemented methods use File | Settings | File Templates.
+    public UserSessionModel getUserSession(String id) {
+        if (updated != null) return updated.getUserSession(id);
+        return cacheSession.getUserSession(id, this);
     }
 
     @Override
-    public RoleModel getRole(String name) {
-        return null;  //To change body of implemented methods use File | Settings | File Templates.
+    public List<UserSessionModel> getUserSessions(UserModel user) {
+        if (updated != null) return updated.getUserSessions(user);
+        return cacheSession.getUserSessions(user, this);
     }
 
     @Override
-    public RoleModel addRole(String name) {
-        return null;  //To change body of implemented methods use File | Settings | File Templates.
+    public void removeUserSession(UserSessionModel session) {
+        if (updated != null) {
+            updated.removeUserSession(session);
+        } else {
+            cacheSession.removeUserSession(session);
+
+        }
     }
 
     @Override
-    public RoleModel addRole(String id, String name) {
-        return null;  //To change body of implemented methods use File | Settings | File Templates.
+    public void removeUserSessions(UserModel user) {
+        if (updated != null) {
+            updated.removeUserSessions(user);
+        } else {
+            cacheSession.removeUserSessions(this, user);
+
+        }
     }
 
     @Override
-    public boolean removeRole(RoleModel role) {
-        return false;  //To change body of implemented methods use File | Settings | File Templates.
+    public void removeExpiredUserSessions() {
+        if (updated != null) {
+            updated.removeExpiredUserSessions();
+        } else {
+            cacheSession.removeExpiredUserSessions(this);
+
+        }
     }
 
     @Override
-    public Set<RoleModel> getRoles() {
-        return null;  //To change body of implemented methods use File | Settings | File Templates.
+    public void removeUserSessions() {
+        if (updated != null) {
+            updated.removeUserSessions();
+        } else {
+            cacheSession.removeUserSessions(this);
+
+        }
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) return true;
+        if (!(o instanceof RealmModel)) return false;
+
+        RealmModel that = (RealmModel) o;
+        return that.getId().equals(getId());
     }
 
+    @Override
+    public int hashCode() {
+        return getId().hashCode();
+    }
 }
diff --git a/model/jpa/src/main/java/org/keycloak/models/jpa/JpaKeycloakSession.java b/model/jpa/src/main/java/org/keycloak/models/jpa/JpaKeycloakSession.java
index d97f703..5ee0b47 100755
--- a/model/jpa/src/main/java/org/keycloak/models/jpa/JpaKeycloakSession.java
+++ b/model/jpa/src/main/java/org/keycloak/models/jpa/JpaKeycloakSession.java
@@ -8,6 +8,7 @@ import javax.persistence.EntityManager;
 import javax.persistence.TypedQuery;
 import java.lang.reflect.Proxy;
 import java.util.ArrayList;
+import java.util.HashSet;
 import java.util.LinkedList;
 import java.util.List;
 import java.util.Map;
@@ -41,14 +42,14 @@ public class JpaKeycloakSession implements KeycloakSession {
         realm.setId(id);
         em.persist(realm);
         em.flush();
-        return new RealmAdapter(em, realm);
+        return new RealmAdapter(this, em, realm);
     }
 
     @Override
     public RealmModel getRealm(String id) {
         RealmEntity realm = em.find(RealmEntity.class, id);
         if (realm == null) return null;
-        return new RealmAdapter(em, realm);
+        return new RealmAdapter(this, em, realm);
     }
 
     @Override
@@ -57,7 +58,7 @@ public class JpaKeycloakSession implements KeycloakSession {
         List<RealmEntity> entities = query.getResultList();
         List<RealmModel> realms = new ArrayList<RealmModel>();
         for (RealmEntity entity : entities) {
-            realms.add(new RealmAdapter(em, entity));
+            realms.add(new RealmAdapter(this, em, entity));
         }
         return realms;
     }
@@ -71,7 +72,7 @@ public class JpaKeycloakSession implements KeycloakSession {
         if (entities.size() > 1) throw new IllegalStateException("Should not be more than one realm with same name");
         RealmEntity realm = query.getResultList().get(0);
         if (realm == null) return null;
-        return new RealmAdapter(em, realm);
+        return new RealmAdapter(this, em, realm);
     }
 
     @Override
@@ -113,7 +114,7 @@ public class JpaKeycloakSession implements KeycloakSession {
             return false;
         }
 
-        RealmAdapter adapter = new RealmAdapter(em, realm);
+        RealmAdapter adapter = new RealmAdapter(this, em, realm);
         adapter.removeUserSessions();
         for (ApplicationEntity a : new LinkedList<ApplicationEntity>(realm.getApplications())) {
             adapter.removeApplication(a.getId());
@@ -149,7 +150,21 @@ public class JpaKeycloakSession implements KeycloakSession {
 
     @Override
     public UserModel getUserBySocialLink(SocialLinkModel socialLink, RealmModel realm) {
-        return null;  //To change body of implemented methods use File | Settings | File Templates.
+        TypedQuery<UserEntity> query = em.createNamedQuery("findUserByLinkAndRealm", UserEntity.class);
+        RealmEntity realmEntity = em.getReference(RealmEntity.class, realm.getId());
+        query.setParameter("realm", realmEntity);
+        query.setParameter("socialProvider", socialLink.getSocialProvider());
+        query.setParameter("socialUserId", socialLink.getSocialUserId());
+        List<UserEntity> results = query.getResultList();
+        if (results.isEmpty()) {
+            return null;
+        } else if (results.size() > 1) {
+            throw new IllegalStateException("More results found for socialProvider=" + socialLink.getSocialProvider() +
+                    ", socialUserId=" + socialLink.getSocialUserId() + ", results=" + results);
+        } else {
+            UserEntity user = results.get(0);
+            return new UserAdapter(realm, em, user);
+        }
     }
 
     @Override
@@ -172,14 +187,33 @@ public class JpaKeycloakSession implements KeycloakSession {
         return null;  //To change body of implemented methods use File | Settings | File Templates.
     }
 
+    private SocialLinkEntity findSocialLink(UserModel user, String socialProvider) {
+        TypedQuery<SocialLinkEntity> query = em.createNamedQuery("findSocialLinkByUserAndProvider", SocialLinkEntity.class);
+        UserEntity userEntity = em.getReference(UserEntity.class, user.getId());
+        query.setParameter("user", userEntity);
+        query.setParameter("socialProvider", socialProvider);
+        List<SocialLinkEntity> results = query.getResultList();
+        return results.size() > 0 ? results.get(0) : null;
+    }
+
+
     @Override
     public Set<SocialLinkModel> getSocialLinks(UserModel user, RealmModel realm) {
-        return null;  //To change body of implemented methods use File | Settings | File Templates.
+        TypedQuery<SocialLinkEntity> query = em.createNamedQuery("findSocialLinkByUser", SocialLinkEntity.class);
+        UserEntity userEntity = em.getReference(UserEntity.class, user.getId());
+        query.setParameter("user", userEntity);
+        List<SocialLinkEntity> results = query.getResultList();
+        Set<SocialLinkModel> set = new HashSet<SocialLinkModel>();
+        for (SocialLinkEntity entity : results) {
+            set.add(new SocialLinkModel(entity.getSocialProvider(), entity.getSocialUserId(), entity.getSocialUsername()));
+        }
+        return set;
     }
 
     @Override
     public SocialLinkModel getSocialLink(UserModel user, String socialProvider, RealmModel realm) {
-        return null;  //To change body of implemented methods use File | Settings | File Templates.
+        SocialLinkEntity entity = findSocialLink(user, socialProvider);
+        return (entity != null) ? new SocialLinkModel(entity.getSocialProvider(), entity.getSocialUserId(), entity.getSocialUsername()) : null;
     }
 
     @Override
@@ -194,11 +228,93 @@ public class JpaKeycloakSession implements KeycloakSession {
 
     @Override
     public ApplicationModel getApplicationById(String id, RealmModel realm) {
-        return null;  //To change body of implemented methods use File | Settings | File Templates.
+        ApplicationEntity app = em.find(ApplicationEntity.class, id);
+
+        // Check if application belongs to this realm
+        if (app == null || !realm.getId().equals(app.getRealm().getId())) return null;
+        return new ApplicationAdapter(realm, em, app);
     }
 
     @Override
     public OAuthClientModel getOAuthClientById(String id, RealmModel realm) {
         return null;  //To change body of implemented methods use File | Settings | File Templates.
     }
+
+    @Override
+    public UsernameLoginFailureModel getUserLoginFailure(String username, RealmModel realm) {
+        String id = username + "-" + realm.getId();
+        UsernameLoginFailureEntity entity = em.find(UsernameLoginFailureEntity.class, id);
+        if (entity == null) return null;
+        return new UsernameLoginFailureAdapter(entity);
+    }
+
+    @Override
+    public UsernameLoginFailureModel addUserLoginFailure(String username, RealmModel realm) {
+        UsernameLoginFailureModel model = getUserLoginFailure(username, realm);
+        if (model != null) return model;
+        String id = username + "-" + realm.getId();
+        UsernameLoginFailureEntity entity = new UsernameLoginFailureEntity();
+        entity.setId(id);
+        entity.setUsername(username);
+        RealmEntity realmEntity = em.getReference(RealmEntity.class, realm.getId());
+        entity.setRealm(realmEntity);
+        em.persist(entity);
+        return new UsernameLoginFailureAdapter(entity);
+    }
+
+    @Override
+    public List<UsernameLoginFailureModel> getAllUserLoginFailures() {
+        TypedQuery<UsernameLoginFailureEntity> query = em.createNamedQuery("getAllFailures", UsernameLoginFailureEntity.class);
+        List<UsernameLoginFailureEntity> entities = query.getResultList();
+        List<UsernameLoginFailureModel> models = new ArrayList<UsernameLoginFailureModel>();
+        for (UsernameLoginFailureEntity entity : entities) {
+            models.add(new UsernameLoginFailureAdapter(entity));
+        }
+        return models;
+    }
+
+    @Override
+    public UserSessionModel createUserSession(RealmModel realm, UserModel user, String ipAddress) {
+        return null;  //To change body of implemented methods use File | Settings | File Templates.
+    }
+
+    @Override
+    public UserSessionModel getUserSession(String id, RealmModel realm) {
+        return null;  //To change body of implemented methods use File | Settings | File Templates.
+    }
+
+    @Override
+    public List<UserSessionModel> getUserSessions(UserModel user, RealmModel realm) {
+        return null;  //To change body of implemented methods use File | Settings | File Templates.
+    }
+
+    @Override
+    public Set<UserSessionModel> getUserSessions(RealmModel realm, ClientModel client) {
+        return null;  //To change body of implemented methods use File | Settings | File Templates.
+    }
+
+    @Override
+    public int getActiveUserSessions(RealmModel realm, ClientModel client) {
+        return 0;  //To change body of implemented methods use File | Settings | File Templates.
+    }
+
+    @Override
+    public void removeUserSession(UserSessionModel session) {
+        //To change body of implemented methods use File | Settings | File Templates.
+    }
+
+    @Override
+    public void removeUserSessions(RealmModel realm, UserModel user) {
+        //To change body of implemented methods use File | Settings | File Templates.
+    }
+
+    @Override
+    public void removeExpiredUserSessions(RealmModel realm) {
+        //To change body of implemented methods use File | Settings | File Templates.
+    }
+
+    @Override
+    public void removeUserSessions(RealmModel realm) {
+        //To change body of implemented methods use File | Settings | File Templates.
+    }
 }
diff --git a/model/jpa/src/main/java/org/keycloak/models/jpa/RealmAdapter.java b/model/jpa/src/main/java/org/keycloak/models/jpa/RealmAdapter.java
index 1d350de..9d319a6 100755
--- a/model/jpa/src/main/java/org/keycloak/models/jpa/RealmAdapter.java
+++ b/model/jpa/src/main/java/org/keycloak/models/jpa/RealmAdapter.java
@@ -3,6 +3,7 @@ package org.keycloak.models.jpa;
 import org.keycloak.models.AuthenticationLinkModel;
 import org.keycloak.models.AuthenticationProviderModel;
 import org.keycloak.models.ClientModel;
+import org.keycloak.models.KeycloakSession;
 import org.keycloak.models.ModelDuplicateException;
 import org.keycloak.models.RoleContainerModel;
 import org.keycloak.models.UserCredentialValueModel;
@@ -63,9 +64,11 @@ public class RealmAdapter implements RealmModel {
     protected EntityManager em;
     protected volatile transient PublicKey publicKey;
     protected volatile transient PrivateKey privateKey;
+    protected KeycloakSession session;
     private PasswordPolicy passwordPolicy;
 
-    public RealmAdapter(EntityManager em, RealmEntity realm) {
+    public RealmAdapter(KeycloakSession session, EntityManager em, RealmEntity realm) {
+        this.session = session;
         this.em = em;
         this.realm = realm;
     }
@@ -422,62 +425,32 @@ public class RealmAdapter implements RealmModel {
 
     @Override
     public UserModel getUser(String name) {
-        TypedQuery<UserEntity> query = em.createNamedQuery("getRealmUserByLoginName", UserEntity.class);
-        query.setParameter("loginName", name);
-        query.setParameter("realm", realm);
-        List<UserEntity> results = query.getResultList();
-        if (results.size() == 0) return null;
-        return new UserAdapter(this, em, results.get(0));
+        return session.getUserByUsername(name, this);
     }
 
     @Override
     public UsernameLoginFailureModel getUserLoginFailure(String username) {
-        String id = username + "-" + realm.getId();
-        UsernameLoginFailureEntity entity = em.find(UsernameLoginFailureEntity.class, id);
-        if (entity == null) return null;
-        return new UsernameLoginFailureAdapter(entity);
+        return session.getUserLoginFailure(username, this);
     }
 
     @Override
     public UsernameLoginFailureModel addUserLoginFailure(String username) {
-        UsernameLoginFailureModel model = getUserLoginFailure(username);
-        if (model != null) return model;
-        String id = username + "-" + realm.getId();
-        UsernameLoginFailureEntity entity = new UsernameLoginFailureEntity();
-        entity.setId(id);
-        entity.setUsername(username);
-        entity.setRealm(realm);
-        em.persist(entity);
-        return new UsernameLoginFailureAdapter(entity);
+        return session.addUserLoginFailure(username, this);
     }
 
     @Override
     public List<UsernameLoginFailureModel> getAllUserLoginFailures() {
-        TypedQuery<UsernameLoginFailureEntity> query = em.createNamedQuery("getAllFailures", UsernameLoginFailureEntity.class);
-        List<UsernameLoginFailureEntity> entities = query.getResultList();
-        List<UsernameLoginFailureModel> models = new ArrayList<UsernameLoginFailureModel>();
-        for (UsernameLoginFailureEntity entity : entities) {
-            models.add(new UsernameLoginFailureAdapter(entity));
-        }
-        return models;
+        return session.getAllUserLoginFailures();
     }
 
     @Override
     public UserModel getUserByEmail(String email) {
-        TypedQuery<UserEntity> query = em.createNamedQuery("getRealmUserByEmail", UserEntity.class);
-        query.setParameter("email", email);
-        query.setParameter("realm", realm);
-        List<UserEntity> results = query.getResultList();
-        return results.isEmpty() ? null : new UserAdapter(this, em, results.get(0));
+        return session.getUserByEmail(email, this);
     }
 
     @Override
     public UserModel getUserById(String id) {
-        UserEntity entity = em.find(UserEntity.class, id);
-
-        // Check if user belongs to this realm
-        if (entity == null || !this.realm.equals(entity.getRealm())) return null;
-        return new UserAdapter(this, em, entity);
+        return session.getUserById(id, this);
     }
 
     @Override
@@ -678,11 +651,7 @@ public class RealmAdapter implements RealmModel {
 
     @Override
     public ApplicationModel getApplicationById(String id) {
-        ApplicationEntity app = em.find(ApplicationEntity.class, id);
-
-        // Check if application belongs to this realm
-        if (app == null || !this.realm.equals(app.getRealm())) return null;
-        return new ApplicationAdapter(this, em, app);
+        return session.getApplicationById(id, this);
     }
 
     @Override
@@ -692,38 +661,17 @@ public class RealmAdapter implements RealmModel {
 
     @Override
     public UserModel getUserBySocialLink(SocialLinkModel socialLink) {
-        TypedQuery<UserEntity> query = em.createNamedQuery("findUserByLinkAndRealm", UserEntity.class);
-        query.setParameter("realm", realm);
-        query.setParameter("socialProvider", socialLink.getSocialProvider());
-        query.setParameter("socialUserId", socialLink.getSocialUserId());
-        List<UserEntity> results = query.getResultList();
-        if (results.isEmpty()) {
-            return null;
-        } else if (results.size() > 1) {
-            throw new IllegalStateException("More results found for socialProvider=" + socialLink.getSocialProvider() +
-                    ", socialUserId=" + socialLink.getSocialUserId() + ", results=" + results);
-        } else {
-            UserEntity user = results.get(0);
-            return new UserAdapter(this, em, user);
-        }
+        return session.getUserBySocialLink(socialLink, this);
     }
 
     @Override
     public Set<SocialLinkModel> getSocialLinks(UserModel user) {
-        TypedQuery<SocialLinkEntity> query = em.createNamedQuery("findSocialLinkByUser", SocialLinkEntity.class);
-        query.setParameter("user", ((UserAdapter) user).getUser());
-        List<SocialLinkEntity> results = query.getResultList();
-        Set<SocialLinkModel> set = new HashSet<SocialLinkModel>();
-        for (SocialLinkEntity entity : results) {
-            set.add(new SocialLinkModel(entity.getSocialProvider(), entity.getSocialUserId(), entity.getSocialUsername()));
-        }
-        return set;
+        return session.getSocialLinks(user, this);
     }
 
     @Override
     public SocialLinkModel getSocialLink(UserModel user, String socialProvider) {
-        SocialLinkEntity entity = findSocialLink(user, socialProvider);
-        return (entity != null) ? new SocialLinkModel(entity.getSocialProvider(), entity.getSocialUserId(), entity.getSocialUsername()) : null;
+        return session.getSocialLink(user, socialProvider, this);
     }
 
     @Override
@@ -738,6 +686,16 @@ public class RealmAdapter implements RealmModel {
         em.flush();
     }
 
+    private SocialLinkEntity findSocialLink(UserModel user, String socialProvider) {
+        TypedQuery<SocialLinkEntity> query = em.createNamedQuery("findSocialLinkByUserAndProvider", SocialLinkEntity.class);
+        UserEntity userEntity = em.getReference(UserEntity.class, user.getId());
+        query.setParameter("user", userEntity);
+        query.setParameter("socialProvider", socialProvider);
+        List<SocialLinkEntity> results = query.getResultList();
+        return results.size() > 0 ? results.get(0) : null;
+    }
+
+
     @Override
     public boolean removeSocialLink(UserModel user, String socialProvider) {
         SocialLinkEntity entity = findSocialLink(user, socialProvider);
@@ -750,33 +708,6 @@ public class RealmAdapter implements RealmModel {
         }
     }
 
-    private SocialLinkEntity findSocialLink(UserModel user, String socialProvider) {
-        TypedQuery<SocialLinkEntity> query = em.createNamedQuery("findSocialLinkByUserAndProvider", SocialLinkEntity.class);
-        query.setParameter("user", ((UserAdapter) user).getUser());
-        query.setParameter("socialProvider", socialProvider);
-        List<SocialLinkEntity> results = query.getResultList();
-        return results.size() > 0 ? results.get(0) : null;
-    }
-
-    @Override
-    public AuthenticationLinkModel getAuthenticationLink(UserModel user) {
-        UserEntity userEntity = ((UserAdapter) user).getUser();
-        AuthenticationLinkEntity authLinkEntity = userEntity.getAuthenticationLink();
-        return authLinkEntity == null ? null : new AuthenticationLinkModel(authLinkEntity.getAuthProvider(), authLinkEntity.getAuthUserId());
-    }
-
-    @Override
-    public void setAuthenticationLink(UserModel user, AuthenticationLinkModel authenticationLink) {
-        AuthenticationLinkEntity entity = new AuthenticationLinkEntity();
-        entity.setAuthProvider(authenticationLink.getAuthProvider());
-        entity.setAuthUserId(authenticationLink.getAuthUserId());
-
-        UserEntity userEntity = ((UserAdapter) user).getUser();
-        userEntity.setAuthenticationLink(entity);
-        em.persist(entity);
-        em.persist(userEntity);
-        em.flush();
-    }
 
     @Override
     public boolean isSocial() {
diff --git a/model/jpa/src/main/java/org/keycloak/models/jpa/UserAdapter.java b/model/jpa/src/main/java/org/keycloak/models/jpa/UserAdapter.java
index 4cd2dde..f7eb178 100755
--- a/model/jpa/src/main/java/org/keycloak/models/jpa/UserAdapter.java
+++ b/model/jpa/src/main/java/org/keycloak/models/jpa/UserAdapter.java
@@ -1,12 +1,14 @@
 package org.keycloak.models.jpa;
 
 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.jpa.entities.AuthenticationLinkEntity;
 import org.keycloak.models.jpa.entities.CredentialEntity;
 import org.keycloak.models.jpa.entities.RoleEntity;
 import org.keycloak.models.jpa.entities.UserEntity;
@@ -338,4 +340,24 @@ public class UserAdapter implements UserModel {
         }
         return roles;
     }
+
+    @Override
+    public AuthenticationLinkModel getAuthenticationLink() {
+        AuthenticationLinkEntity authLinkEntity = user.getAuthenticationLink();
+        return authLinkEntity == null ? null : new AuthenticationLinkModel(authLinkEntity.getAuthProvider(), authLinkEntity.getAuthUserId());
+    }
+
+    @Override
+    public void setAuthenticationLink(AuthenticationLinkModel authenticationLink) {
+        AuthenticationLinkEntity entity = new AuthenticationLinkEntity();
+        entity.setAuthProvider(authenticationLink.getAuthProvider());
+        entity.setAuthUserId(authenticationLink.getAuthUserId());
+
+        user.setAuthenticationLink(entity);
+        em.persist(entity);
+        em.persist(user);
+        em.flush();
+    }
+
+
 }
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 042ba4f..4078453 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
@@ -5,6 +5,7 @@ import com.mongodb.DBObject;
 import com.mongodb.QueryBuilder;
 import org.keycloak.models.ApplicationModel;
 import org.keycloak.models.AuthenticationLinkModel;
+import org.keycloak.models.ClientModel;
 import org.keycloak.models.KeycloakSession;
 import org.keycloak.models.KeycloakTransaction;
 import org.keycloak.models.OAuthClientModel;
@@ -12,6 +13,8 @@ import org.keycloak.models.RealmModel;
 import org.keycloak.models.RoleModel;
 import org.keycloak.models.SocialLinkModel;
 import org.keycloak.models.UserModel;
+import org.keycloak.models.UserSessionModel;
+import org.keycloak.models.UsernameLoginFailureModel;
 import org.keycloak.models.mongo.api.MongoStore;
 import org.keycloak.models.mongo.api.context.MongoStoreInvocationContext;
 import org.keycloak.models.mongo.impl.context.TransactionMongoStoreInvocationContext;
@@ -203,4 +206,64 @@ public class MongoKeycloakSession implements KeycloakSession {
     public OAuthClientModel getOAuthClientById(String id, RealmModel realm) {
         return null;  //To change body of implemented methods use File | Settings | File Templates.
     }
+
+    @Override
+    public UsernameLoginFailureModel getUserLoginFailure(String username, RealmModel realm) {
+        return null;  //To change body of implemented methods use File | Settings | File Templates.
+    }
+
+    @Override
+    public UsernameLoginFailureModel addUserLoginFailure(String username, RealmModel realm) {
+        return null;  //To change body of implemented methods use File | Settings | File Templates.
+    }
+
+    @Override
+    public List<UsernameLoginFailureModel> getAllUserLoginFailures() {
+        return null;  //To change body of implemented methods use File | Settings | File Templates.
+    }
+
+    @Override
+    public UserSessionModel createUserSession(RealmModel realm, UserModel user, String ipAddress) {
+        return null;  //To change body of implemented methods use File | Settings | File Templates.
+    }
+
+    @Override
+    public UserSessionModel getUserSession(String id, RealmModel realm) {
+        return null;  //To change body of implemented methods use File | Settings | File Templates.
+    }
+
+    @Override
+    public List<UserSessionModel> getUserSessions(UserModel user, RealmModel realm) {
+        return null;  //To change body of implemented methods use File | Settings | File Templates.
+    }
+
+    @Override
+    public Set<UserSessionModel> getUserSessions(RealmModel realm, ClientModel client) {
+        return null;  //To change body of implemented methods use File | Settings | File Templates.
+    }
+
+    @Override
+    public int getActiveUserSessions(RealmModel realm, ClientModel client) {
+        return 0;  //To change body of implemented methods use File | Settings | File Templates.
+    }
+
+    @Override
+    public void removeUserSession(UserSessionModel session) {
+        //To change body of implemented methods use File | Settings | File Templates.
+    }
+
+    @Override
+    public void removeUserSessions(RealmModel realm, UserModel user) {
+        //To change body of implemented methods use File | Settings | File Templates.
+    }
+
+    @Override
+    public void removeExpiredUserSessions(RealmModel realm) {
+        //To change body of implemented methods use File | Settings | File Templates.
+    }
+
+    @Override
+    public void removeUserSessions(RealmModel realm) {
+        //To change body of implemented methods use File | Settings | File Templates.
+    }
 }
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 2e02d6e..7861fb6 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
@@ -976,29 +976,6 @@ public class RealmAdapter extends AbstractMongoAdapter<MongoRealmEntity> impleme
         return null;
     }
 
-    @Override
-    public AuthenticationLinkModel getAuthenticationLink(UserModel user) {
-        MongoUserEntity userEntity = ((UserAdapter) user).getUser();
-        AuthenticationLinkEntity authLinkEntity = userEntity.getAuthenticationLink();
-
-        if (authLinkEntity == null) {
-            return null;
-        } else {
-            return new AuthenticationLinkModel(authLinkEntity.getAuthProvider(), authLinkEntity.getAuthUserId());
-        }
-    }
-
-    @Override
-    public void setAuthenticationLink(UserModel user, AuthenticationLinkModel authenticationLink) {
-        MongoUserEntity userEntity = ((UserAdapter) user).getUser();
-        AuthenticationLinkEntity authLinkEntity = new AuthenticationLinkEntity();
-        authLinkEntity.setAuthProvider(authenticationLink.getAuthProvider());
-        authLinkEntity.setAuthUserId(authenticationLink.getAuthUserId());
-        userEntity.setAuthenticationLink(authLinkEntity);
-
-        getMongoStore().updateEntity(userEntity, invocationContext);
-    }
-
     protected void updateRealm() {
         super.updateMongoEntity();
     }
diff --git a/model/mongo/src/main/java/org/keycloak/models/mongo/keycloak/adapters/UserAdapter.java b/model/mongo/src/main/java/org/keycloak/models/mongo/keycloak/adapters/UserAdapter.java
index 1cbf1ed..0416cc0 100755
--- a/model/mongo/src/main/java/org/keycloak/models/mongo/keycloak/adapters/UserAdapter.java
+++ b/model/mongo/src/main/java/org/keycloak/models/mongo/keycloak/adapters/UserAdapter.java
@@ -1,12 +1,14 @@
 package org.keycloak.models.mongo.keycloak.adapters;
 
 import org.keycloak.models.ApplicationModel;
+import org.keycloak.models.AuthenticationLinkModel;
 import org.keycloak.models.ClientModel;
 import org.keycloak.models.RealmModel;
 import org.keycloak.models.RoleModel;
 import org.keycloak.models.UserCredentialModel;
 import org.keycloak.models.UserCredentialValueModel;
 import org.keycloak.models.UserModel;
+import org.keycloak.models.entities.AuthenticationLinkEntity;
 import org.keycloak.models.entities.CredentialEntity;
 import org.keycloak.models.mongo.api.context.MongoStoreInvocationContext;
 import org.keycloak.models.mongo.keycloak.entities.MongoRoleEntity;
@@ -325,6 +327,29 @@ public class UserAdapter extends AbstractMongoAdapter<MongoUserEntity> implement
         return result;
     }
 
+    @Override
+    public AuthenticationLinkModel getAuthenticationLink() {
+        AuthenticationLinkEntity authLinkEntity = user.getAuthenticationLink();
+
+        if (authLinkEntity == null) {
+            return null;
+        } else {
+            return new AuthenticationLinkModel(authLinkEntity.getAuthProvider(), authLinkEntity.getAuthUserId());
+        }
+    }
+
+    @Override
+    public void setAuthenticationLink(AuthenticationLinkModel authenticationLink) {
+        AuthenticationLinkEntity authLinkEntity = new AuthenticationLinkEntity();
+        authLinkEntity.setAuthProvider(authenticationLink.getAuthProvider());
+        authLinkEntity.setAuthUserId(authenticationLink.getAuthUserId());
+        user.setAuthenticationLink(authLinkEntity);
+
+        getMongoStore().updateEntity(user, invocationContext);
+    }
+
+
+
 
 
 
diff --git a/model/tests/src/test/java/org/keycloak/model/test/AuthProvidersExternalModelTest.java b/model/tests/src/test/java/org/keycloak/model/test/AuthProvidersExternalModelTest.java
index 961b674..bcd36fa 100755
--- a/model/tests/src/test/java/org/keycloak/model/test/AuthProvidersExternalModelTest.java
+++ b/model/tests/src/test/java/org/keycloak/model/test/AuthProvidersExternalModelTest.java
@@ -97,7 +97,7 @@ public class AuthProvidersExternalModelTest extends AbstractModelTest {
             Assert.assertEquals("john@email.org", john2.getEmail());
 
             // Verify link exists
-            AuthenticationLinkModel authLink = realm2.getAuthenticationLink(john2);
+            AuthenticationLinkModel authLink = john2.getAuthenticationLink();
             Assert.assertNotNull(authLink);
             Assert.assertEquals(authLink.getAuthProvider(), AuthProviderConstants.PROVIDER_NAME_EXTERNAL_MODEL);
             Assert.assertEquals(authLink.getAuthUserId(), realm1.getUser("john").getId());
@@ -115,7 +115,7 @@ public class AuthProvidersExternalModelTest extends AbstractModelTest {
         // Add john to realm2 and set authentication link
         UserModel john = realm2.addUser("john");
         john.setEnabled(true);
-        realm2.setAuthenticationLink(john, new AuthenticationLinkModel(AuthProviderConstants.PROVIDER_NAME_EXTERNAL_MODEL, realm1.getUser("john").getId()));
+        john.setAuthenticationLink(new AuthenticationLinkModel(AuthProviderConstants.PROVIDER_NAME_EXTERNAL_MODEL, realm1.getUser("john").getId()));
 
         try {
             // this is needed for externalModel provider
diff --git a/model/tests/src/test/java/org/keycloak/model/test/AuthProvidersLDAPTest.java b/model/tests/src/test/java/org/keycloak/model/test/AuthProvidersLDAPTest.java
index 083a967..108fd5f 100755
--- a/model/tests/src/test/java/org/keycloak/model/test/AuthProvidersLDAPTest.java
+++ b/model/tests/src/test/java/org/keycloak/model/test/AuthProvidersLDAPTest.java
@@ -97,7 +97,7 @@ public class AuthProvidersLDAPTest extends AbstractModelTest {
         Assert.assertEquals("john@email.org", john.getEmail());
 
         // Verify link exists
-        AuthenticationLinkModel authLink = realm.getAuthenticationLink(john);
+        AuthenticationLinkModel authLink = john.getAuthenticationLink();
         Assert.assertNotNull(authLink);
         Assert.assertEquals(authLink.getAuthProvider(), AuthProviderConstants.PROVIDER_NAME_PICKETLINK);
     }
diff --git a/model/tests/src/test/java/org/keycloak/model/test/ImportTest.java b/model/tests/src/test/java/org/keycloak/model/test/ImportTest.java
index 3eaf973..bd10ac1 100755
--- a/model/tests/src/test/java/org/keycloak/model/test/ImportTest.java
+++ b/model/tests/src/test/java/org/keycloak/model/test/ImportTest.java
@@ -221,7 +221,7 @@ public class ImportTest extends AbstractModelTest {
         Assert.assertTrue(authProv3.isPasswordUpdateSupported());
 
         // Test authentication linking
-        AuthenticationLinkModel authLink = realm.getAuthenticationLink(socialUser);
+        AuthenticationLinkModel authLink = socialUser.getAuthenticationLink();
         Assert.assertEquals(AuthProviderConstants.PROVIDER_NAME_PICKETLINK, authLink.getAuthProvider());
         Assert.assertEquals("myUser1", authLink.getAuthUserId());
     }
diff --git a/services/src/main/java/org/keycloak/services/managers/AuthenticationManager.java b/services/src/main/java/org/keycloak/services/managers/AuthenticationManager.java
index 513d9c0..76b8876 100755
--- a/services/src/main/java/org/keycloak/services/managers/AuthenticationManager.java
+++ b/services/src/main/java/org/keycloak/services/managers/AuthenticationManager.java
@@ -275,7 +275,7 @@ public class AuthenticationManager {
                 user.setFirstName(authUser.getFirstName());
                 user.setLastName(authUser.getLastName());
                 user.setEmail(authUser.getEmail());
-                realm.setAuthenticationLink(user, new AuthenticationLinkModel(authUser.getProviderName(), authUser.getId()));
+                user.setAuthenticationLink(new AuthenticationLinkModel(authUser.getProviderName(), authUser.getId()));
                 logger.info("User " + authUser.getUsername() + " created and linked with provider " + authUser.getProviderName());
             } else {
                 logger.warn("User " + username + " not found");
diff --git a/services/src/main/java/org/keycloak/services/managers/RealmManager.java b/services/src/main/java/org/keycloak/services/managers/RealmManager.java
index e39e20b..248e0ae 100755
--- a/services/src/main/java/org/keycloak/services/managers/RealmManager.java
+++ b/services/src/main/java/org/keycloak/services/managers/RealmManager.java
@@ -575,7 +575,7 @@ public class RealmManager {
         if (userRep.getAuthenticationLink() != null) {
             AuthenticationLinkRepresentation link = userRep.getAuthenticationLink();
             AuthenticationLinkModel authLink = new AuthenticationLinkModel(link.getAuthProvider(), link.getAuthUserId());
-            newRealm.setAuthenticationLink(user, authLink);
+            user.setAuthenticationLink(authLink);
         }
         return user;
     }
diff --git a/services/src/main/java/org/keycloak/services/resources/AccountService.java b/services/src/main/java/org/keycloak/services/resources/AccountService.java
index 3ba8d16..16e08c1 100755
--- a/services/src/main/java/org/keycloak/services/resources/AccountService.java
+++ b/services/src/main/java/org/keycloak/services/resources/AccountService.java
@@ -157,7 +157,7 @@ public class AccountService {
             }
             account.setUser(auth.getUser());
 
-            AuthenticationLinkModel authLinkModel = realm.getAuthenticationLink(auth.getUser());
+            AuthenticationLinkModel authLinkModel = auth.getUser().getAuthenticationLink();
             if (authLinkModel != null) {
                 AuthenticationProviderModel authProviderModel = AuthenticationProviderManager.getConfiguredProviderModel(realm, authLinkModel.getAuthProvider());
                 passwordUpdateSupported = authProviderModel.isPasswordUpdateSupported();
@@ -513,7 +513,7 @@ public class AccountService {
                 if (link != null) {
 
                     // Removing last social provider is not possible if you don't have other possibility to authenticate
-                    if (realm.getSocialLinks(user).size() > 1 || realm.getAuthenticationLink(user) != null) {
+                    if (realm.getSocialLinks(user).size() > 1 || user.getAuthenticationLink() != null) {
                         realm.removeSocialLink(user, providerId);
 
                         logger.debug("Social provider " + providerId + " removed successfully from user " + user.getLoginName());