keycloak-aplcache

mongo fed

9/30/2016 5:48:59 PM

Details

diff --git a/model/jpa/src/main/java/org/keycloak/storage/jpa/JpaUserFederatedStorageProvider.java b/model/jpa/src/main/java/org/keycloak/storage/jpa/JpaUserFederatedStorageProvider.java
index 090674b..713447b 100644
--- a/model/jpa/src/main/java/org/keycloak/storage/jpa/JpaUserFederatedStorageProvider.java
+++ b/model/jpa/src/main/java/org/keycloak/storage/jpa/JpaUserFederatedStorageProvider.java
@@ -30,18 +30,14 @@ import org.keycloak.models.ProtocolMapperModel;
 import org.keycloak.models.RealmModel;
 import org.keycloak.models.RoleModel;
 import org.keycloak.models.UserConsentModel;
-import org.keycloak.models.UserCredentialModel;
-import org.keycloak.models.UserCredentialValueModel;
 import org.keycloak.models.UserFederationProviderModel;
 import org.keycloak.models.UserModel;
-import org.keycloak.models.utils.FederatedCredentials;
 import org.keycloak.models.utils.KeycloakModelUtils;
 import org.keycloak.storage.StorageId;
 import org.keycloak.storage.UserStorageProvider;
 import org.keycloak.storage.federated.UserAttributeFederatedStorage;
 import org.keycloak.storage.federated.UserBrokerLinkFederatedStorage;
 import org.keycloak.storage.federated.UserConsentFederatedStorage;
-import org.keycloak.storage.federated.UserCredentialsFederatedStorage;
 import org.keycloak.storage.federated.UserFederatedStorageProvider;
 import org.keycloak.storage.federated.UserGroupMembershipFederatedStorage;
 import org.keycloak.storage.federated.UserRequiredActionsFederatedStorage;
@@ -77,7 +73,6 @@ public class JpaUserFederatedStorageProvider implements
         UserAttributeFederatedStorage,
         UserBrokerLinkFederatedStorage,
         UserConsentFederatedStorage,
-        UserCredentialsFederatedStorage,
         UserGroupMembershipFederatedStorage,
         UserRequiredActionsFederatedStorage,
         UserRoleMappingsFederatedStorage,
@@ -428,76 +423,6 @@ public class JpaUserFederatedStorageProvider implements
 
 
     @Override
-    public List<UserCredentialValueModel> getCredentials(RealmModel realm, UserModel user) {
-        TypedQuery<FederatedUserCredentialEntity> query = em.createNamedQuery("federatedUserCredentialByUser", FederatedUserCredentialEntity.class)
-                .setParameter("userId", user.getId());
-        List<FederatedUserCredentialEntity> results = query.getResultList();
-        List<UserCredentialValueModel> list = new LinkedList<>();
-        for (FederatedUserCredentialEntity credEntity : results) {
-            UserCredentialValueModel credModel = new UserCredentialValueModel();
-            credModel.setId(credEntity.getId());
-            credModel.setType(credEntity.getType());
-            credModel.setDevice(credEntity.getDevice());
-            credModel.setValue(credEntity.getValue());
-            credModel.setCreatedDate(credEntity.getCreatedDate());
-            credModel.setSalt(credEntity.getSalt());
-            credModel.setHashIterations(credEntity.getHashIterations());
-            credModel.setCounter(credEntity.getCounter());
-            credModel.setAlgorithm(credEntity.getAlgorithm());
-            credModel.setDigits(credEntity.getDigits());
-            credModel.setPeriod(credEntity.getPeriod());
-
-            list.add(credModel);
-        }
-        return list;
-    }
-
-    @Override
-    public void updateCredential(RealmModel realm, UserModel user, UserCredentialModel cred) {
-        createIndex(realm, user);
-        FederatedCredentials.updateCredential(session, this, realm, user, cred);
-
-    }
-
-    @Override
-    public void updateCredential(RealmModel realm, UserModel user, UserCredentialValueModel cred) {
-        createIndex(realm, user);
-        FederatedUserCredentialEntity entity = null;
-        if (cred.getId() != null) entity = em.find(FederatedUserCredentialEntity.class, cred.getId());
-        boolean newEntity = false;
-        if (entity == null) {
-            entity = new FederatedUserCredentialEntity();
-            entity.setId(KeycloakModelUtils.generateId());
-            newEntity = true;
-        }
-        entity.setUserId(user.getId());
-        entity.setRealmId(realm.getId());
-        entity.setStorageProviderId(StorageId.resolveProviderId(user));
-        entity.setAlgorithm(cred.getAlgorithm());
-        entity.setCounter(cred.getCounter());
-        Long createdDate = cred.getCreatedDate();
-        if (createdDate == null) createdDate = System.currentTimeMillis();
-        entity.setCreatedDate(createdDate);
-        entity.setDevice(cred.getDevice());
-        entity.setDigits(cred.getDigits());
-        entity.setHashIterations(cred.getHashIterations());
-        entity.setPeriod(cred.getPeriod());
-        entity.setSalt(cred.getSalt());
-        entity.setType(cred.getType());
-        entity.setValue(cred.getValue());
-        if (newEntity) {
-            em.persist(entity);
-        }
-
-    }
-
-    @Override
-    public void removeCredential(RealmModel realm, UserModel user, UserCredentialValueModel cred) {
-        FederatedUserCredentialEntity entity = em.find(FederatedUserCredentialEntity.class, cred.getId());
-        em.remove(entity);
-    }
-
-    @Override
     public Set<GroupModel> getGroups(RealmModel realm, UserModel user) {
         Set<GroupModel> set = new HashSet<>();
         TypedQuery<FederatedUserGroupMembershipEntity> query = em.createNamedQuery("feduserGroupMembership", FederatedUserGroupMembershipEntity.class);
@@ -639,36 +564,6 @@ public class JpaUserFederatedStorageProvider implements
     }
 
     @Override
-    public boolean removeCredential(RealmModel realm, String id) {
-        return false;
-    }
-
-    @Override
-    public CredentialModel getCredentialById(String id) {
-        return null;
-    }
-
-    @Override
-    public List<CredentialModel> getCredentials(RealmModel realm) {
-        return null;
-    }
-
-    @Override
-    public List<CredentialModel> getUserCredentials(RealmModel realm, UserModel user) {
-        return null;
-    }
-
-    @Override
-    public List<CredentialModel> getCredentialsByType(RealmModel realm, UserModel user, String type) {
-        return null;
-    }
-
-    @Override
-    public CredentialModel getCredentialByNameAndType(RealmModel realm, UserModel user, String name, String type) {
-        return null;
-    }
-
-    @Override
     public void updateCredential(RealmModel realm, UserModel user, CredentialModel cred) {
         FederatedUserCredentialEntity entity = em.find(FederatedUserCredentialEntity.class, cred.getId());
         if (entity == null) return;
@@ -686,7 +581,7 @@ public class JpaUserFederatedStorageProvider implements
         if (entity.getCredentialAttributes().isEmpty() && (cred.getConfig() == null || cred.getConfig().isEmpty())) {
 
         } else {
-            MultivaluedHashMap<String, String> attrs = cred.getConfig();
+            MultivaluedHashMap<String, String> attrs = new MultivaluedHashMap<>();
             MultivaluedHashMap<String, String> config = cred.getConfig();
             if (config == null) config = new MultivaluedHashMap<>();
 
diff --git a/model/mongo/src/main/java/org/keycloak/connections/mongo/DefaultMongoConnectionFactoryProvider.java b/model/mongo/src/main/java/org/keycloak/connections/mongo/DefaultMongoConnectionFactoryProvider.java
index 107fc50..45d24d2 100755
--- a/model/mongo/src/main/java/org/keycloak/connections/mongo/DefaultMongoConnectionFactoryProvider.java
+++ b/model/mongo/src/main/java/org/keycloak/connections/mongo/DefaultMongoConnectionFactoryProvider.java
@@ -65,22 +65,23 @@ public class DefaultMongoConnectionFactoryProvider implements MongoConnectionPro
             "org.keycloak.models.mongo.keycloak.entities.MongoMigrationModelEntity",
             "org.keycloak.models.mongo.keycloak.entities.MongoOnlineUserSessionEntity",
             "org.keycloak.models.mongo.keycloak.entities.MongoOfflineUserSessionEntity",
-            "org.keycloak.models.entities.IdentityProviderEntity",
-            "org.keycloak.models.entities.ClientIdentityProviderMappingEntity",
-            "org.keycloak.models.entities.RequiredCredentialEntity",
-            "org.keycloak.models.entities.CredentialEntity",
-            "org.keycloak.models.entities.FederatedIdentityEntity",
-            "org.keycloak.models.entities.UserFederationProviderEntity",
-            "org.keycloak.models.entities.UserFederationMapperEntity",
-            "org.keycloak.models.entities.ProtocolMapperEntity",
-            "org.keycloak.models.entities.IdentityProviderMapperEntity",
-            "org.keycloak.models.entities.AuthenticationExecutionEntity",
-            "org.keycloak.models.entities.AuthenticationFlowEntity",
-            "org.keycloak.models.entities.AuthenticatorConfigEntity",
-            "org.keycloak.models.entities.RequiredActionProviderEntity",
-            "org.keycloak.models.entities.PersistentUserSessionEntity",
-            "org.keycloak.models.entities.PersistentClientSessionEntity",
-            "org.keycloak.models.entities.ComponentEntity",
+            "org.keycloak.models.mongo.keycloak.entities.IdentityProviderEntity",
+            "org.keycloak.models.mongo.keycloak.entities.ClientIdentityProviderMappingEntity",
+            "org.keycloak.models.mongo.keycloak.entities.RequiredCredentialEntity",
+            "org.keycloak.models.mongo.keycloak.entities.CredentialEntity",
+            "org.keycloak.models.mongo.keycloak.entities.FederatedIdentityEntity",
+            "org.keycloak.models.mongo.keycloak.entities.UserFederationProviderEntity",
+            "org.keycloak.models.mongo.keycloak.entities.UserFederationMapperEntity",
+            "org.keycloak.models.mongo.keycloak.entities.ProtocolMapperEntity",
+            "org.keycloak.models.mongo.keycloak.entities.IdentityProviderMapperEntity",
+            "org.keycloak.models.mongo.keycloak.entities.AuthenticationExecutionEntity",
+            "org.keycloak.models.mongo.keycloak.entities.AuthenticationFlowEntity",
+            "org.keycloak.models.mongo.keycloak.entities.AuthenticatorConfigEntity",
+            "org.keycloak.models.mongo.keycloak.entities.RequiredActionProviderEntity",
+            "org.keycloak.models.mongo.keycloak.entities.PersistentUserSessionEntity",
+            "org.keycloak.models.mongo.keycloak.entities.PersistentClientSessionEntity",
+            "org.keycloak.models.mongo.keycloak.entities.ComponentEntity",
+            "org.keycloak.storage.mongo.entity.FederatedUser",
             "org.keycloak.authorization.mongo.entities.PolicyEntity",
             "org.keycloak.authorization.mongo.entities.ResourceEntity",
             "org.keycloak.authorization.mongo.entities.ResourceServerEntity",
diff --git a/model/mongo/src/main/java/org/keycloak/storage/mongo/entity/FederatedUser.java b/model/mongo/src/main/java/org/keycloak/storage/mongo/entity/FederatedUser.java
new file mode 100644
index 0000000..c810649
--- /dev/null
+++ b/model/mongo/src/main/java/org/keycloak/storage/mongo/entity/FederatedUser.java
@@ -0,0 +1,124 @@
+/*
+ * Copyright 2016 Red Hat, Inc. and/or its affiliates
+ * and other contributors as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.keycloak.storage.mongo.entity;
+
+import com.mongodb.DBObject;
+import com.mongodb.QueryBuilder;
+import org.keycloak.connections.mongo.api.MongoCollection;
+import org.keycloak.connections.mongo.api.MongoIdentifiableEntity;
+import org.keycloak.connections.mongo.api.context.MongoStoreInvocationContext;
+import org.keycloak.models.mongo.keycloak.entities.AbstractIdentifiableEntity;
+import org.keycloak.models.mongo.keycloak.entities.CredentialEntity;
+import org.keycloak.models.mongo.keycloak.entities.FederatedIdentityEntity;
+import org.keycloak.models.mongo.keycloak.entities.MongoUserConsentEntity;
+import org.keycloak.models.mongo.keycloak.entities.UserConsentEntity;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
+ * @version $Revision: 1 $
+ */
+@MongoCollection(collectionName = "federatedusers")
+public class FederatedUser extends AbstractIdentifiableEntity implements MongoIdentifiableEntity {
+    protected String realmId;
+    protected String storageId;
+
+    private Map<String, List<String>> attributes;
+    private List<String> roleIds;
+    private List<String> groupIds;
+    private List<String> requiredActions;
+    private List<CredentialEntity> credentials;
+    private List<FederatedIdentityEntity> federatedIdentities;
+
+    public String getRealmId() {
+        return realmId;
+    }
+
+    public void setRealmId(String realmId) {
+        this.realmId = realmId;
+    }
+
+    public String getStorageId() {
+        return storageId;
+    }
+
+    public void setStorageId(String storageId) {
+        this.storageId = storageId;
+    }
+
+    public Map<String, List<String>> getAttributes() {
+        return attributes;
+    }
+
+    public void setAttributes(Map<String, List<String>> attributes) {
+        this.attributes = attributes;
+    }
+
+    public List<String> getRoleIds() {
+        return roleIds;
+    }
+
+    public void setRoleIds(List<String> roleIds) {
+        this.roleIds = roleIds;
+    }
+
+    public List<String> getGroupIds() {
+        return groupIds;
+    }
+
+    public void setGroupIds(List<String> groupIds) {
+        this.groupIds = groupIds;
+    }
+
+    public List<String> getRequiredActions() {
+        return requiredActions;
+    }
+
+    public void setRequiredActions(List<String> requiredActions) {
+        this.requiredActions = requiredActions;
+    }
+
+    public List<CredentialEntity> getCredentials() {
+        return credentials;
+    }
+
+    public void setCredentials(List<CredentialEntity> credentials) {
+        this.credentials = credentials;
+    }
+
+    public List<FederatedIdentityEntity> getFederatedIdentities() {
+        return federatedIdentities;
+    }
+
+    public void setFederatedIdentities(List<FederatedIdentityEntity> federatedIdentities) {
+        this.federatedIdentities = federatedIdentities;
+    }
+
+    @Override
+    public void afterRemove(MongoStoreInvocationContext context) {
+        // Remove all consents of this user
+        DBObject query = new QueryBuilder()
+                .and("userId").is(getId())
+                .get();
+
+        context.getMongoStore().removeEntities(MongoUserConsentEntity.class, query, true, context);
+    }
+
+}
diff --git a/model/mongo/src/main/java/org/keycloak/storage/mongo/MongoUserFederatedStorageProvider.java b/model/mongo/src/main/java/org/keycloak/storage/mongo/MongoUserFederatedStorageProvider.java
new file mode 100644
index 0000000..f232450
--- /dev/null
+++ b/model/mongo/src/main/java/org/keycloak/storage/mongo/MongoUserFederatedStorageProvider.java
@@ -0,0 +1,571 @@
+/*
+ * Copyright 2016 Red Hat, Inc. and/or its affiliates
+ * and other contributors as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.keycloak.storage.mongo;
+
+import com.mongodb.BasicDBObject;
+import com.mongodb.DBObject;
+import com.mongodb.QueryBuilder;
+import org.keycloak.common.util.MultivaluedHashMap;
+import org.keycloak.component.ComponentModel;
+import org.keycloak.connections.mongo.api.MongoStore;
+import org.keycloak.connections.mongo.api.context.MongoStoreInvocationContext;
+import org.keycloak.credential.CredentialModel;
+import org.keycloak.credential.UserCredentialStore;
+import org.keycloak.models.ClientModel;
+import org.keycloak.models.FederatedIdentityModel;
+import org.keycloak.models.GroupModel;
+import org.keycloak.models.KeycloakSession;
+import org.keycloak.models.ProtocolMapperModel;
+import org.keycloak.models.RealmModel;
+import org.keycloak.models.RoleModel;
+import org.keycloak.models.UserConsentModel;
+import org.keycloak.models.UserFederationProviderModel;
+import org.keycloak.models.UserModel;
+import org.keycloak.models.mongo.keycloak.entities.CredentialEntity;
+import org.keycloak.models.mongo.keycloak.entities.FederatedIdentityEntity;
+import org.keycloak.models.utils.KeycloakModelUtils;
+import org.keycloak.storage.StorageId;
+import org.keycloak.storage.federated.UserAttributeFederatedStorage;
+import org.keycloak.storage.federated.UserBrokerLinkFederatedStorage;
+import org.keycloak.storage.federated.UserConsentFederatedStorage;
+import org.keycloak.storage.federated.UserFederatedStorageProvider;
+import org.keycloak.storage.federated.UserGroupMembershipFederatedStorage;
+import org.keycloak.storage.federated.UserRequiredActionsFederatedStorage;
+import org.keycloak.storage.federated.UserRoleMappingsFederatedStorage;
+import org.keycloak.storage.mongo.entity.FederatedUser;
+
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Set;
+
+/**
+ * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
+ * @version $Revision: 1 $
+ */
+public class MongoUserFederatedStorageProvider implements
+        UserFederatedStorageProvider,
+        UserAttributeFederatedStorage,
+        UserBrokerLinkFederatedStorage,
+        UserConsentFederatedStorage,
+        UserGroupMembershipFederatedStorage,
+        UserRequiredActionsFederatedStorage,
+        UserRoleMappingsFederatedStorage,
+        UserCredentialStore {
+
+    private final MongoStoreInvocationContext invocationContext;
+    private final KeycloakSession session;
+
+    public MongoUserFederatedStorageProvider(KeycloakSession session, MongoStoreInvocationContext invocationContext) {
+        this.session = session;
+        this.invocationContext = invocationContext;
+    }
+
+    protected MongoStore getMongoStore() {
+        return invocationContext.getMongoStore();
+    }
+
+
+    protected FederatedUser addUserEntity(RealmModel realm, String id) {
+        FederatedUser userEntity = new FederatedUser();
+        userEntity.setId(id);
+        userEntity.setStorageId(StorageId.providerId(id));
+        userEntity.setRealmId(realm.getId());
+
+        getMongoStore().insertEntity(userEntity, invocationContext);
+        return userEntity;
+    }
+
+    protected FederatedUser getUserById(String id) {
+        return getMongoStore().loadEntity(FederatedUser.class, id, invocationContext);
+    }
+
+    protected FederatedUser findOrCreate(RealmModel realm, String id) {
+        FederatedUser user = getUserById(id);
+        if (user != null) return user;
+        return addUserEntity(realm, id);
+    }
+
+
+
+    @Override
+    public boolean removeStoredCredential(RealmModel realm, UserModel user, String id) {
+        FederatedUser userEntity = getUserById(user.getId());
+        if (userEntity == null) return false;
+        CredentialEntity ce = getCredentialEntity(id, userEntity);
+        if (ce != null) return getMongoStore().pullItemFromList(userEntity, "credentials", ce, invocationContext);
+        return false;
+    }
+
+    private CredentialEntity getCredentialEntity(String id, FederatedUser userEntity) {
+        CredentialEntity ce = null;
+        if (userEntity.getCredentials() != null) {
+            for (CredentialEntity credentialEntity : userEntity.getCredentials()) {
+                if (credentialEntity.getId().equals(id)) {
+                    ce = credentialEntity;
+                    break;
+
+                }
+            }
+        }
+        return ce;
+    }
+
+    protected CredentialModel toModel(CredentialEntity entity) {
+        CredentialModel model = new CredentialModel();
+        model.setId(entity.getId());
+        model.setHashIterations(entity.getHashIterations());
+        model.setType(entity.getType());
+        model.setValue(entity.getValue());
+        model.setAlgorithm(entity.getAlgorithm());
+        model.setSalt(entity.getSalt());
+        model.setPeriod(entity.getPeriod());
+        model.setCounter(entity.getCounter());
+        model.setCreatedDate(entity.getCreatedDate());
+        model.setDevice(entity.getDevice());
+        model.setDigits(entity.getDigits());
+        MultivaluedHashMap<String, String> config = new MultivaluedHashMap<>();
+        model.setConfig(config);
+        if (entity.getConfig() != null) {
+            config.putAll(entity.getConfig());
+        }
+
+        return model;
+    }
+
+    @Override
+    public CredentialModel getStoredCredentialById(RealmModel realm, UserModel user, String id) {
+        FederatedUser userEntity = getUserById(id);
+        if (userEntity != null && userEntity.getCredentials() != null) {
+            for (CredentialEntity credentialEntity : userEntity.getCredentials()) {
+                if (credentialEntity.getId().equals(id)) {
+                    return toModel(credentialEntity);
+
+                }
+            }
+        }
+        return null;
+    }
+
+    @Override
+    public List<CredentialModel> getStoredCredentials(RealmModel realm, UserModel user) {
+        FederatedUser userEntity = getUserById(user.getId());
+        if (userEntity != null && userEntity.getCredentials() != null) {
+            List<CredentialModel> list = new LinkedList<>();
+            for (CredentialEntity credentialEntity : userEntity.getCredentials()) {
+                list.add(toModel(credentialEntity));
+            }
+            return list;
+        }
+        return Collections.EMPTY_LIST;
+    }
+
+    @Override
+    public List<CredentialModel> getStoredCredentialsByType(RealmModel realm, UserModel user, String type) {
+        FederatedUser userEntity = getUserById(user.getId());
+        if (userEntity != null && userEntity.getCredentials() != null) {
+            List<CredentialModel> list = new LinkedList<>();
+            for (CredentialEntity credentialEntity : userEntity.getCredentials()) {
+                if (type.equals(credentialEntity.getType())) list.add(toModel(credentialEntity));
+            }
+            return list;
+        }
+        return Collections.EMPTY_LIST;
+    }
+
+    @Override
+    public CredentialModel getStoredCredentialByNameAndType(RealmModel realm, UserModel user, String name, String type) {
+        FederatedUser userEntity = getUserById(user.getId());
+        if (userEntity != null && userEntity.getCredentials() != null) {
+            for (CredentialEntity credentialEntity : userEntity.getCredentials()) {
+                if (credentialEntity.getDevice().equals(name) && type.equals(credentialEntity.getType())) {
+                    return toModel(credentialEntity);
+
+                }
+            }
+        }
+        return null;
+    }
+
+    @Override
+    public List<String> getStoredUsers(RealmModel realm, int first, int max) {
+        QueryBuilder queryBuilder = new QueryBuilder()
+                .and("realmId").is(realm.getId());
+
+        DBObject query = queryBuilder.get();
+        List<FederatedUser> users = getMongoStore().loadEntities(FederatedUser.class, query, null, first, max, invocationContext);
+        List<String> ids = new LinkedList<>();
+        for (FederatedUser user : users) ids.add(user.getId());
+        return ids;
+    }
+
+    @Override
+    public void preRemove(RealmModel realm) {
+
+    }
+
+    @Override
+    public void preRemove(RealmModel realm, UserFederationProviderModel link) {
+
+    }
+
+    @Override
+    public void preRemove(RealmModel realm, GroupModel group) {
+
+    }
+
+    @Override
+    public void preRemove(RealmModel realm, RoleModel role) {
+
+    }
+
+    @Override
+    public void preRemove(RealmModel realm, ClientModel client) {
+
+    }
+
+    @Override
+    public void preRemove(ProtocolMapperModel protocolMapper) {
+
+    }
+
+    @Override
+    public void preRemove(RealmModel realm, UserModel user) {
+
+    }
+
+    @Override
+    public void preRemove(RealmModel realm, ComponentModel model) {
+
+    }
+
+    @Override
+    public void close() {
+
+    }
+
+    @Override
+    public void setSingleAttribute(RealmModel realm, UserModel user, String name, String value) {
+        FederatedUser userEntity = findOrCreate(realm, user.getId());
+        if (userEntity.getAttributes() == null) {
+            userEntity.setAttributes(new HashMap<>());
+        }
+
+        List<String> attrValues = new LinkedList<>();
+        attrValues.add(value);
+        userEntity.getAttributes().put(name, attrValues);
+        getMongoStore().updateEntity(userEntity, invocationContext);
+    }
+
+    @Override
+    public void setAttribute(RealmModel realm, UserModel user, String name, List<String> values) {
+        FederatedUser userEntity = findOrCreate(realm, user.getId());
+        if (userEntity.getAttributes() == null) {
+            userEntity.setAttributes(new HashMap<>());
+        }
+
+        userEntity.getAttributes().put(name, values);
+        getMongoStore().updateEntity(userEntity, invocationContext);
+
+    }
+
+    @Override
+    public void removeAttribute(RealmModel realm, UserModel user, String name) {
+        FederatedUser userEntity = getUserById(user.getId());
+        if (userEntity == null || userEntity.getAttributes() == null) return;
+
+        userEntity.getAttributes().remove(name);
+        getMongoStore().updateEntity(userEntity, invocationContext);
+    }
+
+    @Override
+    public MultivaluedHashMap<String, String> getAttributes(RealmModel realm, UserModel user) {
+        FederatedUser userEntity = getUserById(user.getId());
+        if (userEntity == null || userEntity.getAttributes() == null) return new MultivaluedHashMap<>();
+        MultivaluedHashMap<String, String> result = new MultivaluedHashMap<>();
+        result.putAll(userEntity.getAttributes());
+        return result;
+    }
+
+    @Override
+    public List<String> getUsersByUserAttribute(RealmModel realm, String name, String value) {
+        QueryBuilder queryBuilder = new QueryBuilder()
+                .and("realmId").is(realm.getId());
+        queryBuilder.and("attributes." + name).is(value);
+
+        List<FederatedUser> users = getMongoStore().loadEntities(FederatedUser.class, queryBuilder.get(), invocationContext);
+        List<String> ids = new LinkedList<>();
+        for (FederatedUser user : users) ids.add(user.getId());
+        return ids;
+    }
+
+    @Override
+    public String getUserByFederatedIdentity(FederatedIdentityModel socialLink, RealmModel realm) {
+        DBObject query = new QueryBuilder()
+                .and("federatedIdentities.identityProvider").is(socialLink.getIdentityProvider())
+                .and("federatedIdentities.userId").is(socialLink.getUserId())
+                .and("realmId").is(realm.getId())
+                .get();
+        FederatedUser userEntity = getMongoStore().loadSingleEntity(FederatedUser.class, query, invocationContext);
+        return userEntity != null ? userEntity.getId() : null;
+    }
+
+    @Override
+    public void addFederatedIdentity(RealmModel realm, UserModel user, FederatedIdentityModel socialLink) {
+        FederatedUser userEntity = findOrCreate(realm, user.getId());
+        FederatedIdentityEntity federatedIdentityEntity = new FederatedIdentityEntity();
+        federatedIdentityEntity.setIdentityProvider(socialLink.getIdentityProvider());
+        federatedIdentityEntity.setUserId(socialLink.getUserId());
+        federatedIdentityEntity.setUserName(socialLink.getUserName().toLowerCase());
+        federatedIdentityEntity.setToken(socialLink.getToken());
+
+        getMongoStore().pushItemToList(userEntity, "federatedIdentities", federatedIdentityEntity, true, invocationContext);
+    }
+
+    @Override
+    public boolean removeFederatedIdentity(RealmModel realm, UserModel user, String socialProvider) {
+        FederatedUser userEntity = getUserById(user.getId());
+        if (userEntity == null) return false;
+
+        FederatedIdentityEntity federatedIdentityEntity = findFederatedIdentityLink(userEntity, socialProvider);
+        if (federatedIdentityEntity == null) {
+            return false;
+        }
+        return getMongoStore().pullItemFromList(userEntity, "federatedIdentities", federatedIdentityEntity, invocationContext);    }
+
+    private FederatedIdentityEntity findFederatedIdentityLink(FederatedUser userEntity, String identityProvider) {
+        List<FederatedIdentityEntity> linkEntities = userEntity.getFederatedIdentities();
+        if (linkEntities == null) {
+            return null;
+        }
+
+        for (FederatedIdentityEntity federatedIdentityEntity : linkEntities) {
+            if (federatedIdentityEntity.getIdentityProvider().equals(identityProvider)) {
+                return federatedIdentityEntity;
+            }
+        }
+        return null;
+    }
+
+    @Override
+    public void updateFederatedIdentity(RealmModel realm, UserModel federatedUser, FederatedIdentityModel federatedIdentityModel) {
+        FederatedUser userEntity = getUserById(federatedUser.getId());
+        if (userEntity == null) return;
+        FederatedIdentityEntity federatedIdentityEntity = findFederatedIdentityLink(userEntity, federatedIdentityModel.getIdentityProvider());
+        if (federatedIdentityEntity == null) return;
+        //pushItemToList updates the whole federatedIdentities array in Mongo so we just need to remove this object from the Java
+        //List and pushItemToList will handle the DB update.
+        userEntity.getFederatedIdentities().remove(federatedIdentityEntity);
+        federatedIdentityEntity.setToken(federatedIdentityModel.getToken());
+        getMongoStore().pushItemToList(userEntity, "federatedIdentities", federatedIdentityEntity, true, invocationContext);
+    }
+
+    @Override
+    public Set<FederatedIdentityModel> getFederatedIdentities(UserModel user, RealmModel realm) {
+        FederatedUser userEntity = getUserById(user.getId());
+        if (userEntity == null) return Collections.EMPTY_SET;
+        List<FederatedIdentityEntity> linkEntities = userEntity.getFederatedIdentities();
+
+        if (linkEntities == null) {
+            return Collections.EMPTY_SET;
+        }
+
+        Set<FederatedIdentityModel> result = new HashSet<FederatedIdentityModel>();
+        for (FederatedIdentityEntity federatedIdentityEntity : linkEntities) {
+            FederatedIdentityModel model = new FederatedIdentityModel(federatedIdentityEntity.getIdentityProvider(),
+                    federatedIdentityEntity.getUserId(), federatedIdentityEntity.getUserName(), federatedIdentityEntity.getToken());
+            result.add(model);
+        }
+        return result;
+    }
+
+    @Override
+    public FederatedIdentityModel getFederatedIdentity(UserModel user, String socialProvider, RealmModel realm) {
+        FederatedUser userEntity = getUserById(user.getId());
+        if (userEntity == null) return null;
+        FederatedIdentityEntity federatedIdentityEntity = findFederatedIdentityLink(userEntity, socialProvider);
+
+        return federatedIdentityEntity != null ? new FederatedIdentityModel(federatedIdentityEntity.getIdentityProvider(), federatedIdentityEntity.getUserId(),
+                federatedIdentityEntity.getUserName(), federatedIdentityEntity.getToken()) : null;
+    }
+
+    @Override
+    public void addConsent(RealmModel realm, UserModel user, UserConsentModel consent) {
+        session.userLocalStorage().addConsent(realm, user, consent);
+
+    }
+
+    @Override
+    public UserConsentModel getConsentByClient(RealmModel realm, UserModel user, String clientInternalId) {
+        return session.userLocalStorage().getConsentByClient(realm, user, clientInternalId);
+    }
+
+    @Override
+    public List<UserConsentModel> getConsents(RealmModel realm, UserModel user) {
+        return session.userLocalStorage().getConsents(realm, user);
+    }
+
+    @Override
+    public void updateConsent(RealmModel realm, UserModel user, UserConsentModel consent) {
+        session.userLocalStorage().updateConsent(realm, user, consent);
+
+    }
+
+    @Override
+    public boolean revokeConsentForClient(RealmModel realm, UserModel user, String clientInternalId) {
+        return session.userLocalStorage().revokeConsentForClient(realm, user, clientInternalId);
+    }
+
+    @Override
+    public void updateCredential(RealmModel realm, UserModel user, CredentialModel cred) {
+        FederatedUser userEntity = getUserById(user.getId());
+        if (userEntity == null) return;
+        CredentialEntity entity = getCredentialEntity(cred.getId(), userEntity);
+        if (entity == null) return;
+        toEntity(cred, entity);
+        userEntity.getCredentials().remove(entity);
+
+        getMongoStore().pushItemToList(userEntity, "credentials", entity, true, invocationContext);
+    }
+
+    private void toEntity(CredentialModel cred, CredentialEntity entity) {
+        entity.setAlgorithm(cred.getAlgorithm());
+        entity.setCounter(cred.getCounter());
+        entity.setCreatedDate(cred.getCreatedDate());
+        entity.setDevice(cred.getDevice());
+        entity.setDigits(cred.getDigits());
+        entity.setHashIterations(cred.getHashIterations());
+        entity.setPeriod(cred.getPeriod());
+        entity.setSalt(cred.getSalt());
+        entity.setType(cred.getType());
+        entity.setValue(cred.getValue());
+
+        if (cred.getConfig() == null) entity.setConfig(null);
+        else {
+            MultivaluedHashMap<String, String> newConfig = new MultivaluedHashMap<>();
+            newConfig.putAll(cred.getConfig());
+            entity.setConfig(newConfig);
+        }
+    }
+
+    @Override
+    public CredentialModel createCredential(RealmModel realm, UserModel user, CredentialModel cred) {
+        FederatedUser userEntity = findOrCreate(realm, user.getId());
+        CredentialEntity entity = new CredentialEntity();
+        entity.setId(KeycloakModelUtils.generateId());
+        toEntity(cred, entity);
+        getMongoStore().pushItemToList(userEntity, "credentials", entity, true, invocationContext);
+        cred.setId(entity.getId());
+        return cred;
+    }
+
+    @Override
+    public Set<GroupModel> getGroups(RealmModel realm, UserModel user) {
+        FederatedUser userEntity = getUserById(user.getId());
+        if (userEntity == null || userEntity.getGroupIds() == null || userEntity.getGroupIds().isEmpty()) return Collections.EMPTY_SET;
+        Set<GroupModel> groups = new HashSet<>();
+        for (String groupId : userEntity.getGroupIds()) {
+            GroupModel group = session.realms().getGroupById(groupId, realm);
+            if (group != null) groups.add(group);
+        }
+
+        return groups;
+    }
+
+    @Override
+    public void joinGroup(RealmModel realm, UserModel user, GroupModel group) {
+        FederatedUser userEntity = findOrCreate(realm, user.getId());
+        getMongoStore().pushItemToList(userEntity, "groupIds", group.getId(), true, invocationContext);
+
+
+    }
+
+    @Override
+    public void leaveGroup(RealmModel realm, UserModel user, GroupModel group) {
+        FederatedUser userEntity = getUserById(user.getId());
+        if (userEntity == null || group == null) return;
+        getMongoStore().pullItemFromList(userEntity, "groupIds", group.getId(), invocationContext);
+
+
+    }
+
+    @Override
+    public List<String> getMembership(RealmModel realm, GroupModel group, int firstResult, int max) {
+        QueryBuilder queryBuilder = new QueryBuilder()
+                .and("realmId").is(realm.getId());
+        queryBuilder.and("groupIds").is(group.getId());
+
+        List<FederatedUser> users = getMongoStore().loadEntities(FederatedUser.class, queryBuilder.get(), null, firstResult, max, invocationContext);
+        List<String> ids = new LinkedList<>();
+        for (FederatedUser user : users) ids.add(user.getId());
+        return ids;
+    }
+
+    @Override
+    public Set<String> getRequiredActions(RealmModel realm, UserModel user) {
+        FederatedUser userEntity = getUserById(user.getId());
+        if (userEntity == null || userEntity.getRequiredActions() == null || userEntity.getRequiredActions().isEmpty()) return Collections.EMPTY_SET;
+        Set<String> set = new HashSet<>();
+        set.addAll(userEntity.getRequiredActions());
+        return set;
+    }
+
+    @Override
+    public void addRequiredAction(RealmModel realm, UserModel user, String action) {
+        FederatedUser userEntity = findOrCreate(realm, user.getId());
+        getMongoStore().pushItemToList(userEntity, "requiredActions", action, true, invocationContext);
+
+    }
+
+    @Override
+    public void removeRequiredAction(RealmModel realm, UserModel user, String action) {
+        FederatedUser userEntity = getUserById(user.getId());
+        if (userEntity == null || userEntity.getRequiredActions() == null || userEntity.getRequiredActions().isEmpty()) return;
+        getMongoStore().pullItemFromList(userEntity, "requiredActions", action, invocationContext);
+
+    }
+
+    @Override
+    public void grantRole(RealmModel realm, UserModel user, RoleModel role) {
+        FederatedUser userEntity = findOrCreate(realm, user.getId());
+        getMongoStore().pushItemToList(userEntity, "roleIds", role.getId(), true, invocationContext);
+
+    }
+
+    @Override
+    public Set<RoleModel> getRoleMappings(RealmModel realm, UserModel user) {
+        FederatedUser userEntity = getUserById(user.getId());
+        if (userEntity == null || userEntity.getRoleIds() == null || userEntity.getRoleIds().isEmpty()) return Collections.EMPTY_SET;
+        Set<RoleModel> roles = new HashSet<>();
+        for (String roleId : userEntity.getRoleIds()) {
+            RoleModel role = realm.getRoleById(roleId);
+            if (role != null) roles.add(role);
+        }
+        return roles;
+    }
+
+    @Override
+    public void deleteRoleMapping(RealmModel realm, UserModel user, RoleModel role) {
+        FederatedUser userEntity = getUserById(user.getId());
+        if (userEntity == null || userEntity.getRoleIds() == null || userEntity.getRoleIds().isEmpty()) return;
+        getMongoStore().pullItemFromList(userEntity, "roleIds", role.getId(), invocationContext);
+
+    }
+}
diff --git a/model/mongo/src/main/java/org/keycloak/storage/mongo/MongoUserFederatedStorageProviderFactory.java b/model/mongo/src/main/java/org/keycloak/storage/mongo/MongoUserFederatedStorageProviderFactory.java
new file mode 100644
index 0000000..d07e872
--- /dev/null
+++ b/model/mongo/src/main/java/org/keycloak/storage/mongo/MongoUserFederatedStorageProviderFactory.java
@@ -0,0 +1,57 @@
+/*
+ * Copyright 2016 Red Hat, Inc. and/or its affiliates
+ * and other contributors as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.keycloak.storage.mongo;
+
+import org.keycloak.Config;
+import org.keycloak.connections.mongo.MongoConnectionProvider;
+import org.keycloak.models.KeycloakSession;
+import org.keycloak.models.KeycloakSessionFactory;
+import org.keycloak.provider.ProviderFactory;
+import org.keycloak.storage.federated.UserFederatedStorageProvider;
+import org.keycloak.storage.federated.UserFederatedStorageProviderFactory;
+
+/**
+ * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
+ * @version $Revision: 1 $
+ */
+public class MongoUserFederatedStorageProviderFactory implements UserFederatedStorageProviderFactory {
+    @Override
+    public UserFederatedStorageProvider create(KeycloakSession session) {
+        MongoConnectionProvider connection = session.getProvider(MongoConnectionProvider.class);
+        return new MongoUserFederatedStorageProvider(session, connection.getInvocationContext());
+    }
+
+    @Override
+    public void init(Config.Scope config) {
+
+    }
+
+    @Override
+    public void postInit(KeycloakSessionFactory factory) {
+
+    }
+
+    @Override
+    public void close() {
+
+    }
+
+    @Override
+    public String getId() {
+        return "mongo";
+    }
+}
diff --git a/model/mongo/src/main/resources/META-INF/services/org.keycloak.storage.federated.UserFederatedStorageProviderFactory b/model/mongo/src/main/resources/META-INF/services/org.keycloak.storage.federated.UserFederatedStorageProviderFactory
new file mode 100644
index 0000000..c6afa25
--- /dev/null
+++ b/model/mongo/src/main/resources/META-INF/services/org.keycloak.storage.federated.UserFederatedStorageProviderFactory
@@ -0,0 +1 @@
+org.keycloak.storage.mongo.MongoUserFederatedStorageProviderFactory
\ No newline at end of file
diff --git a/server-spi/src/main/java/org/keycloak/storage/federated/UserFederatedStorageProvider.java b/server-spi/src/main/java/org/keycloak/storage/federated/UserFederatedStorageProvider.java
index 5bf764b..b8d4e35 100755
--- a/server-spi/src/main/java/org/keycloak/storage/federated/UserFederatedStorageProvider.java
+++ b/server-spi/src/main/java/org/keycloak/storage/federated/UserFederatedStorageProvider.java
@@ -37,7 +37,6 @@ public interface UserFederatedStorageProvider extends Provider,
         UserAttributeFederatedStorage,
         UserBrokerLinkFederatedStorage,
         UserConsentFederatedStorage,
-        UserCredentialsFederatedStorage,
         UserGroupMembershipFederatedStorage,
         UserRequiredActionsFederatedStorage,
         UserRoleMappingsFederatedStorage {
diff --git a/server-spi/src/main/java/org/keycloak/storage/StorageId.java b/server-spi/src/main/java/org/keycloak/storage/StorageId.java
index ab44e47..e7ada01 100644
--- a/server-spi/src/main/java/org/keycloak/storage/StorageId.java
+++ b/server-spi/src/main/java/org/keycloak/storage/StorageId.java
@@ -63,6 +63,9 @@ public class StorageId implements Serializable {
     public static String externalId(String keycloakId) {
         return new StorageId(keycloakId).getExternalId();
     }
+    public static String providerId(String keycloakId) {
+        return new StorageId(keycloakId).getProviderId();
+    }
 
 
 
diff --git a/testsuite/integration/pom.xml b/testsuite/integration/pom.xml
index 555e1fa..f67fc35 100755
--- a/testsuite/integration/pom.xml
+++ b/testsuite/integration/pom.xml
@@ -459,6 +459,7 @@
                                     <systemPropertyVariables>
                                         <keycloak.realm.provider>mongo</keycloak.realm.provider>
                                         <keycloak.user.provider>mongo</keycloak.user.provider>
+                                        <keycloak.userFederatedStorage.provider>mongo</keycloak.userFederatedStorage.provider>
                                         <keycloak.userSessionPersister.provider>mongo</keycloak.userSessionPersister.provider>
                                         <keycloak.eventsStore.provider>mongo</keycloak.eventsStore.provider>
                                         <keycloak.authorization.provider>mongo</keycloak.authorization.provider>
diff --git a/testsuite/integration/src/test/resources/META-INF/keycloak-server.json b/testsuite/integration/src/test/resources/META-INF/keycloak-server.json
index b676b99..06b4e52 100755
--- a/testsuite/integration/src/test/resources/META-INF/keycloak-server.json
+++ b/testsuite/integration/src/test/resources/META-INF/keycloak-server.json
@@ -22,6 +22,10 @@
         "provider": "${keycloak.user.provider:jpa}"
     },
 
+    "userFederatedStorage": {
+        "provider": "${keycloak.userFederatedStorage.provider:jpa}"
+    },
+
     "userSessionPersister": {
         "provider": "${keycloak.userSessionPersister.provider:jpa}"
     },