keycloak-aplcache
Changes
model/mongo/src/main/java/org/keycloak/connections/mongo/DefaultMongoConnectionFactoryProvider.java 33(+17 -16)
model/mongo/src/main/java/org/keycloak/storage/mongo/MongoUserFederatedStorageProvider.java 571(+571 -0)
model/mongo/src/main/java/org/keycloak/storage/mongo/MongoUserFederatedStorageProviderFactory.java 57(+57 -0)
model/mongo/src/main/resources/META-INF/services/org.keycloak.storage.federated.UserFederatedStorageProviderFactory 1(+1 -0)
server-spi/src/main/java/org/keycloak/storage/federated/UserCredentialsFederatedStorage.java 48(+0 -48)
testsuite/integration/pom.xml 1(+1 -0)
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();
+ }
testsuite/integration/pom.xml 1(+1 -0)
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}"
},