/*
* 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.models.mongo.keycloak.adapters;
import com.mongodb.BasicDBObject;
import com.mongodb.DBObject;
import com.mongodb.QueryBuilder;
import org.keycloak.common.util.MultivaluedHashMap;
import org.keycloak.common.util.Time;
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.CredentialValidationOutput;
import org.keycloak.models.FederatedIdentityModel;
import org.keycloak.models.GroupModel;
import org.keycloak.models.KeycloakSession;
import org.keycloak.models.ModelDuplicateException;
import org.keycloak.models.ModelException;
import org.keycloak.models.ProtocolMapperModel;
import org.keycloak.models.RealmModel;
import org.keycloak.models.RequiredActionProviderModel;
import org.keycloak.models.RoleModel;
import org.keycloak.models.UserConsentModel;
import org.keycloak.models.UserCredentialModel;
import org.keycloak.models.UserFederationProviderModel;
import org.keycloak.models.UserModel;
import org.keycloak.models.UserProvider;
import org.keycloak.models.cache.CachedUserModel;
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.MongoUserEntity;
import org.keycloak.models.mongo.keycloak.entities.UserConsentEntity;
import org.keycloak.models.utils.KeycloakModelUtils;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
import java.util.Iterator;
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>
*/
public class MongoUserProvider implements UserProvider, UserCredentialStore {
private final MongoStoreInvocationContext invocationContext;
private final KeycloakSession session;
public MongoUserProvider(KeycloakSession session, MongoStoreInvocationContext invocationContext) {
this.session = session;
this.invocationContext = invocationContext;
}
@Override
public void close() {
}
@Override
public UserAdapter 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(session, realm, user, invocationContext);
}
}
@Override
public UserModel getUserByUsername(String username, RealmModel realm) {
DBObject query = new QueryBuilder()
.and("username").is(username.toLowerCase())
.and("realmId").is(realm.getId())
.get();
MongoUserEntity user = getMongoStore().loadSingleEntity(MongoUserEntity.class, query, invocationContext);
if (user == null) {
return null;
} else {
return new UserAdapter(session, realm, user, invocationContext);
}
}
@Override
public UserModel getUserByEmail(String email, RealmModel realm) {
DBObject query = new QueryBuilder()
.and("email").is(email.toLowerCase())
.and("realmId").is(realm.getId())
.get();
MongoUserEntity user = getMongoStore().loadSingleEntity(MongoUserEntity.class, query, invocationContext);
if (user == null) {
return null;
} else {
return new UserAdapter(session, realm, user, invocationContext);
}
}
@Override
public List<UserModel> getGroupMembers(RealmModel realm, GroupModel group, int firstResult, int maxResults) {
QueryBuilder queryBuilder = new QueryBuilder()
.and("realmId").is(realm.getId());
queryBuilder.and("groupIds").is(group.getId());
DBObject sort = new BasicDBObject("username", 1);
List<MongoUserEntity> users = getMongoStore().loadEntities(MongoUserEntity.class, queryBuilder.get(), sort, firstResult, maxResults, invocationContext);
return convertUserEntities(realm, users);
}
protected MongoStore getMongoStore() {
return invocationContext.getMongoStore();
}
@Override
public List<UserModel> getGroupMembers(RealmModel realm, GroupModel group) {
return getGroupMembers(realm, group, -1, -1);
}
@Override
public UserModel 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();
MongoUserEntity userEntity = getMongoStore().loadSingleEntity(MongoUserEntity.class, query, invocationContext);
return userEntity == null ? null : new UserAdapter(session, realm, userEntity, invocationContext);
}
@Override
public UserModel getServiceAccount(ClientModel client) {
DBObject query = new QueryBuilder()
.and("serviceAccountClientLink").is(client.getId())
.and("realmId").is(client.getRealm().getId())
.get();
MongoUserEntity userEntity = getMongoStore().loadSingleEntity(MongoUserEntity.class, query, invocationContext);
return userEntity == null ? null : new UserAdapter(session, client.getRealm(), 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(session, realm, user, invocationContext));
}
return userModels;
}
@Override
public List<UserModel> getUsers(RealmModel realm) {
return getUsers(realm, false);
}
@Override
public List<UserModel> getUsers(RealmModel realm, int firstResult, int maxResults) {
return getUsers(realm, firstResult, maxResults, false);
}
@Override
public List<UserModel> getUsers(RealmModel realm, boolean includeServiceAccounts) {
return getUsers(realm, -1, -1, includeServiceAccounts);
}
@Override
public int getUsersCount(RealmModel realm) {
DBObject query = new QueryBuilder()
.and("realmId").is(realm.getId())
.get();
return getMongoStore().countEntities(MongoUserEntity.class, query, invocationContext);
}
@Override
public List<UserModel> getUsers(RealmModel realm, int firstResult, int maxResults, boolean includeServiceAccounts) {
QueryBuilder queryBuilder = new QueryBuilder()
.and("realmId").is(realm.getId());
if (!includeServiceAccounts) {
queryBuilder = queryBuilder.and("serviceAccountClientLink").is(null);
}
DBObject query = queryBuilder.get();
DBObject sort = new BasicDBObject("username", 1);
List<MongoUserEntity> users = getMongoStore().loadEntities(MongoUserEntity.class, query, sort, firstResult, maxResults, invocationContext);
return convertUserEntities(realm, users);
}
@Override
public List<UserModel> searchForUser(String search, RealmModel realm) {
return searchForUser(search, realm, -1, -1);
}
@Override
public List<UserModel>
searchForUser(String search, RealmModel realm, int firstResult, int maxResults) {
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().and("serviceAccountClientLink").is(null).get(),
new QueryBuilder().or(
new QueryBuilder().put("username").regex(caseInsensitivePattern).get(),
new QueryBuilder().put("email").regex(caseInsensitivePattern).get(),
nameBuilder.get()
).get()
);
DBObject sort = new BasicDBObject("username", 1);
List<MongoUserEntity> users = getMongoStore().loadEntities(MongoUserEntity.class, builder.get(), sort, firstResult, maxResults, invocationContext);
return convertUserEntities(realm, users);
}
@Override
public List<UserModel> searchForUser(Map<String, String> attributes, RealmModel realm) {
return searchForUser(attributes, realm, -1, -1);
}
@Override
public List<UserModel> searchForUser(Map<String, String> attributes, RealmModel realm, int firstResult, int maxResults) {
QueryBuilder queryBuilder = new QueryBuilder()
.and("realmId").is(realm.getId());
for (Map.Entry<String, String> entry : attributes.entrySet()) {
if (entry.getKey().equalsIgnoreCase(UserModel.USERNAME)) {
queryBuilder.and(UserModel.USERNAME).regex(Pattern.compile(".*" + entry.getValue() + ".*", Pattern.CASE_INSENSITIVE));
} else if (entry.getKey().equalsIgnoreCase(UserModel.FIRST_NAME)) {
queryBuilder.and(UserModel.FIRST_NAME).regex(Pattern.compile(".*" + entry.getValue() + ".*", Pattern.CASE_INSENSITIVE));
} else if (entry.getKey().equalsIgnoreCase(UserModel.LAST_NAME)) {
queryBuilder.and(UserModel.LAST_NAME).regex(Pattern.compile(".*" + entry.getValue() + ".*", Pattern.CASE_INSENSITIVE));
} else if (entry.getKey().equalsIgnoreCase(UserModel.EMAIL)) {
queryBuilder.and(UserModel.EMAIL).regex(Pattern.compile(".*" + entry.getValue() + ".*", Pattern.CASE_INSENSITIVE));
}
}
DBObject sort = new BasicDBObject("username", 1);
List<MongoUserEntity> users = getMongoStore().loadEntities(MongoUserEntity.class, queryBuilder.get(), sort, firstResult, maxResults, invocationContext);
return convertUserEntities(realm, users);
}
@Override
public List<UserModel> searchForUserByUserAttribute(String attrName, String attrValue, RealmModel realm) {
QueryBuilder queryBuilder = new QueryBuilder()
.and("realmId").is(realm.getId());
queryBuilder.and("attributes." + attrName).is(attrValue);
List<MongoUserEntity> users = getMongoStore().loadEntities(MongoUserEntity.class, queryBuilder.get(), invocationContext);
return convertUserEntities(realm, users);
}
@Override
public Set<FederatedIdentityModel> getFederatedIdentities(UserModel userModel, RealmModel realm) {
UserAdapter user = getUserById(userModel.getId(), realm);
MongoUserEntity userEntity = user.getUser();
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) {
UserAdapter mongoUser = getUserById(user.getId(), realm);
MongoUserEntity userEntity = mongoUser.getUser();
FederatedIdentityEntity federatedIdentityEntity = findFederatedIdentityLink(userEntity, socialProvider);
return federatedIdentityEntity != null ? new FederatedIdentityModel(federatedIdentityEntity.getIdentityProvider(), federatedIdentityEntity.getUserId(),
federatedIdentityEntity.getUserName(), federatedIdentityEntity.getToken()) : null;
}
@Override
public UserAdapter addUser(RealmModel realm, String id, String username, boolean addDefaultRoles, boolean addDefaultRequiredActions) {
UserAdapter userModel = addUserEntity(realm, id, username.toLowerCase());
if (addDefaultRoles) {
for (String r : realm.getDefaultRoles()) {
userModel.grantRole(realm.getRole(r));
}
for (ClientModel application : realm.getClients()) {
for (String r : application.getDefaultRoles()) {
userModel.grantRole(application.getRole(r));
}
}
for (GroupModel g : realm.getDefaultGroups()) {
userModel.joinGroup(g);
}
}
if (addDefaultRequiredActions) {
for (RequiredActionProviderModel r : realm.getRequiredActionProviders()) {
if (r.isEnabled() && r.isDefaultAction()) {
userModel.addRequiredAction(r.getAlias());
}
}
}
return userModel;
}
protected UserAdapter addUserEntity(RealmModel realm, String id, String username) {
MongoUserEntity userEntity = new MongoUserEntity();
userEntity.setId(id);
userEntity.setUsername(username);
userEntity.setCreatedTimestamp(System.currentTimeMillis());
// Compatibility with JPA model, which has user disabled by default
// userEntity.setEnabled(true);
userEntity.setRealmId(realm.getId());
getMongoStore().insertEntity(userEntity, invocationContext);
return new UserAdapter(session, realm, userEntity, invocationContext);
}
@Override
public boolean removeUser(RealmModel realm, UserModel user) {
return getMongoStore().removeEntity(MongoUserEntity.class, user.getId(), invocationContext);
}
@Override
public void addFederatedIdentity(RealmModel realm, UserModel user, FederatedIdentityModel identity) {
UserAdapter mongoUser = getUserById(user.getId(), realm);
MongoUserEntity userEntity = mongoUser.getUser();
FederatedIdentityEntity federatedIdentityEntity = new FederatedIdentityEntity();
federatedIdentityEntity.setIdentityProvider(identity.getIdentityProvider());
federatedIdentityEntity.setUserId(identity.getUserId());
federatedIdentityEntity.setUserName(identity.getUserName().toLowerCase());
federatedIdentityEntity.setToken(identity.getToken());
getMongoStore().pushItemToList(userEntity, "federatedIdentities", federatedIdentityEntity, true, invocationContext);
}
@Override
public void updateFederatedIdentity(RealmModel realm, UserModel federatedUser, FederatedIdentityModel federatedIdentityModel) {
UserAdapter mongoUser = getUserById(federatedUser.getId(), realm);
MongoUserEntity userEntity = mongoUser.getUser();
FederatedIdentityEntity federatedIdentityEntity = findFederatedIdentityLink(userEntity, federatedIdentityModel.getIdentityProvider());
//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 boolean removeFederatedIdentity(RealmModel realm, UserModel userModel, String socialProvider) {
UserAdapter user = getUserById(userModel.getId(), realm);
MongoUserEntity userEntity = user.getUser();
FederatedIdentityEntity federatedIdentityEntity = findFederatedIdentityLink(userEntity, socialProvider);
if (federatedIdentityEntity == null) {
return false;
}
return getMongoStore().pullItemFromList(userEntity, "federatedIdentities", federatedIdentityEntity, invocationContext);
}
private FederatedIdentityEntity findFederatedIdentityLink(MongoUserEntity 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 UserModel addUser(RealmModel realm, String username) {
return this.addUser(realm, null, username, true, true);
}
@Override
public void grantToAllUsers(RealmModel realm, RoleModel role) {
DBObject query = new QueryBuilder()
.and("realmId").is(realm.getId())
.get();
DBObject update = new QueryBuilder()
.and("$push").is(new BasicDBObject("roleIds", role.getId()))
.get();
int count = getMongoStore().updateEntities(MongoUserEntity.class, query, update, invocationContext);
}
@Override
public void preRemove(RealmModel realm) {
DBObject query = new QueryBuilder()
.and("realmId").is(realm.getId())
.get();
getMongoStore().removeEntities(MongoUserEntity.class, query, true, invocationContext);
}
@Override
public void preRemove(RealmModel realm, UserFederationProviderModel link) {
// Remove all users linked with federationProvider and their consents
DBObject query = new QueryBuilder()
.and("realmId").is(realm.getId())
.and("federationLink").is(link.getId())
.get();
getMongoStore().removeEntities(MongoUserEntity.class, query, true, invocationContext);
}
@Override
public void preRemove(RealmModel realm, ClientModel client) {
// Remove all role mappings and consents mapped to all roles of this client
for (RoleModel role : client.getRoles()) {
preRemove(realm, role);
}
// Finally remove all consents of this client
DBObject query = new QueryBuilder()
.and("clientId").is(client.getId())
.get();
getMongoStore().removeEntities(MongoUserConsentEntity.class, query, false, invocationContext);
}
@Override
public void preRemove(ProtocolMapperModel protocolMapper) {
// Remove this protocol mapper from all consents, which has it
DBObject query = new QueryBuilder()
.and("grantedProtocolMappers").is(protocolMapper.getId())
.get();
DBObject pull = new BasicDBObject("$pull", query);
getMongoStore().updateEntities(MongoUserConsentEntity.class, query, pull, invocationContext);
}
@Override
public void preRemove(RealmModel realm, GroupModel group) {
// Remove this role from all users, which has it
DBObject query = new QueryBuilder()
.and("groupIds").is(group.getId())
.get();
DBObject pull = new BasicDBObject("$pull", query);
getMongoStore().updateEntities(MongoUserEntity.class, query, pull, invocationContext);
}
@Override
public void preRemove(RealmModel realm, RoleModel role) {
// Remove this role from all users, which has it
DBObject query = new QueryBuilder()
.and("roleIds").is(role.getId())
.get();
DBObject pull = new BasicDBObject("$pull", query);
getMongoStore().updateEntities(MongoUserEntity.class, query, pull, invocationContext);
// Remove this role from all consents, which has it
query = new QueryBuilder()
.and("grantedRoles").is(role.getId())
.get();
pull = new BasicDBObject("$pull", query);
getMongoStore().updateEntities(MongoUserConsentEntity.class, query, pull, invocationContext);
}
@Override
public void addConsent(RealmModel realm, String userId, UserConsentModel consent) {
String clientId = consent.getClient().getId();
if (getConsentEntityByClientId(userId, clientId) != null) {
throw new ModelDuplicateException("Consent already exists for client [" + clientId + "] and user [" + userId + "]");
}
long currentTime = Time.currentTimeMillis();
MongoUserConsentEntity consentEntity = new MongoUserConsentEntity();
consentEntity.setUserId(userId);
consentEntity.setClientId(clientId);
consentEntity.setCreatedDate(currentTime);
consentEntity.setLastUpdatedDate(currentTime);
fillEntityFromModel(consent, consentEntity);
getMongoStore().insertEntity(consentEntity, invocationContext);
}
@Override
public UserConsentModel getConsentByClient(RealmModel realm, String userId, String clientId) {
UserConsentEntity consentEntity = getConsentEntityByClientId(userId, clientId);
return consentEntity!=null ? toConsentModel(realm, consentEntity) : null;
}
@Override
public List<UserConsentModel> getConsents(RealmModel realm, String userId) {
List<UserConsentModel> result = new ArrayList<UserConsentModel>();
DBObject query = new QueryBuilder()
.and("userId").is(userId)
.get();
List<MongoUserConsentEntity> grantedConsents = getMongoStore().loadEntities(MongoUserConsentEntity.class, query, invocationContext);
for (UserConsentEntity consentEntity : grantedConsents) {
UserConsentModel model = toConsentModel(realm, consentEntity);
result.add(model);
}
return result;
}
private MongoUserConsentEntity getConsentEntityByClientId(String userId, String clientId) {
DBObject query = new QueryBuilder()
.and("userId").is(userId)
.and("clientId").is(clientId)
.get();
return getMongoStore().loadSingleEntity(MongoUserConsentEntity.class, query, invocationContext);
}
private UserConsentModel toConsentModel(RealmModel realm, UserConsentEntity entity) {
ClientModel client = realm.getClientById(entity.getClientId());
if (client == null) {
throw new ModelException("Client with id " + entity.getClientId() + " is not available");
}
UserConsentModel model = new UserConsentModel(client);
model.setCreatedDate(entity.getCreatedDate());
model.setLastUpdatedDate(entity.getLastUpdatedDate());
for (String roleId : entity.getGrantedRoles()) {
RoleModel roleModel = realm.getRoleById(roleId);
if (roleModel != null) {
model.addGrantedRole(roleModel);
}
}
for (String protMapperId : entity.getGrantedProtocolMappers()) {
ProtocolMapperModel protocolMapper = client.getProtocolMapperById(protMapperId);
model.addGrantedProtocolMapper(protocolMapper);
}
return model;
}
// Fill roles and protocolMappers to entity
private void fillEntityFromModel(UserConsentModel consent, MongoUserConsentEntity consentEntity) {
List<String> roleIds = new LinkedList<String>();
for (RoleModel role : consent.getGrantedRoles()) {
roleIds.add(role.getId());
}
consentEntity.setGrantedRoles(roleIds);
List<String> protMapperIds = new LinkedList<String>();
for (ProtocolMapperModel protMapperModel : consent.getGrantedProtocolMappers()) {
protMapperIds.add(protMapperModel.getId());
}
consentEntity.setGrantedProtocolMappers(protMapperIds);
consentEntity.setLastUpdatedDate(Time.currentTimeMillis());
}
@Override
public void updateConsent(RealmModel realm, String userId, UserConsentModel consent) {
String clientId = consent.getClient().getId();
MongoUserConsentEntity consentEntity = getConsentEntityByClientId(userId, clientId);
if (consentEntity == null) {
throw new ModelException("Consent not found for client [" + clientId + "] and user [" + userId + "]");
} else {
fillEntityFromModel(consent, consentEntity);
getMongoStore().updateEntity(consentEntity, invocationContext);
}
}
@Override
public boolean revokeConsentForClient(RealmModel realm, String userId, String clientId) {
MongoUserConsentEntity entity = getConsentEntityByClientId(userId, clientId);
if (entity == null) {
return false;
}
return getMongoStore().removeEntity(entity, invocationContext);
}
@Override
public void preRemove(RealmModel realm, ComponentModel component) {
}
@Override
public void updateCredential(RealmModel realm, UserModel user, CredentialModel cred) {
MongoUserEntity mongoUser = getMongoUserEntity(user);
CredentialEntity credentialEntity = getCredentialEntity(cred, mongoUser);
if (credentialEntity == null) return;
// old store may not have id set
if (credentialEntity.getId() == null) credentialEntity.setId(KeycloakModelUtils.generateId());
setValues(cred, credentialEntity);
getMongoStore().updateEntity(mongoUser, invocationContext);
}
public CredentialEntity getCredentialEntity(CredentialModel cred, MongoUserEntity mongoUser) {
CredentialEntity credentialEntity = null;
// old store may not have id set
for (CredentialEntity entity : mongoUser.getCredentials()) {
if (cred.getId() != null && cred.getId().equals(entity.getId())) {
credentialEntity = entity;
break;
} else if (cred.getType().equals(entity.getType())) {
credentialEntity = entity;
break;
}
}
return credentialEntity;
}
public MongoUserEntity getMongoUserEntity(UserModel user) {
UserAdapter adapter = null;
if (user instanceof CachedUserModel) {
adapter = (UserAdapter)((CachedUserModel)user).getDelegateForUpdate();
} else if (user instanceof UserAdapter ){
adapter = (UserAdapter)user;
} else {
return getMongoStore().loadEntity(MongoUserEntity.class, user.getId(), invocationContext);
}
return adapter.getMongoEntity();
}
@Override
public CredentialModel createCredential(RealmModel realm, UserModel user, CredentialModel cred) {
MongoUserEntity mongoUser = getMongoUserEntity(user);
CredentialEntity credentialEntity = new CredentialEntity();
credentialEntity.setId(KeycloakModelUtils.generateId());
setValues(cred, credentialEntity);
cred.setId(credentialEntity.getId());
mongoUser.getCredentials().add(credentialEntity);
getMongoStore().updateEntity(mongoUser, invocationContext);
cred.setId(credentialEntity.getId());
return cred;
}
public void setValues(CredentialModel cred, CredentialEntity credentialEntity) {
credentialEntity.setType(cred.getType());
credentialEntity.setDevice(cred.getDevice());
credentialEntity.setValue(cred.getValue());
credentialEntity.setSalt(cred.getSalt());
credentialEntity.setDevice(cred.getDevice());
credentialEntity.setHashIterations(cred.getHashIterations());
credentialEntity.setCounter(cred.getCounter());
credentialEntity.setAlgorithm(cred.getAlgorithm());
credentialEntity.setDigits(cred.getDigits());
credentialEntity.setPeriod(cred.getPeriod());
if (cred.getConfig() == null) {
credentialEntity.setConfig(null);
}
else {
if (credentialEntity.getConfig() == null) credentialEntity.setConfig(new MultivaluedHashMap<>());
credentialEntity.getConfig().clear();
credentialEntity.getConfig().putAll(cred.getConfig());
}
}
@Override
public boolean removeStoredCredential(RealmModel realm, UserModel user, String id) {
MongoUserEntity mongoUser = getMongoUserEntity(user);
Iterator<CredentialEntity> it = mongoUser.getCredentials().iterator();
while (it.hasNext()) {
CredentialEntity entity = it.next();
if (id.equals(entity.getId())) {
it.remove();
getMongoStore().updateEntity(mongoUser, invocationContext);
return true;
}
}
return false;
}
@Override
public CredentialModel getStoredCredentialById(RealmModel realm, UserModel user, String id) {
MongoUserEntity mongoUser = getMongoUserEntity(user);
for (CredentialEntity credEntity : mongoUser.getCredentials()) {
if(id.equals(credEntity.getId())) {
if (credEntity.getId() == null) {
credEntity.setId(KeycloakModelUtils.generateId());
getMongoStore().updateEntity(mongoUser, invocationContext);
}
return toModel(credEntity);
}
}
return null;
}
public CredentialModel toModel(CredentialEntity credEntity) {
CredentialModel credModel = new CredentialModel();
credModel.setId(credEntity.getId());
credModel.setType(credEntity.getType());
credModel.setDevice(credEntity.getDevice());
credModel.setCreatedDate(credEntity.getCreatedDate());
credModel.setValue(credEntity.getValue());
credModel.setSalt(credEntity.getSalt());
credModel.setHashIterations(credEntity.getHashIterations());
credModel.setAlgorithm(credEntity.getAlgorithm());
credModel.setCounter(credEntity.getCounter());
credModel.setPeriod(credEntity.getPeriod());
credModel.setDigits(credEntity.getDigits());
if (credEntity.getConfig() != null) {
credModel.setConfig(new MultivaluedHashMap<>());
credModel.getConfig().putAll(credEntity.getConfig());
}
return credModel;
}
@Override
public List<CredentialModel> getStoredCredentials(RealmModel realm, UserModel user) {
List<CredentialModel> list = new LinkedList<>();
MongoUserEntity mongoUser = getMongoUserEntity(user);
boolean update = false;
for (CredentialEntity credEntity : mongoUser.getCredentials()) {
if (credEntity.getId() == null) {
credEntity.setId(KeycloakModelUtils.generateId());
update = true;
}
CredentialModel credModel = toModel(credEntity);
list.add(credModel);
}
if (update) getMongoStore().updateEntity(mongoUser, invocationContext);
return list;
}
@Override
public List<CredentialModel> getStoredCredentialsByType(RealmModel realm, UserModel user, String type) {
List<CredentialModel> list = new LinkedList<>();
MongoUserEntity mongoUser = getMongoUserEntity(user);
boolean update = false;
for (CredentialEntity credEntity : mongoUser.getCredentials()) {
if (credEntity.getId() == null) {
credEntity.setId(KeycloakModelUtils.generateId());
update = true;
}
if (credEntity.getType().equals(type)) {
CredentialModel credModel = toModel(credEntity);
list.add(credModel);
}
}
if (update) getMongoStore().updateEntity(mongoUser, invocationContext);
return list;
}
@Override
public CredentialModel getStoredCredentialByNameAndType(RealmModel realm, UserModel user, String name, String type) {
MongoUserEntity mongoUser = getMongoUserEntity(user);
boolean update = false;
CredentialModel credModel = null;
for (CredentialEntity credEntity : mongoUser.getCredentials()) {
if (credEntity.getId() == null) {
credEntity.setId(KeycloakModelUtils.generateId());
update = true;
}
if (credEntity.getType().equals(type) && name.equals(credEntity.getDevice())) {
credModel = toModel(credEntity);
break;
}
}
if (update) getMongoStore().updateEntity(mongoUser, invocationContext);
return credModel;
}
}