keycloak-aplcache

Changes

model/api/src/main/java/org/keycloak/models/RoleMapperModel.java 15(+0 -15)

model/jpa/src/main/java/org/keycloak/models/jpa/entities/ApplicationRoleEntity.java 45(+0 -45)

model/jpa/src/main/java/org/keycloak/models/jpa/entities/RealmRoleEntity.java 42(+0 -42)

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/authentication/authentication-model/src/main/java/org/keycloak/authentication/model/AbstractModelAuthenticationProvider.java b/authentication/authentication-model/src/main/java/org/keycloak/authentication/model/AbstractModelAuthenticationProvider.java
old mode 100644
new mode 100755
index 5c6b834..730f3f4
--- a/authentication/authentication-model/src/main/java/org/keycloak/authentication/model/AbstractModelAuthenticationProvider.java
+++ b/authentication/authentication-model/src/main/java/org/keycloak/authentication/model/AbstractModelAuthenticationProvider.java
@@ -66,7 +66,7 @@ public abstract class AbstractModelAuthenticationProvider implements Authenticat
         cred.setType(CredentialRepresentation.PASSWORD);
         cred.setValue(password);
 
-        realm.updateCredential(user, cred);
+        user.updateCredential(cred);
         return true;
     }
 
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 cdfdcab..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);
@@ -247,7 +247,7 @@ public class ModelExporter {
                 userEntity.setAttributes(userModel.getAttributes());
 
                 // roleIds
-                Set<RoleModel> roles = realm.getRoleMappings(userModel);
+                Set<RoleModel> roles = userModel.getRoleMappings();
                 List<String> roleIds = new ArrayList<String>();
                 for (RoleModel role : roles) {
                     roleIds.add(role.getId());
@@ -255,7 +255,7 @@ public class ModelExporter {
                 userEntity.setRoleIds(roleIds);
 
                 // credentials
-                List<UserCredentialValueModel> credentials = realm.getCredentialsDirectly(userModel);
+                List<UserCredentialValueModel> credentials = userModel.getCredentialsDirectly();
                 List<CredentialEntity> credEntities = new ArrayList<CredentialEntity>();
                 for (UserCredentialValueModel credModel : credentials) {
                     CredentialEntity credEntity = new CredentialEntity();
@@ -298,7 +298,7 @@ public class ModelExporter {
     }
 
     private List<String> getScopeIds(ClientModel clientModel) {
-        Set<RoleModel> allScopes = clientModel.getRealm().getScopeMappings(clientModel);
+        Set<RoleModel> allScopes = clientModel.getScopeMappings();
         List<String> scopeIds = new ArrayList<String>();
         for (RoleModel role : allScopes) {
             scopeIds.add(role.getId());
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 be78099..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
@@ -207,7 +207,7 @@ public class ModelImporter {
     private void addScopes(RealmModel realm, ClientModel client, ClientEntity clientEntity) {
         for (String scopeId : clientEntity.getScopeIds()) {
             RoleModel scope = realm.getRoleById(scopeId);
-            realm.addScopeMapping(client, scope);
+            client.addScopeMapping(scope);
         }
     }
 
@@ -246,8 +246,8 @@ public class ModelImporter {
             UserModel user = realm.addUser(userEntity.getId(), userEntity.getLoginName());
 
             // We need to remove defaultRoles here as realm.addUser is automatically adding them. We may add them later during roles mapping processing
-            for (RoleModel role : realm.getRoleMappings(user)) {
-                realm.deleteRoleMapping(user, role);
+            for (RoleModel role : user.getRoleMappings()) {
+                user.deleteRoleMapping(role);
             }
 
             this.propertiesManager.setBasicPropertiesToModel(user, userEntity);
@@ -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
@@ -291,7 +291,7 @@ public class ModelImporter {
             if (userEntity.getRoleIds() != null) {
                 for (String roleId : userEntity.getRoleIds()) {
                     RoleModel role = realm.getRoleById(roleId);
-                    realm.grantRole(user, role);
+                    user.grantRole(role);
                 }
             }
 
@@ -302,7 +302,7 @@ public class ModelImporter {
                     UserCredentialValueModel credModel = new UserCredentialValueModel();
                     this.propertiesManager.setBasicPropertiesToModel(credModel, credEntity);
 
-                    realm.updateCredentialDirectly(user, credModel);
+                    user.updateCredentialDirectly(credModel);
                 }
             }
         }
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/ApplicationModel.java b/model/api/src/main/java/org/keycloak/models/ApplicationModel.java
index ad583b3..2433fad 100755
--- a/model/api/src/main/java/org/keycloak/models/ApplicationModel.java
+++ b/model/api/src/main/java/org/keycloak/models/ApplicationModel.java
@@ -32,8 +32,6 @@ public interface ApplicationModel extends RoleContainerModel, ClientModel {
 
     void updateDefaultRoles(String[] defaultRoles);
 
-    Set<RoleModel> getApplicationRoleMappings(UserModel user);
-
     Set<RoleModel> getApplicationScopeMappings(ClientModel client);
 
     boolean isBearerOnly();
diff --git a/model/api/src/main/java/org/keycloak/models/ClientModel.java b/model/api/src/main/java/org/keycloak/models/ClientModel.java
index 3784f9e..321d014 100755
--- a/model/api/src/main/java/org/keycloak/models/ClientModel.java
+++ b/model/api/src/main/java/org/keycloak/models/ClientModel.java
@@ -57,6 +57,13 @@ public interface ClientModel {
     boolean isDirectGrantsOnly();
     void setDirectGrantsOnly(boolean flag);
 
+    Set<RoleModel> getScopeMappings();
+    void addScopeMapping(RoleModel role);
+    void deleteScopeMapping(RoleModel role);
+    Set<RoleModel> getRealmScopeMappings();
+    boolean hasScope(RoleModel role);
+
+
     RealmModel getRealm();
 
     /**
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 aa61bec..d0e4a34 100755
--- a/model/api/src/main/java/org/keycloak/models/KeycloakSession.java
+++ b/model/api/src/main/java/org/keycloak/models/KeycloakSession.java
@@ -3,21 +3,56 @@ package org.keycloak.models;
 import org.keycloak.provider.Provider;
 
 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 interface KeycloakSession extends Provider {
+    // Note: The reason there are so many query methods here is for layering a cache on top of an persistent KeycloakSession
+
     KeycloakTransaction getTransaction();
 
     RealmModel createRealm(String name);
     RealmModel createRealm(String id, String name);
     RealmModel getRealm(String id);
     RealmModel getRealmByName(String name);
+
+    UserModel getUserById(String id, RealmModel realm);
+    UserModel getUserByUsername(String username, RealmModel realm);
+    UserModel getUserByEmail(String email, RealmModel realm);
+    UserModel getUserBySocialLink(SocialLinkModel socialLink, RealmModel realm);
+    List<UserModel> getUsers(RealmModel realm);
+    List<UserModel> searchForUser(String search, RealmModel realm);
+    List<UserModel> searchForUserByAttributes(Map<String, String> attributes, RealmModel realm);
+
+    Set<SocialLinkModel> getSocialLinks(UserModel user, RealmModel realm);
+    SocialLinkModel getSocialLink(UserModel user, String socialProvider, RealmModel realm);
+
+
+    RoleModel getRoleById(String id, RealmModel realm);
+    ApplicationModel getApplicationById(String id, RealmModel realm);
+    OAuthClientModel getOAuthClientById(String id, RealmModel realm);
     List<RealmModel> getRealms();
     boolean removeRealm(String id);
 
+    UsernameLoginFailureModel getUserLoginFailure(String username, RealmModel realm);
+    UsernameLoginFailureModel addUserLoginFailure(String username, RealmModel realm);
+    List<UsernameLoginFailureModel> getAllUserLoginFailures(RealmModel realm);
+
+    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 c2ec9f3..f669968 100755
--- a/model/api/src/main/java/org/keycloak/models/RealmModel.java
+++ b/model/api/src/main/java/org/keycloak/models/RealmModel.java
@@ -10,7 +10,7 @@ import java.util.Set;
  * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
  * @version $Revision: 1 $
  */
-public interface RealmModel extends RoleContainerModel, RoleMapperModel, ScopeMapperModel {
+public interface RealmModel extends RoleContainerModel {
 
     String getId();
 
@@ -110,12 +110,6 @@ public interface RealmModel extends RoleContainerModel, RoleMapperModel, ScopeMa
 
     boolean validateTOTP(UserModel user, String password, String token);
 
-    void updateCredential(UserModel user, UserCredentialModel cred);
-
-    List<UserCredentialValueModel> getCredentialsDirectly(UserModel user);
-
-    void updateCredentialDirectly(UserModel user, UserCredentialValueModel cred);
-
     UserModel getUser(String name);
 
     UserModel getUserByEmail(String email);
@@ -163,10 +157,6 @@ public interface RealmModel extends RoleContainerModel, RoleMapperModel, ScopeMa
 
     boolean removeSocialLink(UserModel user, String socialProvider);
 
-    AuthenticationLinkModel getAuthenticationLink(UserModel user);
-
-    void setAuthenticationLink(UserModel user, AuthenticationLinkModel authenticationLink);
-
     boolean isSocial();
 
     void setSocial(boolean social);
@@ -211,10 +201,6 @@ public interface RealmModel extends RoleContainerModel, RoleMapperModel, ScopeMa
 
     void setAuthenticationProviders(List<AuthenticationProviderModel> authenticationProviders);
 
-    Set<RoleModel> getRealmRoleMappings(UserModel user);
-
-    Set<RoleModel> getRealmScopeMappings(ClientModel client);
-
     String getLoginTheme();
 
     void setLoginTheme(String name);
@@ -231,7 +217,6 @@ public interface RealmModel extends RoleContainerModel, RoleMapperModel, ScopeMa
 
     void setEmailTheme(String name);
 
-    boolean hasScope(ClientModel client, RoleModel role);
 
     /**
      * Time in seconds since epoc
diff --git a/model/api/src/main/java/org/keycloak/models/ScopeMapperModel.java b/model/api/src/main/java/org/keycloak/models/ScopeMapperModel.java
index 480943b..0bfd293 100755
--- a/model/api/src/main/java/org/keycloak/models/ScopeMapperModel.java
+++ b/model/api/src/main/java/org/keycloak/models/ScopeMapperModel.java
@@ -8,7 +8,5 @@ import java.util.Set;
  * @version $Revision: 1 $
  */
 public interface ScopeMapperModel {
-    Set<RoleModel> getScopeMappings(ClientModel client);
-    void addScopeMapping(ClientModel client, RoleModel role);
-    void deleteScopeMapping(ClientModel client, RoleModel role);
+
 }
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 b01cf93..3a7bd0b 100755
--- a/model/api/src/main/java/org/keycloak/models/UserModel.java
+++ b/model/api/src/main/java/org/keycloak/models/UserModel.java
@@ -1,5 +1,6 @@
 package org.keycloak.models;
 
+import java.util.List;
 import java.util.Map;
 import java.util.Set;
 
@@ -60,6 +61,28 @@ public interface UserModel {
     int getNotBefore();
     void setNotBefore(int notBefore);
 
+    void updateCredential(UserCredentialModel cred);
+
+    List<UserCredentialValueModel> getCredentialsDirectly();
+
+    void updateCredentialDirectly(UserCredentialValueModel cred);
+
+    AuthenticationLinkModel getAuthenticationLink();
+
+    void setAuthenticationLink(AuthenticationLinkModel authenticationLink);
+
+
+
+    Set<RoleModel> getRealmRoleMappings();
+    Set<RoleModel> getApplicationRoleMappings(ApplicationModel app);
+    boolean hasRole(RoleModel role);
+    void grantRole(RoleModel role);
+    Set<RoleModel> getRoleMappings();
+    void deleteRoleMapping(RoleModel role);
+
+
+
+
 
     public static enum RequiredAction {
         VERIFY_EMAIL, UPDATE_PROFILE, CONFIGURE_TOTP, UPDATE_PASSWORD
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
new file mode 100755
index 0000000..9aec5d4
--- /dev/null
+++ b/model/invalidation-cache/model-adapters/src/main/java/org/keycloak/models/cache/CacheKeycloakSession.java
@@ -0,0 +1,291 @@
+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;
+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;
+
+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 CacheKeycloakSession implements KeycloakSession {
+    protected KeycloakCache cache;
+    protected ProviderSession providerSession;
+    protected KeycloakSession sessionDelegate;
+    protected KeycloakTransaction transactionDelegate;
+    protected boolean transactionActive;
+    protected boolean setRollbackOnly;
+
+    protected Set<String> realmInvalidations = new HashSet<String>();
+    protected boolean clearAll;
+
+    protected KeycloakSession getDelegate() {
+        if (!transactionActive) throw new IllegalStateException("Cannot access delegate without a transaction");
+        if (sessionDelegate != null) return sessionDelegate;
+        sessionDelegate = providerSession.getProvider(KeycloakSession.class);
+        transactionDelegate = sessionDelegate.getTransaction();
+        if (!transactionDelegate.isActive()) {
+            transactionDelegate.begin();
+            if (setRollbackOnly) {
+                transactionDelegate.setRollbackOnly();
+            }
+        }
+        return sessionDelegate;
+    }
+
+    public void registerInvalidation(RealmAdapter realm) {
+        realmInvalidations.add(realm.getId());
+    }
+
+    public void runInvalidations() {
+        for (String id : realmInvalidations) {
+            cache.invalidateCachedRealmById(id);
+        }
+
+    }
+
+    @Override
+    public KeycloakTransaction getTransaction() {
+        return new KeycloakTransaction() {
+            @Override
+            public void begin() {
+                transactionActive = true;
+            }
+
+            @Override
+            public void commit() {
+                if (sessionDelegate == null) return;
+                try {
+                    sessionDelegate.getTransaction().commit();
+                } finally {
+                    runInvalidations();
+                }
+            }
+
+            @Override
+            public void rollback() {
+                setRollbackOnly = true;
+                if (sessionDelegate == null) return;
+                try {
+                    sessionDelegate.getTransaction().commit();
+                } finally {
+                    runInvalidations();
+                }
+            }
+
+            @Override
+            public void setRollbackOnly() {
+                setRollbackOnly = true;
+                if (sessionDelegate == null) return;
+                sessionDelegate.getTransaction().setRollbackOnly();
+                setRollbackOnly = true;
+            }
+
+            @Override
+            public boolean getRollbackOnly() {
+                return setRollbackOnly;
+            }
+
+            @Override
+            public boolean isActive() {
+                return transactionActive;
+            }
+        };
+    }
+
+    @Override
+    public RealmModel createRealm(String name) {
+        return getDelegate().createRealm(name);
+    }
+
+    @Override
+    public RealmModel createRealm(String id, String name) {
+        return getDelegate().createRealm(id, name);
+    }
+
+    @Override
+    public RealmModel getRealm(String id) {
+        CachedRealm cached = cache.getCachedRealm(id);
+        if (cached == null) {
+            RealmModel model = getDelegate().getRealm(id);
+            if (model == null) return null;
+            cached = new CachedRealm(cache, this, model);
+        }
+        return new RealmAdapter(cached, this);
+    }
+
+    @Override
+    public RealmModel getRealmByName(String name) {
+        CachedRealm cached = cache.getCachedRealmByName(name);
+        if (cached == null) {
+            RealmModel model = getDelegate().getRealmByName(name);
+            if (model == null) return null;
+            cached = new CachedRealm(cache, this, model);
+        }
+        return new RealmAdapter(cached, this);
+    }
+
+    @Override
+    public UserModel getUserById(String id, RealmModel realm) {
+        return null;  //To change body of implemented methods use File | Settings | File Templates.
+    }
+
+    @Override
+    public UserModel getUserByUsername(String username, RealmModel realm) {
+        return null;  //To change body of implemented methods use File | Settings | File Templates.
+    }
+
+    @Override
+    public UserModel getUserByEmail(String email, RealmModel realm) {
+        return null;  //To change body of implemented methods use File | Settings | File Templates.
+    }
+
+    @Override
+    public List<RealmModel> getRealms() {
+        // we don't cache this for now
+        return getDelegate().getRealms();
+    }
+
+    @Override
+    public boolean removeRealm(String id) {
+        cache.invalidateCachedRealmById(id);
+        boolean didIt = getDelegate().removeRealm(id);
+        realmInvalidations.add(id);
+
+        return didIt;
+    }
+
+    @Override
+    public void removeAllData() {
+        cache.clear();
+        getDelegate().removeAllData();
+        clearAll = true;
+    }
+
+    @Override
+    public void close() {
+        if (sessionDelegate != null) sessionDelegate.close();
+    }
+
+    @Override
+    public UserModel getUserBySocialLink(SocialLinkModel socialLink, RealmModel realm) {
+        return null;  //To change body of implemented methods use File | Settings | File Templates.
+    }
+
+    @Override
+    public List<UserModel> getUsers(RealmModel realm) {
+        return null;  //To change body of implemented methods use File | Settings | File Templates.
+    }
+
+    @Override
+    public List<UserModel> searchForUser(String search, RealmModel realm) {
+        return null;  //To change body of implemented methods use File | Settings | File Templates.
+    }
+
+    @Override
+    public List<UserModel> searchForUserByAttributes(Map<String, String> attributes, RealmModel realm) {
+        return null;  //To change body of implemented methods use File | Settings | File Templates.
+    }
+
+    @Override
+    public Set<SocialLinkModel> getSocialLinks(UserModel user, RealmModel realm) {
+        return null;  //To change body of implemented methods use File | Settings | File Templates.
+    }
+
+    @Override
+    public SocialLinkModel getSocialLink(UserModel user, String socialProvider, RealmModel realm) {
+        return null;  //To change body of implemented methods use File | Settings | File Templates.
+    }
+
+    @Override
+    public RoleModel getRoleById(String id, RealmModel realm) {
+        return null;  //To change body of implemented methods use File | Settings | File Templates.
+    }
+
+    @Override
+    public ApplicationModel getApplicationById(String id, RealmModel realm) {
+        return null;  //To change body of implemented methods use File | Settings | File Templates.
+    }
+
+    @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) {
+        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(RealmModel realm) {
+        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/CachedApplication.java b/model/invalidation-cache/model-adapters/src/main/java/org/keycloak/models/cache/entities/CachedApplication.java
new file mode 100755
index 0000000..6aab1ac
--- /dev/null
+++ b/model/invalidation-cache/model-adapters/src/main/java/org/keycloak/models/cache/entities/CachedApplication.java
@@ -0,0 +1,70 @@
+package org.keycloak.models.cache.entities;
+
+import org.keycloak.models.ApplicationModel;
+import org.keycloak.models.ClientModel;
+import org.keycloak.models.KeycloakSession;
+import org.keycloak.models.RealmModel;
+import org.keycloak.models.RoleModel;
+import org.keycloak.models.UserModel;
+import org.keycloak.models.UserSessionModel;
+import org.keycloak.models.cache.KeycloakCache;
+
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.LinkedList;
+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 CachedApplication extends CachedClient {
+    private boolean surrogateAuthRequired;
+    private String managementUrl;
+    private String baseUrl;
+    private List<String> defaultRoles = new LinkedList<String>();
+    private boolean bearerOnly;
+    private Map<String, String> roles = new HashMap<String, String>();
+
+    public CachedApplication(KeycloakCache cache, KeycloakSession delegate, RealmModel realm, ApplicationModel model) {
+        super(cache, delegate, realm, model);
+        surrogateAuthRequired = model.isSurrogateAuthRequired();
+        managementUrl = model.getManagementUrl();
+        baseUrl = model.getBaseUrl();
+        defaultRoles.addAll(model.getDefaultRoles());
+        bearerOnly = model.isBearerOnly();
+        for (RoleModel role : model.getRoles()) {
+            roles.put(role.getName(), role.getId());
+            cache.addCachedRole(new CachedApplicationRole(id, role));
+        }
+
+
+    }
+
+    public boolean isSurrogateAuthRequired() {
+        return surrogateAuthRequired;
+    }
+
+    public String getManagementUrl() {
+        return managementUrl;
+    }
+
+    public String getBaseUrl() {
+        return baseUrl;
+    }
+
+    public List<String> getDefaultRoles() {
+        return defaultRoles;
+    }
+
+    public boolean isBearerOnly() {
+        return bearerOnly;
+    }
+
+    public Map<String, String> getRoles() {
+        return roles;
+    }
+
+}
diff --git a/model/invalidation-cache/model-adapters/src/main/java/org/keycloak/models/cache/entities/CachedApplicationRole.java b/model/invalidation-cache/model-adapters/src/main/java/org/keycloak/models/cache/entities/CachedApplicationRole.java
new file mode 100755
index 0000000..269fba9
--- /dev/null
+++ b/model/invalidation-cache/model-adapters/src/main/java/org/keycloak/models/cache/entities/CachedApplicationRole.java
@@ -0,0 +1,21 @@
+package org.keycloak.models.cache.entities;
+
+import org.keycloak.models.RoleModel;
+
+/**
+ * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
+ * @version $Revision: 1 $
+ */
+public class CachedApplicationRole extends CachedRole {
+    private final String appId;
+
+    public CachedApplicationRole(String appId, RoleModel model) {
+        super(model);
+        this.appId = appId;
+
+    }
+
+    public String getAppId() {
+        return appId;
+    }
+}
diff --git a/model/invalidation-cache/model-adapters/src/main/java/org/keycloak/models/cache/entities/CachedClient.java b/model/invalidation-cache/model-adapters/src/main/java/org/keycloak/models/cache/entities/CachedClient.java
new file mode 100755
index 0000000..db22668
--- /dev/null
+++ b/model/invalidation-cache/model-adapters/src/main/java/org/keycloak/models/cache/entities/CachedClient.java
@@ -0,0 +1,90 @@
+package org.keycloak.models.cache.entities;
+
+import org.keycloak.models.ApplicationModel;
+import org.keycloak.models.ClientModel;
+import org.keycloak.models.KeycloakSession;
+import org.keycloak.models.RealmModel;
+import org.keycloak.models.RoleModel;
+import org.keycloak.models.cache.KeycloakCache;
+
+import java.util.HashSet;
+import java.util.Set;
+
+/**
+ * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
+ * @version $Revision: 1 $
+ */
+public class CachedClient {
+    protected String id;
+    protected String name;
+    protected long allowedClaimsMask;
+    protected Set<String> redirectUris = new HashSet<String>();
+    protected boolean enabled;
+    protected String secret;
+    protected boolean publicClient;
+    protected boolean directGrantsOnly;
+    protected int notBefore;
+    protected Set<String> scope = new HashSet<String>();
+    protected Set<String> webOrigins = new HashSet<String>();
+
+    public CachedClient(KeycloakCache cache, KeycloakSession delegate, RealmModel realm, ClientModel model) {
+        id = model.getId();
+        secret = model.getSecret();
+        name = model.getClientId();
+        enabled = model.isEnabled();
+        notBefore = model.getNotBefore();
+        directGrantsOnly = model.isDirectGrantsOnly();
+        publicClient = model.isPublicClient();
+        allowedClaimsMask = model.getAllowedClaimsMask();
+        redirectUris.addAll(model.getRedirectUris());
+        webOrigins.addAll(model.getWebOrigins());
+        for (RoleModel role : model.getScopeMappings())  {
+            scope.add(role.getId());
+        }
+
+    }
+
+    public String getId() {
+        return id;
+    }
+
+    public String getName() {
+        return name;
+    }
+
+    public long getAllowedClaimsMask() {
+        return allowedClaimsMask;
+    }
+
+    public Set<String> getRedirectUris() {
+        return redirectUris;
+    }
+
+    public boolean isEnabled() {
+        return enabled;
+    }
+
+    public String getSecret() {
+        return secret;
+    }
+
+    public boolean isPublicClient() {
+        return publicClient;
+    }
+
+    public boolean isDirectGrantsOnly() {
+        return directGrantsOnly;
+    }
+
+    public int getNotBefore() {
+        return notBefore;
+    }
+
+    public Set<String> getScope() {
+        return scope;
+    }
+
+    public Set<String> getWebOrigins() {
+        return webOrigins;
+    }
+}
diff --git a/model/invalidation-cache/model-adapters/src/main/java/org/keycloak/models/cache/entities/CachedOAuthClient.java b/model/invalidation-cache/model-adapters/src/main/java/org/keycloak/models/cache/entities/CachedOAuthClient.java
new file mode 100755
index 0000000..c708bd4
--- /dev/null
+++ b/model/invalidation-cache/model-adapters/src/main/java/org/keycloak/models/cache/entities/CachedOAuthClient.java
@@ -0,0 +1,17 @@
+package org.keycloak.models.cache.entities;
+
+import org.keycloak.models.KeycloakSession;
+import org.keycloak.models.OAuthClientModel;
+import org.keycloak.models.RealmModel;
+import org.keycloak.models.cache.KeycloakCache;
+
+/**
+ * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
+ * @version $Revision: 1 $
+ */
+public class CachedOAuthClient extends CachedClient {
+    public CachedOAuthClient(KeycloakCache cache, KeycloakSession delegate, RealmModel realm, OAuthClientModel model) {
+        super(cache, delegate, realm, model);
+
+    }
+}
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
new file mode 100755
index 0000000..cd748eb
--- /dev/null
+++ b/model/invalidation-cache/model-adapters/src/main/java/org/keycloak/models/cache/entities/CachedRealm.java
@@ -0,0 +1,340 @@
+package org.keycloak.models.cache.entities;
+
+import org.keycloak.models.ApplicationModel;
+import org.keycloak.models.AuthenticationProviderModel;
+import org.keycloak.models.KeycloakSession;
+import org.keycloak.models.OAuthClientModel;
+import org.keycloak.models.PasswordPolicy;
+import org.keycloak.models.RealmModel;
+import org.keycloak.models.RequiredCredentialModel;
+import org.keycloak.models.RoleModel;
+import org.keycloak.models.cache.KeycloakCache;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.LinkedList;
+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 CachedRealm {
+
+    private String id;
+    private String name;
+    private boolean enabled;
+    private boolean sslNotRequired;
+    private boolean registrationAllowed;
+    private boolean rememberMe;
+    private boolean verifyEmail;
+    private boolean passwordCredentialGrantAllowed;
+    private boolean resetPasswordAllowed;
+    private boolean social;
+    private boolean updateProfileOnInitialSocialLogin;
+    //--- brute force settings
+    private boolean bruteForceProtected;
+    private int maxFailureWaitSeconds;
+    private int minimumQuickLoginWaitSeconds;
+    private int waitIncrementSeconds;
+    private long quickLoginCheckMilliSeconds;
+    private int maxDeltaTimeSeconds;
+    private int failureFactor;
+    //--- end brute force settings
+
+    private int ssoSessionIdleTimeout;
+    private int ssoSessionMaxLifespan;
+    private int accessTokenLifespan;
+    private int accessCodeLifespan;
+    private int accessCodeLifespanUserAction;
+    private int notBefore;
+    private PasswordPolicy passwordPolicy;
+
+    private String publicKeyPem;
+    private String privateKeyPem;
+
+    private String loginTheme;
+    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>();
+
+    private Map<String, String> smtpConfig = new HashMap<String, String>();
+    private Map<String, String> socialConfig = new HashMap<String, String>();
+    private Map<String, String> ldapServerConfig = new HashMap<String, String>();
+
+    private boolean auditEnabled;
+    private long auditExpiration;
+    private Set<String> auditListeners = new HashSet<String>();
+    private List<String> defaultRoles = new LinkedList<String>();
+    private Map<String, String> realmRoles = new HashMap<String, String>();
+    private Set<String> rolesById = new HashSet<String>();
+    private Map<String, String> applications = new HashMap<String, String>();
+    private Map<String, String> clients = new HashMap<String, String>();
+
+    public CachedRealm() {
+    }
+
+    public CachedRealm(KeycloakCache cache, KeycloakSession delegate, RealmModel model) {
+        id = model.getId();
+        name = model.getName();
+        enabled = model.isEnabled();
+        sslNotRequired = model.isSslNotRequired();
+        registrationAllowed = model.isRegistrationAllowed();
+        rememberMe = model.isRememberMe();
+        verifyEmail = model.isVerifyEmail();
+        passwordCredentialGrantAllowed = model.isPasswordCredentialGrantAllowed();
+        resetPasswordAllowed = model.isResetPasswordAllowed();
+        social = model.isSocial();
+        updateProfileOnInitialSocialLogin = model.isUpdateProfileOnInitialSocialLogin();
+        //--- brute force settings
+        bruteForceProtected = model.isBruteForceProtected();
+        maxFailureWaitSeconds = model.getMaxFailureWaitSeconds();
+        minimumQuickLoginWaitSeconds = model.getMinimumQuickLoginWaitSeconds();
+        waitIncrementSeconds = model.getWaitIncrementSeconds();
+        quickLoginCheckMilliSeconds = model.getQuickLoginCheckMilliSeconds();
+        maxDeltaTimeSeconds = model.getMaxDeltaTimeSeconds();
+        failureFactor = model.getFailureFactor();
+        //--- end brute force settings
+
+        ssoSessionIdleTimeout = model.getSsoSessionIdleTimeout();
+        ssoSessionMaxLifespan = model.getSsoSessionMaxLifespan();
+        accessTokenLifespan = model.getAccessTokenLifespan();
+        accessCodeLifespan = model.getAccessCodeLifespan();
+        accessCodeLifespanUserAction = model.getAccessCodeLifespanUserAction();
+        notBefore = model.getNotBefore();
+        passwordPolicy = model.getPasswordPolicy();
+
+        publicKeyPem = model.getPublicKeyPem();
+        privateKeyPem = model.getPrivateKeyPem();
+
+        loginTheme = model.getLoginTheme();
+        accountTheme = model.getAccountTheme();
+        adminTheme = model.getAdminTheme();
+        emailTheme = model.getEmailTheme();
+
+        requiredCredentials = model.getRequiredCredentials();
+        authenticationProviders = model.getAuthenticationProviders();
+
+        smtpConfig.putAll(model.getSmtpConfig());
+        socialConfig.putAll(model.getSocialConfig());
+        ldapServerConfig.putAll(model.getLdapServerConfig());
+
+        auditEnabled = model.isAuditEnabled();
+        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());
+            rolesById.add(role.getId());
+            CachedRole cachedRole = new CachedRealmRole(role);
+            cache.addCachedRole(cachedRole);
+        }
+
+        for (ApplicationModel app : model.getApplications()) {
+            applications.put(app.getName(), app.getId());
+            CachedApplication cachedApp = new CachedApplication(cache, delegate, model, app);
+            cache.addCachedApplication(cachedApp);
+            for (String roleId : cachedApp.getRoles().values()) {
+                rolesById.add(roleId);
+            }
+        }
+
+        for (OAuthClientModel client : model.getOAuthClients()) {
+            clients.put(client.getClientId(), client.getId());
+            CachedOAuthClient cachedApp = new CachedOAuthClient(cache, delegate, model, client);
+            cache.addCachedOAuthClient(cachedApp);
+        }
+
+    }
+
+
+    public String getId() {
+        return id;
+    }
+
+    public String getMasterAdminApp() {
+        return masterAdminApp;
+    }
+
+    public String getName() {
+        return name;
+    }
+
+    public List<String> getDefaultRoles() {
+        return defaultRoles;
+    }
+
+    public Map<String, String> getRealmRoles() {
+        return realmRoles;
+    }
+
+    public Set<String> getRolesById() {
+        return rolesById;
+    }
+
+    public Map<String, String> getApplications() {
+        return applications;
+    }
+
+    public Map<String, String> getClients() {
+        return clients;
+    }
+
+    public boolean isEnabled() {
+        return enabled;
+    }
+
+    public boolean isSslNotRequired() {
+        return sslNotRequired;
+    }
+
+    public boolean isRegistrationAllowed() {
+        return registrationAllowed;
+    }
+
+    public boolean isPasswordCredentialGrantAllowed() {
+        return passwordCredentialGrantAllowed;
+    }
+
+    public boolean isRememberMe() {
+        return this.rememberMe;
+    }
+
+    public boolean isBruteForceProtected() {
+        return bruteForceProtected;
+    }
+
+    public int getMaxFailureWaitSeconds() {
+        return this.maxFailureWaitSeconds;
+    }
+
+    public int getWaitIncrementSeconds() {
+        return this.waitIncrementSeconds;
+    }
+
+    public int getMinimumQuickLoginWaitSeconds() {
+        return this.minimumQuickLoginWaitSeconds;
+    }
+
+    public long getQuickLoginCheckMilliSeconds() {
+        return quickLoginCheckMilliSeconds;
+    }
+
+    public int getMaxDeltaTimeSeconds() {
+        return maxDeltaTimeSeconds;
+    }
+
+    public int getFailureFactor() {
+        return failureFactor;
+    }
+
+    public boolean isVerifyEmail() {
+        return verifyEmail;
+    }
+
+    public boolean isResetPasswordAllowed() {
+        return resetPasswordAllowed;
+    }
+
+    public int getSsoSessionIdleTimeout() {
+        return ssoSessionIdleTimeout;
+    }
+
+    public int getSsoSessionMaxLifespan() {
+        return ssoSessionMaxLifespan;
+    }
+
+    public int getAccessTokenLifespan() {
+        return accessTokenLifespan;
+    }
+
+    public int getAccessCodeLifespan() {
+        return accessCodeLifespan;
+    }
+
+    public int getAccessCodeLifespanUserAction() {
+        return accessCodeLifespanUserAction;
+    }
+
+    public String getPublicKeyPem() {
+        return publicKeyPem;
+    }
+
+    public String getPrivateKeyPem() {
+        return privateKeyPem;
+    }
+
+    public List<RequiredCredentialModel> getRequiredCredentials() {
+        return requiredCredentials;
+    }
+
+    public PasswordPolicy getPasswordPolicy() {
+        return passwordPolicy;
+    }
+
+    public boolean isSocial() {
+        return social;
+    }
+
+    public boolean isUpdateProfileOnInitialSocialLogin() {
+        return updateProfileOnInitialSocialLogin;
+    }
+
+    public Map<String, String> getSmtpConfig() {
+        return smtpConfig;
+    }
+
+    public Map<String, String> getSocialConfig() {
+        return socialConfig;
+    }
+
+    public Map<String, String> getLdapServerConfig() {
+        return ldapServerConfig;
+    }
+
+    public List<AuthenticationProviderModel> getAuthenticationProviders() {
+        return authenticationProviders;
+    }
+
+    public String getLoginTheme() {
+        return loginTheme;
+    }
+
+    public String getAccountTheme() {
+        return accountTheme;
+    }
+
+    public String getAdminTheme() {
+        return this.adminTheme;
+    }
+
+    public String getEmailTheme() {
+        return emailTheme;
+    }
+
+    public int getNotBefore() {
+        return notBefore;
+    }
+
+    public boolean isAuditEnabled() {
+        return auditEnabled;
+    }
+
+    public long getAuditExpiration() {
+        return auditExpiration;
+    }
+
+    public Set<String> getAuditListeners() {
+        return auditListeners;
+    }
+
+}
diff --git a/model/invalidation-cache/model-adapters/src/main/java/org/keycloak/models/cache/entities/CachedRealmRole.java b/model/invalidation-cache/model-adapters/src/main/java/org/keycloak/models/cache/entities/CachedRealmRole.java
new file mode 100755
index 0000000..b6f6668
--- /dev/null
+++ b/model/invalidation-cache/model-adapters/src/main/java/org/keycloak/models/cache/entities/CachedRealmRole.java
@@ -0,0 +1,20 @@
+package org.keycloak.models.cache.entities;
+
+import org.keycloak.models.RoleModel;
+
+import java.util.HashSet;
+import java.util.Set;
+
+/**
+ * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
+ * @version $Revision: 1 $
+ */
+public class CachedRealmRole extends CachedRole {
+
+
+    public CachedRealmRole(RoleModel model) {
+        super(model);
+
+    }
+
+}
diff --git a/model/invalidation-cache/model-adapters/src/main/java/org/keycloak/models/cache/entities/CachedRole.java b/model/invalidation-cache/model-adapters/src/main/java/org/keycloak/models/cache/entities/CachedRole.java
new file mode 100755
index 0000000..ed451e2
--- /dev/null
+++ b/model/invalidation-cache/model-adapters/src/main/java/org/keycloak/models/cache/entities/CachedRole.java
@@ -0,0 +1,51 @@
+package org.keycloak.models.cache.entities;
+
+import org.keycloak.models.RoleModel;
+
+import java.util.HashSet;
+import java.util.Set;
+
+/**
+ * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
+ * @version $Revision: 1 $
+ */
+public class CachedRole {
+    final protected String id;
+    final protected String name;
+    final protected String description;
+    final protected boolean composite;
+    final protected Set<String> composites = new HashSet<String>();
+
+    public CachedRole(RoleModel model) {
+        composite = model.isComposite();
+        description = model.getDescription();
+        id = model.getId();
+        name = model.getName();
+        if (composite) {
+            for (RoleModel child : model.getComposites()) {
+                composites.add(child.getId());
+            }
+        }
+
+    }
+
+    public String getId() {
+        return id;
+    }
+
+    public String getName() {
+        return name;
+    }
+
+    public String getDescription() {
+        return description;
+    }
+
+    public boolean isComposite() {
+        return composite;
+    }
+
+    public Set<String> getComposites() {
+        return composites;
+    }
+}
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
new file mode 100755
index 0000000..52d7094
--- /dev/null
+++ b/model/invalidation-cache/model-adapters/src/main/java/org/keycloak/models/cache/KeycloakCache.java
@@ -0,0 +1,50 @@
+package org.keycloak.models.cache;
+
+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;
+
+/**
+ * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
+ * @version $Revision: 1 $
+ */
+public interface KeycloakCache {
+    void clear();
+
+    CachedRealm getCachedRealm(String id);
+
+    void invalidateCachedRealm(CachedRealm realm);
+
+    void addCachedRealm(CachedRealm realm);
+
+    CachedRealm getCachedRealmByName(String name);
+
+    void invalidateCachedRealmById(String id);
+
+    CachedApplication getApplication(String id);
+
+    void invalidateApplication(CachedApplication app);
+
+    void addCachedApplication(CachedApplication app);
+
+    void invalidateCachedApplicationById(String id);
+
+    CachedOAuthClient getOAuthClient(String id);
+
+    void invalidateOAuthClient(CachedOAuthClient client);
+
+    void addCachedOAuthClient(CachedOAuthClient client);
+
+    void invalidateCachedOAuthClientById(String id);
+
+    CachedRole getRole(String id);
+
+    void invalidateRole(CachedRole role);
+
+    void addCachedRole(CachedRole role);
+
+    void invalidateCachedRoleById(String id);
+
+
+}
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
new file mode 100755
index 0000000..0440f6d
--- /dev/null
+++ b/model/invalidation-cache/model-adapters/src/main/java/org/keycloak/models/cache/RealmAdapter.java
@@ -0,0 +1,971 @@
+package org.keycloak.models.cache;
+
+import org.keycloak.models.ApplicationModel;
+import org.keycloak.models.AuthenticationLinkModel;
+import org.keycloak.models.AuthenticationProviderModel;
+import org.keycloak.models.ClientModel;
+import org.keycloak.models.OAuthClientModel;
+import org.keycloak.models.PasswordPolicy;
+import org.keycloak.models.RealmModel;
+import org.keycloak.models.RequiredCredentialModel;
+import org.keycloak.models.RoleModel;
+import org.keycloak.models.SocialLinkModel;
+import org.keycloak.models.UserCredentialModel;
+import org.keycloak.models.UserCredentialValueModel;
+import org.keycloak.models.UserModel;
+import org.keycloak.models.UserSessionModel;
+import org.keycloak.models.UsernameLoginFailureModel;
+import org.keycloak.models.cache.entities.CachedApplicationRole;
+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.utils.KeycloakModelUtils;
+import org.keycloak.models.utils.Pbkdf2PasswordEncoder;
+import org.keycloak.models.utils.TimeBasedOTP;
+
+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;
+import java.util.Set;
+
+/**
+ * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
+ * @version $Revision: 1 $
+ */
+public class RealmAdapter implements RealmModel {
+    protected CachedRealm cached;
+    protected CacheKeycloakSession cacheSession;
+    protected RealmModel updated;
+    protected KeycloakCache cache;
+    protected volatile transient PublicKey publicKey;
+    protected volatile transient PrivateKey privateKey;
+
+    public RealmAdapter(CachedRealm cached, CacheKeycloakSession cacheSession) {
+        this.cached = cached;
+        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();
+        return cached.getId();
+    }
+
+    @Override
+    public String getName() {
+        if (updated != null) return updated.getName();
+        return cached.getName();
+    }
+
+    @Override
+    public void setName(String name) {
+        getDelegateForUpdate();
+        updated.setName(name);
+    }
+
+    @Override
+    public boolean isEnabled() {
+        if (updated != null) return updated.isEnabled();
+        return cached.isEnabled();
+    }
+
+    @Override
+    public void setEnabled(boolean enabled) {
+        getDelegateForUpdate();
+        updated.setEnabled(enabled);
+    }
+
+    @Override
+    public boolean isSslNotRequired() {
+        if (updated != null) return updated.isSslNotRequired();
+        return cached.isSslNotRequired();
+    }
+
+    @Override
+    public void setSslNotRequired(boolean sslNotRequired) {
+        getDelegateForUpdate();
+        updated.setSslNotRequired(sslNotRequired);
+    }
+
+    @Override
+    public boolean isRegistrationAllowed() {
+        if (updated != null) return updated.isRegistrationAllowed();
+        return cached.isRegistrationAllowed();
+    }
+
+    @Override
+    public void setRegistrationAllowed(boolean registrationAllowed) {
+        getDelegateForUpdate();
+        updated.setRegistrationAllowed(registrationAllowed);
+    }
+
+    @Override
+    public boolean isPasswordCredentialGrantAllowed() {
+        if (updated != null) return updated.isPasswordCredentialGrantAllowed();
+        return cached.isPasswordCredentialGrantAllowed();
+    }
+
+    @Override
+    public void setPasswordCredentialGrantAllowed(boolean passwordCredentialGrantAllowed) {
+        getDelegateForUpdate();
+        updated.setPasswordCredentialGrantAllowed(passwordCredentialGrantAllowed);
+    }
+
+    @Override
+    public boolean isRememberMe() {
+        if (updated != null) return updated.isRememberMe();
+        return cached.isRememberMe();
+    }
+
+    @Override
+    public void setRememberMe(boolean rememberMe) {
+        getDelegateForUpdate();
+        updated.setRememberMe(rememberMe);
+    }
+
+    @Override
+    public boolean isBruteForceProtected() {
+        if (updated != null) return updated.isBruteForceProtected();
+        return cached.isBruteForceProtected();
+    }
+
+    @Override
+    public void setBruteForceProtected(boolean value) {
+        getDelegateForUpdate();
+        updated.setBruteForceProtected(value);
+    }
+
+    @Override
+    public int getMaxFailureWaitSeconds() {
+        if (updated != null) return updated.getMaxFailureWaitSeconds();
+        return cached.getMaxFailureWaitSeconds();
+    }
+
+    @Override
+    public void setMaxFailureWaitSeconds(int val) {
+        getDelegateForUpdate();
+        updated.setMaxFailureWaitSeconds(val);
+    }
+
+    @Override
+    public int getWaitIncrementSeconds() {
+        if (updated != null) return updated.getWaitIncrementSeconds();
+        return cached.getWaitIncrementSeconds();
+    }
+
+    @Override
+    public void setWaitIncrementSeconds(int val) {
+        getDelegateForUpdate();
+        updated.setWaitIncrementSeconds(val);
+    }
+
+    @Override
+    public int getMinimumQuickLoginWaitSeconds() {
+        if (updated != null) return updated.getMinimumQuickLoginWaitSeconds();
+        return cached.getMinimumQuickLoginWaitSeconds();
+    }
+
+    @Override
+    public void setMinimumQuickLoginWaitSeconds(int val) {
+        getDelegateForUpdate();
+        updated.setMinimumQuickLoginWaitSeconds(val);
+    }
+
+    @Override
+    public long getQuickLoginCheckMilliSeconds() {
+        if (updated != null) return updated.getQuickLoginCheckMilliSeconds();
+        return cached.getQuickLoginCheckMilliSeconds();
+    }
+
+    @Override
+    public void setQuickLoginCheckMilliSeconds(long val) {
+        getDelegateForUpdate();
+        updated.setQuickLoginCheckMilliSeconds(val);
+    }
+
+    @Override
+    public int getMaxDeltaTimeSeconds() {
+        if (updated != null) return updated.getMaxDeltaTimeSeconds();
+        return cached.getMaxDeltaTimeSeconds();
+    }
+
+    @Override
+    public void setMaxDeltaTimeSeconds(int val) {
+        getDelegateForUpdate();
+        updated.setMaxDeltaTimeSeconds(val);
+    }
+
+    @Override
+    public int getFailureFactor() {
+        if (updated != null) return updated.getFailureFactor();
+        return cached.getFailureFactor();
+    }
+
+    @Override
+    public void setFailureFactor(int failureFactor) {
+        getDelegateForUpdate();
+        updated.setFailureFactor(failureFactor);
+    }
+
+    @Override
+    public boolean isVerifyEmail() {
+        if (updated != null) return updated.isVerifyEmail();
+        return cached.isVerifyEmail();
+    }
+
+    @Override
+    public void setVerifyEmail(boolean verifyEmail) {
+        getDelegateForUpdate();
+        updated.setVerifyEmail(verifyEmail);
+    }
+
+    @Override
+    public boolean isResetPasswordAllowed() {
+        if (updated != null) return updated.isResetPasswordAllowed();
+        return cached.isResetPasswordAllowed();
+    }
+
+    @Override
+    public void setResetPasswordAllowed(boolean resetPasswordAllowed) {
+        getDelegateForUpdate();
+        updated.setResetPasswordAllowed(resetPasswordAllowed);
+    }
+
+    @Override
+    public int getSsoSessionIdleTimeout() {
+        if (updated != null) return updated.getSsoSessionIdleTimeout();
+        return cached.getSsoSessionIdleTimeout();
+    }
+
+    @Override
+    public void setSsoSessionIdleTimeout(int seconds) {
+        getDelegateForUpdate();
+        updated.setSsoSessionIdleTimeout(seconds);
+    }
+
+    @Override
+    public int getSsoSessionMaxLifespan() {
+        if (updated != null) return updated.getSsoSessionMaxLifespan();
+        return cached.getSsoSessionMaxLifespan();
+    }
+
+    @Override
+    public void setSsoSessionMaxLifespan(int seconds) {
+        getDelegateForUpdate();
+        updated.setSsoSessionMaxLifespan(seconds);
+    }
+
+    @Override
+    public int getAccessTokenLifespan() {
+        if (updated != null) return updated.getAccessTokenLifespan();
+        return cached.getAccessTokenLifespan();
+    }
+
+    @Override
+    public void setAccessTokenLifespan(int seconds) {
+        getDelegateForUpdate();
+        updated.setAccessTokenLifespan(seconds);
+    }
+
+    @Override
+    public int getAccessCodeLifespan() {
+        if (updated != null) return updated.getAccessCodeLifespan();
+        return cached.getAccessCodeLifespan();
+    }
+
+    @Override
+    public void setAccessCodeLifespan(int seconds) {
+        getDelegateForUpdate();
+        updated.setAccessCodeLifespan(seconds);
+    }
+
+    @Override
+    public int getAccessCodeLifespanUserAction() {
+        if (updated != null) return updated.getAccessCodeLifespanUserAction();
+        return cached.getAccessCodeLifespanUserAction();
+    }
+
+    @Override
+    public void setAccessCodeLifespanUserAction(int seconds) {
+        getDelegateForUpdate();
+        updated.setAccessCodeLifespanUserAction(seconds);
+    }
+
+    @Override
+    public String getPublicKeyPem() {
+        if (updated != null) return updated.getPublicKeyPem();
+        return cached.getPublicKeyPem();
+    }
+
+    @Override
+    public void setPublicKeyPem(String publicKeyPem) {
+        getDelegateForUpdate();
+        updated.setPublicKeyPem(publicKeyPem);
+    }
+
+    @Override
+    public String getPrivateKeyPem() {
+        if (updated != null) return updated.getPrivateKeyPem();
+        return cached.getPrivateKeyPem();
+    }
+
+    @Override
+    public void setPrivateKeyPem(String privateKeyPem) {
+        getDelegateForUpdate();
+        updated.setPrivateKeyPem(privateKeyPem);
+    }
+
+    @Override
+    public PublicKey getPublicKey() {
+        if (publicKey != null) return publicKey;
+        publicKey = KeycloakModelUtils.getPublicKey(getPublicKeyPem());
+        return publicKey;
+    }
+
+    @Override
+    public void setPublicKey(PublicKey publicKey) {
+        this.publicKey = publicKey;
+        String publicKeyPem = KeycloakModelUtils.getPemFromKey(publicKey);
+        setPublicKeyPem(publicKeyPem);
+    }
+
+    @Override
+    public PrivateKey getPrivateKey() {
+        if (privateKey != null) return privateKey;
+        privateKey = KeycloakModelUtils.getPrivateKey(getPrivateKeyPem());
+        return privateKey;
+    }
+
+    @Override
+    public void setPrivateKey(PrivateKey privateKey) {
+        this.privateKey = privateKey;
+        String privateKeyPem = KeycloakModelUtils.getPemFromKey(privateKey);
+        setPrivateKeyPem(privateKeyPem);
+    }
+
+    @Override
+    public List<RequiredCredentialModel> getRequiredCredentials() {
+
+        List<RequiredCredentialModel> copy = new LinkedList<RequiredCredentialModel>();
+        if (updated != null) copy.addAll(updated.getRequiredCredentials());
+        else copy.addAll(cached.getRequiredCredentials());
+        return copy;
+    }
+
+    @Override
+    public void addRequiredCredential(String cred) {
+        getDelegateForUpdate();
+        updated.addRequiredCredential(cred);
+    }
+
+    @Override
+    public PasswordPolicy getPasswordPolicy() {
+        if (updated != null) return updated.getPasswordPolicy();
+        return cached.getPasswordPolicy();
+    }
+
+    @Override
+    public void setPasswordPolicy(PasswordPolicy policy) {
+        getDelegateForUpdate();
+        updated.setPasswordPolicy(policy);
+    }
+
+    @Override
+    public boolean validatePassword(UserModel user, String password) {
+        for (UserCredentialValueModel cred : user.getCredentialsDirectly()) {
+            if (cred.getType().equals(UserCredentialModel.PASSWORD)) {
+                return new Pbkdf2PasswordEncoder(cred.getSalt()).verify(password, cred.getValue());
+
+            }
+        }
+        return false;
+    }
+
+    @Override
+    public boolean validateTOTP(UserModel user, String password, String token) {
+        if (!validatePassword(user, password)) return false;
+        for (UserCredentialValueModel cred : user.getCredentialsDirectly()) {
+            if (cred.getType().equals(UserCredentialModel.TOTP)) {
+                return new TimeBasedOTP().validate(token, cred.getValue().getBytes());
+            }
+        }
+        return false;
+    }
+
+    @Override
+    public UserModel getUser(String name) {
+        return cacheSession.getUserByUsername(name, this);
+    }
+
+    @Override
+    public UserModel getUserByEmail(String email) {
+        return cacheSession.getUserByEmail(email, this);
+    }
+
+    @Override
+    public UserModel getUserById(String id) {
+        return cacheSession.getUserById(id, this);
+    }
+
+    @Override
+    public UserModel addUser(String id, String username) {
+        getDelegateForUpdate();
+        return updated.addUser(id, username);
+    }
+
+    @Override
+    public UserModel addUser(String username) {
+        getDelegateForUpdate();
+        return updated.addUser(username);
+    }
+
+    @Override
+    public boolean removeUser(String name) {
+        getDelegateForUpdate();
+        return updated.removeUser(name);
+    }
+
+    @Override
+    public RoleModel getRoleById(String id) {
+        if (updated != null) return updated.getRoleById(id);
+        if (!cached.getRolesById().contains(id)) return null;
+        CachedRole cachedRole = cache.getRole(id);
+        if (cachedRole == null) {
+            RoleModel roleModel = cacheSession.getDelegate().getRoleById(id, this);
+            if (roleModel == null) return null;
+            if (roleModel.getContainer() instanceof ApplicationModel) {
+                cachedRole = new CachedApplicationRole(((ApplicationModel) roleModel.getContainer()).getId(), roleModel);
+                cache.addCachedRole(cachedRole);
+            } else {
+                cachedRole = new CachedRealmRole(roleModel);
+            }
+        }
+        return new RoleAdapter(cachedRole, cache, cacheSession, this);
+    }
+
+    @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 ClientModel findClient(String clientId) {
+        if (updated != null) return updated.findClient(clientId);
+        String appId = cached.getApplications().get(clientId);
+        if (appId != null) {
+            return cacheSession.getApplicationById(appId, this);
+        }
+        String oauth = cached.getClients().get(clientId);
+        if (oauth != null) {
+            return cacheSession.getOAuthClientById(oauth, this);
+        }
+        return null;
+    }
+
+    @Override
+    public Map<String, ApplicationModel> getApplicationNameMap() {
+        if (updated != null) return updated.getApplicationNameMap();
+        Map<String, ApplicationModel> map = new HashMap<String, ApplicationModel>();
+        for (String id : cached.getApplications().values()) {
+            ApplicationModel model = cacheSession.getApplicationById(id, this);
+            if (model == null) {
+                throw new IllegalStateException("Cached application not found: " + id);
+            }
+            map.put(model.getName(), model);
+        }
+        return map;
+    }
+
+    @Override
+    public List<ApplicationModel> getApplications() {
+        if (updated != null) return updated.getApplications();
+        List<ApplicationModel> apps = new LinkedList<ApplicationModel>();
+        for (String id : cached.getApplications().values()) {
+            ApplicationModel model = cacheSession.getApplicationById(id, this);
+            if (model == null) {
+                throw new IllegalStateException("Cached application not found: " + id);
+            }
+            apps.add(model);
+        }
+        return apps;
+
+    }
+
+    @Override
+    public ApplicationModel addApplication(String name) {
+        getDelegateForUpdate();
+        return updated.addApplication(name);
+    }
+
+    @Override
+    public ApplicationModel addApplication(String id, String name) {
+        getDelegateForUpdate();
+        return updated.addApplication(id, name);
+    }
+
+    @Override
+    public boolean removeApplication(String id) {
+        getDelegateForUpdate();
+        return updated.removeApplication(id);
+    }
+
+    @Override
+    public ApplicationModel getApplicationById(String id) {
+        if (updated != null) return updated.getApplicationById(id);
+        return cacheSession.getApplicationById(id, this);
+    }
+
+    @Override
+    public ApplicationModel getApplicationByName(String name) {
+        if (updated != null) return updated.getApplicationByName(name);
+        String id = cached.getApplications().get(name);
+        if (id == null) return null;
+        return getApplicationById(id);
+    }
+
+    @Override
+    public void updateRequiredCredentials(Set<String> creds) {
+        getDelegateForUpdate();
+        updated.updateRequiredCredentials(creds);
+    }
+
+    @Override
+    public UserModel getUserBySocialLink(SocialLinkModel socialLink) {
+        if (updated != null) return updated.getUserBySocialLink(socialLink);
+        return cacheSession.getUserBySocialLink(socialLink, this);
+    }
+
+    @Override
+    public Set<SocialLinkModel> getSocialLinks(UserModel user) {
+        if (updated != null) return updated.getSocialLinks(user);
+        return cacheSession.getSocialLinks(user, this);
+    }
+
+    @Override
+    public SocialLinkModel getSocialLink(UserModel user, String socialProvider) {
+        if (updated != null) return updated.getSocialLink(user, socialProvider);
+        return cacheSession.getSocialLink(user, socialProvider, this);
+    }
+
+    @Override
+    public void addSocialLink(UserModel user, SocialLinkModel socialLink) {
+        getDelegateForUpdate();
+        updated.addSocialLink(user, socialLink);
+    }
+
+    @Override
+    public boolean removeSocialLink(UserModel user, String socialProvider) {
+        getDelegateForUpdate();
+        return updated.removeSocialLink(user, socialProvider);
+    }
+
+    @Override
+    public boolean isSocial() {
+        if (updated != null) return updated.isSocial();
+        return cached.isSocial();
+    }
+
+    @Override
+    public void setSocial(boolean social) {
+        getDelegateForUpdate();
+        updated.setSocial(social);
+    }
+
+    @Override
+    public boolean isUpdateProfileOnInitialSocialLogin() {
+        if (updated != null) return updated.isUpdateProfileOnInitialSocialLogin();
+        return cached.isUpdateProfileOnInitialSocialLogin();
+    }
+
+    @Override
+    public void setUpdateProfileOnInitialSocialLogin(boolean updateProfileOnInitialSocialLogin) {
+        getDelegateForUpdate();
+        updated.setUpdateProfileOnInitialSocialLogin(updateProfileOnInitialSocialLogin);
+    }
+
+    @Override
+    public List<UserModel> getUsers() {
+        if (updated != null) return updated.getUsers();
+        return cacheSession.getUsers(this);
+    }
+
+    @Override
+    public List<UserModel> searchForUser(String search) {
+        if (updated != null) return updated.searchForUser(search);
+        return cacheSession.searchForUser(search, this);
+    }
+
+    @Override
+    public List<UserModel> searchForUserByAttributes(Map<String, String> attributes) {
+        if (updated != null) return updated.searchForUserByAttributes(attributes);
+        return cacheSession.searchForUserByAttributes(attributes, this);
+    }
+
+    @Override
+    public OAuthClientModel addOAuthClient(String name) {
+        getDelegateForUpdate();
+        return updated.addOAuthClient(name);
+    }
+
+    @Override
+    public OAuthClientModel addOAuthClient(String id, String name) {
+        getDelegateForUpdate();
+        return updated.addOAuthClient(id, name);
+    }
+
+    @Override
+    public OAuthClientModel getOAuthClient(String name) {
+        if (updated != null) return updated.getOAuthClient(name);
+        String id = cached.getClients().get(name);
+        if (id == null) return null;
+        return getOAuthClientById(id);
+    }
+
+    @Override
+    public OAuthClientModel getOAuthClientById(String id) {
+        if (updated != null) return updated.getOAuthClientById(id);
+        return cacheSession.getOAuthClientById(id, this);
+    }
+
+    @Override
+    public boolean removeOAuthClient(String id) {
+        getDelegateForUpdate();
+        return updated.removeOAuthClient(id);
+    }
+
+    @Override
+    public List<OAuthClientModel> getOAuthClients() {
+        if (updated != null) return updated.getOAuthClients();
+        List<OAuthClientModel> clients = new LinkedList<OAuthClientModel>();
+        for (String id : cached.getClients().values()) {
+            OAuthClientModel model = cacheSession.getOAuthClientById(id, this);
+            if (model == null) {
+                throw new IllegalStateException("Cached oauth client not found: " + id);
+            }
+            clients.add(model);
+        }
+        return clients;
+    }
+
+    @Override
+    public Map<String, String> getSmtpConfig() {
+        if (updated != null) return updated.getSmtpConfig();
+        return cached.getSmtpConfig();
+    }
+
+    @Override
+    public void setSmtpConfig(Map<String, String> smtpConfig) {
+        getDelegateForUpdate();
+        updated.setSmtpConfig(smtpConfig);
+    }
+
+    @Override
+    public Map<String, String> getSocialConfig() {
+        if (updated != null) return updated.getSocialConfig();
+        return cached.getSocialConfig();
+    }
+
+    @Override
+    public void setSocialConfig(Map<String, String> socialConfig) {
+        getDelegateForUpdate();
+        updated.setSocialConfig(socialConfig);
+    }
+
+    @Override
+    public Map<String, String> getLdapServerConfig() {
+        if (updated != null) return updated.getLdapServerConfig();
+        return cached.getLdapServerConfig();
+    }
+
+    @Override
+    public void setLdapServerConfig(Map<String, String> ldapServerConfig) {
+        getDelegateForUpdate();
+        updated.setLdapServerConfig(ldapServerConfig);
+    }
+
+    @Override
+    public List<AuthenticationProviderModel> getAuthenticationProviders() {
+        if (updated != null) return updated.getAuthenticationProviders();
+        return cached.getAuthenticationProviders();
+    }
+
+    @Override
+    public void setAuthenticationProviders(List<AuthenticationProviderModel> authenticationProviders) {
+        getDelegateForUpdate();
+        updated.setAuthenticationProviders(authenticationProviders);
+    }
+
+    @Override
+    public String getLoginTheme() {
+        if (updated != null) return updated.getLoginTheme();
+        return cached.getLoginTheme();
+    }
+
+    @Override
+    public void setLoginTheme(String name) {
+        getDelegateForUpdate();
+        updated.setLoginTheme(name);
+    }
+
+    @Override
+    public String getAccountTheme() {
+        if (updated != null) return updated.getAccountTheme();
+        return cached.getAccountTheme();
+    }
+
+    @Override
+    public void setAccountTheme(String name) {
+        getDelegateForUpdate();
+        updated.setAccountTheme(name);
+    }
+
+    @Override
+    public String getAdminTheme() {
+        if (updated != null) return updated.getAdminTheme();
+        return cached.getAdminTheme();
+    }
+
+    @Override
+    public void setAdminTheme(String name) {
+        getDelegateForUpdate();
+        updated.setAdminTheme(name);
+    }
+
+    @Override
+    public String getEmailTheme() {
+        if (updated != null) return updated.getEmailTheme();
+        return cached.getEmailTheme();
+    }
+
+    @Override
+    public void setEmailTheme(String name) {
+        getDelegateForUpdate();
+        updated.setEmailTheme(name);
+    }
+
+    @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 boolean removeRoleById(String id) {
+        getDelegateForUpdate();
+        return updated.removeRoleById(id);
+    }
+
+    @Override
+    public boolean isAuditEnabled() {
+        if (updated != null) return updated.isAuditEnabled();
+        return cached.isAuditEnabled();
+    }
+
+    @Override
+    public void setAuditEnabled(boolean enabled) {
+        getDelegateForUpdate();
+        updated.setAuditEnabled(enabled);
+    }
+
+    @Override
+    public long getAuditExpiration() {
+        if (updated != null) return updated.getAuditExpiration();
+        return cached.getAuditExpiration();
+    }
+
+    @Override
+    public void setAuditExpiration(long expiration) {
+        getDelegateForUpdate();
+        updated.setAuditExpiration(expiration);
+    }
+
+    @Override
+    public Set<String> getAuditListeners() {
+        if (updated != null) return updated.getAuditListeners();
+        return cached.getAuditListeners();
+    }
+
+    @Override
+    public void setAuditListeners(Set<String> listeners) {
+        getDelegateForUpdate();
+        updated.setAuditListeners(listeners);
+    }
+
+    @Override
+    public ApplicationModel getMasterAdminApp() {
+        if (updated != null) return updated.getMasterAdminApp();
+        return getApplicationById(cached.getMasterAdminApp());
+    }
+
+    @Override
+    public void setMasterAdminApp(ApplicationModel app) {
+        getDelegateForUpdate();
+        updated.setMasterAdminApp(app);
+    }
+
+    @Override
+    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 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.getRealmRoles().values()) {
+            roles.add(cacheSession.getRoleById(id, this));
+        }
+        return roles;
+    }
+
+    @Override
+    public ClientModel findClientById(String id) {
+        ClientModel model = getApplicationById(id);
+        if (model != null) return model;
+        return getOAuthClientById(id);
+    }
+
+
+    @Override
+    public UsernameLoginFailureModel getUserLoginFailure(String username) {
+        if (updated != null) return updated.getUserLoginFailure(username);
+        return cacheSession.getUserLoginFailure(username, this);
+    }
+
+    @Override
+    public UsernameLoginFailureModel addUserLoginFailure(String username) {
+        if (updated != null) return updated.addUserLoginFailure(username);
+        return cacheSession.addUserLoginFailure(username, this);
+    }
+
+    @Override
+    public List<UsernameLoginFailureModel> getAllUserLoginFailures() {
+        if (updated != null) return updated.getAllUserLoginFailures();
+        return cacheSession.getAllUserLoginFailures(this);
+    }
+
+    @Override
+    public UserSessionModel createUserSession(UserModel user, String ipAddress) {
+        if (updated != null) return updated.createUserSession(user, ipAddress);
+        return cacheSession.createUserSession(this, user, ipAddress);
+    }
+
+    @Override
+    public UserSessionModel getUserSession(String id) {
+        if (updated != null) return updated.getUserSession(id);
+        return cacheSession.getUserSession(id, this);
+    }
+
+    @Override
+    public List<UserSessionModel> getUserSessions(UserModel user) {
+        if (updated != null) return updated.getUserSessions(user);
+        return cacheSession.getUserSessions(user, this);
+    }
+
+    @Override
+    public void removeUserSession(UserSessionModel session) {
+        if (updated != null) {
+            updated.removeUserSession(session);
+        } else {
+            cacheSession.removeUserSession(session);
+
+        }
+    }
+
+    @Override
+    public void removeUserSessions(UserModel user) {
+        if (updated != null) {
+            updated.removeUserSessions(user);
+        } else {
+            cacheSession.removeUserSessions(this, user);
+
+        }
+    }
+
+    @Override
+    public void removeExpiredUserSessions() {
+        if (updated != null) {
+            updated.removeExpiredUserSessions();
+        } else {
+            cacheSession.removeExpiredUserSessions(this);
+
+        }
+    }
+
+    @Override
+    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/invalidation-cache/model-adapters/src/main/java/org/keycloak/models/cache/RoleAdapter.java b/model/invalidation-cache/model-adapters/src/main/java/org/keycloak/models/cache/RoleAdapter.java
new file mode 100755
index 0000000..a7f8890
--- /dev/null
+++ b/model/invalidation-cache/model-adapters/src/main/java/org/keycloak/models/cache/RoleAdapter.java
@@ -0,0 +1,121 @@
+package org.keycloak.models.cache;
+
+import org.keycloak.models.RealmModel;
+import org.keycloak.models.RoleContainerModel;
+import org.keycloak.models.RoleModel;
+import org.keycloak.models.cache.entities.CachedApplicationRole;
+import org.keycloak.models.cache.entities.CachedRealmRole;
+import org.keycloak.models.cache.entities.CachedRole;
+import org.keycloak.models.utils.KeycloakModelUtils;
+
+import java.util.HashSet;
+import java.util.Set;
+
+/**
+ * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
+ * @version $Revision: 1 $
+ */
+public class RoleAdapter implements RoleModel {
+
+    protected RoleModel updated;
+    protected CachedRole cached;
+    protected KeycloakCache cache;
+    protected CacheKeycloakSession cacheSession;
+    protected RealmModel realm;
+
+    public RoleAdapter(CachedRole 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) {
+            updated = cacheSession.getDelegate().getRoleById(getId(), realm);
+            if (updated == null) throw new IllegalStateException("Not found in database");
+        }
+    }
+
+
+    @Override
+    public String getName() {
+        if (updated != null) return updated.getName();
+        return cached.getName();
+    }
+
+    @Override
+    public String getDescription() {
+        if (updated != null) return updated.getDescription();
+        return cached.getDescription();
+    }
+
+    @Override
+    public void setDescription(String description) {
+        getDelegateForUpdate();
+        updated.setDescription(description);
+    }
+
+    @Override
+    public String getId() {
+        if (updated != null) return updated.getId();
+        return cached.getId();
+    }
+
+    @Override
+    public void setName(String name) {
+        getDelegateForUpdate();
+        updated.setName(name);
+    }
+
+    @Override
+    public boolean isComposite() {
+        if (updated != null) return updated.isComposite();
+        return cached.isComposite();
+    }
+
+    @Override
+    public void addCompositeRole(RoleModel role) {
+        getDelegateForUpdate();
+        updated.addCompositeRole(role);
+    }
+
+    @Override
+    public void removeCompositeRole(RoleModel role) {
+        getDelegateForUpdate();
+        updated.removeCompositeRole(role);
+    }
+
+    @Override
+    public Set<RoleModel> getComposites() {
+        if (updated != null) return updated.getComposites();
+        Set<RoleModel> set = new HashSet<RoleModel>();
+        for (String id : cached.getComposites()) {
+            RoleModel role = realm.getRoleById(id);
+            if (role == null) {
+                throw new IllegalStateException("Could not find composite: " + id);
+            }
+            set.add(role);
+        }
+        return set;
+    }
+
+    @Override
+    public RoleContainerModel getContainer() {
+        if (cached instanceof CachedRealmRole) {
+            return realm;
+        } else {
+            CachedApplicationRole appRole = (CachedApplicationRole)cached;
+            return realm.getApplicationById(appRole.getAppId());
+        }
+    }
+
+    @Override
+    public boolean hasRole(RoleModel role) {
+        if (this.equals(role)) return true;
+        if (!isComposite()) return false;
+
+        Set<RoleModel> visited = new HashSet<RoleModel>();
+        return KeycloakModelUtils.searchFor(role, this, visited);
+    }
+}
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
new file mode 100755
index 0000000..317b351
--- /dev/null
+++ b/model/invalidation-cache/model-adapters/src/main/java/org/keycloak/models/cache/SimpleCache.java
@@ -0,0 +1,122 @@
+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 java.util.List;
+import java.util.concurrent.ConcurrentHashMap;
+
+/**
+ * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
+ * @version $Revision: 1 $
+ */
+public class SimpleCache implements KeycloakCache {
+
+    protected ConcurrentHashMap<String, CachedRealm> realmCache = new ConcurrentHashMap<String, CachedRealm>();
+    protected ConcurrentHashMap<String, CachedRealm> realmCacheByName = new ConcurrentHashMap<String, CachedRealm>();
+
+    @Override
+    public void clear() {
+        realmCache.clear();
+        realmCacheByName.clear();
+    }
+
+    @Override
+    public CachedRealm getCachedRealm(String id) {
+        return realmCache.get(id);
+    }
+
+    @Override
+    public void invalidateCachedRealm(CachedRealm realm) {
+        realmCache.remove(realm.getId());
+        realmCacheByName.remove(realm.getName());
+    }
+
+    @Override
+    public void invalidateCachedRealmById(String id) {
+        CachedRealm cached = realmCache.remove(id);
+        if (cached != null) realmCacheByName.remove(cached.getName());
+    }
+
+
+    @Override
+    public void addCachedRealm(CachedRealm realm) {
+        realmCache.put(realm.getId(), realm);
+        realmCache.put(realm.getName(), realm);
+
+    }
+
+    @Override
+    public CachedRealm getCachedRealmByName(String name) {
+        return realmCacheByName.get(name);
+    }
+
+    @Override
+    public CachedApplication getApplication(String id) {
+        return null;  //To change body of implemented methods use File | Settings | File Templates.
+    }
+
+    @Override
+    public void invalidateApplication(CachedApplication app) {
+        //To change body of implemented methods use File | Settings | File Templates.
+    }
+
+    @Override
+    public void addCachedApplication(CachedApplication app) {
+        //To change body of implemented methods use File | Settings | File Templates.
+    }
+
+    @Override
+    public void invalidateCachedApplicationById(String id) {
+        //To change body of implemented methods use File | Settings | File Templates.
+    }
+
+    @Override
+    public CachedOAuthClient getOAuthClient(String id) {
+        return null;  //To change body of implemented methods use File | Settings | File Templates.
+    }
+
+    @Override
+    public void invalidateOAuthClient(CachedOAuthClient client) {
+        //To change body of implemented methods use File | Settings | File Templates.
+    }
+
+    @Override
+    public void addCachedOAuthClient(CachedOAuthClient client) {
+        //To change body of implemented methods use File | Settings | File Templates.
+    }
+
+    @Override
+    public void invalidateCachedOAuthClientById(String id) {
+        //To change body of implemented methods use File | Settings | File Templates.
+    }
+
+    @Override
+    public CachedRole getRole(String id) {
+        return null;  //To change body of implemented methods use File | Settings | File Templates.
+    }
+
+    @Override
+    public void invalidateRole(CachedRole role) {
+        //To change body of implemented methods use File | Settings | File Templates.
+    }
+
+    @Override
+    public void addCachedRole(CachedRole role) {
+        //To change body of implemented methods use File | Settings | File Templates.
+    }
+
+    @Override
+    public void invalidateCachedRoleById(String id) {
+        //To change body of implemented methods use File | Settings | File Templates.
+    }
+}
diff --git a/model/jpa/src/main/java/org/keycloak/models/jpa/ApplicationAdapter.java b/model/jpa/src/main/java/org/keycloak/models/jpa/ApplicationAdapter.java
index c2c684a..31574ee 100755
--- a/model/jpa/src/main/java/org/keycloak/models/jpa/ApplicationAdapter.java
+++ b/model/jpa/src/main/java/org/keycloak/models/jpa/ApplicationAdapter.java
@@ -2,6 +2,7 @@ package org.keycloak.models.jpa;
 
 import org.keycloak.models.ApplicationModel;
 import org.keycloak.models.ClientModel;
+import org.keycloak.models.ModelDuplicateException;
 import org.keycloak.models.RealmModel;
 import org.keycloak.models.RoleContainerModel;
 import org.keycloak.models.RoleModel;
@@ -100,10 +101,10 @@ public class ApplicationAdapter extends ClientAdapter implements ApplicationMode
 
     @Override
     public RoleModel getRole(String name) {
-        TypedQuery<ApplicationRoleEntity> query = em.createNamedQuery("getAppRoleByName", ApplicationRoleEntity.class);
+        TypedQuery<RoleEntity> query = em.createNamedQuery("getAppRoleByName", RoleEntity.class);
         query.setParameter("name", name);
         query.setParameter("application", entity);
-        List<ApplicationRoleEntity> roles = query.getResultList();
+        List<RoleEntity> roles = query.getResultList();
         if (roles.size() == 0) return null;
         return new RoleAdapter(realm, em, roles.get(0));
     }
@@ -115,10 +116,12 @@ public class ApplicationAdapter extends ClientAdapter implements ApplicationMode
 
     @Override
     public RoleModel addRole(String id, String name) {
-        ApplicationRoleEntity roleEntity = new ApplicationRoleEntity();
+        RoleEntity roleEntity = new RoleEntity();
         roleEntity.setId(id);
         roleEntity.setName(name);
         roleEntity.setApplication(applicationEntity);
+        roleEntity.setApplicationRole(true);
+        roleEntity.setRealmId(realm.getId());
         em.persist(roleEntity);
         applicationEntity.getRoles().add(roleEntity);
         em.flush();
@@ -133,9 +136,9 @@ public class ApplicationAdapter extends ClientAdapter implements ApplicationMode
         }
         if (!roleAdapter.getContainer().equals(this)) return false;
 
-        if (!(roleAdapter.getRole() instanceof ApplicationRoleEntity)) return false;
+        if (!roleAdapter.getRole().isApplicationRole()) return false;
 
-        ApplicationRoleEntity role = (ApplicationRoleEntity)roleAdapter.getRole();
+        RoleEntity role = roleAdapter.getRole();
 
         applicationEntity.getRoles().remove(role);
         applicationEntity.getDefaultRoles().remove(role);
@@ -153,7 +156,7 @@ public class ApplicationAdapter extends ClientAdapter implements ApplicationMode
     @Override
     public Set<RoleModel> getRoles() {
         Set<RoleModel> list = new HashSet<RoleModel>();
-        Collection<ApplicationRoleEntity> roles = applicationEntity.getRoles();
+        Collection<RoleEntity> roles = applicationEntity.getRoles();
         if (roles == null) return list;
         for (RoleEntity entity : roles) {
             list.add(new RoleAdapter(realm, em, entity));
@@ -162,27 +165,8 @@ public class ApplicationAdapter extends ClientAdapter implements ApplicationMode
     }
 
     @Override
-    public Set<RoleModel> getApplicationRoleMappings(UserModel user) {
-        Set<RoleModel> roleMappings = realm.getRoleMappings(user);
-
-        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 Set<RoleModel> getApplicationScopeMappings(ClientModel client) {
-        Set<RoleModel> roleMappings = realm.getScopeMappings(client);
+        Set<RoleModel> roleMappings = client.getScopeMappings();
 
         Set<RoleModel> appRoles = new HashSet<RoleModel>();
         for (RoleModel role : roleMappings) {
diff --git a/model/jpa/src/main/java/org/keycloak/models/jpa/ClientAdapter.java b/model/jpa/src/main/java/org/keycloak/models/jpa/ClientAdapter.java
index f16d955..f8bc8f6 100755
--- a/model/jpa/src/main/java/org/keycloak/models/jpa/ClientAdapter.java
+++ b/model/jpa/src/main/java/org/keycloak/models/jpa/ClientAdapter.java
@@ -2,9 +2,12 @@ package org.keycloak.models.jpa;
 
 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.jpa.entities.ClientEntity;
 import org.keycloak.models.jpa.entities.ClientUserSessionAssociationEntity;
+import org.keycloak.models.jpa.entities.ScopeMappingEntity;
 
 import javax.persistence.EntityManager;
 import javax.persistence.Query;
@@ -175,6 +178,74 @@ public abstract class ClientAdapter implements ClientModel {
     }
 
     @Override
+    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(realm.getId())) {
+                    appRoles.add(role);
+                }
+            }
+        }
+
+        return appRoles;
+    }
+
+
+
+    @Override
+    public Set<RoleModel> getScopeMappings() {
+        TypedQuery<ScopeMappingEntity> query = em.createNamedQuery("clientScopeMappings", ScopeMappingEntity.class);
+        query.setParameter("client", getEntity());
+        List<ScopeMappingEntity> entities = query.getResultList();
+        Set<RoleModel> roles = new HashSet<RoleModel>();
+        for (ScopeMappingEntity entity : entities) {
+            roles.add(new RoleAdapter(realm, em, entity.getRole()));
+        }
+        return roles;
+    }
+
+    @Override
+    public void addScopeMapping(RoleModel role) {
+        if (hasScope(role)) return;
+        ScopeMappingEntity entity = new ScopeMappingEntity();
+        entity.setClient(getEntity());
+        entity.setRole(((RoleAdapter) role).getRole());
+        em.persist(entity);
+    }
+
+    @Override
+    public void deleteScopeMapping(RoleModel role) {
+        TypedQuery<ScopeMappingEntity> query = getRealmScopeMappingQuery((RoleAdapter) role);
+        List<ScopeMappingEntity> results = query.getResultList();
+        if (results.size() == 0) return;
+        for (ScopeMappingEntity entity : results) {
+            em.remove(entity);
+        }
+    }
+
+    protected TypedQuery<ScopeMappingEntity> getRealmScopeMappingQuery(RoleAdapter role) {
+        TypedQuery<ScopeMappingEntity> query = em.createNamedQuery("hasScope", ScopeMappingEntity.class);
+        query.setParameter("client", getEntity());
+        query.setParameter("role", ((RoleAdapter) role).getRole());
+        return query;
+    }
+
+    @Override
+    public boolean hasScope(RoleModel role) {
+        Set<RoleModel> roles = getScopeMappings();
+        if (roles.contains(role)) return true;
+
+        for (RoleModel mapping : roles) {
+            if (mapping.hasRole(role)) return true;
+        }
+        return false;
+    }
+
+    @Override
     public boolean equals(Object o) {
         if (this == o) return true;
         if (!this.getClass().equals(o.getClass())) return false;
diff --git a/model/jpa/src/main/java/org/keycloak/models/jpa/entities/AbstractRoleMappingEntity.java b/model/jpa/src/main/java/org/keycloak/models/jpa/entities/AbstractRoleMappingEntity.java
index 101d558..685aed7 100755
--- a/model/jpa/src/main/java/org/keycloak/models/jpa/entities/AbstractRoleMappingEntity.java
+++ b/model/jpa/src/main/java/org/keycloak/models/jpa/entities/AbstractRoleMappingEntity.java
@@ -1,5 +1,6 @@
 package org.keycloak.models.jpa.entities;
 
+import javax.persistence.FetchType;
 import javax.persistence.GeneratedValue;
 import javax.persistence.Id;
 import javax.persistence.ManyToOne;
@@ -17,9 +18,9 @@ public class AbstractRoleMappingEntity {
     @GenericGenerator(name="keycloak_generator", strategy="org.keycloak.models.jpa.utils.JpaIdGenerator")
     @GeneratedValue(generator = "keycloak_generator")
     protected String id;
-    @ManyToOne
+    @ManyToOne(fetch= FetchType.LAZY)
     protected UserEntity user;
-    @ManyToOne
+    @ManyToOne(fetch= FetchType.LAZY)
     protected RoleEntity role;
 
     public String getId() {
diff --git a/model/jpa/src/main/java/org/keycloak/models/jpa/entities/ApplicationEntity.java b/model/jpa/src/main/java/org/keycloak/models/jpa/entities/ApplicationEntity.java
index adcae87..8327bd0 100755
--- a/model/jpa/src/main/java/org/keycloak/models/jpa/entities/ApplicationEntity.java
+++ b/model/jpa/src/main/java/org/keycloak/models/jpa/entities/ApplicationEntity.java
@@ -34,7 +34,7 @@ public class ApplicationEntity extends ClientEntity {
     private boolean bearerOnly;
 
     @OneToMany(fetch = FetchType.EAGER, cascade ={CascadeType.REMOVE}, orphanRemoval = true, mappedBy = "application")
-    Collection<ApplicationRoleEntity> roles = new ArrayList<ApplicationRoleEntity>();
+    Collection<RoleEntity> roles = new ArrayList<RoleEntity>();
 
     @OneToMany(fetch = FetchType.LAZY, cascade ={CascadeType.REMOVE}, orphanRemoval = true)
     @JoinTable(name="ApplicationDefaultRoles")
@@ -64,11 +64,11 @@ public class ApplicationEntity extends ClientEntity {
         this.managementUrl = managementUrl;
     }
 
-    public Collection<ApplicationRoleEntity> getRoles() {
+    public Collection<RoleEntity> getRoles() {
         return roles;
     }
 
-    public void setRoles(Collection<ApplicationRoleEntity> roles) {
+    public void setRoles(Collection<RoleEntity> roles) {
         this.roles = roles;
     }
 
diff --git a/model/jpa/src/main/java/org/keycloak/models/jpa/entities/RealmEntity.java b/model/jpa/src/main/java/org/keycloak/models/jpa/entities/RealmEntity.java
index 3fbed83..8fd8a56 100755
--- a/model/jpa/src/main/java/org/keycloak/models/jpa/entities/RealmEntity.java
+++ b/model/jpa/src/main/java/org/keycloak/models/jpa/entities/RealmEntity.java
@@ -91,7 +91,7 @@ public class RealmEntity {
     Collection<ApplicationEntity> applications = new ArrayList<ApplicationEntity>();
 
     @OneToMany(fetch = FetchType.LAZY, cascade ={CascadeType.REMOVE}, orphanRemoval = true, mappedBy = "realm")
-    Collection<RealmRoleEntity> roles = new ArrayList<RealmRoleEntity>();
+    Collection<RoleEntity> roles = new ArrayList<RoleEntity>();
 
     @ElementCollection
     @MapKeyColumn(name="name")
@@ -292,17 +292,17 @@ public class RealmEntity {
         this.applications = applications;
     }
 
-    public Collection<RealmRoleEntity> getRoles() {
+    public Collection<RoleEntity> getRoles() {
         return roles;
     }
 
-    public void setRoles(Collection<RealmRoleEntity> roles) {
+    public void setRoles(Collection<RoleEntity> roles) {
         this.roles = roles;
     }
 
-    public void addRole(RealmRoleEntity role) {
+    public void addRole(RoleEntity role) {
         if (roles == null) {
-            roles = new ArrayList<RealmRoleEntity>();
+            roles = new ArrayList<RoleEntity>();
         }
         roles.add(role);
     }
diff --git a/model/jpa/src/main/java/org/keycloak/models/jpa/entities/RoleEntity.java b/model/jpa/src/main/java/org/keycloak/models/jpa/entities/RoleEntity.java
index 3792995..c6f3eb1 100755
--- a/model/jpa/src/main/java/org/keycloak/models/jpa/entities/RoleEntity.java
+++ b/model/jpa/src/main/java/org/keycloak/models/jpa/entities/RoleEntity.java
@@ -1,5 +1,6 @@
 package org.keycloak.models.jpa.entities;
 
+import javax.persistence.Column;
 import javax.persistence.Entity;
 import javax.persistence.FetchType;
 import javax.persistence.GeneratedValue;
@@ -9,6 +10,9 @@ import javax.persistence.InheritanceType;
 import javax.persistence.JoinColumn;
 import javax.persistence.JoinTable;
 import javax.persistence.ManyToMany;
+import javax.persistence.ManyToOne;
+import javax.persistence.NamedQueries;
+import javax.persistence.NamedQuery;
 import javax.persistence.Table;
 import javax.persistence.UniqueConstraint;
 import java.util.ArrayList;
@@ -21,16 +25,38 @@ import org.hibernate.annotations.GenericGenerator;
  * @version $Revision: 1 $
  */
 @Entity
-@Inheritance(strategy = InheritanceType.SINGLE_TABLE)
 @Table(uniqueConstraints = {
-        @UniqueConstraint(columnNames = { "name", "application" }),
+        @UniqueConstraint(columnNames = { "name", "application"}),
         @UniqueConstraint(columnNames = { "name", "realm" })
+
+})
+@NamedQueries({
+        @NamedQuery(name="getAppRoleByName", query="select role from RoleEntity role where role.name = :name and role.application = :application"),
+        @NamedQuery(name="getRealmRoleByName", query="select role from RoleEntity role where role.applicationRole = false and role.name = :name and role.realm = :realm")
 })
-public abstract class RoleEntity {
+
+public class RoleEntity {
     @Id
+    @Column(name="id")
     private String id;
 
+    private String name;
     private String description;
+
+    // hax! couldn't get constraint to work properly
+    private String realmId;
+
+    @ManyToOne(fetch = FetchType.LAZY)
+    @JoinColumn(name = "realm")
+    private RealmEntity realm;
+
+    @Column(name="applicationRole")
+    private boolean applicationRole;
+
+    @ManyToOne(fetch = FetchType.LAZY)
+    @JoinColumn(name = "application")
+    private ApplicationEntity application;
+
     @ManyToMany(fetch = FetchType.LAZY, cascade = {})
     @JoinTable(name = "CompositeRole", joinColumns = @JoinColumn(name = "composite"), inverseJoinColumns = @JoinColumn(name = "role"))
     private Collection<RoleEntity> compositeRoles = new ArrayList<RoleEntity>();
@@ -43,9 +69,21 @@ public abstract class RoleEntity {
         this.id = id;
     }
 
-    public abstract String getName();
+    public String getRealmId() {
+        return realmId;
+    }
+
+    public void setRealmId(String realmId) {
+        this.realmId = realmId;
+    }
+
+    public String getName() {
+        return name;
+    }
 
-    public abstract void setName(String name);
+    public void setName(String name) {
+        this.name = name;
+    }
 
     public String getDescription() {
         return description;
@@ -63,6 +101,30 @@ public abstract class RoleEntity {
         this.compositeRoles = compositeRoles;
     }
 
+    public boolean isApplicationRole() {
+        return applicationRole;
+    }
+
+    public void setApplicationRole(boolean applicationRole) {
+        this.applicationRole = applicationRole;
+    }
+
+    public RealmEntity getRealm() {
+        return realm;
+    }
+
+    public void setRealm(RealmEntity realm) {
+        this.realm = realm;
+    }
+
+    public ApplicationEntity getApplication() {
+        return application;
+    }
+
+    public void setApplication(ApplicationEntity application) {
+        this.application = application;
+    }
+
     @Override
     public boolean equals(Object o) {
         if (this == o) return true;
diff --git a/model/jpa/src/main/java/org/keycloak/models/jpa/entities/UserEntity.java b/model/jpa/src/main/java/org/keycloak/models/jpa/entities/UserEntity.java
index f51ed94..39d03a4 100755
--- a/model/jpa/src/main/java/org/keycloak/models/jpa/entities/UserEntity.java
+++ b/model/jpa/src/main/java/org/keycloak/models/jpa/entities/UserEntity.java
@@ -32,6 +32,7 @@ import java.util.Set;
  * @version $Revision: 1 $
  */
 @NamedQueries({
+        @NamedQuery(name="getRealmUserById", query="select u from UserEntity u where u.id = :id and u.realm = :realm"),
         @NamedQuery(name="getRealmUserByLoginName", query="select u from UserEntity u where u.loginName = :loginName and u.realm = :realm"),
         @NamedQuery(name="getRealmUserByEmail", query="select u from UserEntity u where u.email = :email and u.realm = :realm"),
         @NamedQuery(name="getRealmUserByLastName", query="select u from UserEntity u where u.lastName = :lastName and u.realm = :realm"),
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 36aabd6..b55b602 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
@@ -3,13 +3,18 @@ package org.keycloak.models.jpa;
 import org.keycloak.models.*;
 import org.keycloak.models.jpa.entities.*;
 import org.keycloak.models.utils.KeycloakModelUtils;
+import org.keycloak.util.Time;
 
 import javax.persistence.EntityManager;
+import javax.persistence.Query;
 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;
+import java.util.Set;
 
 /**
  * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
@@ -39,14 +44,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
@@ -55,7 +60,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;
     }
@@ -69,7 +74,39 @@ 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
+    public UserModel getUserById(String id, RealmModel realmModel) {
+        TypedQuery<UserEntity> query = em.createNamedQuery("getRealmUserById", UserEntity.class);
+        query.setParameter("id", id);
+        RealmEntity realm = em.getReference(RealmEntity.class, realmModel.getId());
+        query.setParameter("realm", realm);
+        List<UserEntity> entities = query.getResultList();
+        if (entities.size() == 0) return null;
+        return new UserAdapter(realmModel, em, entities.get(0));
+    }
+
+    @Override
+    public UserModel getUserByUsername(String username, RealmModel realmModel) {
+        TypedQuery<UserEntity> query = em.createNamedQuery("getRealmUserByLoginName", UserEntity.class);
+        query.setParameter("loginName", username);
+        RealmEntity realm = em.getReference(RealmEntity.class, realmModel.getId());
+        query.setParameter("realm", realm);
+        List<UserEntity> results = query.getResultList();
+        if (results.size() == 0) return null;
+        return new UserAdapter(realmModel, em, results.get(0));
+    }
+
+    @Override
+    public UserModel getUserByEmail(String email, RealmModel realmModel) {
+        TypedQuery<UserEntity> query = em.createNamedQuery("getRealmUserByEmail", UserEntity.class);
+        query.setParameter("email", email);
+        RealmEntity realm = em.getReference(RealmEntity.class, realmModel.getId());
+        query.setParameter("realm", realm);
+        List<UserEntity> results = query.getResultList();
+        return results.isEmpty() ? null : new UserAdapter(realmModel, em, results.get(0));
     }
 
     @Override
@@ -79,7 +116,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());
@@ -112,4 +149,249 @@ public class JpaKeycloakSession implements KeycloakSession {
             removeRealm(realm.getId());
         }
     }
+
+    @Override
+    public UserModel getUserBySocialLink(SocialLinkModel socialLink, RealmModel realm) {
+        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
+    public List<UserModel> getUsers(RealmModel realm) {
+        TypedQuery<UserEntity> query = em.createQuery("select u from UserEntity u where u.realm = :realm", UserEntity.class);
+        RealmEntity realmEntity = em.getReference(RealmEntity.class, realm.getId());
+        query.setParameter("realm", realmEntity);
+        List<UserEntity> results = query.getResultList();
+        List<UserModel> users = new ArrayList<UserModel>();
+        for (UserEntity entity : results) users.add(new UserAdapter(realm, em, entity));
+        return users;
+    }
+
+    @Override
+    public List<UserModel> searchForUser(String search, RealmModel realm) {
+        TypedQuery<UserEntity> query = em.createQuery("select u from UserEntity u where u.realm = :realm and ( lower(u.loginName) like :search or lower(concat(u.firstName, ' ', u.lastName)) like :search or u.email like :search )", UserEntity.class);
+        RealmEntity realmEntity = em.getReference(RealmEntity.class, realm.getId());
+        query.setParameter("realm", realmEntity);
+        query.setParameter("search", "%" + search.toLowerCase() + "%");
+        List<UserEntity> results = query.getResultList();
+        List<UserModel> users = new ArrayList<UserModel>();
+        for (UserEntity entity : results) users.add(new UserAdapter(realm, em, entity));
+        return users;
+    }
+
+    @Override
+    public List<UserModel> searchForUserByAttributes(Map<String, String> attributes, RealmModel realm) {
+        StringBuilder builder = new StringBuilder("select u from UserEntity u");
+        boolean first = true;
+        for (Map.Entry<String, String> entry : attributes.entrySet()) {
+            String attribute = null;
+            if (entry.getKey().equals(UserModel.LOGIN_NAME)) {
+                attribute = "lower(loginName)";
+            } else if (entry.getKey().equalsIgnoreCase(UserModel.FIRST_NAME)) {
+                attribute = "lower(firstName)";
+            } else if (entry.getKey().equalsIgnoreCase(UserModel.LAST_NAME)) {
+                attribute = "lower(lastName)";
+            } else if (entry.getKey().equalsIgnoreCase(UserModel.EMAIL)) {
+                attribute = "lower(email)";
+            }
+            if (attribute == null) continue;
+            if (first) {
+                first = false;
+                builder.append(" where realm = :realm");
+            } else {
+                builder.append(" and ");
+            }
+            builder.append(attribute).append(" like '%").append(entry.getValue().toLowerCase()).append("%'");
+        }
+        String q = builder.toString();
+        TypedQuery<UserEntity> query = em.createQuery(q, UserEntity.class);
+        RealmEntity realmEntity = em.getReference(RealmEntity.class, realm.getId());
+        query.setParameter("realm", realmEntity);
+        List<UserEntity> results = query.getResultList();
+        List<UserModel> users = new ArrayList<UserModel>();
+        for (UserEntity entity : results) users.add(new UserAdapter(realm, em, entity));
+        return users;
+    }
+
+    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) {
+        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) {
+        SocialLinkEntity entity = findSocialLink(user, socialProvider);
+        return (entity != null) ? new SocialLinkModel(entity.getSocialProvider(), entity.getSocialUserId(), entity.getSocialUsername()) : null;
+    }
+
+    @Override
+    public RoleModel getRoleById(String id, RealmModel realm) {
+        RoleEntity entity = em.find(RoleEntity.class, id);
+        if (entity == null) return null;
+        if (!realm.getId().equals(entity.getRealmId())) return null;
+        return new RoleAdapter(realm, em, entity);
+    }
+
+    @Override
+    public ApplicationModel getApplicationById(String id, RealmModel realm) {
+        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) {
+        OAuthClientEntity client = em.find(OAuthClientEntity.class, id);
+
+        // Check if client belongs to this realm
+        if (client == null || !realm.getId().equals(client.getRealm().getId())) return null;
+        return new OAuthClientAdapter(realm, client, em);
+    }
+
+    @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(RealmModel realm) {
+        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) {
+        UserSessionEntity entity = new UserSessionEntity();
+        entity.setRealmId(realm.getId());
+        entity.setUserId(user.getId());
+        entity.setIpAddress(ipAddress);
+
+        int currentTime = Time.currentTime();
+
+        entity.setStarted(currentTime);
+        entity.setLastSessionRefresh(currentTime);
+
+        em.persist(entity);
+        return new UserSessionAdapter(em, realm, entity);
+    }
+
+    @Override
+    public UserSessionModel getUserSession(String id, RealmModel realm) {
+        UserSessionEntity entity = em.find(UserSessionEntity.class, id);
+        return entity != null ? new UserSessionAdapter(em, realm, entity) : null;
+    }
+
+    @Override
+    public List<UserSessionModel> getUserSessions(UserModel user, RealmModel realm) {
+        List<UserSessionModel> sessions = new LinkedList<UserSessionModel>();
+        for (UserSessionEntity e : em.createNamedQuery("getUserSessionByUser", UserSessionEntity.class)
+                .setParameter("userId", user.getId()).getResultList()) {
+            sessions.add(new UserSessionAdapter(em, realm, e));
+        }
+        return sessions;
+    }
+
+    @Override
+    public Set<UserSessionModel> getUserSessions(RealmModel realm, ClientModel client) {
+        Set<UserSessionModel> list = new HashSet<UserSessionModel>();
+        TypedQuery<ClientUserSessionAssociationEntity> query = em.createNamedQuery("getClientUserSessionByClient", ClientUserSessionAssociationEntity.class);
+        String id = client.getId();
+        query.setParameter("clientId", id);
+        List<ClientUserSessionAssociationEntity> results = query.getResultList();
+        for (ClientUserSessionAssociationEntity entity : results) {
+            list.add(new UserSessionAdapter(em, realm, entity.getSession()));
+        }
+        return list;
+    }
+
+    @Override
+    public int getActiveUserSessions(RealmModel realm, ClientModel client) {
+        Query query = em.createNamedQuery("getActiveClientSessions");
+        query.setParameter("clientId", client.getId());
+        Object count = query.getSingleResult();
+        return ((Number)count).intValue();
+    }
+
+    @Override
+    public void removeUserSession(UserSessionModel session) {
+        em.remove(((UserSessionAdapter) session).getEntity());
+    }
+
+    @Override
+    public void removeUserSessions(RealmModel realm, UserModel user) {
+        em.createNamedQuery("removeClientUserSessionByUser").setParameter("userId", user.getId()).executeUpdate();
+        em.createNamedQuery("removeUserSessionByUser").setParameter("userId", user.getId()).executeUpdate();
+    }
+
+    @Override
+    public void removeExpiredUserSessions(RealmModel realm) {
+        TypedQuery<UserSessionEntity> query = em.createNamedQuery("getUserSessionExpired", UserSessionEntity.class)
+                .setParameter("maxTime", Time.currentTime() - realm.getSsoSessionMaxLifespan())
+                .setParameter("idleTime", Time.currentTime() - realm.getSsoSessionIdleTimeout());
+        List<UserSessionEntity> results = query.getResultList();
+        for (UserSessionEntity entity : results) {
+            em.remove(entity);
+        }
+    }
+
+    @Override
+    public void removeUserSessions(RealmModel realm) {
+        em.createNamedQuery("removeClientUserSessionByRealm").setParameter("realmId", realm.getId()).executeUpdate();
+        em.createNamedQuery("removeRealmUserSessions").setParameter("realmId", realm.getId()).executeUpdate();
+    }
 }
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 1c4cae0..89ab556 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,18 +3,17 @@ 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;
 import org.keycloak.models.UserSessionModel;
 import org.keycloak.models.UsernameLoginFailureModel;
 import org.keycloak.models.jpa.entities.ApplicationEntity;
-import org.keycloak.models.jpa.entities.ApplicationRoleEntity;
 import org.keycloak.models.jpa.entities.AuthenticationLinkEntity;
 import org.keycloak.models.jpa.entities.AuthenticationProviderEntity;
-import org.keycloak.models.jpa.entities.CredentialEntity;
 import org.keycloak.models.jpa.entities.OAuthClientEntity;
 import org.keycloak.models.jpa.entities.RealmEntity;
-import org.keycloak.models.jpa.entities.RealmRoleEntity;
 import org.keycloak.models.jpa.entities.RequiredCredentialEntity;
 import org.keycloak.models.jpa.entities.RoleEntity;
 import org.keycloak.models.jpa.entities.ScopeMappingEntity;
@@ -65,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;
     }
@@ -424,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(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(this);
     }
 
     @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(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(entity);
+        return session.getUserById(id, this);
     }
 
     @Override
@@ -495,15 +466,15 @@ public class RealmAdapter implements RealmModel {
         entity.setRealm(realm);
         em.persist(entity);
         em.flush();
-        UserModel userModel = new UserAdapter(entity);
+        UserModel userModel = new UserAdapter(this, em, entity);
 
         for (String r : getDefaultRoles()) {
-            grantRole(userModel, getRole(r));
+            userModel.grantRole(getRole(r));
         }
 
         for (ApplicationModel application : getApplications()) {
             for (String r : application.getDefaultRoles()) {
-                grantRole(userModel, application.getRole(r));
+                userModel.grantRole(application.getRole(r));
             }
         }
 
@@ -522,7 +493,8 @@ public class RealmAdapter implements RealmModel {
     }
 
     private void removeUser(UserEntity user) {
-        removeUserSessions(user);
+        em.createNamedQuery("removeClientUserSessionByUser").setParameter("userId", user.getId()).executeUpdate();
+        em.createNamedQuery("removeUserSessionByUser").setParameter("userId", user.getId()).executeUpdate();
 
         em.createQuery("delete from " + UserRoleMappingEntity.class.getSimpleName() + " where user = :user").setParameter("user", user).executeUpdate();
         em.createQuery("delete from " + SocialLinkEntity.class.getSimpleName() + " where user = :user").setParameter("user", user).executeUpdate();
@@ -680,11 +652,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
@@ -694,38 +662,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(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
@@ -740,6 +687,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);
@@ -752,33 +709,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() {
@@ -804,55 +734,17 @@ public class RealmAdapter implements RealmModel {
 
     @Override
     public List<UserModel> getUsers() {
-        TypedQuery<UserEntity> query = em.createQuery("select u from UserEntity u where u.realm = :realm", UserEntity.class);
-        query.setParameter("realm", realm);
-        List<UserEntity> results = query.getResultList();
-        List<UserModel> users = new ArrayList<UserModel>();
-        for (UserEntity entity : results) users.add(new UserAdapter(entity));
-        return users;
+        return session.getUsers(this);
     }
 
     @Override
     public List<UserModel> searchForUser(String search) {
-        TypedQuery<UserEntity> query = em.createQuery("select u from UserEntity u where u.realm = :realm and ( lower(u.loginName) like :search or lower(concat(u.firstName, ' ', u.lastName)) like :search or u.email like :search )", UserEntity.class);
-        query.setParameter("realm", realm);
-        query.setParameter("search", "%" + search.toLowerCase() + "%");
-        List<UserEntity> results = query.getResultList();
-        List<UserModel> users = new ArrayList<UserModel>();
-        for (UserEntity entity : results) users.add(new UserAdapter(entity));
-        return users;
+        return session.searchForUser(search, this);
     }
 
     @Override
     public List<UserModel> searchForUserByAttributes(Map<String, String> attributes) {
-        StringBuilder builder = new StringBuilder("select u from UserEntity u");
-        boolean first = true;
-        for (Map.Entry<String, String> entry : attributes.entrySet()) {
-            String attribute = null;
-            if (entry.getKey().equals(UserModel.LOGIN_NAME)) {
-                attribute = "lower(loginName)";
-            } else if (entry.getKey().equalsIgnoreCase(UserModel.FIRST_NAME)) {
-                attribute = "lower(firstName)";
-            } else if (entry.getKey().equalsIgnoreCase(UserModel.LAST_NAME)) {
-                attribute = "lower(lastName)";
-            } else if (entry.getKey().equalsIgnoreCase(UserModel.EMAIL)) {
-                attribute = "lower(email)";
-            }
-            if (attribute == null) continue;
-            if (first) {
-                first = false;
-                builder.append(" where ");
-            } else {
-                builder.append(" and ");
-            }
-            builder.append(attribute).append(" like '%").append(entry.getValue().toLowerCase()).append("%'");
-        }
-        String q = builder.toString();
-        TypedQuery<UserEntity> query = em.createQuery(q, UserEntity.class);
-        List<UserEntity> results = query.getResultList();
-        List<UserModel> users = new ArrayList<UserModel>();
-        for (UserEntity entity : results) users.add(new UserAdapter(entity));
-        return users;
+        return session.searchForUserByAttributes(attributes, this);
     }
 
     @Override
@@ -896,11 +788,7 @@ public class RealmAdapter implements RealmModel {
 
     @Override
     public OAuthClientModel getOAuthClientById(String id) {
-        OAuthClientEntity client = em.find(OAuthClientEntity.class, id);
-
-        // Check if client belongs to this realm
-        if (client == null || !this.realm.getId().equals(client.getRealm().getId())) return null;
-        return new OAuthClientAdapter(this, client, em);
+        return session.getOAuthClientById(id, this);
     }
 
 
@@ -1003,10 +891,10 @@ public class RealmAdapter implements RealmModel {
 
     @Override
     public RoleModel getRole(String name) {
-        TypedQuery<RealmRoleEntity> query = em.createNamedQuery("getRealmRoleByName", RealmRoleEntity.class);
+        TypedQuery<RoleEntity> query = em.createNamedQuery("getRealmRoleByName", RoleEntity.class);
         query.setParameter("name", name);
         query.setParameter("realm", realm);
-        List<RealmRoleEntity> roles = query.getResultList();
+        List<RoleEntity> roles = query.getResultList();
         if (roles.size() == 0) return null;
         return new RoleAdapter(this, em, roles.get(0));
     }
@@ -1018,10 +906,11 @@ public class RealmAdapter implements RealmModel {
 
     @Override
     public RoleModel addRole(String id, String name) {
-        RealmRoleEntity entity = new RealmRoleEntity();
+        RoleEntity entity = new RoleEntity();
         entity.setId(id);
         entity.setName(name);
         entity.setRealm(realm);
+        entity.setRealmId(realm.getId());
         realm.getRoles().add(entity);
         em.persist(entity);
         em.flush();
@@ -1051,7 +940,7 @@ public class RealmAdapter implements RealmModel {
     @Override
     public Set<RoleModel> getRoles() {
         Set<RoleModel> list = new HashSet<RoleModel>();
-        Collection<RealmRoleEntity> roles = realm.getRoles();
+        Collection<RoleEntity> roles = realm.getRoles();
         if (roles == null) return list;
         for (RoleEntity entity : roles) {
             list.add(new RoleAdapter(this, em, entity));
@@ -1061,16 +950,7 @@ public class RealmAdapter implements RealmModel {
 
     @Override
     public RoleModel getRoleById(String id) {
-        RoleEntity entity = em.find(RoleEntity.class, id);
-        if (entity == null) return null;
-        if (entity instanceof RealmRoleEntity) {
-            RealmRoleEntity roleEntity = (RealmRoleEntity) entity;
-            if (!roleEntity.getRealm().getId().equals(getId())) return null;
-        } else {
-            ApplicationRoleEntity roleEntity = (ApplicationRoleEntity) entity;
-            if (!roleEntity.getApplication().getRealm().getId().equals(getId())) return null;
-        }
-        return new RoleAdapter(this, em, entity);
+        return session.getRoleById(id, this);
     }
 
     @Override
@@ -1080,147 +960,16 @@ public class RealmAdapter implements RealmModel {
         return role.getContainer().removeRole(role);
     }
 
-    @Override
-    public boolean hasRole(UserModel user, RoleModel role) {
-        Set<RoleModel> roles = getRoleMappings(user);
-        if (roles.contains(role)) return true;
-
-        for (RoleModel mapping : roles) {
-            if (mapping.hasRole(role)) return true;
-        }
-        return false;
-    }
-
-    @Override
-    public boolean hasScope(ClientModel client, RoleModel role) {
-        Set<RoleModel> roles = getScopeMappings(client);
-        if (roles.contains(role)) return true;
-
-        for (RoleModel mapping : roles) {
-            if (mapping.hasRole(role)) return true;
-        }
-        return false;
-    }
-
-
-    protected TypedQuery<UserRoleMappingEntity> getUserRoleMappingEntityTypedQuery(UserAdapter user, RoleAdapter role) {
-        TypedQuery<UserRoleMappingEntity> query = em.createNamedQuery("userHasRole", UserRoleMappingEntity.class);
-        query.setParameter("user", user.getUser());
-        query.setParameter("role", role.getRole());
-        return query;
-    }
-
-    @Override
-    public void grantRole(UserModel user, RoleModel role) {
-        if (hasRole(user, role)) return;
-        UserRoleMappingEntity entity = new UserRoleMappingEntity();
-        entity.setUser(((UserAdapter) user).getUser());
-        entity.setRole(((RoleAdapter) role).getRole());
-        em.persist(entity);
-        em.flush();
-    }
-
-    @Override
-    public Set<RoleModel> getRealmRoleMappings(UserModel user) {
-        Set<RoleModel> roleMappings = getRoleMappings(user);
-
-        Set<RoleModel> realmRoles = new HashSet<RoleModel>();
-        for (RoleModel role : roleMappings) {
-            RoleContainerModel container = role.getContainer();
-            if (container instanceof RealmModel) {
-                realmRoles.add(role);
-            }
-        }
-        return realmRoles;
-    }
-
 
-    @Override
-    public Set<RoleModel> getRoleMappings(UserModel user) {
-        TypedQuery<UserRoleMappingEntity> query = em.createNamedQuery("userRoleMappings", UserRoleMappingEntity.class);
-        query.setParameter("user", ((UserAdapter) user).getUser());
-        List<UserRoleMappingEntity> entities = query.getResultList();
-        Set<RoleModel> roles = new HashSet<RoleModel>();
-        for (UserRoleMappingEntity entity : entities) {
-            roles.add(new RoleAdapter(this, em, entity.getRole()));
-        }
-        return roles;
-    }
 
-    @Override
-    public void deleteRoleMapping(UserModel user, RoleModel role) {
-        if (user == null || role == null) return;
 
-        TypedQuery<UserRoleMappingEntity> query = getUserRoleMappingEntityTypedQuery((UserAdapter) user, (RoleAdapter) role);
-        List<UserRoleMappingEntity> results = query.getResultList();
-        if (results.size() == 0) return;
-        for (UserRoleMappingEntity entity : results) {
-            em.remove(entity);
-        }
-        em.flush();
-    }
-
-    @Override
-    public Set<RoleModel> getRealmScopeMappings(ClientModel client) {
-        Set<RoleModel> roleMappings = getScopeMappings(client);
-
-        Set<RoleModel> appRoles = new HashSet<RoleModel>();
-        for (RoleModel role : roleMappings) {
-            RoleContainerModel container = role.getContainer();
-            if (container instanceof RealmModel) {
-                if (((RealmModel) container).getId().equals(getId())) {
-                    appRoles.add(role);
-                }
-            }
-        }
-
-        return appRoles;
-    }
-
-
-    @Override
-    public Set<RoleModel> getScopeMappings(ClientModel client) {
-        TypedQuery<ScopeMappingEntity> query = em.createNamedQuery("clientScopeMappings", ScopeMappingEntity.class);
-        query.setParameter("client", ((ClientAdapter) client).getEntity());
-        List<ScopeMappingEntity> entities = query.getResultList();
-        Set<RoleModel> roles = new HashSet<RoleModel>();
-        for (ScopeMappingEntity entity : entities) {
-            roles.add(new RoleAdapter(this, em, entity.getRole()));
-        }
-        return roles;
-    }
-
-    @Override
-    public void addScopeMapping(ClientModel client, RoleModel role) {
-        if (hasScope(client, role)) return;
-        ScopeMappingEntity entity = new ScopeMappingEntity();
-        entity.setClient(((ClientAdapter) client).getEntity());
-        entity.setRole(((RoleAdapter) role).getRole());
-        em.persist(entity);
-    }
-
-    @Override
-    public void deleteScopeMapping(ClientModel client, RoleModel role) {
-        TypedQuery<ScopeMappingEntity> query = getRealmScopeMappingQuery((ClientAdapter) client, (RoleAdapter) role);
-        List<ScopeMappingEntity> results = query.getResultList();
-        if (results.size() == 0) return;
-        for (ScopeMappingEntity entity : results) {
-            em.remove(entity);
-        }
-    }
-
-    protected TypedQuery<ScopeMappingEntity> getRealmScopeMappingQuery(ClientAdapter client, RoleAdapter role) {
-        TypedQuery<ScopeMappingEntity> query = em.createNamedQuery("hasScope", ScopeMappingEntity.class);
-        query.setParameter("client", client.getEntity());
-        query.setParameter("role", ((RoleAdapter) role).getRole());
-        return query;
-    }
 
     @Override
     public boolean validatePassword(UserModel user, String password) {
-        for (CredentialEntity cred : ((UserAdapter) user).getUser().getCredentials()) {
+        for (UserCredentialValueModel cred : user.getCredentialsDirectly()) {
             if (cred.getType().equals(UserCredentialModel.PASSWORD)) {
                 return new Pbkdf2PasswordEncoder(cred.getSalt()).verify(password, cred.getValue());
+
             }
         }
         return false;
@@ -1229,7 +978,7 @@ public class RealmAdapter implements RealmModel {
     @Override
     public boolean validateTOTP(UserModel user, String password, String token) {
         if (!validatePassword(user, password)) return false;
-        for (CredentialEntity cred : ((UserAdapter) user).getUser().getCredentials()) {
+        for (UserCredentialValueModel cred : user.getCredentialsDirectly()) {
             if (cred.getType().equals(UserCredentialModel.TOTP)) {
                 return new TimeBasedOTP().validate(token, cred.getValue().getBytes());
             }
@@ -1238,81 +987,6 @@ public class RealmAdapter implements RealmModel {
     }
 
     @Override
-    public void updateCredential(UserModel user, UserCredentialModel cred) {
-        UserEntity userEntity = ((UserAdapter) user).getUser();
-        CredentialEntity credentialEntity = getCredentialEntity(userEntity, cred.getType());
-
-        if (credentialEntity == null) {
-            credentialEntity = new CredentialEntity();
-            credentialEntity.setType(cred.getType());
-            credentialEntity.setDevice(cred.getDevice());
-            credentialEntity.setUser(userEntity);
-            em.persist(credentialEntity);
-            userEntity.getCredentials().add(credentialEntity);
-        }
-        if (cred.getType().equals(UserCredentialModel.PASSWORD)) {
-            byte[] salt = getSalt();
-            credentialEntity.setValue(new Pbkdf2PasswordEncoder(salt).encode(cred.getValue()));
-            credentialEntity.setSalt(salt);
-        } else {
-            credentialEntity.setValue(cred.getValue());
-        }
-        credentialEntity.setDevice(cred.getDevice());
-        em.flush();
-    }
-
-    private CredentialEntity getCredentialEntity(UserEntity userEntity, String credType) {
-        for (CredentialEntity entity : userEntity.getCredentials()) {
-            if (entity.getType().equals(credType)) {
-                return entity;
-            }
-        }
-
-        return null;
-    }
-
-    @Override
-    public List<UserCredentialValueModel> getCredentialsDirectly(UserModel user) {
-        UserEntity userEntity = ((UserAdapter) user).getUser();
-        List<CredentialEntity> credentials = new ArrayList<CredentialEntity>(userEntity.getCredentials());
-        List<UserCredentialValueModel> result = new ArrayList<UserCredentialValueModel>();
-
-        if (credentials != null) {
-            for (CredentialEntity credEntity : credentials) {
-                UserCredentialValueModel credModel = new UserCredentialValueModel();
-                credModel.setType(credEntity.getType());
-                credModel.setDevice(credEntity.getDevice());
-                credModel.setValue(credEntity.getValue());
-                credModel.setSalt(credEntity.getSalt());
-
-                result.add(credModel);
-            }
-        }
-
-        return result;
-    }
-
-    @Override
-    public void updateCredentialDirectly(UserModel user, UserCredentialValueModel credModel) {
-        UserEntity userEntity = ((UserAdapter) user).getUser();
-        CredentialEntity credentialEntity = getCredentialEntity(userEntity, credModel.getType());
-
-        if (credentialEntity == null) {
-            credentialEntity = new CredentialEntity();
-            credentialEntity.setType(credModel.getType());
-            credentialEntity.setUser(userEntity);
-            em.persist(credentialEntity);
-            userEntity.getCredentials().add(credentialEntity);
-        }
-
-        credentialEntity.setValue(credModel.getValue());
-        credentialEntity.setSalt(credModel.getSalt());
-        credentialEntity.setDevice(credModel.getDevice());
-
-        em.flush();
-    }
-
-    @Override
     public PasswordPolicy getPasswordPolicy() {
         if (passwordPolicy == null) {
             passwordPolicy = new PasswordPolicy(realm.getPasswordPolicy());
@@ -1424,66 +1098,38 @@ public class RealmAdapter implements RealmModel {
 
     @Override
     public UserSessionModel createUserSession(UserModel user, String ipAddress) {
-        UserSessionEntity entity = new UserSessionEntity();
-        entity.setRealmId(realm.getId());
-        entity.setUserId(user.getId());
-        entity.setIpAddress(ipAddress);
-
-        int currentTime = Time.currentTime();
-
-        entity.setStarted(currentTime);
-        entity.setLastSessionRefresh(currentTime);
-
-        em.persist(entity);
-        return new UserSessionAdapter(em, this, entity);
+        return session.createUserSession(this, user, ipAddress);
     }
 
     @Override
     public UserSessionModel getUserSession(String id) {
-        UserSessionEntity entity = em.find(UserSessionEntity.class, id);
-        return entity != null ? new UserSessionAdapter(em, this, entity) : null;
+        return session.getUserSession(id, this);
     }
 
     @Override
     public List<UserSessionModel> getUserSessions(UserModel user) {
-        List<UserSessionModel> sessions = new LinkedList<UserSessionModel>();
-        for (UserSessionEntity e : em.createNamedQuery("getUserSessionByUser", UserSessionEntity.class).setParameter("userId", user.getId()).getResultList()) {
-            sessions.add(new UserSessionAdapter(em, this, e));
-        }
-        return sessions;
+        return session.getUserSessions(user, this);
     }
 
     @Override
     public void removeUserSession(UserSessionModel session) {
-        em.remove(((UserSessionAdapter) session).getEntity());
+        this.session.removeUserSession(session);
     }
 
     @Override
     public void removeUserSessions() {
-        em.createNamedQuery("removeClientUserSessionByRealm").setParameter("realmId", realm.getId()).executeUpdate();
-        em.createNamedQuery("removeRealmUserSessions").setParameter("realmId", realm.getId()).executeUpdate();
+        session.removeUserSessions(this);
 
     }
 
     @Override
     public void removeUserSessions(UserModel user) {
-        removeUserSessions(((UserAdapter) user).getUser());
-    }
-
-    private void removeUserSessions(UserEntity user) {
-        em.createNamedQuery("removeClientUserSessionByUser").setParameter("userId", user.getId()).executeUpdate();
-        em.createNamedQuery("removeUserSessionByUser").setParameter("userId", user.getId()).executeUpdate();
+        session.removeUserSessions(this, user);
     }
 
     @Override
     public void removeExpiredUserSessions() {
-        TypedQuery<UserSessionEntity> query = em.createNamedQuery("getUserSessionExpired", UserSessionEntity.class)
-                .setParameter("maxTime", Time.currentTime() - getSsoSessionMaxLifespan())
-                .setParameter("idleTime", Time.currentTime() - getSsoSessionIdleTimeout());
-        List<UserSessionEntity> results = query.getResultList();
-        for (UserSessionEntity entity : results) {
-            em.remove(entity);
-        }
+        session.removeExpiredUserSessions(this);
     }
 
 }
diff --git a/model/jpa/src/main/java/org/keycloak/models/jpa/RoleAdapter.java b/model/jpa/src/main/java/org/keycloak/models/jpa/RoleAdapter.java
index 421cffa..c947c8f 100755
--- a/model/jpa/src/main/java/org/keycloak/models/jpa/RoleAdapter.java
+++ b/model/jpa/src/main/java/org/keycloak/models/jpa/RoleAdapter.java
@@ -3,8 +3,6 @@ package org.keycloak.models.jpa;
 import org.keycloak.models.RealmModel;
 import org.keycloak.models.RoleContainerModel;
 import org.keycloak.models.RoleModel;
-import org.keycloak.models.jpa.entities.ApplicationRoleEntity;
-import org.keycloak.models.jpa.entities.RealmRoleEntity;
 import org.keycloak.models.jpa.entities.RoleEntity;
 import org.keycloak.models.utils.KeycloakModelUtils;
 
@@ -106,15 +104,12 @@ public class RoleAdapter implements RoleModel {
 
     @Override
     public RoleContainerModel getContainer() {
-        if (role instanceof ApplicationRoleEntity) {
-            ApplicationRoleEntity entity = (ApplicationRoleEntity)role;
-            return new ApplicationAdapter(realm, em, entity.getApplication());
-        } else if (role instanceof RealmRoleEntity) {
-            RealmRoleEntity entity = (RealmRoleEntity)role;
-            return new RealmAdapter(em, entity.getRealm());
+        if (role.isApplicationRole()) {
+            return realm.getApplicationById(role.getApplication().getId());
 
+        } else {
+            return realm;
         }
-        throw new IllegalStateException("Unknown role entity type");
     }
 
     @Override
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 9857062..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,13 +1,31 @@
 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;
+import org.keycloak.models.jpa.entities.UserRoleMappingEntity;
+import org.keycloak.models.utils.Pbkdf2PasswordEncoder;
 
+import javax.persistence.EntityManager;
+import javax.persistence.TypedQuery;
+import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.HashSet;
+import java.util.List;
 import java.util.Map;
 import java.util.Set;
 
+import static org.keycloak.models.utils.Pbkdf2PasswordEncoder.getSalt;
+
 /**
  * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
  * @version $Revision: 1 $
@@ -15,9 +33,13 @@ import java.util.Set;
 public class UserAdapter implements UserModel {
 
     protected UserEntity user;
+    protected EntityManager em;
+    protected RealmModel realm;
 
-    public UserAdapter(UserEntity user) {
+    public UserAdapter(RealmModel realm, EntityManager em, UserEntity user) {
+        this.em = em;
         this.user = user;
+        this.realm = realm;
     }
 
     public UserEntity getUser() {
@@ -160,6 +182,182 @@ public class UserAdapter implements UserModel {
         user.setNotBefore(notBefore);
     }
 
+    @Override
+    public void updateCredential(UserCredentialModel cred) {
+        CredentialEntity credentialEntity = getCredentialEntity(user, cred.getType());
+
+        if (credentialEntity == null) {
+            credentialEntity = new CredentialEntity();
+            credentialEntity.setType(cred.getType());
+            credentialEntity.setDevice(cred.getDevice());
+            credentialEntity.setUser(user);
+            em.persist(credentialEntity);
+            user.getCredentials().add(credentialEntity);
+        }
+        if (cred.getType().equals(UserCredentialModel.PASSWORD)) {
+            byte[] salt = getSalt();
+            credentialEntity.setValue(new Pbkdf2PasswordEncoder(salt).encode(cred.getValue()));
+            credentialEntity.setSalt(salt);
+        } else {
+            credentialEntity.setValue(cred.getValue());
+        }
+        credentialEntity.setDevice(cred.getDevice());
+        em.flush();
+    }
+
+    private CredentialEntity getCredentialEntity(UserEntity userEntity, String credType) {
+        for (CredentialEntity entity : userEntity.getCredentials()) {
+            if (entity.getType().equals(credType)) {
+                return entity;
+            }
+        }
+
+        return null;
+    }
+
+    @Override
+    public List<UserCredentialValueModel> getCredentialsDirectly() {
+        List<CredentialEntity> credentials = new ArrayList<CredentialEntity>(user.getCredentials());
+        List<UserCredentialValueModel> result = new ArrayList<UserCredentialValueModel>();
+
+        if (credentials != null) {
+            for (CredentialEntity credEntity : credentials) {
+                UserCredentialValueModel credModel = new UserCredentialValueModel();
+                credModel.setType(credEntity.getType());
+                credModel.setDevice(credEntity.getDevice());
+                credModel.setValue(credEntity.getValue());
+                credModel.setSalt(credEntity.getSalt());
+
+                result.add(credModel);
+            }
+        }
+
+        return result;
+    }
+
+    @Override
+    public void updateCredentialDirectly(UserCredentialValueModel credModel) {
+        CredentialEntity credentialEntity = getCredentialEntity(user, credModel.getType());
+
+        if (credentialEntity == null) {
+            credentialEntity = new CredentialEntity();
+            credentialEntity.setType(credModel.getType());
+            credentialEntity.setUser(user);
+            em.persist(credentialEntity);
+            user.getCredentials().add(credentialEntity);
+        }
+
+        credentialEntity.setValue(credModel.getValue());
+        credentialEntity.setSalt(credModel.getSalt());
+        credentialEntity.setDevice(credModel.getDevice());
+
+        em.flush();
+    }
+
+    @Override
+    public boolean hasRole(RoleModel role) {
+        Set<RoleModel> roles = getRoleMappings();
+        if (roles.contains(role)) return true;
+
+        for (RoleModel mapping : roles) {
+            if (mapping.hasRole(role)) return true;
+        }
+        return false;
+    }
+
+    protected TypedQuery<UserRoleMappingEntity> getUserRoleMappingEntityTypedQuery(RoleModel role) {
+        TypedQuery<UserRoleMappingEntity> query = em.createNamedQuery("userHasRole", UserRoleMappingEntity.class);
+        query.setParameter("user", getUser());
+        RoleEntity roleEntity = em.getReference(RoleEntity.class, role.getId());
+        query.setParameter("role", roleEntity);
+        return query;
+    }
+
+    @Override
+    public void grantRole(RoleModel role) {
+        if (hasRole(role)) return;
+        UserRoleMappingEntity entity = new UserRoleMappingEntity();
+        entity.setUser(getUser());
+        RoleEntity roleEntity = em.getReference(RoleEntity.class, role.getId());
+        entity.setRole(roleEntity);
+        em.persist(entity);
+        em.flush();
+    }
+
+    @Override
+    public Set<RoleModel> getRealmRoleMappings() {
+        Set<RoleModel> roleMappings = getRoleMappings();
+
+        Set<RoleModel> realmRoles = new HashSet<RoleModel>();
+        for (RoleModel role : roleMappings) {
+            RoleContainerModel container = role.getContainer();
+            if (container instanceof RealmModel) {
+                realmRoles.add(role);
+            }
+        }
+        return realmRoles;
+    }
+
+
+    @Override
+    public Set<RoleModel> getRoleMappings() {
+        TypedQuery<UserRoleMappingEntity> query = em.createNamedQuery("userRoleMappings", UserRoleMappingEntity.class);
+        query.setParameter("user", getUser());
+        List<UserRoleMappingEntity> entities = query.getResultList();
+        Set<RoleModel> roles = new HashSet<RoleModel>();
+        for (UserRoleMappingEntity entity : entities) {
+            roles.add(realm.getRoleById(entity.getRole().getId()));
+        }
+        return roles;
+    }
+
+    @Override
+    public void deleteRoleMapping(RoleModel role) {
+        if (user == null || role == null) return;
+
+        TypedQuery<UserRoleMappingEntity> query = getUserRoleMappingEntityTypedQuery(role);
+        List<UserRoleMappingEntity> results = query.getResultList();
+        if (results.size() == 0) return;
+        for (UserRoleMappingEntity entity : results) {
+            em.remove(entity);
+        }
+        em.flush();
+    }
+
+    @Override
+    public Set<RoleModel> getApplicationRoleMappings(ApplicationModel app) {
+        Set<RoleModel> roleMappings = getRoleMappings();
+
+        Set<RoleModel> roles = new HashSet<RoleModel>();
+        for (RoleModel role : roleMappings) {
+            RoleContainerModel container = role.getContainer();
+            if (container instanceof ApplicationModel) {
+                ApplicationModel appModel = (ApplicationModel)container;
+                if (appModel.getId().equals(app.getId())) {
+                   roles.add(role);
+                }
+            }
+        }
+        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/jpa/src/test/resources/META-INF/persistence.xml b/model/jpa/src/test/resources/META-INF/persistence.xml
index c79ddab..a150d05 100755
--- a/model/jpa/src/test/resources/META-INF/persistence.xml
+++ b/model/jpa/src/test/resources/META-INF/persistence.xml
@@ -11,8 +11,7 @@
         <class>org.keycloak.models.jpa.entities.RealmEntity</class>
         <class>org.keycloak.models.jpa.entities.RequiredCredentialEntity</class>
         <class>org.keycloak.models.jpa.entities.AuthenticationProviderEntity</class>
-        <class>org.keycloak.models.jpa.entities.ApplicationRoleEntity</class>
-        <class>org.keycloak.models.jpa.entities.RealmRoleEntity</class>
+        <class>org.keycloak.models.jpa.entities.RoleEntity</class>
         <class>org.keycloak.models.jpa.entities.SocialLinkEntity</class>
         <class>org.keycloak.models.jpa.entities.AuthenticationLinkEntity</class>
         <class>org.keycloak.models.jpa.entities.UserEntity</class>
diff --git a/model/mongo/src/main/java/org/keycloak/models/mongo/keycloak/adapters/ApplicationAdapter.java b/model/mongo/src/main/java/org/keycloak/models/mongo/keycloak/adapters/ApplicationAdapter.java
index 68a2d72..9569b3d 100755
--- a/model/mongo/src/main/java/org/keycloak/models/mongo/keycloak/adapters/ApplicationAdapter.java
+++ b/model/mongo/src/main/java/org/keycloak/models/mongo/keycloak/adapters/ApplicationAdapter.java
@@ -4,6 +4,7 @@ import com.mongodb.DBObject;
 import com.mongodb.QueryBuilder;
 import org.keycloak.models.ApplicationModel;
 import org.keycloak.models.ClientModel;
+import org.keycloak.models.KeycloakSession;
 import org.keycloak.models.RealmModel;
 import org.keycloak.models.RoleModel;
 import org.keycloak.models.UserModel;
@@ -22,8 +23,8 @@ import java.util.Set;
  */
 public class ApplicationAdapter extends ClientAdapter<MongoApplicationEntity> implements ApplicationModel {
 
-    public ApplicationAdapter(RealmAdapter realm, MongoApplicationEntity applicationEntity, MongoStoreInvocationContext invContext) {
-        super(realm, applicationEntity, invContext);
+    public ApplicationAdapter(KeycloakSession session, RealmModel realm, MongoApplicationEntity applicationEntity, MongoStoreInvocationContext invContext) {
+        super(session, realm, applicationEntity, invContext);
     }
 
     @Override
@@ -118,7 +119,7 @@ public class ApplicationAdapter extends ClientAdapter<MongoApplicationEntity> im
         if (role == null) {
             return null;
         } else {
-            return new RoleAdapter(getRealm(), role, invocationContext);
+            return new RoleAdapter(session, getRealm(), role, invocationContext);
         }
     }
 
@@ -136,7 +137,7 @@ public class ApplicationAdapter extends ClientAdapter<MongoApplicationEntity> im
 
         getMongoStore().insertEntity(roleEntity, invocationContext);
 
-        return new RoleAdapter(getRealm(), roleEntity, this, invocationContext);
+        return new RoleAdapter(session, getRealm(), roleEntity, this, invocationContext);
     }
 
     @Override
@@ -153,33 +154,20 @@ public class ApplicationAdapter extends ClientAdapter<MongoApplicationEntity> im
 
         Set<RoleModel> result = new HashSet<RoleModel>();
         for (MongoRoleEntity role : roles) {
-            result.add(new RoleAdapter(getRealm(), role, this, invocationContext));
+            result.add(new RoleAdapter(session, getRealm(), role, this, invocationContext));
         }
 
         return result;
     }
 
     @Override
-    public Set<RoleModel> getApplicationRoleMappings(UserModel user) {
-        Set<RoleModel> result = new HashSet<RoleModel>();
-        List<MongoRoleEntity> roles = MongoModelUtils.getAllRolesOfUser(user, invocationContext);
-
-        for (MongoRoleEntity role : roles) {
-            if (getId().equals(role.getApplicationId())) {
-                result.add(new RoleAdapter(getRealm(), role, this, invocationContext));
-            }
-        }
-        return result;
-    }
-
-    @Override
     public Set<RoleModel> getApplicationScopeMappings(ClientModel client) {
         Set<RoleModel> result = new HashSet<RoleModel>();
         List<MongoRoleEntity> roles = MongoModelUtils.getAllScopesOfClient(client, invocationContext);
 
         for (MongoRoleEntity role : roles) {
             if (getId().equals(role.getApplicationId())) {
-                result.add(new RoleAdapter(getRealm(), role, this, invocationContext));
+                result.add(new RoleAdapter(session, getRealm(), role, this, invocationContext));
             }
         }
         return result;
diff --git a/model/mongo/src/main/java/org/keycloak/models/mongo/keycloak/adapters/ClientAdapter.java b/model/mongo/src/main/java/org/keycloak/models/mongo/keycloak/adapters/ClientAdapter.java
index 9cde3e3..614204b 100755
--- a/model/mongo/src/main/java/org/keycloak/models/mongo/keycloak/adapters/ClientAdapter.java
+++ b/model/mongo/src/main/java/org/keycloak/models/mongo/keycloak/adapters/ClientAdapter.java
@@ -8,12 +8,16 @@ import java.util.Set;
 import com.mongodb.DBObject;
 import com.mongodb.QueryBuilder;
 import org.keycloak.models.ClientModel;
+import org.keycloak.models.KeycloakSession;
 import org.keycloak.models.RealmModel;
+import org.keycloak.models.RoleModel;
 import org.keycloak.models.UserSessionModel;
 import org.keycloak.models.entities.ClientEntity;
 import org.keycloak.models.mongo.api.MongoIdentifiableEntity;
 import org.keycloak.models.mongo.api.context.MongoStoreInvocationContext;
+import org.keycloak.models.mongo.keycloak.entities.MongoRoleEntity;
 import org.keycloak.models.mongo.keycloak.entities.MongoUserSessionEntity;
+import org.keycloak.models.mongo.utils.MongoModelUtils;
 
 /**
  * @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
@@ -21,12 +25,14 @@ import org.keycloak.models.mongo.keycloak.entities.MongoUserSessionEntity;
 public abstract class ClientAdapter<T extends MongoIdentifiableEntity> extends AbstractMongoAdapter<T> implements ClientModel {
 
     protected final T clientEntity;
-    private final RealmAdapter realm;
+    private final RealmModel realm;
+    protected  KeycloakSession session;
 
-    public ClientAdapter(RealmAdapter realm, T clientEntity, MongoStoreInvocationContext invContext) {
+    public ClientAdapter(KeycloakSession session, RealmModel realm, T clientEntity, MongoStoreInvocationContext invContext) {
         super(invContext);
         this.clientEntity = clientEntity;
         this.realm = realm;
+        this.session = session;
     }
 
     @Override
@@ -153,7 +159,7 @@ public abstract class ClientAdapter<T extends MongoIdentifiableEntity> extends A
     }
 
     @Override
-    public RealmAdapter getRealm() {
+    public RealmModel getRealm() {
         return realm;
     }
 
@@ -170,22 +176,66 @@ public abstract class ClientAdapter<T extends MongoIdentifiableEntity> extends A
 
     @Override
     public Set<UserSessionModel> getUserSessions() {
-        DBObject query = new QueryBuilder()
-                .and("associatedClientIds").is(getId())
-                .get();
-        List<MongoUserSessionEntity> sessions = getMongoStore().loadEntities(MongoUserSessionEntity.class, query, invocationContext);
-
-        Set<UserSessionModel> result = new HashSet<UserSessionModel>();
-        for (MongoUserSessionEntity session : sessions) {
-            result.add(new UserSessionAdapter(session, realm, invocationContext));
+        return session.getUserSessions(realm, this);
+    }
+
+    @Override
+    public int getActiveUserSessions() {
+        return session.getActiveUserSessions(realm, this);
+    }
+
+    @Override
+    public Set<RoleModel> getScopeMappings() {
+        Set<RoleModel> result = new HashSet<RoleModel>();
+        List<MongoRoleEntity> roles = MongoModelUtils.getAllScopesOfClient(this, invocationContext);
+
+        for (MongoRoleEntity role : roles) {
+            if (realm.getId().equals(role.getRealmId())) {
+                result.add(new RoleAdapter(session, realm, role, realm, invocationContext));
+            } else {
+                // Likely applicationRole, but we don't have this application yet
+                result.add(new RoleAdapter(session, realm, role, invocationContext));
+            }
         }
         return result;
+    }
+
+    @Override
+    public Set<RoleModel> getRealmScopeMappings() {
+        Set<RoleModel> allScopes = getScopeMappings();
+
+        // Filter to retrieve just realm roles TODO: Maybe improve to avoid filter programmatically... Maybe have separate fields for realmRoles and appRoles on user?
+        Set<RoleModel> realmRoles = new HashSet<RoleModel>();
+        for (RoleModel role : allScopes) {
+            MongoRoleEntity roleEntity = ((RoleAdapter) role).getRole();
 
+            if (realm.getId().equals(roleEntity.getRealmId())) {
+                realmRoles.add(role);
+            }
+        }
+        return realmRoles;
     }
 
     @Override
-    public int getActiveUserSessions() {
-        // todo, something more efficient like COUNT in JPAQL?
-        return getUserSessions().size();
+    public boolean hasScope(RoleModel role) {
+        Set<RoleModel> roles = getScopeMappings();
+        if (roles.contains(role)) return true;
+
+        for (RoleModel mapping : roles) {
+            if (mapping.hasRole(role)) return true;
+        }
+        return false;
+    }
+
+
+    @Override
+    public void addScopeMapping(RoleModel role) {
+        getMongoStore().pushItemToList(this.getMongoEntity(), "scopeIds", role.getId(), true, invocationContext);
+    }
+
+    @Override
+    public void deleteScopeMapping(RoleModel role) {
+        getMongoStore().pullItemFromList(this.getMongoEntity(), "scopeIds", role.getId(), invocationContext);
     }
+
 }
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 0c13eb9..018e4e6 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
@@ -3,17 +3,40 @@ package org.keycloak.models.mongo.keycloak.adapters;
 import com.mongodb.BasicDBObject;
 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;
 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.entities.SocialLinkEntity;
 import org.keycloak.models.mongo.api.MongoStore;
 import org.keycloak.models.mongo.api.context.MongoStoreInvocationContext;
 import org.keycloak.models.mongo.impl.context.TransactionMongoStoreInvocationContext;
+import org.keycloak.models.mongo.keycloak.entities.MongoApplicationEntity;
+import org.keycloak.models.mongo.keycloak.entities.MongoOAuthClientEntity;
 import org.keycloak.models.mongo.keycloak.entities.MongoRealmEntity;
+import org.keycloak.models.mongo.keycloak.entities.MongoRoleEntity;
+import org.keycloak.models.mongo.keycloak.entities.MongoUserEntity;
+import org.keycloak.models.mongo.keycloak.entities.MongoUserSessionEntity;
+import org.keycloak.models.mongo.keycloak.entities.MongoUsernameLoginFailureEntity;
 import org.keycloak.models.utils.KeycloakModelUtils;
+import org.keycloak.util.Time;
 
 import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.LinkedList;
 import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.regex.Pattern;
 
 /**
  * @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
@@ -57,13 +80,13 @@ public class MongoKeycloakSession implements KeycloakSession {
 
         getMongoStore().insertEntity(newRealm, invocationContext);
 
-        return new RealmAdapter(newRealm, invocationContext);
+        return new RealmAdapter(this, newRealm, invocationContext);
     }
 
     @Override
     public RealmModel getRealm(String id) {
         MongoRealmEntity realmEntity = getMongoStore().loadEntity(MongoRealmEntity.class, id, invocationContext);
-        return realmEntity != null ? new RealmAdapter(realmEntity, invocationContext) : null;
+        return realmEntity != null ? new RealmAdapter(this, realmEntity, invocationContext) : null;
     }
 
     @Override
@@ -73,7 +96,7 @@ public class MongoKeycloakSession implements KeycloakSession {
 
         List<RealmModel> results = new ArrayList<RealmModel>();
         for (MongoRealmEntity realmEntity : realms) {
-            results.add(new RealmAdapter(realmEntity, invocationContext));
+            results.add(new RealmAdapter(this, realmEntity, invocationContext));
         }
         return results;
     }
@@ -86,7 +109,49 @@ public class MongoKeycloakSession implements KeycloakSession {
         MongoRealmEntity realm = getMongoStore().loadSingleEntity(MongoRealmEntity.class, query, invocationContext);
 
         if (realm == null) return null;
-        return new RealmAdapter(realm, invocationContext);
+        return new RealmAdapter(this, realm, invocationContext);
+    }
+
+    @Override
+    public UserModel getUserById(String id, RealmModel realm) {
+        MongoUserEntity user = getMongoStore().loadEntity(MongoUserEntity.class, id, invocationContext);
+
+        // Check that it's user from this realm
+        if (user == null || !realm.getId().equals(user.getRealmId())) {
+            return null;
+        } else {
+            return new UserAdapter(this, realm, user, invocationContext);
+        }
+    }
+
+    @Override
+    public UserModel getUserByUsername(String username, RealmModel realm) {
+        DBObject query = new QueryBuilder()
+                .and("loginName").is(username)
+                .and("realmId").is(realm.getId())
+                .get();
+        MongoUserEntity user = getMongoStore().loadSingleEntity(MongoUserEntity.class, query, invocationContext);
+
+        if (user == null) {
+            return null;
+        } else {
+            return new UserAdapter(this, realm, user, invocationContext);
+        }
+    }
+
+    @Override
+    public UserModel getUserByEmail(String email, RealmModel realm) {
+        DBObject query = new QueryBuilder()
+                .and("email").is(email)
+                .and("realmId").is(realm.getId())
+                .get();
+        MongoUserEntity user = getMongoStore().loadSingleEntity(MongoUserEntity.class, query, invocationContext);
+
+        if (user == null) {
+            return null;
+        } else {
+            return new UserAdapter(this, realm, user, invocationContext);
+        }
     }
 
     @Override
@@ -97,4 +162,299 @@ public class MongoKeycloakSession implements KeycloakSession {
     protected MongoStore getMongoStore() {
         return invocationContext.getMongoStore();
     }
+
+    @Override
+    public UserModel getUserBySocialLink(SocialLinkModel socialLink, RealmModel realm) {
+        DBObject query = new QueryBuilder()
+                .and("socialLinks.socialProvider").is(socialLink.getSocialProvider())
+                .and("socialLinks.socialUserId").is(socialLink.getSocialUserId())
+                .and("realmId").is(realm.getId())
+                .get();
+        MongoUserEntity userEntity = getMongoStore().loadSingleEntity(MongoUserEntity.class, query, invocationContext);
+        return userEntity == null ? null : new UserAdapter(this, realm, userEntity, invocationContext);
+    }
+
+    protected List<UserModel> convertUserEntities(RealmModel realm, List<MongoUserEntity> userEntities) {
+        List<UserModel> userModels = new ArrayList<UserModel>();
+        for (MongoUserEntity user : userEntities) {
+            userModels.add(new UserAdapter(this, realm, user, invocationContext));
+        }
+        return userModels;
+    }
+
+
+    @Override
+    public List<UserModel> getUsers(RealmModel realm) {
+        DBObject query = new QueryBuilder()
+                .and("realmId").is(realm.getId())
+                .get();
+        List<MongoUserEntity> users = getMongoStore().loadEntities(MongoUserEntity.class, query, invocationContext);
+        return convertUserEntities(realm, users);
+    }
+
+    @Override
+    public List<UserModel> searchForUser(String search, RealmModel realm) {
+        search = search.trim();
+        Pattern caseInsensitivePattern = Pattern.compile("(?i:" + search + ")");
+
+        QueryBuilder nameBuilder;
+        int spaceInd = search.lastIndexOf(" ");
+
+        // Case when we have search string like "ohn Bow". Then firstName must end with "ohn" AND lastName must start with "bow" (everything case-insensitive)
+        if (spaceInd != -1) {
+            String firstName = search.substring(0, spaceInd);
+            String lastName = search.substring(spaceInd + 1);
+            Pattern firstNamePattern = Pattern.compile("(?i:" + firstName + "$)");
+            Pattern lastNamePattern = Pattern.compile("(?i:^" + lastName + ")");
+            nameBuilder = new QueryBuilder().and(
+                    new QueryBuilder().put("firstName").regex(firstNamePattern).get(),
+                    new QueryBuilder().put("lastName").regex(lastNamePattern).get()
+            );
+        } else {
+            // Case when we have search without spaces like "foo". The firstName OR lastName could be "foo" (everything case-insensitive)
+            nameBuilder = new QueryBuilder().or(
+                    new QueryBuilder().put("firstName").regex(caseInsensitivePattern).get(),
+                    new QueryBuilder().put("lastName").regex(caseInsensitivePattern).get()
+            );
+        }
+
+        QueryBuilder builder = new QueryBuilder().and(
+                new QueryBuilder().and("realmId").is(realm.getId()).get(),
+                new QueryBuilder().or(
+                        new QueryBuilder().put("loginName").regex(caseInsensitivePattern).get(),
+                        new QueryBuilder().put("email").regex(caseInsensitivePattern).get(),
+                        nameBuilder.get()
+
+                ).get()
+        );
+
+        List<MongoUserEntity> users = getMongoStore().loadEntities(MongoUserEntity.class, builder.get(), invocationContext);
+        return convertUserEntities(realm, users);    }
+
+    @Override
+    public List<UserModel> searchForUserByAttributes(Map<String, String> attributes, RealmModel realm) {
+        QueryBuilder queryBuilder = new QueryBuilder()
+                .and("realmId").is(realm.getId());
+
+        for (Map.Entry<String, String> entry : attributes.entrySet()) {
+            if (entry.getKey().equals(UserModel.LOGIN_NAME)) {
+                queryBuilder.and("loginName").regex(Pattern.compile("(?i:" + entry.getValue() + "$)"));
+            } else if (entry.getKey().equalsIgnoreCase(UserModel.FIRST_NAME)) {
+                queryBuilder.and(UserModel.FIRST_NAME).regex(Pattern.compile("(?i:" + entry.getValue() + "$)"));
+
+            } else if (entry.getKey().equalsIgnoreCase(UserModel.LAST_NAME)) {
+                queryBuilder.and(UserModel.LAST_NAME).regex(Pattern.compile("(?i:" + entry.getValue() + "$)"));
+
+            } else if (entry.getKey().equalsIgnoreCase(UserModel.EMAIL)) {
+                queryBuilder.and(UserModel.EMAIL).regex(Pattern.compile("(?i:" + entry.getValue() + "$)"));
+            }
+        }
+        List<MongoUserEntity> users = getMongoStore().loadEntities(MongoUserEntity.class, queryBuilder.get(), invocationContext);
+        return convertUserEntities(realm, users);
+    }
+
+    @Override
+    public Set<SocialLinkModel> getSocialLinks(UserModel user, RealmModel realm) {
+        MongoUserEntity userEntity = ((UserAdapter) user).getUser();
+        List<SocialLinkEntity> linkEntities = userEntity.getSocialLinks();
+
+        if (linkEntities == null) {
+            return Collections.EMPTY_SET;
+        }
+
+        Set<SocialLinkModel> result = new HashSet<SocialLinkModel>();
+        for (SocialLinkEntity socialLinkEntity : linkEntities) {
+            SocialLinkModel model = new SocialLinkModel(socialLinkEntity.getSocialProvider(),
+                    socialLinkEntity.getSocialUserId(), socialLinkEntity.getSocialUsername());
+            result.add(model);
+        }
+        return result;
+    }
+
+    private SocialLinkEntity findSocialLink(UserModel user, String socialProvider) {
+        MongoUserEntity userEntity = ((UserAdapter) user).getUser();
+        List<SocialLinkEntity> linkEntities = userEntity.getSocialLinks();
+        if (linkEntities == null) {
+            return null;
+        }
+
+        for (SocialLinkEntity socialLinkEntity : linkEntities) {
+            if (socialLinkEntity.getSocialProvider().equals(socialProvider)) {
+                return socialLinkEntity;
+            }
+        }
+        return null;
+    }
+
+
+    @Override
+    public SocialLinkModel getSocialLink(UserModel user, String socialProvider, RealmModel realm) {
+        SocialLinkEntity socialLinkEntity = findSocialLink(user, socialProvider);
+        return socialLinkEntity != null ? new SocialLinkModel(socialLinkEntity.getSocialProvider(), socialLinkEntity.getSocialUserId(), socialLinkEntity.getSocialUsername()) : null;
+    }
+
+    @Override
+    public RoleModel getRoleById(String id, RealmModel realm) {
+        MongoRoleEntity role = getMongoStore().loadEntity(MongoRoleEntity.class, id, invocationContext);
+        if (role == null) return null;
+        if (role.getRealmId() != null && !role.getRealmId().equals(realm.getId())) return null;
+        if (role.getApplicationId() != null && realm.getApplicationById(role.getApplicationId()) == null) return null;
+        return new RoleAdapter(this, realm, role, null, invocationContext);
+    }
+
+    @Override
+    public ApplicationModel getApplicationById(String id, RealmModel realm) {
+        MongoApplicationEntity appData = getMongoStore().loadEntity(MongoApplicationEntity.class, id, invocationContext);
+
+        // Check if application belongs to this realm
+        if (appData == null || !realm.getId().equals(appData.getRealmId())) {
+            return null;
+        }
+
+        return new ApplicationAdapter(this, realm, appData, invocationContext);
+    }
+
+    @Override
+    public OAuthClientModel getOAuthClientById(String id, RealmModel realm) {
+        MongoOAuthClientEntity clientEntity = getMongoStore().loadEntity(MongoOAuthClientEntity.class, id, invocationContext);
+
+        // Check if client belongs to this realm
+        if (clientEntity == null || !realm.getId().equals(clientEntity.getRealmId())) return null;
+
+        return new OAuthClientAdapter(this, realm, clientEntity, invocationContext);
+    }
+
+    @Override
+    public UsernameLoginFailureModel getUserLoginFailure(String username, RealmModel realm) {
+        DBObject query = new QueryBuilder()
+                .and("username").is(username)
+                .and("realmId").is(realm.getId())
+                .get();
+        MongoUsernameLoginFailureEntity user = getMongoStore().loadSingleEntity(MongoUsernameLoginFailureEntity.class, query, invocationContext);
+
+        if (user == null) {
+            return null;
+        } else {
+            return new UsernameLoginFailureAdapter(invocationContext, user);
+        }
+    }
+
+    @Override
+    public UsernameLoginFailureModel addUserLoginFailure(String username, RealmModel realm) {
+        UsernameLoginFailureModel userLoginFailure = getUserLoginFailure(username, realm);
+        if (userLoginFailure != null) {
+            return userLoginFailure;
+        }
+
+        MongoUsernameLoginFailureEntity userEntity = new MongoUsernameLoginFailureEntity();
+        userEntity.setUsername(username);
+        userEntity.setRealmId(realm.getId());
+
+        getMongoStore().insertEntity(userEntity, invocationContext);
+        return new UsernameLoginFailureAdapter(invocationContext, userEntity);
+    }
+
+    @Override
+    public List<UsernameLoginFailureModel> getAllUserLoginFailures(RealmModel realm) {
+        DBObject query = new QueryBuilder()
+                .and("realmId").is(realm.getId())
+                .get();
+        List<MongoUsernameLoginFailureEntity> failures = getMongoStore().loadEntities(MongoUsernameLoginFailureEntity.class, query, invocationContext);
+
+        List<UsernameLoginFailureModel> result = new ArrayList<UsernameLoginFailureModel>();
+
+        if (failures == null) return result;
+        for (MongoUsernameLoginFailureEntity failure : failures) {
+            result.add(new UsernameLoginFailureAdapter(invocationContext, failure));
+        }
+
+        return result;
+    }
+
+    @Override
+    public UserSessionModel createUserSession(RealmModel realm, UserModel user, String ipAddress) {
+        MongoUserSessionEntity entity = new MongoUserSessionEntity();
+        entity.setRealmId(realm.getId());
+        entity.setUser(user.getId());
+        entity.setIpAddress(ipAddress);
+
+        int currentTime = Time.currentTime();
+
+        entity.setStarted(currentTime);
+        entity.setLastSessionRefresh(currentTime);
+
+        getMongoStore().insertEntity(entity, invocationContext);
+        return new UserSessionAdapter(entity, realm, invocationContext);
+    }
+
+    @Override
+    public UserSessionModel getUserSession(String id, RealmModel realm) {
+        MongoUserSessionEntity entity = getMongoStore().loadEntity(MongoUserSessionEntity.class, id, invocationContext);
+        if (entity == null) {
+            return null;
+        } else {
+            return new UserSessionAdapter(entity, realm, invocationContext);
+        }
+    }
+
+    @Override
+    public List<UserSessionModel> getUserSessions(UserModel user, RealmModel realm) {
+        DBObject query = new BasicDBObject("user", user.getId());
+        List<UserSessionModel> sessions = new LinkedList<UserSessionModel>();
+        for (MongoUserSessionEntity e : getMongoStore().loadEntities(MongoUserSessionEntity.class, query, invocationContext)) {
+            sessions.add(new UserSessionAdapter(e, realm, invocationContext));
+        }
+        return sessions;
+    }
+
+    @Override
+    public Set<UserSessionModel> getUserSessions(RealmModel realm, ClientModel client) {
+        DBObject query = new QueryBuilder()
+                .and("associatedClientIds").is(client.getId())
+                .get();
+        List<MongoUserSessionEntity> sessions = getMongoStore().loadEntities(MongoUserSessionEntity.class, query, invocationContext);
+
+        Set<UserSessionModel> result = new HashSet<UserSessionModel>();
+        for (MongoUserSessionEntity session : sessions) {
+            result.add(new UserSessionAdapter(session, realm, invocationContext));
+        }
+        return result;
+    }
+
+    @Override
+    public int getActiveUserSessions(RealmModel realm, ClientModel client) {
+        return getUserSessions(realm, client).size();
+    }
+
+    @Override
+    public void removeUserSession(UserSessionModel session) {
+        getMongoStore().removeEntity(((UserSessionAdapter) session).getMongoEntity(), invocationContext);
+    }
+
+    @Override
+    public void removeUserSessions(RealmModel realm, UserModel user) {
+        DBObject query = new BasicDBObject("user", user.getId());
+        getMongoStore().removeEntities(MongoUserSessionEntity.class, query, invocationContext);
+    }
+
+    @Override
+    public void removeUserSessions(RealmModel realm) {
+        DBObject query = new BasicDBObject("realmId", realm.getId());
+        getMongoStore().removeEntities(MongoUserSessionEntity.class, query, invocationContext);
+    }
+
+    @Override
+    public void removeExpiredUserSessions(RealmModel realm) {
+        int currentTime = Time.currentTime();
+        DBObject query = new QueryBuilder()
+                .and("started").lessThan(currentTime - realm.getSsoSessionMaxLifespan())
+                .get();
+
+        getMongoStore().removeEntities(MongoUserSessionEntity.class, query, invocationContext);
+        query = new QueryBuilder()
+                .and("lastSessionRefresh").lessThan(currentTime - realm.getSsoSessionIdleTimeout())
+                .get();
+
+        getMongoStore().removeEntities(MongoUserSessionEntity.class, query, invocationContext);
+    }
 }
diff --git a/model/mongo/src/main/java/org/keycloak/models/mongo/keycloak/adapters/OAuthClientAdapter.java b/model/mongo/src/main/java/org/keycloak/models/mongo/keycloak/adapters/OAuthClientAdapter.java
index 11d5670..c008aaa 100755
--- a/model/mongo/src/main/java/org/keycloak/models/mongo/keycloak/adapters/OAuthClientAdapter.java
+++ b/model/mongo/src/main/java/org/keycloak/models/mongo/keycloak/adapters/OAuthClientAdapter.java
@@ -1,5 +1,6 @@
 package org.keycloak.models.mongo.keycloak.adapters;
 
+import org.keycloak.models.KeycloakSession;
 import org.keycloak.models.OAuthClientModel;
 import org.keycloak.models.RealmModel;
 import org.keycloak.models.mongo.api.context.MongoStoreInvocationContext;
@@ -10,8 +11,8 @@ import org.keycloak.models.mongo.keycloak.entities.MongoOAuthClientEntity;
  */
 public class OAuthClientAdapter extends ClientAdapter<MongoOAuthClientEntity> implements OAuthClientModel {
 
-    public OAuthClientAdapter(RealmAdapter realm, MongoOAuthClientEntity oauthClientEntity, MongoStoreInvocationContext invContext) {
-        super(realm, oauthClientEntity, invContext);
+    public OAuthClientAdapter(KeycloakSession session, RealmModel realm, MongoOAuthClientEntity oauthClientEntity, MongoStoreInvocationContext invContext) {
+        super(session, realm, oauthClientEntity, invContext);
     }
 
     @Override
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 da20338..5c187c2 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
@@ -8,6 +8,7 @@ import org.keycloak.models.ApplicationModel;
 import org.keycloak.models.AuthenticationLinkModel;
 import org.keycloak.models.AuthenticationProviderModel;
 import org.keycloak.models.ClientModel;
+import org.keycloak.models.KeycloakSession;
 import org.keycloak.models.OAuthClientModel;
 import org.keycloak.models.PasswordPolicy;
 import org.keycloak.models.RealmModel;
@@ -64,10 +65,12 @@ public class RealmAdapter extends AbstractMongoAdapter<MongoRealmEntity> impleme
     protected volatile transient PrivateKey privateKey;
 
     private volatile transient PasswordPolicy passwordPolicy;
+    private volatile transient KeycloakSession session;
 
-    public RealmAdapter(MongoRealmEntity realmEntity, MongoStoreInvocationContext invocationContext) {
+    public RealmAdapter(KeycloakSession session, MongoRealmEntity realmEntity, MongoStoreInvocationContext invocationContext) {
         super(invocationContext);
         this.realm = realmEntity;
+        this.session = session;
     }
 
     @Override
@@ -445,92 +448,34 @@ public class RealmAdapter extends AbstractMongoAdapter<MongoRealmEntity> impleme
     }
 
     @Override
-    public UserAdapter getUser(String name) {
-        DBObject query = new QueryBuilder()
-                .and("loginName").is(name)
-                .and("realmId").is(getId())
-                .get();
-        MongoUserEntity user = getMongoStore().loadSingleEntity(MongoUserEntity.class, query, invocationContext);
-
-        if (user == null) {
-            return null;
-        } else {
-            return new UserAdapter(user, invocationContext);
-        }
+    public UserModel getUser(String name) {
+        return session.getUserByUsername(name, this);
     }
 
     @Override
-    public UsernameLoginFailureAdapter getUserLoginFailure(String name) {
-        DBObject query = new QueryBuilder()
-                .and("username").is(name)
-                .and("realmId").is(getId())
-                .get();
-        MongoUsernameLoginFailureEntity user = getMongoStore().loadSingleEntity(MongoUsernameLoginFailureEntity.class, query, invocationContext);
-
-        if (user == null) {
-            return null;
-        } else {
-            return new UsernameLoginFailureAdapter(invocationContext, user);
-        }
+    public UsernameLoginFailureModel getUserLoginFailure(String name) {
+        return session.getUserLoginFailure(name, this);
     }
 
     @Override
-    public UsernameLoginFailureAdapter addUserLoginFailure(String username) {
-        UsernameLoginFailureAdapter userLoginFailure = getUserLoginFailure(username);
-        if (userLoginFailure != null) {
-            return userLoginFailure;
-        }
-
-        MongoUsernameLoginFailureEntity userEntity = new MongoUsernameLoginFailureEntity();
-        userEntity.setUsername(username);
-        userEntity.setRealmId(getId());
-
-        getMongoStore().insertEntity(userEntity, invocationContext);
-        return new UsernameLoginFailureAdapter(invocationContext, userEntity);
+    public UsernameLoginFailureModel addUserLoginFailure(String username) {
+        return session.addUserLoginFailure(username, this);
     }
 
+
     @Override
     public List<UsernameLoginFailureModel> getAllUserLoginFailures() {
-        DBObject query = new QueryBuilder()
-                .and("realmId").is(getId())
-                .get();
-        List<MongoUsernameLoginFailureEntity> failures = getMongoStore().loadEntities(MongoUsernameLoginFailureEntity.class, query, invocationContext);
-
-        List<UsernameLoginFailureModel> result = new ArrayList<UsernameLoginFailureModel>();
-
-        if (failures == null) return result;
-        for (MongoUsernameLoginFailureEntity failure : failures) {
-            result.add(new UsernameLoginFailureAdapter(invocationContext, failure));
-        }
-
-        return result;
+        return session.getAllUserLoginFailures(this);
     }
 
     @Override
     public UserModel getUserByEmail(String email) {
-        DBObject query = new QueryBuilder()
-                .and("email").is(email)
-                .and("realmId").is(getId())
-                .get();
-        MongoUserEntity user = getMongoStore().loadSingleEntity(MongoUserEntity.class, query, invocationContext);
-
-        if (user == null) {
-            return null;
-        } else {
-            return new UserAdapter(user, invocationContext);
-        }
+        return session.getUserByEmail(email, this);
     }
 
     @Override
     public UserModel getUserById(String id) {
-        MongoUserEntity user = getMongoStore().loadEntity(MongoUserEntity.class, id, invocationContext);
-
-        // Check that it's user from this realm
-        if (user == null || !getId().equals(user.getRealmId())) {
-            return null;
-        } else {
-            return new UserAdapter(user, invocationContext);
-        }
+        return session.getUserById(id, this);
     }
 
     @Override
@@ -543,12 +488,12 @@ public class RealmAdapter extends AbstractMongoAdapter<MongoRealmEntity> impleme
         UserAdapter userModel = addUserEntity(id, username);
 
         for (String r : getDefaultRoles()) {
-            grantRole(userModel, getRole(r));
+           userModel.grantRole(getRole(r));
         }
 
         for (ApplicationModel application : getApplications()) {
             for (String r : application.getDefaultRoles()) {
-                grantRole(userModel, application.getRole(r));
+                userModel.grantRole(application.getRole(r));
             }
         }
 
@@ -564,7 +509,7 @@ public class RealmAdapter extends AbstractMongoAdapter<MongoRealmEntity> impleme
         userEntity.setRealmId(getId());
 
         getMongoStore().insertEntity(userEntity, invocationContext);
-        return new UserAdapter(userEntity, invocationContext);
+        return new UserAdapter(session, this, userEntity, invocationContext);
     }
 
     @Override
@@ -586,7 +531,7 @@ public class RealmAdapter extends AbstractMongoAdapter<MongoRealmEntity> impleme
         if (role == null) {
             return null;
         } else {
-            return new RoleAdapter(this, role, this, invocationContext);
+            return new RoleAdapter(session, this, role, this, invocationContext);
         }
     }
 
@@ -604,7 +549,7 @@ public class RealmAdapter extends AbstractMongoAdapter<MongoRealmEntity> impleme
 
         getMongoStore().insertEntity(roleEntity, invocationContext);
 
-        return new RoleAdapter(this, roleEntity, this, invocationContext);
+        return new RoleAdapter(session, this, roleEntity, this, invocationContext);
     }
 
     @Override
@@ -628,7 +573,7 @@ public class RealmAdapter extends AbstractMongoAdapter<MongoRealmEntity> impleme
 
         if (roles == null) return result;
         for (MongoRoleEntity role : roles) {
-            result.add(new RoleAdapter(this, role, this, invocationContext));
+            result.add(new RoleAdapter(session, this, role, this, invocationContext));
         }
 
         return result;
@@ -636,15 +581,7 @@ public class RealmAdapter extends AbstractMongoAdapter<MongoRealmEntity> impleme
 
     @Override
     public RoleModel getRoleById(String id) {
-        MongoRoleEntity role = getMongoStore().loadEntity(MongoRoleEntity.class, id, invocationContext);
-        if (role == null) return null;
-        if (role.getRealmId() != null) {
-            if (!role.getRealmId().equals(this.getId())) return null;
-        } else {
-            ApplicationModel app = getApplicationById(role.getApplicationId());
-            if (app == null) return null;
-        }
-        return new RoleAdapter(this, role, null, invocationContext);
+        return session.getRoleById(id, this);
     }
 
     @Override
@@ -696,14 +633,7 @@ public class RealmAdapter extends AbstractMongoAdapter<MongoRealmEntity> impleme
 
     @Override
     public ApplicationModel getApplicationById(String id) {
-        MongoApplicationEntity appData = getMongoStore().loadEntity(MongoApplicationEntity.class, id, invocationContext);
-
-        // Check if application belongs to this realm
-        if (appData == null || !getId().equals(appData.getRealmId())) {
-            return null;
-        }
-
-        return new ApplicationAdapter(this, appData, invocationContext);
+        return session.getApplicationById(id, this);
     }
 
     @Override
@@ -713,7 +643,7 @@ public class RealmAdapter extends AbstractMongoAdapter<MongoRealmEntity> impleme
                 .and("name").is(name)
                 .get();
         MongoApplicationEntity appEntity = getMongoStore().loadSingleEntity(MongoApplicationEntity.class, query, invocationContext);
-        return appEntity == null ? null : new ApplicationAdapter(this, appEntity, invocationContext);
+        return appEntity == null ? null : new ApplicationAdapter(session, this, appEntity, invocationContext);
     }
 
     @Override
@@ -734,7 +664,7 @@ public class RealmAdapter extends AbstractMongoAdapter<MongoRealmEntity> impleme
 
         List<ApplicationModel> result = new ArrayList<ApplicationModel>();
         for (MongoApplicationEntity appData : appDatas) {
-            result.add(new ApplicationAdapter(this, appData, invocationContext));
+            result.add(new ApplicationAdapter(session, this, appData, invocationContext));
         }
         return result;
     }
@@ -753,7 +683,7 @@ public class RealmAdapter extends AbstractMongoAdapter<MongoRealmEntity> impleme
         appData.setEnabled(true);
         getMongoStore().insertEntity(appData, invocationContext);
 
-        return new ApplicationAdapter(this, appData, invocationContext);
+        return new ApplicationAdapter(session, this, appData, invocationContext);
     }
 
     @Override
@@ -762,117 +692,6 @@ public class RealmAdapter extends AbstractMongoAdapter<MongoRealmEntity> impleme
     }
 
     @Override
-    public boolean hasRole(UserModel user, RoleModel role) {
-        Set<RoleModel> roles = getRoleMappings(user);
-        if (roles.contains(role)) return true;
-
-        for (RoleModel mapping : roles) {
-            if (mapping.hasRole(role)) return true;
-        }
-        return false;
-    }
-
-    @Override
-    public void grantRole(UserModel user, RoleModel role) {
-        MongoUserEntity userEntity = ((UserAdapter) user).getUser();
-        getMongoStore().pushItemToList(userEntity, "roleIds", role.getId(), true, invocationContext);
-    }
-
-    @Override
-    public Set<RoleModel> getRoleMappings(UserModel user) {
-        Set<RoleModel> result = new HashSet<RoleModel>();
-        List<MongoRoleEntity> roles = MongoModelUtils.getAllRolesOfUser(user, invocationContext);
-
-        for (MongoRoleEntity role : roles) {
-            if (getId().equals(role.getRealmId())) {
-                result.add(new RoleAdapter(this, role, this, invocationContext));
-            } else {
-                // Likely applicationRole, but we don't have this application yet
-                result.add(new RoleAdapter(this, role, invocationContext));
-            }
-        }
-        return result;
-    }
-
-    @Override
-    public Set<RoleModel> getRealmRoleMappings(UserModel user) {
-        Set<RoleModel> allRoles = getRoleMappings(user);
-
-        // Filter to retrieve just realm roles TODO: Maybe improve to avoid filter programmatically... Maybe have separate fields for realmRoles and appRoles on user?
-        Set<RoleModel> realmRoles = new HashSet<RoleModel>();
-        for (RoleModel role : allRoles) {
-            MongoRoleEntity roleEntity = ((RoleAdapter) role).getRole();
-
-            if (getId().equals(roleEntity.getRealmId())) {
-                realmRoles.add(role);
-            }
-        }
-        return realmRoles;
-    }
-
-    @Override
-    public void deleteRoleMapping(UserModel user, RoleModel role) {
-        if (user == null || role == null) return;
-
-        MongoUserEntity userEntity = ((UserAdapter) user).getUser();
-        getMongoStore().pullItemFromList(userEntity, "roleIds", role.getId(), invocationContext);
-    }
-
-    @Override
-    public Set<RoleModel> getScopeMappings(ClientModel client) {
-        Set<RoleModel> result = new HashSet<RoleModel>();
-        List<MongoRoleEntity> roles = MongoModelUtils.getAllScopesOfClient(client, invocationContext);
-
-        for (MongoRoleEntity role : roles) {
-            if (getId().equals(role.getRealmId())) {
-                result.add(new RoleAdapter(this, role, this, invocationContext));
-            } else {
-                // Likely applicationRole, but we don't have this application yet
-                result.add(new RoleAdapter(this, role, invocationContext));
-            }
-        }
-        return result;
-    }
-
-    @Override
-    public Set<RoleModel> getRealmScopeMappings(ClientModel client) {
-        Set<RoleModel> allScopes = getScopeMappings(client);
-
-        // Filter to retrieve just realm roles TODO: Maybe improve to avoid filter programmatically... Maybe have separate fields for realmRoles and appRoles on user?
-        Set<RoleModel> realmRoles = new HashSet<RoleModel>();
-        for (RoleModel role : allScopes) {
-            MongoRoleEntity roleEntity = ((RoleAdapter) role).getRole();
-
-            if (getId().equals(roleEntity.getRealmId())) {
-                realmRoles.add(role);
-            }
-        }
-        return realmRoles;
-    }
-
-    @Override
-    public boolean hasScope(ClientModel client, RoleModel role) {
-        Set<RoleModel> roles = getScopeMappings(client);
-        if (roles.contains(role)) return true;
-
-        for (RoleModel mapping : roles) {
-            if (mapping.hasRole(role)) return true;
-        }
-        return false;
-    }
-
-
-    @Override
-    public void addScopeMapping(ClientModel client, RoleModel role) {
-        getMongoStore().pushItemToList(((AbstractMongoAdapter) client).getMongoEntity(), "scopeIds", role.getId(), true, invocationContext);
-    }
-
-    @Override
-    public void deleteScopeMapping(ClientModel client, RoleModel role) {
-        getMongoStore().pullItemFromList(((AbstractMongoAdapter) client).getMongoEntity(), "scopeIds", role.getId(), invocationContext);
-    }
-
-    @Override
     public OAuthClientModel addOAuthClient(String name) {
         return this.addOAuthClient(null, name);
     }
@@ -885,7 +704,7 @@ public class RealmAdapter extends AbstractMongoAdapter<MongoRealmEntity> impleme
         oauthClient.setName(name);
         getMongoStore().insertEntity(oauthClient, invocationContext);
 
-        return new OAuthClientAdapter(this, oauthClient, invocationContext);
+        return new OAuthClientAdapter(session, this, oauthClient, invocationContext);
     }
 
     @Override
@@ -900,17 +719,12 @@ public class RealmAdapter extends AbstractMongoAdapter<MongoRealmEntity> impleme
                 .and("name").is(name)
                 .get();
         MongoOAuthClientEntity oauthClient = getMongoStore().loadSingleEntity(MongoOAuthClientEntity.class, query, invocationContext);
-        return oauthClient == null ? null : new OAuthClientAdapter(this, oauthClient, invocationContext);
+        return oauthClient == null ? null : new OAuthClientAdapter(session, this, oauthClient, invocationContext);
     }
 
     @Override
     public OAuthClientModel getOAuthClientById(String id) {
-        MongoOAuthClientEntity clientEntity = getMongoStore().loadEntity(MongoOAuthClientEntity.class, id, invocationContext);
-
-        // Check if client belongs to this realm
-        if (clientEntity == null || !getId().equals(clientEntity.getRealmId())) return null;
-
-        return new OAuthClientAdapter(this, clientEntity, invocationContext);
+        return session.getOAuthClientById(id, this);
     }
 
     @Override
@@ -921,7 +735,7 @@ public class RealmAdapter extends AbstractMongoAdapter<MongoRealmEntity> impleme
         List<MongoOAuthClientEntity> results = getMongoStore().loadEntities(MongoOAuthClientEntity.class, query, invocationContext);
         List<OAuthClientModel> list = new ArrayList<OAuthClientModel>();
         for (MongoOAuthClientEntity data : results) {
-            list.add(new OAuthClientAdapter(this, data, invocationContext));
+            list.add(new OAuthClientAdapter(session, this, data, invocationContext));
         }
         return list;
     }
@@ -994,7 +808,7 @@ public class RealmAdapter extends AbstractMongoAdapter<MongoRealmEntity> impleme
 
     @Override
     public boolean validatePassword(UserModel user, String password) {
-        for (CredentialEntity cred : ((UserAdapter) user).getUser().getCredentials()) {
+        for (UserCredentialValueModel cred : user.getCredentialsDirectly()) {
             if (cred.getType().equals(UserCredentialModel.PASSWORD)) {
                 return new Pbkdf2PasswordEncoder(cred.getSalt()).verify(password, cred.getValue());
             }
@@ -1005,7 +819,7 @@ public class RealmAdapter extends AbstractMongoAdapter<MongoRealmEntity> impleme
     @Override
     public boolean validateTOTP(UserModel user, String password, String token) {
         if (!validatePassword(user, password)) return false;
-        for (CredentialEntity cred : ((UserAdapter) user).getUser().getCredentials()) {
+        for (UserCredentialValueModel cred : user.getCredentialsDirectly()) {
             if (cred.getType().equals(UserCredentialModel.TOTP)) {
                 return new TimeBasedOTP().validate(token, cred.getValue().getBytes());
             }
@@ -1014,107 +828,21 @@ public class RealmAdapter extends AbstractMongoAdapter<MongoRealmEntity> impleme
     }
 
 
-    @Override
-    public void updateCredential(UserModel user, UserCredentialModel cred) {
-        MongoUserEntity userEntity = ((UserAdapter) user).getUser();
-        CredentialEntity credentialEntity = getCredentialEntity(userEntity, cred.getType());
-
-        if (credentialEntity == null) {
-            credentialEntity = new CredentialEntity();
-            credentialEntity.setType(cred.getType());
-            credentialEntity.setDevice(cred.getDevice());
-            userEntity.getCredentials().add(credentialEntity);
-        }
-        if (cred.getType().equals(UserCredentialModel.PASSWORD)) {
-            byte[] salt = Pbkdf2PasswordEncoder.getSalt();
-            credentialEntity.setValue(new Pbkdf2PasswordEncoder(salt).encode(cred.getValue()));
-            credentialEntity.setSalt(salt);
-        } else {
-            credentialEntity.setValue(cred.getValue());
-        }
-        credentialEntity.setDevice(cred.getDevice());
-
-        getMongoStore().updateEntity(userEntity, invocationContext);
-    }
-
-    private CredentialEntity getCredentialEntity(MongoUserEntity userEntity, String credType) {
-        for (CredentialEntity entity : userEntity.getCredentials()) {
-            if (entity.getType().equals(credType)) {
-                return entity;
-            }
-        }
-
-        return null;
-    }
-
-    @Override
-    public List<UserCredentialValueModel> getCredentialsDirectly(UserModel user) {
-        MongoUserEntity userEntity = ((UserAdapter) user).getUser();
-        List<CredentialEntity> credentials = userEntity.getCredentials();
-        List<UserCredentialValueModel> result = new ArrayList<UserCredentialValueModel>();
-        for (CredentialEntity credEntity : credentials) {
-            UserCredentialValueModel credModel = new UserCredentialValueModel();
-            credModel.setType(credEntity.getType());
-            credModel.setDevice(credEntity.getDevice());
-            credModel.setValue(credEntity.getValue());
-            credModel.setSalt(credEntity.getSalt());
-
-            result.add(credModel);
-        }
-
-        return result;
-    }
-
-    @Override
-    public void updateCredentialDirectly(UserModel user, UserCredentialValueModel credModel) {
-        MongoUserEntity userEntity = ((UserAdapter) user).getUser();
-        CredentialEntity credentialEntity = getCredentialEntity(userEntity, credModel.getType());
-
-        if (credentialEntity == null) {
-            credentialEntity = new CredentialEntity();
-            credentialEntity.setType(credModel.getType());
-            userEntity.getCredentials().add(credentialEntity);
-        }
-
-        credentialEntity.setValue(credModel.getValue());
-        credentialEntity.setSalt(credModel.getSalt());
-        credentialEntity.setDevice(credModel.getDevice());
 
-        getMongoStore().updateEntity(userEntity, invocationContext);
-    }
 
     @Override
     public UserModel getUserBySocialLink(SocialLinkModel socialLink) {
-        DBObject query = new QueryBuilder()
-                .and("socialLinks.socialProvider").is(socialLink.getSocialProvider())
-                .and("socialLinks.socialUserId").is(socialLink.getSocialUserId())
-                .and("realmId").is(getId())
-                .get();
-        MongoUserEntity userEntity = getMongoStore().loadSingleEntity(MongoUserEntity.class, query, invocationContext);
-        return userEntity == null ? null : new UserAdapter(userEntity, invocationContext);
+        return session.getUserBySocialLink(socialLink, this);
     }
 
     @Override
     public Set<SocialLinkModel> getSocialLinks(UserModel user) {
-        MongoUserEntity userEntity = ((UserAdapter) user).getUser();
-        List<SocialLinkEntity> linkEntities = userEntity.getSocialLinks();
-
-        if (linkEntities == null) {
-            return Collections.EMPTY_SET;
-        }
-
-        Set<SocialLinkModel> result = new HashSet<SocialLinkModel>();
-        for (SocialLinkEntity socialLinkEntity : linkEntities) {
-            SocialLinkModel model = new SocialLinkModel(socialLinkEntity.getSocialProvider(), socialLinkEntity.getSocialUserId(), socialLinkEntity.getSocialUsername());
-            result.add(model);
-        }
-        return result;
+        return session.getSocialLinks(user, this);
     }
 
     @Override
     public SocialLinkModel getSocialLink(UserModel user, String socialProvider) {
-        SocialLinkEntity socialLinkEntity = findSocialLink(user, socialProvider);
-        return socialLinkEntity != null ? new SocialLinkModel(socialLinkEntity.getSocialProvider(), socialLinkEntity.getSocialUserId(), socialLinkEntity.getSocialUsername()) : null;
+        return session.getSocialLink(user, socialProvider, this);
     }
 
     @Override
@@ -1154,29 +882,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();
     }
@@ -1191,82 +896,20 @@ public class RealmAdapter extends AbstractMongoAdapter<MongoRealmEntity> impleme
 
     @Override
     public List<UserModel> getUsers() {
-        DBObject query = new QueryBuilder()
-                .and("realmId").is(getId())
-                .get();
-        List<MongoUserEntity> users = getMongoStore().loadEntities(MongoUserEntity.class, query, invocationContext);
-        return convertUserEntities(users);
+        return session.getUsers(this);
     }
 
     @Override
     public List<UserModel> searchForUser(String search) {
-        search = search.trim();
-        Pattern caseInsensitivePattern = Pattern.compile("(?i:" + search + ")");
-
-        QueryBuilder nameBuilder;
-        int spaceInd = search.lastIndexOf(" ");
-
-        // Case when we have search string like "ohn Bow". Then firstName must end with "ohn" AND lastName must start with "bow" (everything case-insensitive)
-        if (spaceInd != -1) {
-            String firstName = search.substring(0, spaceInd);
-            String lastName = search.substring(spaceInd + 1);
-            Pattern firstNamePattern = Pattern.compile("(?i:" + firstName + "$)");
-            Pattern lastNamePattern = Pattern.compile("(?i:^" + lastName + ")");
-            nameBuilder = new QueryBuilder().and(
-                    new QueryBuilder().put("firstName").regex(firstNamePattern).get(),
-                    new QueryBuilder().put("lastName").regex(lastNamePattern).get()
-            );
-        } else {
-            // Case when we have search without spaces like "foo". The firstName OR lastName could be "foo" (everything case-insensitive)
-            nameBuilder = new QueryBuilder().or(
-                    new QueryBuilder().put("firstName").regex(caseInsensitivePattern).get(),
-                    new QueryBuilder().put("lastName").regex(caseInsensitivePattern).get()
-            );
-        }
-
-        QueryBuilder builder = new QueryBuilder().and(
-                new QueryBuilder().and("realmId").is(getId()).get(),
-                new QueryBuilder().or(
-                        new QueryBuilder().put("loginName").regex(caseInsensitivePattern).get(),
-                        new QueryBuilder().put("email").regex(caseInsensitivePattern).get(),
-                        nameBuilder.get()
+        return session.searchForUser(search, this);
 
-                ).get()
-        );
-
-        List<MongoUserEntity> users = getMongoStore().loadEntities(MongoUserEntity.class, builder.get(), invocationContext);
-        return convertUserEntities(users);
     }
 
     @Override
     public List<UserModel> searchForUserByAttributes(Map<String, String> attributes) {
-        QueryBuilder queryBuilder = new QueryBuilder()
-                .and("realmId").is(getId());
-
-        for (Map.Entry<String, String> entry : attributes.entrySet()) {
-            if (entry.getKey().equals(UserModel.LOGIN_NAME)) {
-                queryBuilder.and("loginName").regex(Pattern.compile("(?i:" + entry.getValue() + "$)"));
-            } else if (entry.getKey().equalsIgnoreCase(UserModel.FIRST_NAME)) {
-                queryBuilder.and(UserModel.FIRST_NAME).regex(Pattern.compile("(?i:" + entry.getValue() + "$)"));
-
-            } else if (entry.getKey().equalsIgnoreCase(UserModel.LAST_NAME)) {
-                queryBuilder.and(UserModel.LAST_NAME).regex(Pattern.compile("(?i:" + entry.getValue() + "$)"));
-
-            } else if (entry.getKey().equalsIgnoreCase(UserModel.EMAIL)) {
-                queryBuilder.and(UserModel.EMAIL).regex(Pattern.compile("(?i:" + entry.getValue() + "$)"));
-            }
-        }
-        List<MongoUserEntity> users = getMongoStore().loadEntities(MongoUserEntity.class, queryBuilder.get(), invocationContext);
-        return convertUserEntities(users);
+        return session.searchForUserByAttributes(attributes, this);
     }
 
-    protected List<UserModel> convertUserEntities(List<MongoUserEntity> userEntities) {
-        List<UserModel> userModels = new ArrayList<UserModel>();
-        for (MongoUserEntity user : userEntities) {
-            userModels.add(new UserAdapter(user, invocationContext));
-        }
-        return userModels;
-    }
 
     @Override
     public Map<String, String> getSmtpConfig() {
@@ -1367,7 +1010,7 @@ public class RealmAdapter extends AbstractMongoAdapter<MongoRealmEntity> impleme
     @Override
     public ApplicationModel getMasterAdminApp() {
         MongoApplicationEntity appData = getMongoStore().loadEntity(MongoApplicationEntity.class, realm.getAdminAppId(), invocationContext);
-        return appData != null ? new ApplicationAdapter(this, appData, invocationContext) : null;
+        return appData != null ? new ApplicationAdapter(session, this, appData, invocationContext) : null;
     }
 
     @Override
@@ -1383,70 +1026,37 @@ public class RealmAdapter extends AbstractMongoAdapter<MongoRealmEntity> impleme
 
     @Override
     public UserSessionModel createUserSession(UserModel user, String ipAddress) {
-        MongoUserSessionEntity entity = new MongoUserSessionEntity();
-        entity.setRealmId(getId());
-        entity.setUser(user.getId());
-        entity.setIpAddress(ipAddress);
-
-        int currentTime = Time.currentTime();
-
-        entity.setStarted(currentTime);
-        entity.setLastSessionRefresh(currentTime);
-
-        getMongoStore().insertEntity(entity, invocationContext);
-        return new UserSessionAdapter(entity, this, invocationContext);
+        return session.createUserSession(this, user, ipAddress);
     }
 
     @Override
     public UserSessionModel getUserSession(String id) {
-        MongoUserSessionEntity entity = getMongoStore().loadEntity(MongoUserSessionEntity.class, id, invocationContext);
-        if (entity == null) {
-            return null;
-        } else {
-            return new UserSessionAdapter(entity, this, invocationContext);
-        }
+        return session.getUserSession(id, this);
     }
 
     @Override
     public List<UserSessionModel> getUserSessions(UserModel user) {
-        DBObject query = new BasicDBObject("user", user.getId());
-        List<UserSessionModel> sessions = new LinkedList<UserSessionModel>();
-        for (MongoUserSessionEntity e : getMongoStore().loadEntities(MongoUserSessionEntity.class, query, invocationContext)) {
-            sessions.add(new UserSessionAdapter(e, this, invocationContext));
-        }
-        return sessions;
+        return session.getUserSessions(user, this);
     }
 
     @Override
     public void removeUserSession(UserSessionModel session) {
-        getMongoStore().removeEntity(((UserSessionAdapter) session).getMongoEntity(), invocationContext);
+        this.session.removeUserSession(session);
     }
 
     @Override
     public void removeUserSessions(UserModel user) {
-        DBObject query = new BasicDBObject("user", user.getId());
-        getMongoStore().removeEntities(MongoUserSessionEntity.class, query, invocationContext);
+        this.session.removeUserSessions(this, user);
     }
 
     @Override
     public void removeUserSessions() {
-        DBObject query = new BasicDBObject("realmId", getId());
-        getMongoStore().removeEntities(MongoUserSessionEntity.class, query, invocationContext);
+        this.session.removeUserSessions(this);
     }
 
     @Override
     public void removeExpiredUserSessions() {
-        int currentTime = Time.currentTime();
-        DBObject query = new QueryBuilder()
-                .and("started").lessThan(currentTime - realm.getSsoSessionMaxLifespan())
-                .get();
-
-        getMongoStore().removeEntities(MongoUserSessionEntity.class, query, invocationContext);
-        query = new QueryBuilder()
-                .and("lastSessionRefresh").lessThan(currentTime - realm.getSsoSessionIdleTimeout())
-                .get();
-
-        getMongoStore().removeEntities(MongoUserSessionEntity.class, query, invocationContext);
+        this.session.removeExpiredUserSessions(this);
     }
 
 }
diff --git a/model/mongo/src/main/java/org/keycloak/models/mongo/keycloak/adapters/RoleAdapter.java b/model/mongo/src/main/java/org/keycloak/models/mongo/keycloak/adapters/RoleAdapter.java
index 41318bb..6053df3 100755
--- a/model/mongo/src/main/java/org/keycloak/models/mongo/keycloak/adapters/RoleAdapter.java
+++ b/model/mongo/src/main/java/org/keycloak/models/mongo/keycloak/adapters/RoleAdapter.java
@@ -7,6 +7,8 @@ import java.util.Set;
 
 import com.mongodb.DBObject;
 import com.mongodb.QueryBuilder;
+import org.keycloak.models.KeycloakSession;
+import org.keycloak.models.RealmModel;
 import org.keycloak.models.RoleContainerModel;
 import org.keycloak.models.RoleModel;
 import org.keycloak.models.mongo.api.context.MongoStoreInvocationContext;
@@ -24,17 +26,19 @@ public class RoleAdapter extends AbstractMongoAdapter<MongoRoleEntity> implement
 
     private final MongoRoleEntity role;
     private RoleContainerModel roleContainer;
-    private RealmAdapter realm;
+    private RealmModel realm;
+    private KeycloakSession session;
 
-    public RoleAdapter(RealmAdapter realm, MongoRoleEntity roleEntity, MongoStoreInvocationContext invContext) {
-        this(realm, roleEntity, null, invContext);
+    public RoleAdapter(KeycloakSession session, RealmModel realm, MongoRoleEntity roleEntity, MongoStoreInvocationContext invContext) {
+        this(session, realm, roleEntity, null, invContext);
     }
 
-    public RoleAdapter(RealmAdapter realm, MongoRoleEntity roleEntity, RoleContainerModel roleContainer, MongoStoreInvocationContext invContext) {
+    public RoleAdapter(KeycloakSession session, RealmModel realm, MongoRoleEntity roleEntity, RoleContainerModel roleContainer, MongoStoreInvocationContext invContext) {
         super(invContext);
         this.role = roleEntity;
         this.roleContainer = roleContainer;
         this.realm = realm;
+        this.session = session;
     }
 
     @Override
@@ -96,7 +100,7 @@ public class RoleAdapter extends AbstractMongoAdapter<MongoRoleEntity> implement
 
         Set<RoleModel> set = new HashSet<RoleModel>();
         for (MongoRoleEntity childRole : childRoles) {
-            set.add(new RoleAdapter(realm, childRole, invocationContext));
+            set.add(new RoleAdapter(session, realm, childRole, invocationContext));
         }
         return set;
     }
@@ -110,13 +114,13 @@ public class RoleAdapter extends AbstractMongoAdapter<MongoRoleEntity> implement
                 if (realm == null) {
                     throw new IllegalStateException("Realm with id: " + role.getRealmId() + " doesn't exists");
                 }
-                roleContainer = new RealmAdapter(realm, invocationContext);
+                roleContainer = new RealmAdapter(session, realm, invocationContext);
             } else if (role.getApplicationId() != null) {
                 MongoApplicationEntity appEntity = getMongoStore().loadEntity(MongoApplicationEntity.class, role.getApplicationId(), invocationContext);
                 if (appEntity == null) {
                     throw new IllegalStateException("Application with id: " + role.getApplicationId() + " doesn't exists");
                 }
-                roleContainer = new ApplicationAdapter(realm, appEntity, invocationContext);
+                roleContainer = new ApplicationAdapter(session, realm, appEntity, invocationContext);
             } else {
                 throw new IllegalStateException("Both realmId and applicationId are null for role: " + this);
             }
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 c713b9f..b26c50a 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,27 @@
 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.KeycloakSession;
+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;
 import org.keycloak.models.mongo.keycloak.entities.MongoUserEntity;
+import org.keycloak.models.mongo.utils.MongoModelUtils;
+import org.keycloak.models.utils.Pbkdf2PasswordEncoder;
 
+import java.util.ArrayList;
 import java.util.Collections;
 import java.util.HashMap;
 import java.util.HashSet;
+import java.util.List;
 import java.util.Map;
 import java.util.Set;
 
@@ -18,10 +33,14 @@ import java.util.Set;
 public class UserAdapter extends AbstractMongoAdapter<MongoUserEntity> implements UserModel {
 
     private final MongoUserEntity user;
+    private final RealmModel realm;
+    private final KeycloakSession session;
 
-    public UserAdapter(MongoUserEntity userEntity, MongoStoreInvocationContext invContext) {
+    public UserAdapter(KeycloakSession session, RealmModel realm, MongoUserEntity userEntity, MongoStoreInvocationContext invContext) {
         super(invContext);
         this.user = userEntity;
+        this.realm = realm;
+        this.session = session;
     }
 
     @Override
@@ -168,6 +187,72 @@ public class UserAdapter extends AbstractMongoAdapter<MongoUserEntity> implement
         updateUser();
     }
 
+    @Override
+    public void updateCredential(UserCredentialModel cred) {
+        CredentialEntity credentialEntity = getCredentialEntity(user, cred.getType());
+
+        if (credentialEntity == null) {
+            credentialEntity = new CredentialEntity();
+            credentialEntity.setType(cred.getType());
+            credentialEntity.setDevice(cred.getDevice());
+            user.getCredentials().add(credentialEntity);
+        }
+        if (cred.getType().equals(UserCredentialModel.PASSWORD)) {
+            byte[] salt = Pbkdf2PasswordEncoder.getSalt();
+            credentialEntity.setValue(new Pbkdf2PasswordEncoder(salt).encode(cred.getValue()));
+            credentialEntity.setSalt(salt);
+        } else {
+            credentialEntity.setValue(cred.getValue());
+        }
+        credentialEntity.setDevice(cred.getDevice());
+
+        getMongoStore().updateEntity(user, invocationContext);
+    }
+
+    private CredentialEntity getCredentialEntity(MongoUserEntity userEntity, String credType) {
+        for (CredentialEntity entity : userEntity.getCredentials()) {
+            if (entity.getType().equals(credType)) {
+                return entity;
+            }
+        }
+
+        return null;
+    }
+
+    @Override
+    public List<UserCredentialValueModel> getCredentialsDirectly() {
+        List<CredentialEntity> credentials = user.getCredentials();
+        List<UserCredentialValueModel> result = new ArrayList<UserCredentialValueModel>();
+        for (CredentialEntity credEntity : credentials) {
+            UserCredentialValueModel credModel = new UserCredentialValueModel();
+            credModel.setType(credEntity.getType());
+            credModel.setDevice(credEntity.getDevice());
+            credModel.setValue(credEntity.getValue());
+            credModel.setSalt(credEntity.getSalt());
+
+            result.add(credModel);
+        }
+
+        return result;
+    }
+
+    @Override
+    public void updateCredentialDirectly(UserCredentialValueModel credModel) {
+        CredentialEntity credentialEntity = getCredentialEntity(user, credModel.getType());
+
+        if (credentialEntity == null) {
+            credentialEntity = new CredentialEntity();
+            credentialEntity.setType(credModel.getType());
+            user.getCredentials().add(credentialEntity);
+        }
+
+        credentialEntity.setValue(credModel.getValue());
+        credentialEntity.setSalt(credModel.getSalt());
+        credentialEntity.setDevice(credModel.getDevice());
+
+        getMongoStore().updateEntity(user, invocationContext);
+    }
+
     protected void updateUser() {
         super.updateMongoEntity();
     }
@@ -177,6 +262,103 @@ public class UserAdapter extends AbstractMongoAdapter<MongoUserEntity> implement
         return user;
     }
 
+    @Override
+    public boolean hasRole(RoleModel role) {
+        Set<RoleModel> roles = getRoleMappings();
+        if (roles.contains(role)) return true;
+
+        for (RoleModel mapping : roles) {
+            if (mapping.hasRole(role)) return true;
+        }
+        return false;
+    }
+
+    @Override
+    public void grantRole(RoleModel role) {
+        getMongoStore().pushItemToList(getUser(), "roleIds", role.getId(), true, invocationContext);
+    }
+
+    @Override
+    public Set<RoleModel> getRoleMappings() {
+        Set<RoleModel> result = new HashSet<RoleModel>();
+        List<MongoRoleEntity> roles = MongoModelUtils.getAllRolesOfUser(this, invocationContext);
+
+        for (MongoRoleEntity role : roles) {
+            if (realm.getId().equals(role.getRealmId())) {
+                result.add(new RoleAdapter(session, realm, role, realm, invocationContext));
+            } else {
+                // Likely applicationRole, but we don't have this application yet
+                result.add(new RoleAdapter(session, realm, role, invocationContext));
+            }
+        }
+        return result;
+    }
+
+    @Override
+    public Set<RoleModel> getRealmRoleMappings() {
+        Set<RoleModel> allRoles = getRoleMappings();
+
+        // Filter to retrieve just realm roles TODO: Maybe improve to avoid filter programmatically... Maybe have separate fields for realmRoles and appRoles on user?
+        Set<RoleModel> realmRoles = new HashSet<RoleModel>();
+        for (RoleModel role : allRoles) {
+            MongoRoleEntity roleEntity = ((RoleAdapter) role).getRole();
+
+            if (realm.getId().equals(roleEntity.getRealmId())) {
+                realmRoles.add(role);
+            }
+        }
+        return realmRoles;
+    }
+
+    @Override
+    public void deleteRoleMapping(RoleModel role) {
+        if (user == null || role == null) return;
+
+        getMongoStore().pullItemFromList(getUser(), "roleIds", role.getId(), invocationContext);
+    }
+
+    @Override
+    public Set<RoleModel> getApplicationRoleMappings(ApplicationModel app) {
+        Set<RoleModel> result = new HashSet<RoleModel>();
+        List<MongoRoleEntity> roles = MongoModelUtils.getAllRolesOfUser(this, invocationContext);
+
+        for (MongoRoleEntity role : roles) {
+            if (app.getId().equals(role.getApplicationId())) {
+                result.add(new RoleAdapter(session, realm, role, app, invocationContext));
+            }
+        }
+        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/mongo/src/main/java/org/keycloak/models/mongo/keycloak/adapters/UserSessionAdapter.java b/model/mongo/src/main/java/org/keycloak/models/mongo/keycloak/adapters/UserSessionAdapter.java
index bc23df2..29e4b0d 100755
--- a/model/mongo/src/main/java/org/keycloak/models/mongo/keycloak/adapters/UserSessionAdapter.java
+++ b/model/mongo/src/main/java/org/keycloak/models/mongo/keycloak/adapters/UserSessionAdapter.java
@@ -5,6 +5,7 @@ import com.mongodb.QueryBuilder;
 import org.jboss.logging.Logger;
 import org.keycloak.models.ApplicationModel;
 import org.keycloak.models.ClientModel;
+import org.keycloak.models.RealmModel;
 import org.keycloak.models.UserModel;
 import org.keycloak.models.UserSessionModel;
 import org.keycloak.models.entities.ClientEntity;
@@ -24,9 +25,9 @@ public class UserSessionAdapter extends AbstractMongoAdapter<MongoUserSessionEnt
     private static final Logger logger = Logger.getLogger(RealmAdapter.class);
 
     private MongoUserSessionEntity entity;
-    private RealmAdapter realm;
+    private RealmModel realm;
 
-    public UserSessionAdapter(MongoUserSessionEntity entity, RealmAdapter realm, MongoStoreInvocationContext invContext)
+    public UserSessionAdapter(MongoUserSessionEntity entity, RealmModel realm, MongoStoreInvocationContext invContext)
     {
         super(invContext);
         this.entity = entity;
diff --git a/model/tests/src/test/java/org/keycloak/model/test/AdapterTest.java b/model/tests/src/test/java/org/keycloak/model/test/AdapterTest.java
index 84d4586..f3ce4eb 100755
--- a/model/tests/src/test/java/org/keycloak/model/test/AdapterTest.java
+++ b/model/tests/src/test/java/org/keycloak/model/test/AdapterTest.java
@@ -133,7 +133,7 @@ public class AdapterTest extends AbstractModelTest {
         UserCredentialModel cred = new UserCredentialModel();
         cred.setType(CredentialRepresentation.PASSWORD);
         cred.setValue("geheim");
-        realmModel.updateCredential(user, cred);
+        user.updateCredential(cred);
         Assert.assertTrue(realmModel.validatePassword(user, "geheim"));
     }
 
@@ -154,11 +154,11 @@ public class AdapterTest extends AbstractModelTest {
         user.addRequiredAction(UserModel.RequiredAction.UPDATE_PASSWORD);
 
         RoleModel testRole = realmModel.addRole("test");
-        realmModel.grantRole(user, testRole);
+        user.grantRole(testRole);
 
         ApplicationModel app = realmModel.addApplication("test-app");
         RoleModel appRole = app.addRole("test");
-        realmModel.grantRole(user, appRole);
+        user.grantRole(appRole);
 
         SocialLinkModel socialLink = new SocialLinkModel("google", "google1", user.getLoginName());
         realmModel.addSocialLink(user, socialLink);
@@ -166,7 +166,7 @@ public class AdapterTest extends AbstractModelTest {
         UserCredentialModel cred = new UserCredentialModel();
         cred.setType(CredentialRepresentation.PASSWORD);
         cred.setValue("password");
-        realmModel.updateCredential(user, cred);
+        user.updateCredential(cred);
 
         commit();
 
@@ -187,11 +187,11 @@ public class AdapterTest extends AbstractModelTest {
         ApplicationModel app = realmModel.addApplication("test-app");
 
         RoleModel appRole = app.addRole("test");
-        realmModel.grantRole(user, appRole);
-        realmModel.addScopeMapping(client, appRole);
+        user.grantRole(appRole);
+        client.addScopeMapping(appRole);
 
         RoleModel realmRole = realmModel.addRole("test");
-        realmModel.addScopeMapping(app, realmRole);
+        app.addScopeMapping(realmRole);
 
         Assert.assertTrue(realmModel.removeApplication(app.getId()));
         Assert.assertFalse(realmModel.removeApplication(app.getId()));
@@ -208,22 +208,22 @@ public class AdapterTest extends AbstractModelTest {
         UserCredentialModel cred = new UserCredentialModel();
         cred.setType(CredentialRepresentation.PASSWORD);
         cred.setValue("password");
-        realmModel.updateCredential(user, cred);
+        user.updateCredential(cred);
 
         OAuthClientModel client = realmModel.addOAuthClient("client");
 
         ApplicationModel app = realmModel.addApplication("test-app");
 
         RoleModel appRole = app.addRole("test");
-        realmModel.grantRole(user, appRole);
-        realmModel.addScopeMapping(client, appRole);
+        user.grantRole(appRole);
+        client.addScopeMapping(appRole);
 
         RoleModel realmRole = realmModel.addRole("test");
         RoleModel realmRole2 = realmModel.addRole("test2");
         realmRole.addCompositeRole(realmRole2);
         realmRole.addCompositeRole(appRole);
 
-        realmModel.addScopeMapping(app, realmRole);
+        app.addScopeMapping(realmRole);
 
         commit();
         realmModel = identitySession.getRealm("JUGGLER");
@@ -245,11 +245,11 @@ public class AdapterTest extends AbstractModelTest {
         ApplicationModel app = realmModel.addApplication("test-app");
 
         RoleModel appRole = app.addRole("test");
-        realmModel.grantRole(user, appRole);
-        realmModel.addScopeMapping(client, appRole);
+        user.grantRole(appRole);
+        client.addScopeMapping(appRole);
 
         RoleModel realmRole = realmModel.addRole("test");
-        realmModel.addScopeMapping(app, realmRole);
+        app.addScopeMapping(realmRole);
 
         commit();
         realmModel = identitySession.getRealm("JUGGLER");
@@ -436,8 +436,8 @@ public class AdapterTest extends AbstractModelTest {
         Assert.assertEquals(3, roles.size());
         UserModel user = realmModel.addUser("bburke");
         RoleModel realmUserRole = realmModel.getRole("user");
-        realmModel.grantRole(user, realmUserRole);
-        Assert.assertTrue(realmModel.hasRole(user, realmUserRole));
+        user.grantRole(realmUserRole);
+        Assert.assertTrue(user.hasRole(realmUserRole));
         RoleModel found = realmModel.getRoleById(realmUserRole.getId());
         assertNotNull(found);
         assertRolesEquals(found, realmUserRole);
@@ -455,35 +455,35 @@ public class AdapterTest extends AbstractModelTest {
         assertNotNull(found);
         assertRolesEquals(found, appBarRole);
 
-        realmModel.grantRole(user, appBarRole);
-        realmModel.grantRole(user, application.getRole("user"));
+        user.grantRole(appBarRole);
+        user.grantRole(application.getRole("user"));
 
-        roles = realmModel.getRealmRoleMappings(user);
+        roles = user.getRealmRoleMappings();
         Assert.assertEquals(roles.size(), 2);
         assertRolesContains(realmUserRole, roles);
-        Assert.assertTrue(realmModel.hasRole(user, realmUserRole));
+        Assert.assertTrue(user.hasRole(realmUserRole));
         // Role "foo" is default realm role
-        Assert.assertTrue(realmModel.hasRole(user, realmModel.getRole("foo")));
+        Assert.assertTrue(user.hasRole(realmModel.getRole("foo")));
 
-        roles = application.getApplicationRoleMappings(user);
+        roles = user.getApplicationRoleMappings(application);
         Assert.assertEquals(roles.size(), 2);
         assertRolesContains(application.getRole("user"), roles);
         assertRolesContains(appBarRole, roles);
-        Assert.assertTrue(realmModel.hasRole(user, appBarRole));
+        Assert.assertTrue(user.hasRole(appBarRole));
 
         // Test that application role 'user' don't clash with realm role 'user'
         Assert.assertNotEquals(realmModel.getRole("user").getId(), application.getRole("user").getId());
 
-        Assert.assertEquals(6, realmModel.getRoleMappings(user).size());
+        Assert.assertEquals(6, user.getRoleMappings().size());
 
         // Revoke some roles
-        realmModel.deleteRoleMapping(user, realmModel.getRole("foo"));
-        realmModel.deleteRoleMapping(user, appBarRole);
-        roles = realmModel.getRoleMappings(user);
+        user.deleteRoleMapping(realmModel.getRole("foo"));
+        user.deleteRoleMapping(appBarRole);
+        roles = user.getRoleMappings();
         Assert.assertEquals(4, roles.size());
         assertRolesContains(realmUserRole, roles);
         assertRolesContains(application.getRole("user"), roles);
-        Assert.assertFalse(realmModel.hasRole(user, appBarRole));
+        Assert.assertFalse(user.hasRole(appBarRole));
     }
 
     @Test
@@ -495,12 +495,12 @@ public class AdapterTest extends AbstractModelTest {
         RoleModel appRole = app1.addRole("app");
 
         ApplicationModel app2 = realmModel.addApplication("app2");
-        realmModel.addScopeMapping(app2, realmRole);
-        realmModel.addScopeMapping(app2, appRole);
+        app2.addScopeMapping(realmRole);
+        app2.addScopeMapping(appRole);
 
         OAuthClientModel client = realmModel.addOAuthClient("client");
-        realmModel.addScopeMapping(client, realmRole);
-        realmModel.addScopeMapping(client, appRole);
+        client.addScopeMapping(realmRole);
+        client.addScopeMapping(appRole);
 
         commit();
 
@@ -509,12 +509,12 @@ public class AdapterTest extends AbstractModelTest {
         app2 = realmModel.getApplicationByName("app2");
         client = realmModel.getOAuthClient("client");
 
-        Set<RoleModel> scopeMappings = realmModel.getScopeMappings(app2);
+        Set<RoleModel> scopeMappings = app2.getScopeMappings();
         Assert.assertEquals(2, scopeMappings.size());
         Assert.assertTrue(scopeMappings.contains(realmModel.getRole("realm")));
         Assert.assertTrue(scopeMappings.contains(app1.getRole("app")));
 
-        scopeMappings = realmModel.getScopeMappings(client);
+        scopeMappings = client.getScopeMappings();
         Assert.assertEquals(2, scopeMappings.size());
         Assert.assertTrue(scopeMappings.contains(realmModel.getRole("realm")));
         Assert.assertTrue(scopeMappings.contains(app1.getRole("app")));
diff --git a/model/tests/src/test/java/org/keycloak/model/test/AuthenticationManagerTest.java b/model/tests/src/test/java/org/keycloak/model/test/AuthenticationManagerTest.java
index a603226..24e894f 100755
--- a/model/tests/src/test/java/org/keycloak/model/test/AuthenticationManagerTest.java
+++ b/model/tests/src/test/java/org/keycloak/model/test/AuthenticationManagerTest.java
@@ -107,7 +107,7 @@ public class AuthenticationManagerTest extends AbstractModelTest {
         credential.setType(CredentialRepresentation.TOTP);
         credential.setValue(totpSecret);
 
-        realm.updateCredential(user, credential);
+        user.updateCredential(credential);
 
         user.setTotp(true);
 
@@ -175,7 +175,7 @@ public class AuthenticationManagerTest extends AbstractModelTest {
         credential.setType(CredentialRepresentation.PASSWORD);
         credential.setValue("password");
 
-        realm.updateCredential(user, credential);
+        user.updateCredential(credential);
 
         formData = new MultivaluedMapImpl<String, String>();
         formData.add("username", "test");
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 5d28b60..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
@@ -63,7 +63,7 @@ public class AuthProvidersExternalModelTest extends AbstractModelTest {
         UserCredentialModel credential = new UserCredentialModel();
         credential.setType(CredentialRepresentation.PASSWORD);
         credential.setValue("password");
-        realm1.updateCredential(john, credential);
+        john.updateCredential(credential);
 
         am = new AuthenticationManager(providerSession);
     }
@@ -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 cc6eaf1..155b235 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);
     }
@@ -112,7 +112,7 @@ public class AuthProvidersLDAPTest extends AbstractModelTest {
         UserCredentialModel credential = new UserCredentialModel();
         credential.setType(CredentialRepresentation.PASSWORD);
         credential.setValue("pass");
-        realm.updateCredential(realmUser, credential);
+        realmUser.updateCredential(credential);
 
         // User doesn't exists
         MultivaluedMap<String, String> formData = AuthProvidersExternalModelTest.createFormData("invalid", "invalid");
diff --git a/model/tests/src/test/java/org/keycloak/model/test/CompositeRolesModelTest.java b/model/tests/src/test/java/org/keycloak/model/test/CompositeRolesModelTest.java
index 4b872b3..071fcef 100755
--- a/model/tests/src/test/java/org/keycloak/model/test/CompositeRolesModelTest.java
+++ b/model/tests/src/test/java/org/keycloak/model/test/CompositeRolesModelTest.java
@@ -60,8 +60,8 @@ public class CompositeRolesModelTest extends AbstractModelTest {
         UserModel user = realm.getUser(username);
         ApplicationModel application = realm.getApplicationByName(applicationName);
 
-        Set<RoleModel> roleMappings = realm.getRoleMappings(user);
-        Set<RoleModel> scopeMappings = realm.getScopeMappings(application);
+        Set<RoleModel> roleMappings = user.getRoleMappings();
+        Set<RoleModel> scopeMappings = application.getScopeMappings();
         Set<RoleModel> appRoles = application.getRoles();
         if (appRoles != null) scopeMappings.addAll(appRoles);
 
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 cfd04b5..4264ff7 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
@@ -104,7 +104,7 @@ public class ImportTest extends AbstractModelTest {
 
         // Test role mappings
         UserModel admin = realm.getUser("admin");
-        Set<RoleModel> allRoles = realm.getRoleMappings(admin);
+        Set<RoleModel> allRoles = admin.getRoleMappings();
         Assert.assertEquals(5, allRoles.size());
         Assert.assertTrue(allRoles.contains(realm.getRole("admin")));
         Assert.assertTrue(allRoles.contains(application.getRole("app-admin")));
@@ -113,19 +113,19 @@ public class ImportTest extends AbstractModelTest {
         Assert.assertTrue(allRoles.contains(accountApp.getRole(AccountRoles.MANAGE_ACCOUNT)));
 
         UserModel wburke = realm.getUser("wburke");
-        allRoles = realm.getRoleMappings(wburke);
+        allRoles = wburke.getRoleMappings();
         Assert.assertEquals(4, allRoles.size());
         Assert.assertFalse(allRoles.contains(realm.getRole("admin")));
         Assert.assertTrue(allRoles.contains(application.getRole("app-user")));
         Assert.assertTrue(allRoles.contains(otherApp.getRole("otherapp-user")));
 
-        Assert.assertEquals(0, realm.getRealmRoleMappings(wburke).size());
+        Assert.assertEquals(0, wburke.getRealmRoleMappings().size());
 
-        Set<RoleModel> realmRoles = realm.getRealmRoleMappings(admin);
+        Set<RoleModel> realmRoles = admin.getRealmRoleMappings();
         Assert.assertEquals(1, realmRoles.size());
         Assert.assertEquals("admin", realmRoles.iterator().next().getName());
 
-        Set<RoleModel> appRoles = application.getApplicationRoleMappings(admin);
+        Set<RoleModel> appRoles = admin.getApplicationRoleMappings(application);
         Assert.assertEquals(1, appRoles.size());
         Assert.assertEquals("app-admin", appRoles.iterator().next().getName());
 
@@ -136,12 +136,12 @@ public class ImportTest extends AbstractModelTest {
         Assert.assertNotNull(oauthClient);
 
         // Test scope relationship
-        Set<RoleModel> allScopes = realm.getScopeMappings(oauthClient);
+        Set<RoleModel> allScopes = oauthClient.getScopeMappings();
         Assert.assertEquals(2, allScopes.size());
         Assert.assertTrue(allScopes.contains(realm.getRole("admin")));
         Assert.assertTrue(allScopes.contains(application.getRole("app-user")));
 
-        Set<RoleModel> realmScopes = realm.getRealmScopeMappings(oauthClient);
+        Set<RoleModel> realmScopes = oauthClient.getRealmScopeMappings();
         Assert.assertTrue(realmScopes.contains(realm.getRole("admin")));
 
         Set<RoleModel> appScopes = application.getApplicationScopeMappings(oauthClient);
@@ -222,7 +222,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/model/tests/src/test/java/org/keycloak/model/test/MultipleRealmsTest.java b/model/tests/src/test/java/org/keycloak/model/test/MultipleRealmsTest.java
index 35a0981..7f9f6b3 100755
--- a/model/tests/src/test/java/org/keycloak/model/test/MultipleRealmsTest.java
+++ b/model/tests/src/test/java/org/keycloak/model/test/MultipleRealmsTest.java
@@ -37,8 +37,8 @@ public class MultipleRealmsTest extends AbstractModelTest {
         Assert.assertNotEquals(r1user1.getId(), r2user1.getId());
 
         // Test password
-        realm1.updateCredential(r1user1, UserCredentialModel.password("pass1"));
-        realm2.updateCredential(r2user1, UserCredentialModel.password("pass2"));
+        r1user1.updateCredential(UserCredentialModel.password("pass1"));
+        r2user1.updateCredential(UserCredentialModel.password("pass2"));
 
         Assert.assertTrue(realm1.validatePassword(r1user1, "pass1"));
         Assert.assertFalse(realm1.validatePassword(r1user1, "pass2"));
@@ -97,7 +97,7 @@ public class MultipleRealmsTest extends AbstractModelTest {
         realm.addRole("role2");
 
         app1.addRole("app1Role1");
-        realm.addScopeMapping(app1, realm.getRole("role1"));
+        app1.addScopeMapping(realm.getRole("role1"));
 
         realm.addOAuthClient("cl1");
     }
diff --git a/project-integrations/aerogear-ups/auth-server/src/main/resources/META-INF/persistence.xml b/project-integrations/aerogear-ups/auth-server/src/main/resources/META-INF/persistence.xml
index a75390a..a704014 100755
--- a/project-integrations/aerogear-ups/auth-server/src/main/resources/META-INF/persistence.xml
+++ b/project-integrations/aerogear-ups/auth-server/src/main/resources/META-INF/persistence.xml
@@ -10,8 +10,7 @@
         <class>org.keycloak.models.jpa.entities.RealmEntity</class>
         <class>org.keycloak.models.jpa.entities.RequiredCredentialEntity</class>
         <class>org.keycloak.models.jpa.entities.AuthenticationProviderEntity</class>
-        <class>org.keycloak.models.jpa.entities.ApplicationRoleEntity</class>
-        <class>org.keycloak.models.jpa.entities.RealmRoleEntity</class>
+        <class>org.keycloak.models.jpa.entities.RoleEntity</class>
         <class>org.keycloak.models.jpa.entities.SocialLinkEntity</class>
         <class>org.keycloak.models.jpa.entities.AuthenticationLinkEntity</class>
         <class>org.keycloak.models.jpa.entities.UserEntity</class>
diff --git a/server/src/main/resources/META-INF/persistence.xml b/server/src/main/resources/META-INF/persistence.xml
index a75390a..a704014 100755
--- a/server/src/main/resources/META-INF/persistence.xml
+++ b/server/src/main/resources/META-INF/persistence.xml
@@ -10,8 +10,7 @@
         <class>org.keycloak.models.jpa.entities.RealmEntity</class>
         <class>org.keycloak.models.jpa.entities.RequiredCredentialEntity</class>
         <class>org.keycloak.models.jpa.entities.AuthenticationProviderEntity</class>
-        <class>org.keycloak.models.jpa.entities.ApplicationRoleEntity</class>
-        <class>org.keycloak.models.jpa.entities.RealmRoleEntity</class>
+        <class>org.keycloak.models.jpa.entities.RoleEntity</class>
         <class>org.keycloak.models.jpa.entities.SocialLinkEntity</class>
         <class>org.keycloak.models.jpa.entities.AuthenticationLinkEntity</class>
         <class>org.keycloak.models.jpa.entities.UserEntity</class>
diff --git a/services/src/main/java/org/keycloak/services/managers/ApplianceBootstrap.java b/services/src/main/java/org/keycloak/services/managers/ApplianceBootstrap.java
index 653cdc6..43b271f 100755
--- a/services/src/main/java/org/keycloak/services/managers/ApplianceBootstrap.java
+++ b/services/src/main/java/org/keycloak/services/managers/ApplianceBootstrap.java
@@ -71,15 +71,15 @@ public class ApplianceBootstrap {
         UserCredentialModel password = new UserCredentialModel();
         password.setType(UserCredentialModel.PASSWORD);
         password.setValue("admin");
-        realm.updateCredential(adminUser, password);
+        adminUser.updateCredential(password);
         adminUser.addRequiredAction(UserModel.RequiredAction.UPDATE_PASSWORD);
 
         RoleModel adminRole = realm.getRole(AdminRoles.ADMIN);
-        realm.grantRole(adminUser, adminRole);
+        adminUser.grantRole(adminRole);
 
         ApplicationModel accountApp = realm.getApplicationNameMap().get(Constants.ACCOUNT_MANAGEMENT_APP);
         for (String r : accountApp.getDefaultRoles()) {
-            realm.grantRole(adminUser, accountApp.getRole(r));
+            adminUser.grantRole(accountApp.getRole(r));
         }
     }
 
diff --git a/services/src/main/java/org/keycloak/services/managers/ApplicationManager.java b/services/src/main/java/org/keycloak/services/managers/ApplicationManager.java
index ae760e8..af861d4 100755
--- a/services/src/main/java/org/keycloak/services/managers/ApplicationManager.java
+++ b/services/src/main/java/org/keycloak/services/managers/ApplicationManager.java
@@ -126,7 +126,7 @@ public class ApplicationManager {
                 if (role == null) {
                     role = applicationModel.addRole(roleString.trim());
                 }
-                realm.grantRole(user, role);
+                user.grantRole(role);
             }
         }
     }
@@ -139,7 +139,7 @@ public class ApplicationManager {
                     role = applicationModel.addRole(roleString.trim());
                 }
                 ClientModel client = realm.findClient(mapping.getClient());
-                realm.addScopeMapping(client, role);
+                client.addScopeMapping(role);
             }
         }
     }
diff --git a/services/src/main/java/org/keycloak/services/managers/Auth.java b/services/src/main/java/org/keycloak/services/managers/Auth.java
index f13cfb2..01bf896 100755
--- a/services/src/main/java/org/keycloak/services/managers/Auth.java
+++ b/services/src/main/java/org/keycloak/services/managers/Auth.java
@@ -48,7 +48,7 @@ public class Auth {
 
     public boolean hasRealmRole(String role) {
         if (cookie) {
-            return realm.hasRole(user, realm.getRole(role));
+            return user.hasRole(realm.getRole(role));
         } else {
             AccessToken.Access access = token.getRealmAccess();
             return access != null && access.isUserInRole(role);
@@ -66,7 +66,7 @@ public class Auth {
 
     public boolean hasAppRole(ApplicationModel app, String role) {
         if (cookie) {
-            return realm.hasRole(user, app.getRole(role));
+            return user.hasRole(app.getRole(role));
         } else {
             AccessToken.Access access = token.getResourceAccess(app.getName());
             return access != null && access.isUserInRole(role);
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 c897d77..248e0ae 100755
--- a/services/src/main/java/org/keycloak/services/managers/RealmManager.java
+++ b/services/src/main/java/org/keycloak/services/managers/RealmManager.java
@@ -119,7 +119,7 @@ public class RealmManager {
             ApplicationModel realmAdminApp = realm.getApplicationByName(realmAdminApplicationName);
             adminRole = realmAdminApp.getRole(AdminRoles.REALM_ADMIN);
         }
-        realm.addScopeMapping(adminConsole, adminRole);
+        adminConsole.addScopeMapping(adminRole);
     }
 
     public String getMasterRealmAdminApplicationName(RealmModel realm) {
@@ -463,7 +463,7 @@ public class RealmManager {
                     if (role == null) {
                         role = newRealm.addRole(roleString.trim());
                     }
-                    newRealm.grantRole(user, role);
+                    user.grantRole(role);
                 }
             }
         }
@@ -476,7 +476,7 @@ public class RealmManager {
                         role = newRealm.addRole(roleString.trim());
                     }
                     ClientModel client = newRealm.findClient(scope.getClient());
-                    newRealm.addScopeMapping(client, role);
+                    client.addScopeMapping(role);
                 }
 
             }
@@ -569,13 +569,13 @@ public class RealmManager {
         if (userRep.getCredentials() != null) {
             for (CredentialRepresentation cred : userRep.getCredentials()) {
                 UserCredentialModel credential = fromRepresentation(cred);
-                newRealm.updateCredential(user, credential);
+                user.updateCredential(credential);
             }
         }
         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/managers/TokenManager.java b/services/src/main/java/org/keycloak/services/managers/TokenManager.java
index daa7786..3ff68b3 100755
--- a/services/src/main/java/org/keycloak/services/managers/TokenManager.java
+++ b/services/src/main/java/org/keycloak/services/managers/TokenManager.java
@@ -161,10 +161,10 @@ public class TokenManager {
                 if (role == null) {
                     throw new OAuthErrorException(OAuthErrorException.INVALID_GRANT, "Invalid realm role " + roleName);
                 }
-                if (!realm.hasRole(user, role)) {
+                if (!user.hasRole(role)) {
                     throw new OAuthErrorException(OAuthErrorException.INVALID_SCOPE, "User no long has permission for realm role: " + roleName);
                 }
-                if (!realm.hasScope(client, role)) {
+                if (!client.hasScope(role)) {
                     throw new OAuthErrorException(OAuthErrorException.INVALID_SCOPE, "Client no longer has realm scope: " + roleName);
                 }
             }
@@ -180,10 +180,10 @@ public class TokenManager {
                     if (role == null) {
                         throw new OAuthErrorException(OAuthErrorException.INVALID_GRANT, "Invalid refresh token", "Unknown application role: " + roleName);
                     }
-                    if (!realm.hasRole(user, role)) {
+                    if (!user.hasRole(role)) {
                         throw new OAuthErrorException(OAuthErrorException.INVALID_SCOPE, "User no long has permission for application role " + roleName);
                     }
-                    if (clientApp != null && !clientApp.equals(app) && !realm.hasScope(client, role)) {
+                    if (clientApp != null && !clientApp.equals(app) && !client.hasScope(role)) {
                         throw new OAuthErrorException(OAuthErrorException.INVALID_SCOPE, "Client no longer has application scope" + roleName);
                     }
                 }
@@ -210,8 +210,8 @@ public class TokenManager {
     public AccessToken createClientAccessToken(String scopeParam, RealmModel realm, ClientModel client, UserModel user, UserSessionModel session, List<RoleModel> realmRolesRequested, MultivaluedMap<String, RoleModel> resourceRolesRequested) {
         // todo scopeParam is ignored until we figure out a scheme that fits with openid connect
 
-        Set<RoleModel> roleMappings = realm.getRoleMappings(user);
-        Set<RoleModel> scopeMappings = realm.getScopeMappings(client);
+        Set<RoleModel> roleMappings = user.getRoleMappings();
+        Set<RoleModel> scopeMappings = client.getScopeMappings();
         ApplicationModel clientApp = (client instanceof ApplicationModel) ? (ApplicationModel)client : null;
         Set<RoleModel> clientAppRoles = clientApp == null ? null : clientApp.getRoles();
         if (clientAppRoles != null) scopeMappings.addAll(clientAppRoles);
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 a9ee774..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();
@@ -402,7 +402,7 @@ public class AccountService {
         UserCredentialModel credentials = new UserCredentialModel();
         credentials.setType(CredentialRepresentation.TOTP);
         credentials.setValue(totpSecret);
-        realm.updateCredential(user, credentials);
+        user.updateCredential(credentials);
 
         user.setTotp(true);
 
@@ -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());
diff --git a/services/src/main/java/org/keycloak/services/resources/admin/AdminAuth.java b/services/src/main/java/org/keycloak/services/resources/admin/AdminAuth.java
index dcfad7c..ca7dece 100755
--- a/services/src/main/java/org/keycloak/services/resources/admin/AdminAuth.java
+++ b/services/src/main/java/org/keycloak/services/resources/admin/AdminAuth.java
@@ -45,7 +45,7 @@ public class AdminAuth {
     public boolean hasRealmRole(String role) {
         if (client instanceof ApplicationModel) {
             RoleModel roleModel = realm.getRole(role);
-            return realm.hasRole(user, roleModel) && realm.hasScope(client, roleModel);
+            return user.hasRole(roleModel) && client.hasScope(roleModel);
         } else {
             AccessToken.Access access = token.getRealmAccess();
             return access != null && access.isUserInRole(role);
@@ -64,7 +64,7 @@ public class AdminAuth {
     public boolean hasAppRole(ApplicationModel app, String role) {
         if (client instanceof ApplicationModel) {
             RoleModel roleModel = app.getRole(role);
-            return realm.hasRole(user, roleModel) && realm.hasScope(client, roleModel);
+            return user.hasRole(roleModel) && client.hasScope(roleModel);
         } else {
             AccessToken.Access access = token.getResourceAccess(app.getName());
             return access != null && access.isUserInRole(role);
diff --git a/services/src/main/java/org/keycloak/services/resources/admin/AdminConsole.java b/services/src/main/java/org/keycloak/services/resources/admin/AdminConsole.java
index 9104ea9..3f2d0ed 100755
--- a/services/src/main/java/org/keycloak/services/resources/admin/AdminConsole.java
+++ b/services/src/main/java/org/keycloak/services/resources/admin/AdminConsole.java
@@ -200,7 +200,7 @@ public class AdminConsole {
         boolean createRealm = false;
         if (realm.equals(masterRealm)) {
             logger.info("setting up realm access for a master realm user");
-            createRealm = masterRealm.hasRole(user, masterRealm.getRole(AdminRoles.CREATE_REALM));
+            createRealm = user.hasRole(masterRealm.getRole(AdminRoles.CREATE_REALM));
             addMasterRealmAccess(realm, user, realmAccess);
         } else {
             logger.info("setting up realm access for a realm user");
@@ -219,7 +219,7 @@ public class AdminConsole {
         ApplicationModel realmAdminApp = realm.getApplicationByName(realmManager.getRealmAdminApplicationName(realm));
         Set<RoleModel> roles = realmAdminApp.getRoles();
         for (RoleModel role : roles) {
-            if (!realm.hasRole(user, role)) continue;
+            if (!user.hasRole(role)) continue;
             if (!realmAdminAccess.containsKey(realm.getName())) {
                 realmAdminAccess.put(realm.getName(), new HashSet<String>());
             }
@@ -234,7 +234,7 @@ public class AdminConsole {
             ApplicationModel realmAdminApp = realm.getMasterAdminApp();
             Set<RoleModel> roles = realmAdminApp.getRoles();
             for (RoleModel role : roles) {
-                if (!masterRealm.hasRole(user, role)) continue;
+                if (!user.hasRole(role)) continue;
                 if (!realmAdminAccess.containsKey(realm.getName())) {
                     realmAdminAccess.put(realm.getName(), new HashSet<String>());
                 }
diff --git a/services/src/main/java/org/keycloak/services/resources/admin/RealmsAdminResource.java b/services/src/main/java/org/keycloak/services/resources/admin/RealmsAdminResource.java
index 50d5442..9e888a0 100755
--- a/services/src/main/java/org/keycloak/services/resources/admin/RealmsAdminResource.java
+++ b/services/src/main/java/org/keycloak/services/resources/admin/RealmsAdminResource.java
@@ -198,7 +198,7 @@ public class RealmsAdminResource {
         ApplicationModel realmAdminApp = realm.getMasterAdminApp();
         for (String r : AdminRoles.ALL_REALM_ROLES) {
             RoleModel role = realmAdminApp.getRole(r);
-            adminRealm.grantRole(auth.getUser(), role);
+            auth.getUser().grantRole(role);
         }
     }
 
diff --git a/services/src/main/java/org/keycloak/services/resources/admin/ScopeMappedResource.java b/services/src/main/java/org/keycloak/services/resources/admin/ScopeMappedResource.java
index 200e0ae..92b129c 100755
--- a/services/src/main/java/org/keycloak/services/resources/admin/ScopeMappedResource.java
+++ b/services/src/main/java/org/keycloak/services/resources/admin/ScopeMappedResource.java
@@ -58,7 +58,7 @@ public class ScopeMappedResource {
         auth.requireView();
 
         MappingsRepresentation all = new MappingsRepresentation();
-        Set<RoleModel> realmMappings = realm.getRealmScopeMappings(client);
+        Set<RoleModel> realmMappings = client.getRealmScopeMappings();
         if (realmMappings.size() > 0) {
             List<RoleRepresentation> realmRep = new ArrayList<RoleRepresentation>();
             for (RoleModel roleModel : realmMappings) {
@@ -101,7 +101,7 @@ public class ScopeMappedResource {
     public List<RoleRepresentation> getRealmScopeMappings() {
         auth.requireView();
 
-        Set<RoleModel> realmMappings = realm.getRealmScopeMappings(client);
+        Set<RoleModel> realmMappings = client.getRealmScopeMappings();
         List<RoleRepresentation> realmMappingsRep = new ArrayList<RoleRepresentation>();
         for (RoleModel roleModel : realmMappings) {
             realmMappingsRep.add(ModelToRepresentation.toRepresentation(roleModel));
@@ -128,7 +128,7 @@ public class ScopeMappedResource {
     private List<RoleRepresentation> getAvailable(Set<RoleModel> roles) {
         List<RoleRepresentation> available = new ArrayList<RoleRepresentation>();
         for (RoleModel roleModel : roles) {
-            if (realm.hasScope(client, roleModel)) continue;
+            if (client.hasScope(roleModel)) continue;
             available.add(ModelToRepresentation.toRepresentation(roleModel));
         }
         return available;
@@ -155,7 +155,7 @@ public class ScopeMappedResource {
     private List<RoleRepresentation> getComposite(Set<RoleModel> roles) {
         List<RoleRepresentation> composite = new ArrayList<RoleRepresentation>();
         for (RoleModel roleModel : roles) {
-            if (realm.hasScope(client, roleModel)) composite.add(ModelToRepresentation.toRepresentation(roleModel));
+            if (client.hasScope(roleModel)) composite.add(ModelToRepresentation.toRepresentation(roleModel));
         }
         return composite;
     }
@@ -176,7 +176,7 @@ public class ScopeMappedResource {
             if (roleModel == null) {
                 throw new NotFoundException("Role not found");
             }
-            realm.addScopeMapping(client, roleModel);
+            client.addScopeMapping(roleModel);
         }
 
 
@@ -194,9 +194,9 @@ public class ScopeMappedResource {
         auth.requireManage();
 
         if (roles == null) {
-            Set<RoleModel> roleModels = realm.getRealmScopeMappings(client);
+            Set<RoleModel> roleModels = client.getRealmScopeMappings();
             for (RoleModel roleModel : roleModels) {
-                realm.deleteScopeMapping(client, roleModel);
+                client.deleteScopeMapping(roleModel);
             }
 
         } else {
@@ -205,7 +205,7 @@ public class ScopeMappedResource {
                 if (roleModel == null) {
                     throw new NotFoundException("Role not found");
                 }
-                realm.deleteScopeMapping(client, roleModel);
+                client.deleteScopeMapping(roleModel);
             }
         }
     }
@@ -306,7 +306,7 @@ public class ScopeMappedResource {
             if (roleModel == null) {
                 throw new NotFoundException("Role not found");
             }
-            realm.addScopeMapping(client, roleModel);
+            client.addScopeMapping(roleModel);
         }
 
     }
@@ -332,7 +332,7 @@ public class ScopeMappedResource {
         if (roles == null) {
             Set<RoleModel> roleModels = app.getApplicationScopeMappings(client);
             for (RoleModel roleModel : roleModels) {
-                realm.deleteScopeMapping(client, roleModel);
+                client.deleteScopeMapping(roleModel);
             }
 
         } else {
@@ -341,7 +341,7 @@ public class ScopeMappedResource {
                 if (roleModel == null) {
                     throw new NotFoundException("Role not found");
                 }
-                realm.deleteScopeMapping(client, roleModel);
+                client.deleteScopeMapping(roleModel);
             }
         }
     }
diff --git a/services/src/main/java/org/keycloak/services/resources/admin/UsersResource.java b/services/src/main/java/org/keycloak/services/resources/admin/UsersResource.java
index 8297e7f..5af1d41 100755
--- a/services/src/main/java/org/keycloak/services/resources/admin/UsersResource.java
+++ b/services/src/main/java/org/keycloak/services/resources/admin/UsersResource.java
@@ -376,7 +376,7 @@ public class UsersResource {
         }
 
         MappingsRepresentation all = new MappingsRepresentation();
-        Set<RoleModel> realmMappings = realm.getRoleMappings(user);
+        Set<RoleModel> realmMappings = user.getRoleMappings();
         RealmManager manager = new RealmManager(session);
         if (realmMappings.size() > 0) {
             List<RoleRepresentation> realmRep = new ArrayList<RoleRepresentation>();
@@ -390,7 +390,7 @@ public class UsersResource {
         if (applications.size() > 0) {
             Map<String, ApplicationMappingsRepresentation> appMappings = new HashMap<String, ApplicationMappingsRepresentation>();
             for (ApplicationModel application : applications) {
-                Set<RoleModel> roleMappings = application.getApplicationRoleMappings(user);
+                Set<RoleModel> roleMappings = user.getApplicationRoleMappings(application);
                 if (roleMappings.size() > 0) {
                     ApplicationMappingsRepresentation mappings = new ApplicationMappingsRepresentation();
                     mappings.setApplicationId(application.getId());
@@ -426,7 +426,7 @@ public class UsersResource {
             throw new NotFoundException("User not found");
         }
 
-        Set<RoleModel> realmMappings = realm.getRealmRoleMappings(user);
+        Set<RoleModel> realmMappings = user.getRealmRoleMappings();
         List<RoleRepresentation> realmMappingsRep = new ArrayList<RoleRepresentation>();
         for (RoleModel roleModel : realmMappings) {
             realmMappingsRep.add(ModelToRepresentation.toRepresentation(roleModel));
@@ -455,7 +455,7 @@ public class UsersResource {
         Set<RoleModel> roles = realm.getRoles();
         List<RoleRepresentation> realmMappingsRep = new ArrayList<RoleRepresentation>();
         for (RoleModel roleModel : roles) {
-            if (realm.hasRole(user, roleModel)) {
+            if (user.hasRole(roleModel)) {
                realmMappingsRep.add(ModelToRepresentation.toRepresentation(roleModel));
             }
         }
@@ -507,7 +507,7 @@ public class UsersResource {
             if (roleModel == null || !roleModel.getId().equals(role.getId())) {
                 throw new NotFoundException("Role not found");
             }
-            realm.grantRole(user, roleModel);
+            user.grantRole(roleModel);
         }
 
 
@@ -532,9 +532,9 @@ public class UsersResource {
         }
 
         if (roles == null) {
-            Set<RoleModel> roleModels = realm.getRealmRoleMappings(user);
+            Set<RoleModel> roleModels = user.getRealmRoleMappings();
             for (RoleModel roleModel : roleModels) {
-                realm.deleteRoleMapping(user, roleModel);
+                user.deleteRoleMapping(roleModel);
             }
 
         } else {
@@ -543,7 +543,7 @@ public class UsersResource {
                 if (roleModel == null || !roleModel.getId().equals(role.getId())) {
                     throw new NotFoundException("Role not found");
                 }
-                realm.deleteRoleMapping(user, roleModel);
+                user.deleteRoleMapping(roleModel);
             }
         }
     }
@@ -575,7 +575,7 @@ public class UsersResource {
             throw new NotFoundException("Application not found");
         }
 
-        Set<RoleModel> mappings = application.getApplicationRoleMappings(user);
+        Set<RoleModel> mappings = user.getApplicationRoleMappings(application);
         List<RoleRepresentation> mapRep = new ArrayList<RoleRepresentation>();
         for (RoleModel roleModel : mappings) {
             mapRep.add(ModelToRepresentation.toRepresentation(roleModel));
@@ -614,7 +614,7 @@ public class UsersResource {
         Set<RoleModel> roles = application.getRoles();
         List<RoleRepresentation> mapRep = new ArrayList<RoleRepresentation>();
         for (RoleModel roleModel : roles) {
-            if (realm.hasRole(user, roleModel)) mapRep.add(ModelToRepresentation.toRepresentation(roleModel));
+            if (user.hasRole(roleModel)) mapRep.add(ModelToRepresentation.toRepresentation(roleModel));
         }
         logger.debugv("getCompositeApplicationRoleMappings.size() = {0}", mapRep.size());
         return mapRep;
@@ -653,7 +653,7 @@ public class UsersResource {
     protected List<RoleRepresentation> getAvailableRoles(UserModel user, Set<RoleModel> available) {
         Set<RoleModel> roles = new HashSet<RoleModel>();
         for (RoleModel roleModel : available) {
-            if (realm.hasRole(user, roleModel)) continue;
+            if (user.hasRole(roleModel)) continue;
             roles.add(roleModel);
         }
 
@@ -694,7 +694,7 @@ public class UsersResource {
             if (roleModel == null || !roleModel.getId().equals(role.getId())) {
                 throw new NotFoundException("Role not found");
             }
-            realm.grantRole(user, roleModel);
+            user.grantRole(roleModel);
         }
 
     }
@@ -724,13 +724,13 @@ public class UsersResource {
         }
 
         if (roles == null) {
-            Set<RoleModel> roleModels = application.getApplicationRoleMappings(user);
+            Set<RoleModel> roleModels = user.getApplicationRoleMappings(application);
             for (RoleModel roleModel : roleModels) {
                 if (!(roleModel.getContainer() instanceof ApplicationModel)) {
                     ApplicationModel app = (ApplicationModel) roleModel.getContainer();
                     if (!app.getId().equals(application.getId())) continue;
                 }
-                realm.deleteRoleMapping(user, roleModel);
+                user.deleteRoleMapping(roleModel);
             }
 
         } else {
@@ -739,7 +739,7 @@ public class UsersResource {
                 if (roleModel == null || !roleModel.getId().equals(role.getId())) {
                     throw new NotFoundException("Role not found");
                 }
-                realm.deleteRoleMapping(user, roleModel);
+                user.deleteRoleMapping(roleModel);
             }
         }
     }
@@ -766,7 +766,7 @@ public class UsersResource {
         }
 
         UserCredentialModel cred = RealmManager.fromRepresentation(pass);
-        realm.updateCredential(user, cred);
+        user.updateCredential(cred);
         user.addRequiredAction(UserModel.RequiredAction.UPDATE_PASSWORD);
     }
 
diff --git a/services/src/main/java/org/keycloak/services/resources/RequiredActionsService.java b/services/src/main/java/org/keycloak/services/resources/RequiredActionsService.java
index 335b10b..7132d6e 100755
--- a/services/src/main/java/org/keycloak/services/resources/RequiredActionsService.java
+++ b/services/src/main/java/org/keycloak/services/resources/RequiredActionsService.java
@@ -171,7 +171,7 @@ public class RequiredActionsService {
         UserCredentialModel credentials = new UserCredentialModel();
         credentials.setType(CredentialRepresentation.TOTP);
         credentials.setValue(totpSecret);
-        realm.updateCredential(user, credentials);
+        user.updateCredential(credentials);
 
         user.setTotp(true);
 
diff --git a/services/src/main/java/org/keycloak/services/resources/SocialResource.java b/services/src/main/java/org/keycloak/services/resources/SocialResource.java
index 2c7a4f4..08073ec 100755
--- a/services/src/main/java/org/keycloak/services/resources/SocialResource.java
+++ b/services/src/main/java/org/keycloak/services/resources/SocialResource.java
@@ -210,7 +210,7 @@ public class SocialResource {
                 return oauth.forwardToSecurityFailure("User is disabled");
             }
 
-            if (!realm.hasRole(authenticatedUser, realm.getApplicationByName(Constants.ACCOUNT_MANAGEMENT_APP).getRole(AccountRoles.MANAGE_ACCOUNT))) {
+            if (!authenticatedUser.hasRole(realm.getApplicationByName(Constants.ACCOUNT_MANAGEMENT_APP).getRole(AccountRoles.MANAGE_ACCOUNT))) {
                 audit.error(Errors.NOT_ALLOWED);
                 return oauth.forwardToSecurityFailure("Insufficient permissions to link social account");
             }
diff --git a/testsuite/integration/src/main/resources/log4j.properties b/testsuite/integration/src/main/resources/log4j.properties
index bc27773..47ecd4e 100755
--- a/testsuite/integration/src/main/resources/log4j.properties
+++ b/testsuite/integration/src/main/resources/log4j.properties
@@ -4,4 +4,4 @@ log4j.appender.stdout=org.apache.log4j.ConsoleAppender
 log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
 log4j.appender.stdout.layout.ConversionPattern=%d{HH:mm:ss,SSS} %-5p [%c] %m%n
 
-log4j.logger.org.keycloak=debug
\ No newline at end of file
+log4j.logger.org.keycloak=warn
diff --git a/testsuite/integration/src/main/resources/META-INF/persistence.xml b/testsuite/integration/src/main/resources/META-INF/persistence.xml
index 6e68551..39dd390 100755
--- a/testsuite/integration/src/main/resources/META-INF/persistence.xml
+++ b/testsuite/integration/src/main/resources/META-INF/persistence.xml
@@ -11,8 +11,7 @@
         <class>org.keycloak.models.jpa.entities.RealmEntity</class>
         <class>org.keycloak.models.jpa.entities.RequiredCredentialEntity</class>
         <class>org.keycloak.models.jpa.entities.AuthenticationProviderEntity</class>
-        <class>org.keycloak.models.jpa.entities.ApplicationRoleEntity</class>
-        <class>org.keycloak.models.jpa.entities.RealmRoleEntity</class>
+        <class>org.keycloak.models.jpa.entities.RoleEntity</class>
         <class>org.keycloak.models.jpa.entities.SocialLinkEntity</class>
         <class>org.keycloak.models.jpa.entities.AuthenticationLinkEntity</class>
         <class>org.keycloak.models.jpa.entities.UserEntity</class>
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 7bec7a7..7c4925f 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
@@ -82,12 +82,12 @@ public class AccountTest {
             UserModel user2 = appRealm.addUser("test-user-no-access@localhost");
             user2.setEnabled(true);
             for (String r : accountApp.getDefaultRoles()) {
-                appRealm.deleteRoleMapping(user2, accountApp.getRole(r));
+                user2.deleteRoleMapping(accountApp.getRole(r));
             }
             UserCredentialModel creds = new UserCredentialModel();
             creds.setType(CredentialRepresentation.PASSWORD);
             creds.setValue("password");
-            appRealm.updateCredential(user2, creds);
+            user2.updateCredential(creds);
         }
     });
 
@@ -153,7 +153,7 @@ public class AccountTest {
                 cred.setType(CredentialRepresentation.PASSWORD);
                 cred.setValue("password");
 
-                appRealm.updateCredential(user, cred);
+                user.updateCredential(cred);
             }
         });
     }
diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/account/ProfileTest.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/account/ProfileTest.java
index eee56e0..af78795 100755
--- a/testsuite/integration/src/test/java/org/keycloak/testsuite/account/ProfileTest.java
+++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/account/ProfileTest.java
@@ -59,20 +59,20 @@ public class ProfileTest {
             UserModel user2 = appRealm.addUser("test-user-no-access@localhost");
             user2.setEnabled(true);
             for (String r : accountApp.getDefaultRoles()) {
-                appRealm.deleteRoleMapping(user2, accountApp.getRole(r));
+                user2.deleteRoleMapping(accountApp.getRole(r));
             }
             UserCredentialModel creds = new UserCredentialModel();
             creds.setType(CredentialRepresentation.PASSWORD);
             creds.setValue("password");
-            appRealm.updateCredential(user2, creds);
+            user2.updateCredential(creds);
 
             ApplicationModel app = appRealm.getApplicationNameMap().get("test-app");
-            appRealm.addScopeMapping(app, accountApp.getRole(AccountRoles.VIEW_PROFILE));
+            app.addScopeMapping(accountApp.getRole(AccountRoles.VIEW_PROFILE));
             app.addRedirectUri("http://localhost:8081/app/*");
             app.addWebOrigin("http://localtest.me:8081");
 
             ClientModel thirdParty = appRealm.findClient("third-party");
-            appRealm.addScopeMapping(thirdParty, accountApp.getRole(AccountRoles.VIEW_PROFILE));
+            thirdParty.addScopeMapping(accountApp.getRole(AccountRoles.VIEW_PROFILE));
         }
     });
 
diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/composites/CompositeRoleTest.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/composites/CompositeRoleTest.java
index c354f0d..eaae048 100755
--- a/testsuite/integration/src/test/java/org/keycloak/testsuite/composites/CompositeRoleTest.java
+++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/composites/CompositeRoleTest.java
@@ -77,17 +77,17 @@ public class CompositeRoleTest {
 
             final UserModel realmComposite1User = realm.addUser("REALM_COMPOSITE_1_USER");
             realmComposite1User.setEnabled(true);
-            realm.updateCredential(realmComposite1User, UserCredentialModel.password("password"));
-            realm.grantRole(realmComposite1User, realmComposite1);
+            realmComposite1User.updateCredential(UserCredentialModel.password("password"));
+            realmComposite1User.grantRole(realmComposite1);
 
             final UserModel realmRole1User = realm.addUser("REALM_ROLE_1_USER");
             realmRole1User.setEnabled(true);
-            realm.updateCredential(realmRole1User, UserCredentialModel.password("password"));
-            realm.grantRole(realmRole1User, realmRole1);
+            realmRole1User.updateCredential(UserCredentialModel.password("password"));
+            realmRole1User.grantRole(realmRole1);
 
             final ApplicationModel realmComposite1Application = new ApplicationManager(manager).createApplication(realm, "REALM_COMPOSITE_1_APPLICATION");
             realmComposite1Application.setEnabled(true);
-            realm.addScopeMapping(realmComposite1Application, realmComposite1);
+            realmComposite1Application.addScopeMapping(realmComposite1);
             realmComposite1Application.addRedirectUri("http://localhost:8081/app/*");
             realmComposite1Application.setBaseUrl("http://localhost:8081/app");
             realmComposite1Application.setManagementUrl("http://localhost:8081/app/logout");
@@ -95,7 +95,7 @@ public class CompositeRoleTest {
 
             final ApplicationModel realmRole1Application = new ApplicationManager(manager).createApplication(realm, "REALM_ROLE_1_APPLICATION");
             realmRole1Application.setEnabled(true);
-            realm.addScopeMapping(realmRole1Application, realmRole1);
+            realmRole1Application.addScopeMapping(realmRole1);
             realmRole1Application.addRedirectUri("http://localhost:8081/app/*");
             realmRole1Application.setBaseUrl("http://localhost:8081/app");
             realmRole1Application.setManagementUrl("http://localhost:8081/app/logout");
@@ -116,13 +116,13 @@ public class CompositeRoleTest {
 
             final UserModel realmAppCompositeUser = realm.addUser("REALM_APP_COMPOSITE_USER");
             realmAppCompositeUser.setEnabled(true);
-            realm.updateCredential(realmAppCompositeUser, UserCredentialModel.password("password"));
-            realm.grantRole(realmAppCompositeUser, realmAppCompositeRole);
+            realmAppCompositeUser.updateCredential(UserCredentialModel.password("password"));
+            realmAppCompositeUser.grantRole(realmAppCompositeRole);
 
             final UserModel realmAppRoleUser = realm.addUser("REALM_APP_ROLE_USER");
             realmAppRoleUser.setEnabled(true);
-            realm.updateCredential(realmAppRoleUser, UserCredentialModel.password("password"));
-            realm.grantRole(realmAppRoleUser, appRole2);
+            realmAppRoleUser.updateCredential(UserCredentialModel.password("password"));
+            realmAppRoleUser.grantRole(appRole2);
 
             final ApplicationModel appCompositeApplication = new ApplicationManager(manager).createApplication(realm, "APP_COMPOSITE_APPLICATION");
             appCompositeApplication.setEnabled(true);
@@ -131,7 +131,7 @@ public class CompositeRoleTest {
             appCompositeApplication.setManagementUrl("http://localhost:8081/app/logout");
             appCompositeApplication.setSecret("password");
             final RoleModel appCompositeRole = appCompositeApplication.addRole("APP_COMPOSITE_ROLE");
-            realm.addScopeMapping(appCompositeApplication, appRole2);
+            appCompositeApplication.addScopeMapping(appRole2);
             appCompositeRole.addCompositeRole(realmRole1);
             appCompositeRole.addCompositeRole(realmRole2);
             appCompositeRole.addCompositeRole(realmRole3);
@@ -139,9 +139,9 @@ public class CompositeRoleTest {
 
             final UserModel appCompositeUser = realm.addUser("APP_COMPOSITE_USER");
             appCompositeUser.setEnabled(true);
-            realm.updateCredential(appCompositeUser, UserCredentialModel.password("password"));
-            realm.grantRole(appCompositeUser, realmAppCompositeRole);
-            realm.grantRole(appCompositeUser, realmComposite1);
+            appCompositeUser.updateCredential(UserCredentialModel.password("password"));
+            appCompositeUser.grantRole(realmAppCompositeRole);
+            appCompositeUser.grantRole(realmComposite1);
 
             deployServlet("app", "/app", ApplicationServlet.class);
 
diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/forms/AuthProvidersIntegrationTest.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/forms/AuthProvidersIntegrationTest.java
index 839813c..18021da 100755
--- a/testsuite/integration/src/test/java/org/keycloak/testsuite/forms/AuthProvidersIntegrationTest.java
+++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/forms/AuthProvidersIntegrationTest.java
@@ -104,7 +104,7 @@ public class AuthProvidersIntegrationTest {
         creds.setType(CredentialRepresentation.PASSWORD);
         creds.setValue(password);
 
-        realm.updateCredential(user, creds);
+        user.updateCredential(creds);
         return user;
     }
 
diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/forms/LoginTest.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/forms/LoginTest.java
old mode 100644
new mode 100755
index af561d1..277bc7a
--- a/testsuite/integration/src/test/java/org/keycloak/testsuite/forms/LoginTest.java
+++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/forms/LoginTest.java
@@ -61,7 +61,7 @@ public class LoginTest {
             creds.setType(CredentialRepresentation.PASSWORD);
             creds.setValue("password");
 
-            appRealm.updateCredential(user, creds);
+            user.updateCredential(creds);
         }
     });
 
diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/forms/LoginTotpTest.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/forms/LoginTotpTest.java
index 15710b1..eadf367 100755
--- a/testsuite/integration/src/test/java/org/keycloak/testsuite/forms/LoginTotpTest.java
+++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/forms/LoginTotpTest.java
@@ -63,7 +63,7 @@ public class LoginTotpTest {
             UserCredentialModel credentials = new UserCredentialModel();
             credentials.setType(CredentialRepresentation.TOTP);
             credentials.setValue("totpSecret");
-            appRealm.updateCredential(user, credentials);
+            user.updateCredential(credentials);
 
             user.setTotp(true);
             appRealm.setAuditListeners(Collections.singleton("dummy"));
diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/forms/ResetPasswordTest.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/forms/ResetPasswordTest.java
index ae5cfce..0946727 100755
--- a/testsuite/integration/src/test/java/org/keycloak/testsuite/forms/ResetPasswordTest.java
+++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/forms/ResetPasswordTest.java
@@ -72,7 +72,7 @@ public class ResetPasswordTest {
             creds.setType(CredentialRepresentation.PASSWORD);
             creds.setValue("password");
 
-            appRealm.updateCredential(user, creds);
+            user.updateCredential(creds);
             appRealm.setAuditListeners(Collections.singleton("dummy"));
         }
     }));
diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/perf/AccessTokenPerfTest.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/perf/AccessTokenPerfTest.java
index f0b9318..c5d3a02 100755
--- a/testsuite/integration/src/test/java/org/keycloak/testsuite/perf/AccessTokenPerfTest.java
+++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/perf/AccessTokenPerfTest.java
@@ -22,14 +22,20 @@
 package org.keycloak.testsuite.perf;
 
 import org.apache.http.NameValuePair;
+import org.apache.http.client.CookieStore;
+import org.apache.http.client.HttpClient;
 import org.apache.http.client.utils.URLEncodedUtils;
+import org.apache.http.cookie.Cookie;
+import org.apache.http.impl.client.DefaultHttpClient;
 import org.jboss.resteasy.client.jaxrs.ResteasyClient;
 import org.jboss.resteasy.client.jaxrs.ResteasyClientBuilder;
+import org.jboss.resteasy.client.jaxrs.engines.ApacheHttpClient4Engine;
 import org.junit.Assert;
 import org.junit.ClassRule;
 import org.junit.Rule;
 import org.junit.Test;
 import org.keycloak.OAuth2Constants;
+import org.keycloak.adapters.HttpClientBuilder;
 import org.keycloak.audit.Details;
 import org.keycloak.audit.Errors;
 import org.keycloak.audit.Event;
@@ -53,6 +59,8 @@ import javax.ws.rs.core.Response;
 import javax.ws.rs.core.UriBuilder;
 
 import java.net.URI;
+import java.util.Collections;
+import java.util.Date;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
@@ -72,15 +80,22 @@ public class AccessTokenPerfTest {
 
     public static class BrowserLogin implements Runnable
     {
+
+        private WebDriver driver;
+
+        public BrowserLogin() {
+            driver = WebRule.createWebDriver();
+        }
+
         @Override
         public void run() {
-            WebDriver driver = WebRule.createWebDriver();
+            driver.manage().deleteAllCookies();
             OAuthClient oauth = new OAuthClient(driver);
             oauth.doLogin("test-user@localhost", "password");
             String code = oauth.getCurrentQuery().get(OAuth2Constants.CODE);
             AccessTokenResponse response = oauth.doAccessTokenRequest(code, "password");
             Assert.assertEquals(200, response.getStatusCode());
-            driver.close();
+            count.incrementAndGet();
 
         }
     }
@@ -105,7 +120,30 @@ public class AccessTokenPerfTest {
 
 
         public JaxrsClientLogin() {
-            this.client = new ResteasyClientBuilder().build();
+            DefaultHttpClient httpClient = (DefaultHttpClient) new HttpClientBuilder().build();
+            httpClient.setCookieStore(new CookieStore() {
+                @Override
+                public void addCookie(Cookie cookie) {
+                    //To change body of implemented methods use File | Settings | File Templates.
+                }
+
+                @Override
+                public List<Cookie> getCookies() {
+                    return Collections.emptyList();
+                }
+
+                @Override
+                public boolean clearExpired(Date date) {
+                    return false;  //To change body of implemented methods use File | Settings | File Templates.
+                }
+
+                @Override
+                public void clear() {
+                    //To change body of implemented methods use File | Settings | File Templates.
+                }
+            });
+            ApacheHttpClient4Engine engine = new ApacheHttpClient4Engine(httpClient);
+            this.client = new ResteasyClientBuilder().httpEngine(engine).build();
         }
 
         public String getLoginFormUrl(String state) {
@@ -142,7 +180,7 @@ public class AccessTokenPerfTest {
 
         @Override
         public void run() {
-            this.client = new ResteasyClientBuilder().build();
+            //this.client = new ResteasyClientBuilder().build();
             String state = "42";
             Response response = client.target(getLoginFormUrl(state)).request().get();
             URI uri = null;
@@ -173,7 +211,7 @@ public class AccessTokenPerfTest {
                     .header(HttpHeaders.AUTHORIZATION, authorization)
                     .post(Entity.form(form), String.class);
             count.incrementAndGet();
-            client.close();
+            //client.close();
         }
 
         public String getCode(URI uri) {
@@ -196,7 +234,7 @@ public class AccessTokenPerfTest {
     @Test
     public void perfJaxrsClientLogin()
     {
-        long ITERATIONS = 1;
+        long ITERATIONS = 100;
         JaxrsClientLogin login = new JaxrsClientLogin();
         long start = System.currentTimeMillis();
         for (int i = 0; i < ITERATIONS; i++) {
@@ -207,12 +245,13 @@ public class AccessTokenPerfTest {
     }
 
     @Test
-    public void perfBrowserLogin() throws Exception
+    public void perfBrowserLogin()
     {
-        long ITERATIONS = 1;
+        long ITERATIONS = 100;
         long start = System.currentTimeMillis();
+        BrowserLogin login = new BrowserLogin();
         for (int i = 0; i < ITERATIONS; i++) {
-            new BrowserLogin().run();
+            login.run();
         }
         long end = System.currentTimeMillis() - start;
         System.out.println("took: " + end);
@@ -220,7 +259,7 @@ public class AccessTokenPerfTest {
 
     @Test
     public void multiThread() throws Exception {
-        int num_threads = 1;
+        int num_threads = 20;
         Thread[] threads = new Thread[num_threads];
         for (int i = 0; i < num_threads; i++) {
             threads[i] = new Thread(new Runnable() {
diff --git a/testsuite/performance/src/test/java/org/keycloak/testsuite/performance/CreateUsersWorker.java b/testsuite/performance/src/test/java/org/keycloak/testsuite/performance/CreateUsersWorker.java
index 62d22af..ae7795d 100755
--- a/testsuite/performance/src/test/java/org/keycloak/testsuite/performance/CreateUsersWorker.java
+++ b/testsuite/performance/src/test/java/org/keycloak/testsuite/performance/CreateUsersWorker.java
@@ -83,7 +83,7 @@ public class CreateUsersWorker implements Worker {
             UserCredentialModel password = new UserCredentialModel();
             password.setType(CredentialRepresentation.PASSWORD);
             password.setValue(username);
-            realm.updateCredential(user, password);
+            user.updateCredential(password);
         }
 
         // Creating some socialLinks
diff --git a/testsuite/performance/src/test/java/org/keycloak/testsuite/performance/ReadUsersWorker.java b/testsuite/performance/src/test/java/org/keycloak/testsuite/performance/ReadUsersWorker.java
index c125ac5..1eb1044 100755
--- a/testsuite/performance/src/test/java/org/keycloak/testsuite/performance/ReadUsersWorker.java
+++ b/testsuite/performance/src/test/java/org/keycloak/testsuite/performance/ReadUsersWorker.java
@@ -91,13 +91,13 @@ public class ReadUsersWorker implements Worker {
 
             // Read roles of user in realm
             if (readRoles) {
-                realm.getRoleMappings(user);
+                user.getRoleMappings();
             }
 
             // Read scopes of user in realm
             if (readScopes) {
                 ClientModel client = realm.findClient(username);
-                realm.getScopeMappings(client);
+                client.getScopeMappings();
             }
 
             // Validate password (shoould be same as username)
diff --git a/testsuite/performance/src/test/resources/META-INF/persistence.xml b/testsuite/performance/src/test/resources/META-INF/persistence.xml
index 13695fa..87857f0 100755
--- a/testsuite/performance/src/test/resources/META-INF/persistence.xml
+++ b/testsuite/performance/src/test/resources/META-INF/persistence.xml
@@ -11,8 +11,7 @@
         <class>org.keycloak.models.jpa.entities.RealmEntity</class>
         <class>org.keycloak.models.jpa.entities.RequiredCredentialEntity</class>
         <class>org.keycloak.models.jpa.entities.AuthenticationProviderEntity</class>
-        <class>org.keycloak.models.jpa.entities.ApplicationRoleEntity</class>
-        <class>org.keycloak.models.jpa.entities.RealmRoleEntity</class>
+        <class>org.keycloak.models.jpa.entities.RoleEntity</class>
         <class>org.keycloak.models.jpa.entities.SocialLinkEntity</class>
         <class>org.keycloak.models.jpa.entities.AuthenticationLinkEntity</class>
         <class>org.keycloak.models.jpa.entities.UserEntity</class>