user fed refactor

This commit is contained in:
Bill Burke 2016-06-29 15:37:22 -04:00
parent b2d8c6bca2
commit f51098c50b
88 changed files with 6747 additions and 479 deletions

View file

@ -23,6 +23,7 @@ import org.keycloak.models.*;
import org.keycloak.models.cache.CacheRealmProvider;
import org.keycloak.models.cache.infinispan.entities.CachedRealm;
import org.keycloak.models.utils.KeycloakModelUtils;
import org.keycloak.storage.StorageProviderModel;
import java.security.Key;
import java.security.PrivateKey;
@ -739,6 +740,48 @@ public class RealmAdapter implements RealmModel {
}
@Override
public StorageProviderModel addStorageProvider(StorageProviderModel provider) {
getDelegateForUpdate();
return updated.addStorageProvider(provider);
}
@Override
public void updateStorageProvider(StorageProviderModel provider) {
getDelegateForUpdate();
updated.updateStorageProvider(provider);
}
@Override
public void removeStorageProvider(StorageProviderModel provider) {
getDelegateForUpdate();
updated.removeStorageProvider(provider);
}
@Override
public void setStorageProviders(List<StorageProviderModel> providers) {
getDelegateForUpdate();
updated.setStorageProviders(providers);
}
@Override
public List<StorageProviderModel> getStorageProviders() {
if (isUpdated()) return updated.getStorageProviders();
return cached.getStorageProviders();
}
@Override
public StorageProviderModel getStorageProvider(String id) {
if (isUpdated()) return updated.getStorageProvider(id);
for (StorageProviderModel model : cached.getStorageProviders()) {
if (model.getId().equals(id)) return model;
}
return null;
}
@Override
public String getLoginTheme() {
if (isUpdated()) return updated.getLoginTheme();

View file

@ -388,70 +388,6 @@ public class UserAdapter implements UserModel {
return KeycloakModelUtils.isMember(roles, group);
}
@Override
public void addConsent(UserConsentModel consent) {
getDelegateForUpdate();
updated.addConsent(consent);
}
@Override
public UserConsentModel getConsentByClient(String clientId) {
if (updated != null) return updated.getConsentByClient(clientId);
CachedUserConsent cachedConsent = cached.getConsents().get(clientId);
if (cachedConsent == null) {
return null;
}
return toConsentModel(cachedConsent);
}
@Override
public List<UserConsentModel> getConsents() {
if (updated != null) return updated.getConsents();
Collection<CachedUserConsent> cachedConsents = cached.getConsents().values();
List<UserConsentModel> result = new LinkedList<>();
for (CachedUserConsent cachedConsent : cachedConsents) {
UserConsentModel consent = toConsentModel(cachedConsent);
if (consent != null) {
result.add(consent);
}
}
return result;
}
@Override
public void updateConsent(UserConsentModel consent) {
getDelegateForUpdate();
updated.updateConsent(consent);
}
@Override
public boolean revokeConsentForClient(String clientId) {
getDelegateForUpdate();
return updated.revokeConsentForClient(clientId);
}
private UserConsentModel toConsentModel(CachedUserConsent cachedConsent) {
ClientModel client = keycloakSession.realms().getClientById(cachedConsent.getClientDbId(), realm);
if (client == null) {
return null;
}
UserConsentModel consentModel = new UserConsentModel(client);
for (String roleId : cachedConsent.getRoleIds()) {
RoleModel role = keycloakSession.realms().getRoleById(roleId, realm);
if (role != null) {
consentModel.addGrantedRole(role);
}
}
for (ProtocolMapperModel protocolMapper : cachedConsent.getProtocolMappers()) {
consentModel.addGrantedProtocolMapper(protocolMapper);
}
return consentModel;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;

View file

@ -28,6 +28,7 @@ import org.keycloak.models.KeycloakTransaction;
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.UserFederationProviderModel;
import org.keycloak.models.UserModel;
@ -35,7 +36,10 @@ import org.keycloak.models.UserProvider;
import org.keycloak.models.cache.CacheUserProvider;
import org.keycloak.models.cache.infinispan.entities.CachedFederatedIdentityLinks;
import org.keycloak.models.cache.infinispan.entities.CachedUser;
import org.keycloak.models.cache.infinispan.entities.CachedUserConsent;
import org.keycloak.models.cache.infinispan.entities.CachedUserConsents;
import org.keycloak.models.cache.infinispan.entities.UserListQuery;
import org.keycloak.storage.StorageProviderModel;
import java.util.*;
@ -73,7 +77,7 @@ public class UserCacheSession implements CacheUserProvider {
public UserProvider getDelegate() {
if (!transactionActive) throw new IllegalStateException("Cannot access delegate without a transaction");
if (delegate != null) return delegate;
delegate = session.getProvider(UserProvider.class);
delegate = session.userStorageManager();
return delegate;
}
@ -342,7 +346,7 @@ public class UserCacheSession implements CacheUserProvider {
}
@Override
public UserModel getUserByServiceAccountClient(ClientModel client) {
public UserModel getServiceAccount(ClientModel client) {
// Just an attempt to find the user from cache by default serviceAccount username
String username = ServiceAccountConstants.SERVICE_ACCOUNT_USER_PREFIX + client.getClientId();
UserModel user = getUserByUsername(username, client.getRealm());
@ -350,7 +354,7 @@ public class UserCacheSession implements CacheUserProvider {
return user;
}
return getDelegate().getUserByServiceAccountClient(client);
return getDelegate().getServiceAccount(client);
}
@Override
@ -368,6 +372,16 @@ public class UserCacheSession implements CacheUserProvider {
return getDelegate().getUsers(realm, firstResult, maxResults, includeServiceAccounts);
}
@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> searchForUser(String search, RealmModel realm) {
return getDelegate().searchForUser(search, realm);
@ -433,6 +447,101 @@ public class UserCacheSession implements CacheUserProvider {
return null;
}
@Override
public void updateConsent(RealmModel realm, UserModel user, UserConsentModel consent) {
invalidations.add(getConsentCacheKey(user.getId()));
getDelegate().updateConsent(realm, user, consent);
}
@Override
public boolean revokeConsentForClient(RealmModel realm, UserModel user, String clientInternalId) {
invalidations.add(getConsentCacheKey(user.getId()));
return getDelegate().revokeConsentForClient(realm, user, clientInternalId);
}
public String getConsentCacheKey(String userId) {
return userId + ".consents";
}
@Override
public void addConsent(RealmModel realm, UserModel user, UserConsentModel consent) {
invalidations.add(getConsentCacheKey(user.getId()));
getDelegate().addConsent(realm, user, consent);
}
@Override
public UserConsentModel getConsentByClient(RealmModel realm, UserModel user, String clientId) {
logger.tracev("getConsentByClient: {0}", user.getUsername());
String cacheKey = getConsentCacheKey(user.getId());
if (realmInvalidations.contains(realm.getId()) || invalidations.contains(user.getId()) || invalidations.contains(cacheKey)) {
return getDelegate().getConsentByClient(realm, user, clientId);
}
CachedUserConsents cached = cache.get(cacheKey, CachedUserConsents.class);
if (cached == null) {
Long loaded = cache.getCurrentRevision(cacheKey);
List<UserConsentModel> consents = getDelegate().getConsents(realm, user);
cached = new CachedUserConsents(loaded, cacheKey, realm, consents);
cache.addRevisioned(cached, startupRevision);
}
CachedUserConsent cachedConsent = cached.getConsents().get(clientId);
if (cachedConsent == null) return null;
return toConsentModel(realm, cachedConsent);
}
@Override
public List<UserConsentModel> getConsents(RealmModel realm, UserModel user) {
logger.tracev("getConsents: {0}", user.getUsername());
String cacheKey = getConsentCacheKey(user.getId());
if (realmInvalidations.contains(realm.getId()) || invalidations.contains(user.getId()) || invalidations.contains(cacheKey)) {
return getDelegate().getConsents(realm, user);
}
CachedUserConsents cached = cache.get(cacheKey, CachedUserConsents.class);
if (cached == null) {
Long loaded = cache.getCurrentRevision(cacheKey);
List<UserConsentModel> consents = getDelegate().getConsents(realm, user);
cached = new CachedUserConsents(loaded, cacheKey, realm, consents);
cache.addRevisioned(cached, startupRevision);
return consents;
} else {
List<UserConsentModel> result = new LinkedList<>();
for (CachedUserConsent cachedConsent : cached.getConsents().values()) {
UserConsentModel consent = toConsentModel(realm, cachedConsent);
if (consent != null) {
result.add(consent);
}
}
return result;
}
}
private UserConsentModel toConsentModel(RealmModel realm, CachedUserConsent cachedConsent) {
ClientModel client = session.realms().getClientById(cachedConsent.getClientDbId(), realm);
if (client == null) {
return null;
}
UserConsentModel consentModel = new UserConsentModel(client);
for (String roleId : cachedConsent.getRoleIds()) {
RoleModel role = session.realms().getRoleById(roleId, realm);
if (role != null) {
consentModel.addGrantedRole(role);
}
}
for (ProtocolMapperModel protocolMapper : cachedConsent.getProtocolMappers()) {
consentModel.addGrantedProtocolMapper(protocolMapper);
}
return consentModel;
}
@Override
public UserModel addUser(RealmModel realm, String id, String username, boolean addDefaultRoles, boolean addDefaultRequiredActions) {
UserModel user = getDelegate().addUser(realm, id, username, addDefaultRoles, addDefaultRoles);
@ -554,4 +663,9 @@ public class UserCacheSession implements CacheUserProvider {
public void preRemove(ProtocolMapperModel protocolMapper) {
getDelegate().preRemove(protocolMapper);
}
@Override
public void preRemove(RealmModel realm, StorageProviderModel provider) {
getDelegate().preRemove(realm, provider);
}
}

View file

@ -37,6 +37,7 @@ import org.keycloak.models.UserFederationMapperModel;
import org.keycloak.models.UserFederationProviderModel;
import org.keycloak.models.cache.infinispan.RealmCache;
import org.keycloak.common.util.MultivaluedHashMap;
import org.keycloak.storage.StorageProviderModel;
import java.io.Serializable;
import java.security.PrivateKey;
@ -109,6 +110,7 @@ public class CachedRealm extends AbstractRevisioned {
protected List<RequiredCredentialModel> requiredCredentials;
protected List<UserFederationProviderModel> userFederationProviders;
protected List<StorageProviderModel> storageProviders;
protected MultivaluedHashMap<String, UserFederationMapperModel> userFederationMappers = new MultivaluedHashMap<String, UserFederationMapperModel>();
protected Set<UserFederationMapperModel> userFederationMapperSet;
protected List<IdentityProviderModel> identityProviders;
@ -204,6 +206,7 @@ public class CachedRealm extends AbstractRevisioned {
requiredCredentials = model.getRequiredCredentials();
userFederationProviders = model.getUserFederationProviders();
storageProviders = model.getStorageProviders();
userFederationMapperSet = model.getUserFederationMappers();
for (UserFederationMapperModel mapper : userFederationMapperSet) {
this.userFederationMappers.add(mapper.getFederationProviderId(), mapper);
@ -592,4 +595,8 @@ public class CachedRealm extends AbstractRevisioned {
public List<RequiredActionProviderModel> getRequiredActionProviderList() {
return requiredActionProviderList;
}
public List<StorageProviderModel> getStorageProviders() {
return storageProviders;
}
}

View file

@ -53,7 +53,6 @@ public class CachedUser extends AbstractRevisioned implements InRealm {
private Set<String> requiredActions = new HashSet<>();
private Set<String> roleMappings = new HashSet<>();
private Set<String> groups = new HashSet<>();
private Map<String, CachedUserConsent> consents = new HashMap<>(); // Key is client DB Id
@ -82,13 +81,6 @@ public class CachedUser extends AbstractRevisioned implements InRealm {
groups.add(group.getId());
}
}
List<UserConsentModel> consents = user.getConsents();
if (consents != null) {
for (UserConsentModel consent : consents) {
this.consents.put(consent.getClient().getId(), new CachedUserConsent(consent));
}
}
}
public String getRealm() {
@ -155,7 +147,4 @@ public class CachedUser extends AbstractRevisioned implements InRealm {
return groups;
}
public Map<String, CachedUserConsent> getConsents() {
return consents;
}
}

View file

@ -0,0 +1,53 @@
/*
* 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.cache.infinispan.entities;
import org.keycloak.models.RealmModel;
import org.keycloak.models.UserConsentModel;
import java.util.HashMap;
import java.util.List;
/**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $
*/
public class CachedUserConsents extends AbstractRevisioned implements InRealm {
private HashMap<String, CachedUserConsent> consents = new HashMap<>();
private final String realmId;
public CachedUserConsents(Long revision, String id, RealmModel realm,
List<UserConsentModel> consents) {
super(revision, id);
this.realmId = realm.getId();
if (consents != null) {
for (UserConsentModel consent : consents) {
this.consents.put(consent.getClient().getId(), new CachedUserConsent(consent));
}
}
}
@Override
public String getRealm() {
return realmId;
}
public HashMap<String, CachedUserConsent> getConsents() {
return consents;
}
}

View file

@ -22,23 +22,31 @@ 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.jpa.entities.FederatedIdentityEntity;
import org.keycloak.models.jpa.entities.UserAttributeEntity;
import org.keycloak.models.jpa.entities.UserConsentEntity;
import org.keycloak.models.jpa.entities.UserConsentProtocolMapperEntity;
import org.keycloak.models.jpa.entities.UserConsentRoleEntity;
import org.keycloak.models.jpa.entities.UserEntity;
import org.keycloak.models.utils.CredentialValidation;
import org.keycloak.models.utils.KeycloakModelUtils;
import org.keycloak.storage.StorageProviderModel;
import javax.persistence.EntityManager;
import javax.persistence.TypedQuery;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
@ -173,6 +181,164 @@ public class JpaUserProvider implements UserProvider {
}
}
@Override
public void addConsent(RealmModel realm, UserModel user, UserConsentModel consent) {
String clientId = consent.getClient().getId();
UserConsentEntity consentEntity = getGrantedConsentEntity(user, clientId);
if (consentEntity != null) {
throw new ModelDuplicateException("Consent already exists for client [" + clientId + "] and user [" + user.getId() + "]");
}
consentEntity = new UserConsentEntity();
consentEntity.setId(KeycloakModelUtils.generateId());
consentEntity.setUser(em.getReference(UserEntity.class, user.getId()));
consentEntity.setClientId(clientId);
em.persist(consentEntity);
em.flush();
updateGrantedConsentEntity(consentEntity, consent);
}
@Override
public UserConsentModel getConsentByClient(RealmModel realm, UserModel user, String clientId) {
UserConsentEntity entity = getGrantedConsentEntity(user, clientId);
return toConsentModel(realm, entity);
}
@Override
public List<UserConsentModel> getConsents(RealmModel realm, UserModel user) {
TypedQuery<UserConsentEntity> query = em.createNamedQuery("userConsentsByUser", UserConsentEntity.class);
query.setParameter("userId", user.getId());
List<UserConsentEntity> results = query.getResultList();
List<UserConsentModel> consents = new ArrayList<UserConsentModel>();
for (UserConsentEntity entity : results) {
UserConsentModel model = toConsentModel(realm, entity);
consents.add(model);
}
return consents;
}
@Override
public void updateConsent(RealmModel realm, UserModel user, UserConsentModel consent) {
String clientId = consent.getClient().getId();
UserConsentEntity consentEntity = getGrantedConsentEntity(user, clientId);
if (consentEntity == null) {
throw new ModelException("Consent not found for client [" + clientId + "] and user [" + user.getId() + "]");
}
updateGrantedConsentEntity(consentEntity, consent);
}
public boolean revokeConsentForClient(RealmModel realm, UserModel user, String clientId) {
UserConsentEntity consentEntity = getGrantedConsentEntity(user, clientId);
if (consentEntity == null) return false;
em.remove(consentEntity);
em.flush();
return true;
}
private UserConsentEntity getGrantedConsentEntity(UserModel user, String clientId) {
TypedQuery<UserConsentEntity> query = em.createNamedQuery("userConsentByUserAndClient", UserConsentEntity.class);
query.setParameter("userId", user.getId());
query.setParameter("clientId", clientId);
List<UserConsentEntity> results = query.getResultList();
if (results.size() > 1) {
throw new ModelException("More results found for user [" + user.getUsername() + "] and client [" + clientId + "]");
} else if (results.size() == 1) {
return results.get(0);
} else {
return null;
}
}
private UserConsentModel toConsentModel(RealmModel realm, UserConsentEntity entity) {
if (entity == null) {
return null;
}
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);
Collection<UserConsentRoleEntity> grantedRoleEntities = entity.getGrantedRoles();
if (grantedRoleEntities != null) {
for (UserConsentRoleEntity grantedRole : grantedRoleEntities) {
RoleModel grantedRoleModel = realm.getRoleById(grantedRole.getRoleId());
if (grantedRoleModel != null) {
model.addGrantedRole(grantedRoleModel);
}
}
}
Collection<UserConsentProtocolMapperEntity> grantedProtocolMapperEntities = entity.getGrantedProtocolMappers();
if (grantedProtocolMapperEntities != null) {
for (UserConsentProtocolMapperEntity grantedProtMapper : grantedProtocolMapperEntities) {
ProtocolMapperModel protocolMapper = client.getProtocolMapperById(grantedProtMapper.getProtocolMapperId());
model.addGrantedProtocolMapper(protocolMapper );
}
}
return model;
}
// Update roles and protocolMappers to given consentEntity from the consentModel
private void updateGrantedConsentEntity(UserConsentEntity consentEntity, UserConsentModel consentModel) {
Collection<UserConsentProtocolMapperEntity> grantedProtocolMapperEntities = consentEntity.getGrantedProtocolMappers();
Collection<UserConsentProtocolMapperEntity> mappersToRemove = new HashSet<UserConsentProtocolMapperEntity>(grantedProtocolMapperEntities);
for (ProtocolMapperModel protocolMapper : consentModel.getGrantedProtocolMappers()) {
UserConsentProtocolMapperEntity grantedProtocolMapperEntity = new UserConsentProtocolMapperEntity();
grantedProtocolMapperEntity.setUserConsent(consentEntity);
grantedProtocolMapperEntity.setProtocolMapperId(protocolMapper.getId());
// Check if it's already there
if (!grantedProtocolMapperEntities.contains(grantedProtocolMapperEntity)) {
em.persist(grantedProtocolMapperEntity);
em.flush();
grantedProtocolMapperEntities.add(grantedProtocolMapperEntity);
} else {
mappersToRemove.remove(grantedProtocolMapperEntity);
}
}
// Those mappers were no longer on consentModel and will be removed
for (UserConsentProtocolMapperEntity toRemove : mappersToRemove) {
grantedProtocolMapperEntities.remove(toRemove);
em.remove(toRemove);
}
Collection<UserConsentRoleEntity> grantedRoleEntities = consentEntity.getGrantedRoles();
Set<UserConsentRoleEntity> rolesToRemove = new HashSet<UserConsentRoleEntity>(grantedRoleEntities);
for (RoleModel role : consentModel.getGrantedRoles()) {
UserConsentRoleEntity consentRoleEntity = new UserConsentRoleEntity();
consentRoleEntity.setUserConsent(consentEntity);
consentRoleEntity.setRoleId(role.getId());
// Check if it's already there
if (!grantedRoleEntities.contains(consentRoleEntity)) {
em.persist(consentRoleEntity);
em.flush();
grantedRoleEntities.add(consentRoleEntity);
} else {
rolesToRemove.remove(consentRoleEntity);
}
}
// Those roles were no longer on consentModel and will be removed
for (UserConsentRoleEntity toRemove : rolesToRemove) {
grantedRoleEntities.remove(toRemove);
em.remove(toRemove);
}
em.flush();
}
@Override
public void grantToAllUsers(RealmModel realm, RoleModel role) {
int num = em.createNamedQuery("grantRoleToAllUsers")
@ -324,7 +490,7 @@ public class JpaUserProvider implements UserProvider {
}
@Override
public UserModel getUserByServiceAccountClient(ClientModel client) {
public UserModel getServiceAccount(ClientModel client) {
TypedQuery<UserEntity> query = em.createNamedQuery("getRealmUserByServiceAccount", UserEntity.class);
query.setParameter("realmId", client.getRealm().getId());
query.setParameter("clientInternalId", client.getId());
@ -353,6 +519,16 @@ public class JpaUserProvider implements UserProvider {
return ((Number)count).intValue();
}
@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, int firstResult, int maxResults, boolean includeServiceAccounts) {
String queryName = includeServiceAccounts ? "getAllUsersByRealm" : "getAllUsersByRealmExcludeServiceAccount" ;
@ -529,4 +705,9 @@ public class JpaUserProvider implements UserProvider {
// Not supported yet
return null;
}
@Override
public void preRemove(RealmModel realm, StorageProviderModel link) {
}
}

View file

@ -42,6 +42,8 @@ import org.keycloak.models.UserFederationProviderCreationEventImpl;
import org.keycloak.models.UserFederationProviderModel;
import org.keycloak.models.jpa.entities.*;
import org.keycloak.models.utils.KeycloakModelUtils;
import org.keycloak.storage.StorageProvider;
import org.keycloak.storage.StorageProviderModel;
import javax.persistence.EntityManager;
import javax.persistence.TypedQuery;
@ -805,6 +807,15 @@ public class RealmAdapter implements RealmModel, JpaModel<RealmEntity> {
em.flush();
}
private void removeFederationMappersForProvider(String federationProviderId) {
Set<UserFederationMapperEntity> mappers = getUserFederationMapperEntitiesByFederationProvider(federationProviderId);
for (UserFederationMapperEntity mapper : mappers) {
realm.getUserFederationMappers().remove(mapper);
em.remove(mapper);
}
}
@Override
public List<UserFederationProviderModel> getUserFederationProviders() {
List<UserFederationProviderEntity> entities = realm.getUserFederationProviders();
@ -875,15 +886,6 @@ public class RealmAdapter implements RealmModel, JpaModel<RealmEntity> {
}
}
}
private void removeFederationMappersForProvider(String federationProviderId) {
Set<UserFederationMapperEntity> mappers = getUserFederationMapperEntitiesByFederationProvider(federationProviderId);
for (UserFederationMapperEntity mapper : mappers) {
realm.getUserFederationMappers().remove(mapper);
em.remove(mapper);
}
}
@Override
public void updateUserFederationProvider(UserFederationProviderModel model) {
KeycloakModelUtils.ensureUniqueDisplayName(model.getDisplayName(), model, getUserFederationProviders());
@ -994,6 +996,186 @@ public class RealmAdapter implements RealmModel, JpaModel<RealmEntity> {
return null;
}
@Override
public StorageProviderModel getStorageProvider(String id) {
StorageProviderEntity entity = em.find(StorageProviderEntity.class, id);
if (entity == null) return null;
return toModel(entity);
}
@Override
public List<StorageProviderModel> getStorageProviders() {
List<StorageProviderEntity> entities = realm.getStorageProviders();
if (entities.isEmpty()) return Collections.EMPTY_LIST;
List<StorageProviderEntity> copy = new LinkedList<>();
for (StorageProviderEntity entity : entities) {
copy.add(entity);
}
Collections.sort(copy, new Comparator<StorageProviderEntity>() {
@Override
public int compare(StorageProviderEntity o1, StorageProviderEntity o2) {
return o1.getPriority() - o2.getPriority();
}
});
List<StorageProviderModel> result = new LinkedList<>();
for (StorageProviderEntity entity : copy) {
result.add(toModel(entity));
}
return Collections.unmodifiableList(result);
}
protected StorageProviderModel toModel(StorageProviderEntity entity) {
StorageProviderModel model = new StorageProviderModel();
model.setId(entity.getId());
model.setProviderName(entity.getProviderName());
model.getConfig().putAll(entity.getConfig());
model.setPriority(entity.getPriority());
model.setDisplayName(entity.getDisplayName());
return model;
}
@Override
public StorageProviderModel addStorageProvider(StorageProviderModel model) {
KeycloakModelUtils.ensureUniqueDisplayName(model.getDisplayName(), null, getStorageProviders());
String id = KeycloakModelUtils.generateId();
StorageProviderEntity entity = new StorageProviderEntity();
entity.setId(id);
entity.setRealm(realm);
entity.setProviderName(model.getProviderName());
entity.setConfig(model.getConfig());
entity.setPriority(model.getPriority());
String displayName = model.getDisplayName();
if (model.getDisplayName() == null) {
displayName = id;
}
entity.setDisplayName(displayName);
em.persist(entity);
realm.getStorageProviders().add(entity);
em.flush();
StorageProviderModel providerModel = toModel(entity);
return providerModel;
}
@Override
public void removeStorageProvider(StorageProviderModel provider) {
Iterator<StorageProviderEntity> it = realm.getStorageProviders().iterator();
while (it.hasNext()) {
StorageProviderEntity entity = it.next();
if (entity.getId().equals(provider.getId())) {
session.users().preRemove(this, provider);
it.remove();
em.remove(entity);
return;
}
}
}
@Override
public void updateStorageProvider(StorageProviderModel model) {
KeycloakModelUtils.ensureUniqueDisplayName(model.getDisplayName(), model, getStorageProviders());
Iterator<StorageProviderEntity> it = realm.getStorageProviders().iterator();
while (it.hasNext()) {
StorageProviderEntity entity = it.next();
if (entity.getId().equals(model.getId())) {
String displayName = model.getDisplayName();
if (displayName != null) {
entity.setDisplayName(model.getDisplayName());
}
entity.setConfig(model.getConfig());
entity.setPriority(model.getPriority());
entity.setProviderName(model.getProviderName());
entity.setPriority(model.getPriority());
break;
}
}
}
@Override
public void setStorageProviders(List<StorageProviderModel> providers) {
for (StorageProviderModel currentProvider : providers) {
KeycloakModelUtils.ensureUniqueDisplayName(currentProvider.getDisplayName(), currentProvider, providers);
}
Iterator<StorageProviderEntity> it = realm.getStorageProviders().iterator();
while (it.hasNext()) {
StorageProviderEntity entity = it.next();
boolean found = false;
for (StorageProviderModel model : providers) {
if (entity.getId().equals(model.getId())) {
entity.setConfig(model.getConfig());
entity.setPriority(model.getPriority());
entity.setProviderName(model.getProviderName());
String displayName = model.getDisplayName();
if (displayName != null) {
entity.setDisplayName(displayName);
}
found = true;
break;
}
}
if (found) continue;
session.users().preRemove(this, toModel(entity));
removeFederationMappersForProvider(entity.getId());
it.remove();
em.remove(entity);
}
List<StorageProviderModel> add = new LinkedList<>();
for (StorageProviderModel model : providers) {
boolean found = false;
for (StorageProviderEntity entity : realm.getStorageProviders()) {
if (entity.getId().equals(model.getId())) {
found = true;
break;
}
}
if (!found) add.add(model);
}
for (StorageProviderModel model : add) {
StorageProviderEntity entity = new StorageProviderEntity();
if (model.getId() != null) {
entity.setId(model.getId());
} else {
String id = KeycloakModelUtils.generateId();
entity.setId(id);
model.setId(id);
}
entity.setConfig(model.getConfig());
entity.setPriority(model.getPriority());
entity.setProviderName(model.getProviderName());
entity.setPriority(model.getPriority());
String displayName = model.getDisplayName();
if (displayName == null) {
displayName = entity.getId();
}
entity.setDisplayName(displayName);
entity.setRealm(realm);
em.persist(entity);
realm.getStorageProviders().add(entity);
}
}
protected StorageProviderEntity getStorageProviderEntityById(String id) {
for (StorageProviderEntity entity : realm.getStorageProviders()) {
if (entity.getId().equals(id)) {
return entity;
}
}
return null;
}
@Override
public RoleModel getRole(String name) {
return session.realms().getRealmRole(this, name);

View file

@ -668,163 +668,6 @@ public class UserAdapter implements UserModel, JpaModel<UserEntity> {
user.setServiceAccountClientLink(clientInternalId);
}
@Override
public void addConsent(UserConsentModel consent) {
String clientId = consent.getClient().getId();
UserConsentEntity consentEntity = getGrantedConsentEntity(clientId);
if (consentEntity != null) {
throw new ModelDuplicateException("Consent already exists for client [" + clientId + "] and user [" + user.getId() + "]");
}
consentEntity = new UserConsentEntity();
consentEntity.setId(KeycloakModelUtils.generateId());
consentEntity.setUser(user);
consentEntity.setClientId(clientId);
em.persist(consentEntity);
em.flush();
updateGrantedConsentEntity(consentEntity, consent);
}
@Override
public UserConsentModel getConsentByClient(String clientId) {
UserConsentEntity entity = getGrantedConsentEntity(clientId);
return toConsentModel(entity);
}
@Override
public List<UserConsentModel> getConsents() {
TypedQuery<UserConsentEntity> query = em.createNamedQuery("userConsentsByUser", UserConsentEntity.class);
query.setParameter("userId", getId());
List<UserConsentEntity> results = query.getResultList();
List<UserConsentModel> consents = new ArrayList<UserConsentModel>();
for (UserConsentEntity entity : results) {
UserConsentModel model = toConsentModel(entity);
consents.add(model);
}
return consents;
}
@Override
public void updateConsent(UserConsentModel consent) {
String clientId = consent.getClient().getId();
UserConsentEntity consentEntity = getGrantedConsentEntity(clientId);
if (consentEntity == null) {
throw new ModelException("Consent not found for client [" + clientId + "] and user [" + user.getId() + "]");
}
updateGrantedConsentEntity(consentEntity, consent);
}
@Override
public boolean revokeConsentForClient(String clientId) {
UserConsentEntity consentEntity = getGrantedConsentEntity(clientId);
if (consentEntity == null) return false;
em.remove(consentEntity);
em.flush();
return true;
}
private UserConsentEntity getGrantedConsentEntity(String clientId) {
TypedQuery<UserConsentEntity> query = em.createNamedQuery("userConsentByUserAndClient", UserConsentEntity.class);
query.setParameter("userId", getId());
query.setParameter("clientId", clientId);
List<UserConsentEntity> results = query.getResultList();
if (results.size() > 1) {
throw new ModelException("More results found for user [" + getUsername() + "] and client [" + clientId + "]");
} else if (results.size() == 1) {
return results.get(0);
} else {
return null;
}
}
private UserConsentModel toConsentModel(UserConsentEntity entity) {
if (entity == null) {
return null;
}
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);
Collection<UserConsentRoleEntity> grantedRoleEntities = entity.getGrantedRoles();
if (grantedRoleEntities != null) {
for (UserConsentRoleEntity grantedRole : grantedRoleEntities) {
RoleModel grantedRoleModel = realm.getRoleById(grantedRole.getRoleId());
if (grantedRoleModel != null) {
model.addGrantedRole(grantedRoleModel);
}
}
}
Collection<UserConsentProtocolMapperEntity> grantedProtocolMapperEntities = entity.getGrantedProtocolMappers();
if (grantedProtocolMapperEntities != null) {
for (UserConsentProtocolMapperEntity grantedProtMapper : grantedProtocolMapperEntities) {
ProtocolMapperModel protocolMapper = client.getProtocolMapperById(grantedProtMapper.getProtocolMapperId());
model.addGrantedProtocolMapper(protocolMapper );
}
}
return model;
}
// Update roles and protocolMappers to given consentEntity from the consentModel
private void updateGrantedConsentEntity(UserConsentEntity consentEntity, UserConsentModel consentModel) {
Collection<UserConsentProtocolMapperEntity> grantedProtocolMapperEntities = consentEntity.getGrantedProtocolMappers();
Collection<UserConsentProtocolMapperEntity> mappersToRemove = new HashSet<UserConsentProtocolMapperEntity>(grantedProtocolMapperEntities);
for (ProtocolMapperModel protocolMapper : consentModel.getGrantedProtocolMappers()) {
UserConsentProtocolMapperEntity grantedProtocolMapperEntity = new UserConsentProtocolMapperEntity();
grantedProtocolMapperEntity.setUserConsent(consentEntity);
grantedProtocolMapperEntity.setProtocolMapperId(protocolMapper.getId());
// Check if it's already there
if (!grantedProtocolMapperEntities.contains(grantedProtocolMapperEntity)) {
em.persist(grantedProtocolMapperEntity);
em.flush();
grantedProtocolMapperEntities.add(grantedProtocolMapperEntity);
} else {
mappersToRemove.remove(grantedProtocolMapperEntity);
}
}
// Those mappers were no longer on consentModel and will be removed
for (UserConsentProtocolMapperEntity toRemove : mappersToRemove) {
grantedProtocolMapperEntities.remove(toRemove);
em.remove(toRemove);
}
Collection<UserConsentRoleEntity> grantedRoleEntities = consentEntity.getGrantedRoles();
Set<UserConsentRoleEntity> rolesToRemove = new HashSet<UserConsentRoleEntity>(grantedRoleEntities);
for (RoleModel role : consentModel.getGrantedRoles()) {
UserConsentRoleEntity consentRoleEntity = new UserConsentRoleEntity();
consentRoleEntity.setUserConsent(consentEntity);
consentRoleEntity.setRoleId(role.getId());
// Check if it's already there
if (!grantedRoleEntities.contains(consentRoleEntity)) {
em.persist(consentRoleEntity);
em.flush();
grantedRoleEntities.add(consentRoleEntity);
} else {
rolesToRemove.remove(consentRoleEntity);
}
}
// Those roles were no longer on consentModel and will be removed
for (UserConsentRoleEntity toRemove : rolesToRemove) {
grantedRoleEntities.remove(toRemove);
em.remove(toRemove);
}
em.flush();
}
@Override
public boolean equals(Object o) {

View file

@ -136,13 +136,16 @@ public class RealmEntity {
protected String emailTheme;
@OneToMany(cascade ={CascadeType.REMOVE}, orphanRemoval = true, mappedBy = "realm")
Collection<RealmAttributeEntity> attributes = new ArrayList<RealmAttributeEntity>();
Collection<RealmAttributeEntity> attributes = new ArrayList<>();
@OneToMany(cascade ={CascadeType.REMOVE}, orphanRemoval = true, mappedBy = "realm")
Collection<RequiredCredentialEntity> requiredCredentials = new ArrayList<RequiredCredentialEntity>();
Collection<RequiredCredentialEntity> requiredCredentials = new ArrayList<>();
@OneToMany(cascade ={CascadeType.REMOVE}, orphanRemoval = true, mappedBy = "realm")
List<UserFederationProviderEntity> userFederationProviders = new ArrayList<UserFederationProviderEntity>();
List<UserFederationProviderEntity> userFederationProviders = new ArrayList<>();
@OneToMany(cascade ={CascadeType.REMOVE}, orphanRemoval = true, mappedBy = "realm")
List<StorageProviderEntity> storageProviders = new ArrayList<>();
@OneToMany(cascade ={CascadeType.REMOVE}, orphanRemoval = true, mappedBy = "realm")
Collection<UserFederationMapperEntity> userFederationMappers = new ArrayList<UserFederationMapperEntity>();
@ -551,6 +554,14 @@ public class RealmEntity {
this.userFederationProviders = userFederationProviders;
}
public List<StorageProviderEntity> getStorageProviders() {
return storageProviders;
}
public void setStorageProviders(List<StorageProviderEntity> storageProviders) {
this.storageProviders = storageProviders;
}
public Collection<UserFederationMapperEntity> getUserFederationMappers() {
return userFederationMappers;
}

View file

@ -0,0 +1,131 @@
/*
* 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.jpa.entities;
import javax.persistence.Access;
import javax.persistence.AccessType;
import javax.persistence.CollectionTable;
import javax.persistence.Column;
import javax.persistence.ElementCollection;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.MapKeyColumn;
import javax.persistence.Table;
import java.util.Map;
/**
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
* @author <a href="mailto:bburke@redhat.com">Bill Burke</a>
*/
@Entity
@Table(name="STORAGE_PROVIDER")
public class StorageProviderEntity {
@Id
@Column(name="ID", length = 36)
@Access(AccessType.PROPERTY) // we do this because relationships often fetch id, but not entity. This avoids an extra SQL
protected String id;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "REALM_ID")
protected RealmEntity realm;
@Column(name="PROVIDER_NAME")
private String providerName;
@Column(name="PRIORITY")
private int priority;
@ElementCollection
@MapKeyColumn(name="name")
@Column(name="VALUE")
@CollectionTable(name="STORAGE_PROVIDER_CONFIG", joinColumns={ @JoinColumn(name="STORAGE_PROVIDER_ID") })
private Map<String, String> config;
@Column(name="DISPLAY_NAME")
private String displayName;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public RealmEntity getRealm() {
return realm;
}
public void setRealm(RealmEntity realm) {
this.realm = realm;
}
public String getProviderName() {
return providerName;
}
public void setProviderName(String providerName) {
this.providerName = providerName;
}
public int getPriority() {
return priority;
}
public void setPriority(int priority) {
this.priority = priority;
}
public Map<String, String> getConfig() {
return config;
}
public void setConfig(Map<String, String> config) {
this.config = config;
}
public String getDisplayName() {
return displayName;
}
public void setDisplayName(String displayName) {
this.displayName = displayName;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null) return false;
if (!(o instanceof StorageProviderEntity)) return false;
StorageProviderEntity that = (StorageProviderEntity) o;
if (!id.equals(that.getId())) return false;
return true;
}
@Override
public int hashCode() {
return id.hashCode();
}
}

View file

@ -0,0 +1,732 @@
/*
* 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.jpa;
import org.keycloak.common.util.MultivaluedHashMap;
import org.keycloak.models.ClientModel;
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.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.jpa.entities.CredentialEntity;
import org.keycloak.models.utils.FederatedCredentials;
import org.keycloak.models.utils.KeycloakModelUtils;
import org.keycloak.storage.StorageId;
import org.keycloak.storage.StorageProviderModel;
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;
import org.keycloak.storage.federated.UserRoleMappingsFederatedStorage;
import org.keycloak.storage.jpa.entity.BrokerLinkEntity;
import org.keycloak.storage.jpa.entity.FederatedUserAttributeEntity;
import org.keycloak.storage.jpa.entity.FederatedUserConsentEntity;
import org.keycloak.storage.jpa.entity.FederatedUserConsentProtocolMapperEntity;
import org.keycloak.storage.jpa.entity.FederatedUserConsentRoleEntity;
import org.keycloak.storage.jpa.entity.FederatedUserCredentialEntity;
import org.keycloak.storage.jpa.entity.FederatedUserGroupMembershipEntity;
import org.keycloak.storage.jpa.entity.FederatedUserRequiredActionEntity;
import org.keycloak.storage.jpa.entity.FederatedUserRoleMappingEntity;
import javax.persistence.EntityManager;
import javax.persistence.TypedQuery;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
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 JpaUserFederatedStorageProvider implements
UserFederatedStorageProvider,
UserAttributeFederatedStorage,
UserBrokerLinkFederatedStorage,
UserConsentFederatedStorage,
UserCredentialsFederatedStorage,
UserGroupMembershipFederatedStorage,
UserRequiredActionsFederatedStorage,
UserRoleMappingsFederatedStorage {
private final KeycloakSession session;
protected EntityManager em;
public JpaUserFederatedStorageProvider(KeycloakSession session, EntityManager em) {
this.session = session;
this.em = em;
}
@Override
public void close() {
}
@Override
public void setAttribute(RealmModel realm, UserModel user, String name, List<String> values) {
deleteAttribute(realm, user, name);
em.flush();
for (String value : values) {
persistAttributeValue(realm, user, name, value);
}
}
private void deleteAttribute(RealmModel realm, UserModel user, String name) {
em.createNamedQuery("deleteUserFederatedAttributesByUserAndName")
.setParameter("userId", user.getId())
.setParameter("realmId", realm.getId())
.setParameter("name", name)
.executeUpdate();
}
private void persistAttributeValue(RealmModel realm, UserModel user, String name, String value) {
FederatedUserAttributeEntity attr = new FederatedUserAttributeEntity();
attr.setId(KeycloakModelUtils.generateId());
attr.setName(name);
attr.setValue(value);
attr.setUserId(user.getId());
attr.setRealmId(realm.getId());
attr.setStorageProviderId(StorageId.resolveProviderId(user));
em.persist(attr);
}
@Override
public void setSingleAttribute(RealmModel realm, UserModel user, String name, String value) {
deleteAttribute(realm, user, name);
em.flush();
persistAttributeValue(realm, user, name, value);
}
@Override
public void removeAttribute(RealmModel realm, UserModel user, String name) {
deleteAttribute(realm, user, name);
em.flush();
}
@Override
public MultivaluedHashMap<String, String> getAttributes(RealmModel realm, UserModel user) {
TypedQuery<FederatedUserAttributeEntity> query = em.createNamedQuery("getFederatedAttributesByUser", FederatedUserAttributeEntity.class);
List<FederatedUserAttributeEntity> list = query
.setParameter("userId", user.getId())
.setParameter("realmId", realm.getId())
.getResultList();
MultivaluedHashMap<String, String> result = new MultivaluedHashMap<>();
for (FederatedUserAttributeEntity entity : list) {
result.add(entity.getName(), entity.getValue());
}
return result;
}
@Override
public String getUserByFederatedIdentity(FederatedIdentityModel link, RealmModel realm) {
TypedQuery<String> query = em.createNamedQuery("findBrokerLinkByUserAndProvider", String.class)
.setParameter("realmid", realm.getId())
.setParameter("identityProvider", link.getIdentityProvider())
.setParameter("brokerUserId", link.getUserId());
List<String> results = query.getResultList();
if (results.isEmpty()) {
return null;
} else if (results.size() > 1) {
throw new IllegalStateException("More results found for identityProvider=" + link.getIdentityProvider() +
", userId=" + link.getUserId() + ", results=" + results);
} else {
return results.get(0);
}
}
@Override
public void addFederatedIdentity(RealmModel realm, UserModel user, FederatedIdentityModel link) {
BrokerLinkEntity entity = new BrokerLinkEntity();
entity.setRealmId(realm.getId());
entity.setUserId(user.getId());
entity.setBrokerUserId(link.getUserId());
entity.setIdentityProvider(link.getIdentityProvider());
entity.setToken(link.getToken());
entity.setBrokerUserName(link.getUserName());
entity.setStorageProviderId(StorageId.resolveProviderId(user));
em.persist(entity);
}
@Override
public boolean removeFederatedIdentity(RealmModel realm, UserModel user, String socialProvider) {
BrokerLinkEntity entity = getBrokerLinkEntity(user, socialProvider);
if (entity == null) return false;
em.remove(entity);
return true;
}
private BrokerLinkEntity getBrokerLinkEntity(UserModel user, String socialProvider) {
TypedQuery<BrokerLinkEntity> query = em.createNamedQuery("findBrokerLinkByUserAndProvider", BrokerLinkEntity.class)
.setParameter("userId", user.getId())
.setParameter("identityProvider", socialProvider);
List<BrokerLinkEntity> results = query.getResultList();
return results.size() > 0 ? results.get(0) : null;
}
@Override
public void updateFederatedIdentity(RealmModel realm, UserModel user, FederatedIdentityModel model) {
BrokerLinkEntity entity = getBrokerLinkEntity(user, model.getIdentityProvider());
if (entity == null) return;
entity.setBrokerUserName(model.getUserName());
entity.setBrokerUserId(model.getUserId());
entity.setToken(model.getToken());
em.persist(entity);
em.flush();
}
@Override
public Set<FederatedIdentityModel> getFederatedIdentities(UserModel user, RealmModel realm) {
TypedQuery<BrokerLinkEntity> query = em.createNamedQuery("findBrokerLinkByUser", BrokerLinkEntity.class)
.setParameter("userId", user.getId());
List<BrokerLinkEntity> results = query.getResultList();
Set<FederatedIdentityModel> set = new HashSet<>();
for (BrokerLinkEntity entity : results) {
FederatedIdentityModel model = new FederatedIdentityModel(entity.getIdentityProvider(), entity.getBrokerUserId(), entity.getBrokerUserName(), entity.getToken());
set.add(model);
}
return set;
}
@Override
public FederatedIdentityModel getFederatedIdentity(UserModel user, String socialProvider, RealmModel realm) {
BrokerLinkEntity entity = getBrokerLinkEntity(user, socialProvider);
if (entity == null) return null;
return new FederatedIdentityModel(entity.getIdentityProvider(), entity.getBrokerUserId(), entity.getBrokerUserName(), entity.getToken());
}
@Override
public void addConsent(RealmModel realm, UserModel user, UserConsentModel consent) {
String clientId = consent.getClient().getId();
FederatedUserConsentEntity consentEntity = getGrantedConsentEntity(user, clientId);
if (consentEntity != null) {
throw new ModelDuplicateException("Consent already exists for client [" + clientId + "] and user [" + user.getId() + "]");
}
consentEntity = new FederatedUserConsentEntity();
consentEntity.setId(KeycloakModelUtils.generateId());
consentEntity.setUserId(user.getId());
consentEntity.setClientId(clientId);
consentEntity.setStorageProviderId(StorageId.resolveProviderId(user));
em.persist(consentEntity);
em.flush();
updateGrantedConsentEntity(consentEntity, consent);
}
@Override
public UserConsentModel getConsentByClient(RealmModel realm, UserModel user, String clientInternalId) {
FederatedUserConsentEntity entity = getGrantedConsentEntity(user, clientInternalId);
return toConsentModel(realm, entity);
}
@Override
public List<UserConsentModel> getConsents(RealmModel realm, UserModel user) {
TypedQuery<FederatedUserConsentEntity> query = em.createNamedQuery("userFederatedConsentsByUser", FederatedUserConsentEntity.class);
query.setParameter("userId", user.getId());
List<FederatedUserConsentEntity> results = query.getResultList();
List<UserConsentModel> consents = new ArrayList<UserConsentModel>();
for (FederatedUserConsentEntity entity : results) {
UserConsentModel model = toConsentModel(realm, entity);
consents.add(model);
}
return consents;
}
@Override
public void updateConsent(RealmModel realm, UserModel user, UserConsentModel consent) {
String clientId = consent.getClient().getId();
FederatedUserConsentEntity consentEntity = getGrantedConsentEntity(user, clientId);
if (consentEntity == null) {
throw new ModelException("Consent not found for client [" + clientId + "] and user [" + user.getId() + "]");
}
updateGrantedConsentEntity(consentEntity, consent);
}
@Override
public boolean revokeConsentForClient(RealmModel realm, UserModel user, String clientInternalId) {
FederatedUserConsentEntity consentEntity = getGrantedConsentEntity(user, clientInternalId);
if (consentEntity == null) return false;
em.remove(consentEntity);
em.flush();
return true;
}
private FederatedUserConsentEntity getGrantedConsentEntity(UserModel user, String clientId) {
TypedQuery<FederatedUserConsentEntity> query = em.createNamedQuery("userFederatedConsentByUserAndClient", FederatedUserConsentEntity.class);
query.setParameter("userId", user.getId());
query.setParameter("clientId", clientId);
List<FederatedUserConsentEntity> results = query.getResultList();
if (results.size() > 1) {
throw new ModelException("More results found for user [" + user.getUsername() + "] and client [" + clientId + "]");
} else if (results.size() == 1) {
return results.get(0);
} else {
return null;
}
}
private UserConsentModel toConsentModel(RealmModel realm, FederatedUserConsentEntity entity) {
if (entity == null) {
return null;
}
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);
Collection<FederatedUserConsentRoleEntity> grantedRoleEntities = entity.getGrantedRoles();
if (grantedRoleEntities != null) {
for (FederatedUserConsentRoleEntity grantedRole : grantedRoleEntities) {
RoleModel grantedRoleModel = realm.getRoleById(grantedRole.getRoleId());
if (grantedRoleModel != null) {
model.addGrantedRole(grantedRoleModel);
}
}
}
Collection<FederatedUserConsentProtocolMapperEntity> grantedProtocolMapperEntities = entity.getGrantedProtocolMappers();
if (grantedProtocolMapperEntities != null) {
for (FederatedUserConsentProtocolMapperEntity grantedProtMapper : grantedProtocolMapperEntities) {
ProtocolMapperModel protocolMapper = client.getProtocolMapperById(grantedProtMapper.getProtocolMapperId());
model.addGrantedProtocolMapper(protocolMapper);
}
}
return model;
}
// Update roles and protocolMappers to given consentEntity from the consentModel
private void updateGrantedConsentEntity(FederatedUserConsentEntity consentEntity, UserConsentModel consentModel) {
Collection<FederatedUserConsentProtocolMapperEntity> grantedProtocolMapperEntities = consentEntity.getGrantedProtocolMappers();
Collection<FederatedUserConsentProtocolMapperEntity> mappersToRemove = new HashSet<>(grantedProtocolMapperEntities);
for (ProtocolMapperModel protocolMapper : consentModel.getGrantedProtocolMappers()) {
FederatedUserConsentProtocolMapperEntity grantedProtocolMapperEntity = new FederatedUserConsentProtocolMapperEntity();
grantedProtocolMapperEntity.setUserConsent(consentEntity);
grantedProtocolMapperEntity.setProtocolMapperId(protocolMapper.getId());
// Check if it's already there
if (!grantedProtocolMapperEntities.contains(grantedProtocolMapperEntity)) {
em.persist(grantedProtocolMapperEntity);
em.flush();
grantedProtocolMapperEntities.add(grantedProtocolMapperEntity);
} else {
mappersToRemove.remove(grantedProtocolMapperEntity);
}
}
// Those mappers were no longer on consentModel and will be removed
for (FederatedUserConsentProtocolMapperEntity toRemove : mappersToRemove) {
grantedProtocolMapperEntities.remove(toRemove);
em.remove(toRemove);
}
Collection<FederatedUserConsentRoleEntity> grantedRoleEntities = consentEntity.getGrantedRoles();
Set<FederatedUserConsentRoleEntity> rolesToRemove = new HashSet<>(grantedRoleEntities);
for (RoleModel role : consentModel.getGrantedRoles()) {
FederatedUserConsentRoleEntity consentRoleEntity = new FederatedUserConsentRoleEntity();
consentRoleEntity.setUserConsent(consentEntity);
consentRoleEntity.setRoleId(role.getId());
// Check if it's already there
if (!grantedRoleEntities.contains(consentRoleEntity)) {
em.persist(consentRoleEntity);
em.flush();
grantedRoleEntities.add(consentRoleEntity);
} else {
rolesToRemove.remove(consentRoleEntity);
}
}
// Those roles were no longer on consentModel and will be removed
for (FederatedUserConsentRoleEntity toRemove : rolesToRemove) {
grantedRoleEntities.remove(toRemove);
em.remove(toRemove);
}
em.flush();
}
@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) {
FederatedCredentials.updateCredential(session, this, realm, user, cred);
}
@Override
public void updateCredential(RealmModel realm, UserModel user, UserCredentialValueModel cred) {
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);
query.setParameter("userId", user.getId());
List<FederatedUserGroupMembershipEntity> results = query.getResultList();
if (results.size() == 0) return set;
for (FederatedUserGroupMembershipEntity entity : results) {
GroupModel group = realm.getGroupById(entity.getGroupId());
set.add(group);
}
return set;
}
@Override
public void joinGroup(RealmModel realm, UserModel user, GroupModel group) {
if (isMemberOf(realm, user, group)) return;
FederatedUserGroupMembershipEntity entity = new FederatedUserGroupMembershipEntity();
entity.setUserId(user.getId());
entity.setStorageProviderId(StorageId.resolveProviderId(user));
entity.setGroupId(group.getId());
entity.setRealmId(realm.getId());
em.persist(entity);
}
public boolean isMemberOf(RealmModel realm, UserModel user, GroupModel group) {
Set<GroupModel> roles = user.getGroups();
return KeycloakModelUtils.isMember(roles, group);
}
@Override
public void leaveGroup(RealmModel realm, UserModel user, GroupModel group) {
if (user == null || group == null) return;
TypedQuery<FederatedUserGroupMembershipEntity> query1 = em.createNamedQuery("feduserMemberOf", FederatedUserGroupMembershipEntity.class);
query1.setParameter("userId", user.getId());
query1.setParameter("groupId", group.getId());
TypedQuery<FederatedUserGroupMembershipEntity> query = query1;
List<FederatedUserGroupMembershipEntity> results = query.getResultList();
if (results.size() == 0) return;
for (FederatedUserGroupMembershipEntity entity : results) {
em.remove(entity);
}
em.flush();
}
@Override
public Set<String> getRequiredActions(RealmModel realm, UserModel user) {
Set<String> set = new HashSet<>();
List<FederatedUserRequiredActionEntity> values = getRequiredActionEntities(realm, user);
for (FederatedUserRequiredActionEntity entity : values) {
set.add(entity.getAction());
}
return set;
}
private List<FederatedUserRequiredActionEntity> getRequiredActionEntities(RealmModel realm, UserModel user) {
TypedQuery<FederatedUserRequiredActionEntity> query = em.createNamedQuery("getFederatedUserRequiredActionsByUser", FederatedUserRequiredActionEntity.class)
.setParameter("userId", user.getId())
.setParameter("realmId", realm.getId());
return query.getResultList();
}
@Override
public void addRequiredAction(RealmModel realm, UserModel user, String action) {
if (user.getRequiredActions().contains(action)) return;
FederatedUserRequiredActionEntity entity = new FederatedUserRequiredActionEntity();
entity.setUserId(user.getId());
entity.setRealmId(realm.getId());
entity.setStorageProviderId(StorageId.resolveProviderId(user));
entity.setAction(action);
em.persist(entity);
}
@Override
public void removeRequiredAction(RealmModel realm, UserModel user, String action) {
List<FederatedUserRequiredActionEntity> values = getRequiredActionEntities(realm, user);
for (FederatedUserRequiredActionEntity entity : values) {
if (action.equals(entity.getAction())) em.remove(entity);
}
em.flush();
}
@Override
public void grantRole(RealmModel realm, UserModel user, RoleModel role) {
if (user.hasRole(role)) return;
FederatedUserRoleMappingEntity entity = new FederatedUserRoleMappingEntity();
entity.setUserId(user.getId());
entity.setStorageProviderId(StorageId.resolveProviderId(user));
entity.setRealmId(realm.getId());
entity.setRoleId(role.getId());
em.persist(entity);
}
@Override
public Set<RoleModel> getRoleMappings(RealmModel realm, UserModel user) {
Set<RoleModel> set = new HashSet<>();
TypedQuery<FederatedUserRoleMappingEntity> query = em.createNamedQuery("feduserRoleMappings", FederatedUserRoleMappingEntity.class);
query.setParameter("userId", user.getId());
List<FederatedUserRoleMappingEntity> results = query.getResultList();
if (results.size() == 0) return set;
for (FederatedUserRoleMappingEntity entity : results) {
RoleModel role = realm.getRoleById(entity.getRoleId());
set.add(role);
}
return set;
}
@Override
public void deleteRoleMapping(RealmModel realm, UserModel user, RoleModel role) {
TypedQuery<FederatedUserRoleMappingEntity> query = em.createNamedQuery("feduserRoleMappings", FederatedUserRoleMappingEntity.class);
query.setParameter("userId", user.getId());
List<FederatedUserRoleMappingEntity> results = query.getResultList();
for (FederatedUserRoleMappingEntity entity : results) {
if (entity.getRoleId().equals(role.getId())) em.remove(entity);
}
em.flush();
}
@Override
public void preRemove(RealmModel realm) {
int num = em.createNamedQuery("deleteUserConsentRolesByRealm")
.setParameter("realmId", realm.getId()).executeUpdate();
num = em.createNamedQuery("deleteFederatedUserConsentProtMappersByRealm")
.setParameter("realmId", realm.getId()).executeUpdate();
num = em.createNamedQuery("deleteFederatedUserConsentsByRealm")
.setParameter("realmId", realm.getId()).executeUpdate();
num = em.createNamedQuery("deleteFederatedUserRoleMappingsByRealm")
.setParameter("realmId", realm.getId()).executeUpdate();
num = em.createNamedQuery("deleteFederatedUserRequiredActionsByRealm")
.setParameter("realmId", realm.getId()).executeUpdate();
num = em.createNamedQuery("deleteBrokerLinkByRealm")
.setParameter("realmId", realm.getId()).executeUpdate();
num = em.createNamedQuery("deleteFederatedUserCredentialsByRealm")
.setParameter("realmId", realm.getId()).executeUpdate();
num = em.createNamedQuery("deleteUserFederatedAttributesByRealm")
.setParameter("realmId", realm.getId()).executeUpdate();
num = em.createNamedQuery("deleteFederatedUserGroupMembershipByRealm")
.setParameter("realmId", realm.getId()).executeUpdate();
}
@Override
public void preRemove(RealmModel realm, UserFederationProviderModel link) {
int num = em.createNamedQuery("deleteFederatedUserRoleMappingsByRealmAndLink")
.setParameter("realmId", realm.getId())
.setParameter("link", link.getId())
.executeUpdate();
num = em.createNamedQuery("deleteFederatedUserRequiredActionsByRealmAndLink")
.setParameter("realmId", realm.getId())
.setParameter("link", link.getId())
.executeUpdate();
num = em.createNamedQuery("deleteBrokerLinkByRealmAndLink")
.setParameter("realmId", realm.getId())
.setParameter("link", link.getId())
.executeUpdate();
num = em.createNamedQuery("deleteFederatedUserCredentialsByRealmAndLink")
.setParameter("realmId", realm.getId())
.setParameter("link", link.getId())
.executeUpdate();
num = em.createNamedQuery("deleteUserFederatedAttributesByRealmAndLink")
.setParameter("realmId", realm.getId())
.setParameter("link", link.getId())
.executeUpdate();
}
@Override
public void preRemove(RealmModel realm, RoleModel role) {
em.createNamedQuery("deleteFederatedUserRoleMappingsByRole").setParameter("roleId", role.getId()).executeUpdate();
em.createNamedQuery("deleteFederatedUserRoleMappingsByRole").setParameter("roleId", role.getId()).executeUpdate();
}
@Override
public void preRemove(RealmModel realm, GroupModel group) {
em.createNamedQuery("deleteFederatedUserGroupMembershipsByGroup").setParameter("groupId", group.getId()).executeUpdate();
}
@Override
public void preRemove(RealmModel realm, ClientModel client) {
em.createNamedQuery("deleteFederatedUserConsentProtMappersByClient").setParameter("clientId", client.getId()).executeUpdate();
em.createNamedQuery("deleteFederatedUserConsentRolesByClient").setParameter("clientId", client.getId()).executeUpdate();
em.createNamedQuery("deleteFederatedUserConsentsByClient").setParameter("clientId", client.getId()).executeUpdate();
}
@Override
public void preRemove(ProtocolMapperModel protocolMapper) {
em.createNamedQuery("deleteFederatedUserConsentProtMappersByProtocolMapper")
.setParameter("protocolMapperId", protocolMapper.getId())
.executeUpdate();
}
@Override
public void preRemove(RealmModel realm, UserModel user) {
em.createNamedQuery("deleteBrokerLinkByUser")
.setParameter("userId", user.getId())
.setParameter("realmId", realm.getId())
.executeUpdate();
em.createNamedQuery("deleteUserFederatedAttributesByUser")
.setParameter("userId", user.getId())
.setParameter("realmId", realm.getId())
.executeUpdate();
em.createNamedQuery("deleteFederatedUserConsentProtMappersByUser")
.setParameter("userId", user.getId())
.setParameter("realmId", realm.getId())
.executeUpdate();
em.createNamedQuery("deleteFederatedUserConsentRolesByUser")
.setParameter("userId", user.getId())
.setParameter("realmId", realm.getId())
.executeUpdate();
em.createNamedQuery("deleteFederatedUserConsentsByUser")
.setParameter("userId", user.getId())
.setParameter("realmId", realm.getId())
.executeUpdate();
em.createNamedQuery("deleteFederatedUserCredentialByUser")
.setParameter("userId", user.getId())
.setParameter("realmId", realm.getId())
.executeUpdate();
em.createNamedQuery("deleteFederatedUserGroupMembershipsByUser")
.setParameter("userId", user.getId())
.setParameter("realmId", realm.getId())
.executeUpdate();
em.createNamedQuery("getFederatedUserRequiredActionsByUser")
.setParameter("userId", user.getId())
.setParameter("realmId", realm.getId())
.executeUpdate();
em.createNamedQuery("deleteFederatedUserRoleMappingsByUser")
.setParameter("userId", user.getId())
.setParameter("realmId", realm.getId())
.executeUpdate();
}
@Override
public void preRemove(RealmModel realm, StorageProviderModel model) {
em.createNamedQuery("deleteBrokerLinkByStorageProvider")
.setParameter("storageProviderId", model.getId())
.executeUpdate();
em.createNamedQuery("deleteFederatedAttributesByStorageProvider")
.setParameter("storageProviderId", model.getId())
.executeUpdate();
em.createNamedQuery("deleteFederatedUserConsentProtMappersByStorageProvider")
.setParameter("storageProviderId", model.getId())
.executeUpdate();
em.createNamedQuery("deleteFederatedUserRoleMappingsByStorageProvider")
.setParameter("storageProviderId", model.getId())
.executeUpdate();
em.createNamedQuery("deleteFederatedUserConsentsByStorageProvider")
.setParameter("storageProviderId", model.getId())
.executeUpdate();
em.createNamedQuery("deleteFederatedUserCredentialsByStorageProvider")
.setParameter("storageProviderId", model.getId())
.executeUpdate();
em.createNamedQuery("deleteFederatedUserGroupMembershipByStorageProvider")
.setParameter("storageProviderId", model.getId())
.executeUpdate();
em.createNamedQuery("deleteFederatedUserRequiredActionsByStorageProvider")
.setParameter("storageProviderId", model.getId())
.executeUpdate();
em.createNamedQuery("deleteFederatedUserRoleMappingsByStorageProvider")
.setParameter("storageProviderId", model.getId())
.executeUpdate();
}
}

View file

@ -0,0 +1,58 @@
/*
* 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.jpa;
import org.keycloak.Config;
import org.keycloak.connections.jpa.JpaConnectionProvider;
import org.keycloak.models.KeycloakSession;
import org.keycloak.models.KeycloakSessionFactory;
import org.keycloak.storage.federated.UserFederatedStorageProvider;
import org.keycloak.storage.federated.UserFederatedStorageProviderFactory;
import javax.persistence.EntityManager;
/**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $
*/
public class JpaUserFederatedStorageProviderFactory implements UserFederatedStorageProviderFactory {
@Override
public UserFederatedStorageProvider create(KeycloakSession session) {
EntityManager em = session.getProvider(JpaConnectionProvider.class).getEntityManager();
return new JpaUserFederatedStorageProvider(session, em);
}
@Override
public void init(Config.Scope config) {
}
@Override
public void postInit(KeycloakSessionFactory factory) {
}
@Override
public void close() {
}
@Override
public String getId() {
return "jpa";
}
}

View file

@ -0,0 +1,191 @@
/*
* 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.jpa.entity;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.IdClass;
import javax.persistence.NamedQueries;
import javax.persistence.NamedQuery;
import javax.persistence.Table;
import java.io.Serializable;
/**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $
*/
@NamedQueries({
@NamedQuery(name= "findBrokerLinkByUser", query="select link from BrokerLinkEntity link where link.userId = :userId"),
@NamedQuery(name= "findBrokerLinkByUserAndProvider", query="select link from BrokerLinkEntity link where link.userId = :userId and link.identityProvider = :identityProvider"),
@NamedQuery(name= "findUserByBrokerLinkAndRealm", query="select link.userId from BrokerLinkEntity link where link.realmId = :realmId and link.identityProvider = :identityProvider and link.brokerUserId = :brokerUserId"),
@NamedQuery(name= "deleteBrokerLinkByStorageProvider", query="delete from BrokerLinkEntity social where social.storageProviderId = :storageProviderId"),
@NamedQuery(name= "deleteBrokerLinkByRealm", query="delete from BrokerLinkEntity social where social.realmId = :realmId"),
@NamedQuery(name= "deleteBrokerLinkByRealmAndLink", query="delete from BrokerLinkEntity social where social.userId IN (select u.id from UserEntity u where realmId=:realmId and u.federationLink=:link)"),
@NamedQuery(name= "deleteBrokerLinkByUser", query="delete from BrokerLinkEntity social where social.userId = :userId and social.realmId = :realmId")
})
@Table(name="BROKER_LINK")
@Entity
@IdClass(BrokerLinkEntity.Key.class)
public class BrokerLinkEntity {
@Id
private String userId;
@Id
@Column(name = "IDENTITY_PROVIDER")
protected String identityProvider;
@Column(name = "REALM_ID")
protected String realmId;
@Column(name = "STORAGE_PROVIDER_ID")
protected String storageProviderId;
@Column(name = "BROKER_USER_ID")
protected String brokerUserId;
@Column(name = "BROKER_USERNAME")
protected String brokerUserName;
@Column(name = "TOKEN")
protected String token;
public String getUserId() {
return userId;
}
public void setUserId(String userId) {
this.userId = userId;
}
public String getIdentityProvider() {
return identityProvider;
}
public void setIdentityProvider(String identityProvider) {
this.identityProvider = identityProvider;
}
public String getBrokerUserId() {
return brokerUserId;
}
public void setBrokerUserId(String brokerUserId) {
this.brokerUserId = brokerUserId;
}
public String getBrokerUserName() {
return brokerUserName;
}
public void setBrokerUserName(String brokerUserName) {
this.brokerUserName = brokerUserName;
}
public String getStorageProviderId() {
return storageProviderId;
}
public void setStorageProviderId(String storageProviderId) {
this.storageProviderId = storageProviderId;
}
public String getRealmId() {
return realmId;
}
public void setRealmId(String realmId) {
this.realmId = realmId;
}
public void setToken(String token) {
this.token = token;
}
public String getToken() {
return token;
}
public static class Key implements Serializable {
protected String userId;
protected String identityProvider;
public Key() {
}
public Key(String userId, String identityProvider) {
this.userId = userId;
this.identityProvider = identityProvider;
}
public String getUserId() {
return userId;
}
public String getIdentityProvider() {
return identityProvider;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Key key = (Key) o;
if (identityProvider != null ? !identityProvider.equals(key.identityProvider) : key.identityProvider != null)
return false;
if (userId != null ? !userId.equals(key.userId != null ? key.userId : null) : key.userId != null) return false;
return true;
}
@Override
public int hashCode() {
int result = userId != null ? userId.hashCode() : 0;
result = 31 * result + (identityProvider != null ? identityProvider.hashCode() : 0);
return result;
}
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null) return false;
if (!(o instanceof BrokerLinkEntity)) return false;
BrokerLinkEntity key = (BrokerLinkEntity) o;
if (identityProvider != null ? !identityProvider.equals(key.identityProvider) : key.identityProvider != null)
return false;
if (userId != null ? !userId.equals(key.userId != null ? key.userId : null) : key.userId != null) return false;
return true;
}
@Override
public int hashCode() {
int result = userId != null ? userId.hashCode() : 0;
result = 31 * result + (identityProvider != null ? identityProvider.hashCode() : 0);
return result;
}
}

View file

@ -0,0 +1,133 @@
/*
* 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.jpa.entity;
import javax.persistence.Access;
import javax.persistence.AccessType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.NamedQueries;
import javax.persistence.NamedQuery;
import javax.persistence.Table;
/**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $
*/
@NamedQueries({
@NamedQuery(name="getFederatedAttributesByNameAndValue", query="select attr from FederatedUserAttributeEntity attr where attr.name = :name and attr.value = :value and attr.realmId=:realmId"),
@NamedQuery(name="getFederatedAttributesByUser", query="select attr from FederatedUserAttributeEntity attr where attr.userId = :userId and attr.realmId=:realmId"),
@NamedQuery(name="deleteUserFederatedAttributesByUser", query="delete from FederatedUserAttributeEntity attr where attr.userId = :userId and attr.realmId=:realmId"),
@NamedQuery(name="deleteUserFederatedAttributesByUserAndName", query="delete from FederatedUserAttributeEntity attr where attr.userId = :userId and attr.name=:name and attr.realmId=:realmId"),
@NamedQuery(name="deleteUserFederatedAttributesByRealm", query="delete from FederatedUserAttributeEntity attr where attr.realmId=:realmId"),
@NamedQuery(name="deleteFederatedAttributesByStorageProvider", query="delete from FederatedUserAttributeEntity e where e.storageProviderId=:storageProviderId"),
@NamedQuery(name="deleteUserFederatedAttributesByRealmAndLink", query="delete from FederatedUserAttributeEntity attr where attr.userId IN (select u.id from UserEntity u where u.realmId=:realmId and u.federationLink=:link)")
})
@Table(name="FED_USER_ATTRIBUTE")
@Entity
public class FederatedUserAttributeEntity {
@Id
@Column(name="ID", length = 36)
@Access(AccessType.PROPERTY) // we do this because relationships often fetch id, but not entity. This avoids an extra SQL
protected String id;
@Column(name = "USER_ID")
protected String userId;
@Column(name = "REALM_ID")
protected String realmId;
@Column(name = "STORAGE_PROVIDER_ID")
protected String storageProviderId;
@Column(name = "NAME")
protected String name;
@Column(name = "VALUE")
protected String value;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getValue() {
return value;
}
public void setValue(String value) {
this.value = value;
}
public String getUserId() {
return userId;
}
public void setUserId(String userId) {
this.userId = userId;
}
public String getRealmId() {
return realmId;
}
public void setRealmId(String realmId) {
this.realmId = realmId;
}
public String getStorageProviderId() {
return storageProviderId;
}
public void setStorageProviderId(String storageProviderId) {
this.storageProviderId = storageProviderId;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null) return false;
if (!(o instanceof FederatedUserAttributeEntity)) return false;
FederatedUserAttributeEntity that = (FederatedUserAttributeEntity) o;
if (!id.equals(that.getId())) return false;
return true;
}
@Override
public int hashCode() {
return id.hashCode();
}
}

View file

@ -0,0 +1,148 @@
/*
* 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.jpa.entity;
import javax.persistence.Access;
import javax.persistence.AccessType;
import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.NamedQueries;
import javax.persistence.NamedQuery;
import javax.persistence.OneToMany;
import javax.persistence.Table;
import javax.persistence.UniqueConstraint;
import java.util.ArrayList;
import java.util.Collection;
/**
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
*/
@Entity
@Table(name="FED_USER_CONSENT", uniqueConstraints = {
@UniqueConstraint(columnNames = {"USER_ID", "CLIENT_ID"})
})
@NamedQueries({
@NamedQuery(name="userFederatedConsentByUserAndClient", query="select consent from UserConsentEntity consent where consent.userId = :userId and consent.clientId = :clientId"),
@NamedQuery(name="userFederatedConsentsByUser", query="select consent from UserConsentEntity consent where consent.userId = :userId"),
@NamedQuery(name="deleteFederatedUserConsentsByRealm", query="delete from UserConsentEntity consent where consent.realmId=:realmId"),
@NamedQuery(name="deleteFederatedUserConsentsByStorageProvider", query="delete from FederatedUserConsentEntity e where e.storageProviderId=:storageProviderId"),
@NamedQuery(name="deleteFederatedUserConsentsByUser", query="delete from UserConsentEntity consent where consent.userId = :userId and consent.realmId = :realmId"),
@NamedQuery(name="deleteFederatedUserConsentsByClient", query="delete from UserConsentEntity consent where consent.clientId = :clientId"),
})
public class FederatedUserConsentEntity {
@Id
@Column(name="ID", length = 36)
@Access(AccessType.PROPERTY) // we do this because relationships often fetch id, but not entity. This avoids an extra SQL
protected String id;
@Column(name = "USER_ID")
protected String userId;
@Column(name = "REALM_ID")
protected String realmId;
@Column(name = "STORAGE_PROVIDER_ID")
protected String storageProviderId;
@Column(name="CLIENT_ID")
protected String clientId;
@OneToMany(cascade ={CascadeType.REMOVE}, orphanRemoval = true, mappedBy = "userConsent")
Collection<FederatedUserConsentRoleEntity> grantedRoles = new ArrayList<FederatedUserConsentRoleEntity>();
@OneToMany(cascade ={CascadeType.REMOVE}, orphanRemoval = true, mappedBy = "userConsent")
Collection<FederatedUserConsentProtocolMapperEntity> grantedProtocolMappers = new ArrayList<FederatedUserConsentProtocolMapperEntity>();
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getUserId() {
return userId;
}
public void setUserId(String userId) {
this.userId = userId;
}
public String getRealmId() {
return realmId;
}
public void setRealmId(String realmId) {
this.realmId = realmId;
}
public String getStorageProviderId() {
return storageProviderId;
}
public void setStorageProviderId(String storageProviderId) {
this.storageProviderId = storageProviderId;
}
public String getClientId() {
return clientId;
}
public void setClientId(String clientId) {
this.clientId = clientId;
}
public Collection<FederatedUserConsentRoleEntity> getGrantedRoles() {
return grantedRoles;
}
public void setGrantedRoles(Collection<FederatedUserConsentRoleEntity> grantedRoles) {
this.grantedRoles = grantedRoles;
}
public Collection<FederatedUserConsentProtocolMapperEntity> getGrantedProtocolMappers() {
return grantedProtocolMappers;
}
public void setGrantedProtocolMappers(Collection<FederatedUserConsentProtocolMapperEntity> grantedProtocolMappers) {
this.grantedProtocolMappers = grantedProtocolMappers;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null) return false;
if (!(o instanceof FederatedUserConsentEntity)) return false;
FederatedUserConsentEntity that = (FederatedUserConsentEntity) o;
if (!id.equals(that.getId())) return false;
return true;
}
@Override
public int hashCode() {
return id.hashCode();
}
}

View file

@ -0,0 +1,135 @@
/*
* 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.jpa.entity;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.Id;
import javax.persistence.IdClass;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.NamedQueries;
import javax.persistence.NamedQuery;
import javax.persistence.Table;
import java.io.Serializable;
/**
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
*/
@NamedQueries({
@NamedQuery(name="deleteFederatedUserConsentProtMappersByRealm", query=
"delete from FederatedUserConsentProtocolMapperEntity csm where csm.userConsent IN (select consent from FederatedUserConsentEntity consent where consent.realmId = :realmId)"),
@NamedQuery(name="deleteFederatedUserConsentProtMappersByUser", query="delete from FederatedUserConsentProtocolMapperEntity csm where csm.userConsent IN (select consent from FederatedUserConsentEntity consent where consent.userId = :userId and consent.realmId = :realmId)"),
@NamedQuery(name="deleteFederatedUserConsentProtMappersByStorageProvider", query="delete from FederatedUserConsentProtocolMapperEntity csm where csm.userConsent IN (select consent from FederatedUserConsentEntity consent where consent.storageProviderId = :storageProviderId)"),
@NamedQuery(name="deleteFederatedUserConsentProtMappersByProtocolMapper", query="delete from FederatedUserConsentProtocolMapperEntity csm where csm.protocolMapperId = :protocolMapperId"),
@NamedQuery(name="deleteFederatedUserConsentProtMappersByClient", query="delete from FederatedUserConsentProtocolMapperEntity csm where csm.userConsent IN (select consent from FederatedUserConsentEntity consent where consent.clientId = :clientId)"),
})
@Entity
@Table(name="FED_USER_CONSENT_PROT_MAPPER")
@IdClass(FederatedUserConsentProtocolMapperEntity.Key.class)
public class FederatedUserConsentProtocolMapperEntity {
@Id
@ManyToOne(fetch= FetchType.LAZY)
@JoinColumn(name = "USER_CONSENT_ID")
protected FederatedUserConsentEntity userConsent;
@Id
@Column(name="PROTOCOL_MAPPER_ID")
protected String protocolMapperId;
public FederatedUserConsentEntity getUserConsent() {
return userConsent;
}
public void setUserConsent(FederatedUserConsentEntity userConsent) {
this.userConsent = userConsent;
}
public String getProtocolMapperId() {
return protocolMapperId;
}
public void setProtocolMapperId(String protocolMapperId) {
this.protocolMapperId = protocolMapperId;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null) return false;
if (!(o instanceof FederatedUserConsentProtocolMapperEntity)) return false;
FederatedUserConsentProtocolMapperEntity that = (FederatedUserConsentProtocolMapperEntity)o;
Key myKey = new Key(this.userConsent, this.protocolMapperId);
Key hisKey = new Key(that.userConsent, that.protocolMapperId);
return myKey.equals(hisKey);
}
@Override
public int hashCode() {
Key myKey = new Key(this.userConsent, this.protocolMapperId);
return myKey.hashCode();
}
public static class Key implements Serializable {
protected FederatedUserConsentEntity userConsent;
protected String protocolMapperId;
public Key() {
}
public Key(FederatedUserConsentEntity userConsent, String protocolMapperId) {
this.userConsent = userConsent;
this.protocolMapperId = protocolMapperId;
}
public FederatedUserConsentEntity getUserConsent() {
return userConsent;
}
public String getProtocolMapperId() {
return protocolMapperId;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Key key = (Key) o;
if (userConsent != null ? !userConsent.getId().equals(key.userConsent != null ? key.userConsent.getId() : null) : key.userConsent != null) return false;
if (protocolMapperId != null ? !protocolMapperId.equals(key.protocolMapperId) : key.protocolMapperId != null) return false;
return true;
}
@Override
public int hashCode() {
int result = userConsent != null ? userConsent.getId().hashCode() : 0;
result = 31 * result + (protocolMapperId != null ? protocolMapperId.hashCode() : 0);
return result;
}
}
}

View file

@ -0,0 +1,133 @@
/*
* 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.jpa.entity;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.Id;
import javax.persistence.IdClass;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.NamedQueries;
import javax.persistence.NamedQuery;
import javax.persistence.Table;
import java.io.Serializable;
/**
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
*/
@NamedQueries({
@NamedQuery(name="deleteFederatedUserConsentRolesByRealm", query="delete from FederatedUserConsentRoleEntity grantedRole where grantedRole.userConsent IN (select consent from FederatedUserConsentEntity consent where consent.realmId = :realmId)"),
@NamedQuery(name="deleteFederatedUserConsentRolesByUser", query="delete from FederatedUserConsentRoleEntity grantedRole where grantedRole.userConsent IN (select consent from FederatedUserConsentEntity consent where consent.userId = :userId and consent.realmId = :realmId)"),
@NamedQuery(name="deleteFederatedUserConsentRolesByStorageProvider", query="delete from FederatedUserConsentRoleEntity grantedRole where grantedRole.userConsent IN (select consent from FederatedUserConsentEntity consent where consent.storageProviderId = :storageProviderId)"),
@NamedQuery(name="deleteFederatedUserConsentRolesByRole", query="delete from FederatedUserConsentRoleEntity grantedRole where grantedRole.roleId = :roleId"),
@NamedQuery(name="deleteFederatedUserConsentRolesByClient", query="delete from FederatedUserConsentRoleEntity grantedRole where grantedRole.userConsent IN (select consent from FederatedUserConsentEntity consent where consent.clientId = :clientId)"),
})
@Entity
@Table(name="FED_USER_CONSENT_ROLE")
@IdClass(FederatedUserConsentRoleEntity.Key.class)
public class FederatedUserConsentRoleEntity {
@Id
@ManyToOne(fetch= FetchType.LAZY)
@JoinColumn(name = "USER_CONSENT_ID")
protected FederatedUserConsentEntity userConsent;
@Id
@Column(name="ROLE_ID")
protected String roleId;
public FederatedUserConsentEntity getUserConsent() {
return userConsent;
}
public void setUserConsent(FederatedUserConsentEntity userConsent) {
this.userConsent = userConsent;
}
public String getRoleId() {
return roleId;
}
public void setRoleId(String roleId) {
this.roleId = roleId;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null) return false;
if (!(o instanceof FederatedUserConsentRoleEntity)) return false;
FederatedUserConsentRoleEntity that = (FederatedUserConsentRoleEntity)o;
Key myKey = new Key(this.userConsent, this.roleId);
Key hisKey = new Key(that.userConsent, that.roleId);
return myKey.equals(hisKey);
}
@Override
public int hashCode() {
Key myKey = new Key(this.userConsent, this.roleId);
return myKey.hashCode();
}
public static class Key implements Serializable {
protected FederatedUserConsentEntity userConsent;
protected String roleId;
public Key() {
}
public Key(FederatedUserConsentEntity userConsent, String roleId) {
this.userConsent = userConsent;
this.roleId = roleId;
}
public FederatedUserConsentEntity getUserConsent() {
return userConsent;
}
public String getRoleId() {
return roleId;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Key key = (Key) o;
if (userConsent != null ? !userConsent.getId().equals(key.userConsent != null ? key.userConsent.getId() : null) : key.userConsent != null) return false;
if (roleId != null ? !roleId.equals(key.roleId) : key.roleId != null) return false;
return true;
}
@Override
public int hashCode() {
int result = userConsent != null ? userConsent.getId().hashCode() : 0;
result = 31 * result + (roleId != null ? roleId.hashCode() : 0);
return result;
}
}
}

View file

@ -0,0 +1,222 @@
/*
* 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.jpa.entity;
import org.keycloak.models.jpa.entities.UserEntity;
import javax.persistence.Access;
import javax.persistence.AccessType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.NamedQueries;
import javax.persistence.NamedQuery;
import javax.persistence.Table;
/**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $
*/
@NamedQueries({
@NamedQuery(name="federatedUserCredentialByUser", query="select cred from FederatedUserCredentialEntity cred where cred.userId = :userId"),
@NamedQuery(name="federatedUserCredentialByUserAndType", query="select cred from FederatedUserCredentialEntity cred where cred.userId = :userId and cred.type = :type"),
@NamedQuery(name="deleteFederatedUserCredentialByUser", query="delete from FederatedUserCredentialEntity cred where cred.userId = :userId and cred.realmId = :realmId"),
@NamedQuery(name="deleteFederatedUserCredentialByUserAndType", query="delete from FederatedUserCredentialEntity cred where cred.userId = :userId and cred.type = :type"),
@NamedQuery(name="deleteFederatedUserCredentialByUserAndTypeAndDevice", query="delete from FederatedUserCredentialEntity cred where cred.userId = :userId and cred.type = :type and cred.device = :device"),
@NamedQuery(name="deleteFederatedUserCredentialsByRealm", query="delete from FederatedUserCredentialEntity cred where cred.realmId=:realmId"),
@NamedQuery(name="deleteFederatedUserCredentialsByStorageProvider", query="delete from FederatedUserCredentialEntity cred where cred.storageProviderId=:storageProviderId"),
@NamedQuery(name="deleteFederatedUserCredentialsByRealmAndLink", query="delete from FederatedUserCredentialEntity cred where cred.userId IN (select u.id from UserEntity u where u.realmId=:realmId and u.federationLink=:link)")
})
@Table(name="FED_USER_CREDENTIAL")
@Entity
public class FederatedUserCredentialEntity {
@Id
@Column(name="ID", length = 36)
@Access(AccessType.PROPERTY) // we do this because relationships often fetch id, but not entity. This avoids an extra SQL
protected String id;
@Column(name="TYPE")
protected String type;
@Column(name="VALUE")
protected String value;
@Column(name="DEVICE")
protected String device;
@Column(name="SALT")
protected byte[] salt;
@Column(name="HASH_ITERATIONS")
protected int hashIterations;
@Column(name="CREATED_DATE")
protected Long createdDate;
@Column(name="USER_ID")
protected String userId;
@Column(name = "REALM_ID")
protected String realmId;
@Column(name = "STORAGE_PROVIDER_ID")
protected String storageProviderId;
@Column(name="COUNTER")
protected int counter;
@Column(name="ALGORITHM")
protected String algorithm;
@Column(name="DIGITS")
protected int digits;
@Column(name="PERIOD")
protected int period;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getValue() {
return value;
}
public void setValue(String value) {
this.value = value;
}
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
public String getDevice() {
return device;
}
public void setDevice(String device) {
this.device = device;
}
public String getUserId() {
return userId;
}
public void setUserId(String userId) {
this.userId = userId;
}
public String getRealmId() {
return realmId;
}
public void setRealmId(String realmId) {
this.realmId = realmId;
}
public String getStorageProviderId() {
return storageProviderId;
}
public void setStorageProviderId(String storageProviderId) {
this.storageProviderId = storageProviderId;
}
public byte[] getSalt() {
return salt;
}
public void setSalt(byte[] salt) {
this.salt = salt;
}
public int getHashIterations() {
return hashIterations;
}
public void setHashIterations(int hashIterations) {
this.hashIterations = hashIterations;
}
public Long getCreatedDate() {
return createdDate;
}
public void setCreatedDate(Long createdDate) {
this.createdDate = createdDate;
}
public int getCounter() {
return counter;
}
public void setCounter(int counter) {
this.counter = counter;
}
public String getAlgorithm() {
return algorithm;
}
public void setAlgorithm(String algorithm) {
this.algorithm = algorithm;
}
public int getDigits() {
return digits;
}
public void setDigits(int digits) {
this.digits = digits;
}
public int getPeriod() {
return period;
}
public void setPeriod(int period) {
this.period = period;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null) return false;
if (!(o instanceof FederatedUserCredentialEntity)) return false;
FederatedUserCredentialEntity that = (FederatedUserCredentialEntity) o;
if (!id.equals(that.getId())) return false;
return true;
}
@Override
public int hashCode() {
return id.hashCode();
}
}

View file

@ -0,0 +1,161 @@
/*
* 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.jpa.entity;
import org.keycloak.models.jpa.entities.UserEntity;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.IdClass;
import javax.persistence.NamedQueries;
import javax.persistence.NamedQuery;
import javax.persistence.Table;
import java.io.Serializable;
/**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $
*/
@NamedQueries({
@NamedQuery(name="feduserMemberOf", query="select m from FederatedUserGroupMembershipEntity m where m.userId = :userId and m.groupId = :groupId"),
@NamedQuery(name="feduserGroupMembership", query="select m from FederatedUserGroupMembershipEntity m where m.userId = :userId"),
@NamedQuery(name="fedgroupMembership", query="select g.user from FederatedUserGroupMembershipEntity g where g.groupId = :groupId"),
@NamedQuery(name="feduserGroupIds", query="select m.groupId from FederatedUserGroupMembershipEntity m where m.userId = :userId"),
@NamedQuery(name="deleteFederatedUserGroupMembershipByRealm", query="delete from FederatedUserGroupMembershipEntity mapping where mapping.realmId=:realmId"),
@NamedQuery(name="deleteFederatedUserGroupMembershipByStorageProvider", query="delete from FederatedUserGroupMembershipEntity e where e.storageProviderId=:storageProviderId"),
@NamedQuery(name="deleteFederatedUserGroupMembershipsByRealmAndLink", query="delete from FederatedUserGroupMembershipEntity mapping where mapping.userId IN (select u.id from UserEntity u where u.realmId=:realmId and u.federationLink=:link)"),
@NamedQuery(name="deleteFederatedUserGroupMembershipsByGroup", query="delete from FederatedUserGroupMembershipEntity m where m.groupId = :groupId"),
@NamedQuery(name="deleteFederatedUserGroupMembershipsByUser", query="delete from FederatedUserGroupMembershipEntity m where m.userId = :userId and m.realmId = :realmId")
})
@Table(name="FED_USER_GROUP_MEMBERSHIP")
@Entity
@IdClass(FederatedUserGroupMembershipEntity.Key.class)
public class FederatedUserGroupMembershipEntity {
@Id
protected String userId;
@Id
@Column(name = "GROUP_ID")
protected String groupId;
@Column(name = "REALM_ID")
protected String realmId;
@Column(name = "STORAGE_PROVIDER_ID")
protected String storageProviderId;
public String getGroupId() {
return groupId;
}
public void setGroupId(String groupId) {
this.groupId = groupId;
}
public String getUserId() {
return userId;
}
public void setUserId(String userId) {
this.userId = userId;
}
public String getRealmId() {
return realmId;
}
public void setRealmId(String realmId) {
this.realmId = realmId;
}
public String getStorageProviderId() {
return storageProviderId;
}
public void setStorageProviderId(String storageProviderId) {
this.storageProviderId = storageProviderId;
}
public static class Key implements Serializable {
protected String userId;
protected String groupId;
public Key() {
}
public Key(String userId, String groupId) {
this.userId = userId;
this.groupId = groupId;
}
public String getUserId() {
return userId;
}
public String getGroupId() {
return groupId;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Key key = (Key) o;
if (!groupId.equals(key.groupId)) return false;
if (!userId.equals(key.userId)) return false;
return true;
}
@Override
public int hashCode() {
int result = userId.hashCode();
result = 31 * result + groupId.hashCode();
return result;
}
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null) return false;
if (!(o instanceof FederatedUserGroupMembershipEntity)) return false;
FederatedUserGroupMembershipEntity key = (FederatedUserGroupMembershipEntity) o;
if (!groupId.equals(key.groupId)) return false;
if (!userId.equals(key.userId)) return false;
return true;
}
@Override
public int hashCode() {
int result = userId.hashCode();
result = 31 * result + groupId.hashCode();
return result;
}
}

View file

@ -0,0 +1,160 @@
/*
* 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.jpa.entity;
import org.keycloak.models.jpa.entities.UserEntity;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.Id;
import javax.persistence.IdClass;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.NamedQueries;
import javax.persistence.NamedQuery;
import javax.persistence.Table;
import java.io.Serializable;
/**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $
*/
@NamedQueries({
@NamedQuery(name="getFederatedUserRequiredActionsByUser", query="select action from FederatedUserRequiredActionEntity action where action.userId = :userId and attr.realmId=:realmId"),
@NamedQuery(name="deleteFederatedUserRequiredActionsByRealm", query="delete from FederatedUserRequiredActionEntity action where action.realmId=:realmId"),
@NamedQuery(name="deleteFederatedUserRequiredActionsByStorageProvider", query="delete from FederatedUserRequiredActionEntity e where e.storageProviderId=:storageProviderId"),
@NamedQuery(name="deleteFederatedUserRequiredActionsByRealmAndLink", query="delete from FederatedUserRequiredActionEntity action where action.userId IN (select u.id from UserEntity u where u.realmId=:realmId and u.federationLink=:link)")
})
@Entity
@Table(name="FED_USER_REQUIRED_ACTION")
@IdClass(FederatedUserRequiredActionEntity.Key.class)
public class FederatedUserRequiredActionEntity {
@Id
@Column(name="USER_ID")
protected String userId;
@Id
@Column(name="REQUIRED_ACTION")
protected String action;
@Column(name = "REALM_ID")
protected String realmId;
@Column(name = "STORAGE_PROVIDER_ID")
protected String storageProviderId;
public String getAction() {
return action;
}
public void setAction(String action) {
this.action = action;
}
public String getUserId() {
return userId;
}
public void setUserId(String userId) {
this.userId = userId;
}
public String getRealmId() {
return realmId;
}
public void setRealmId(String realmId) {
this.realmId = realmId;
}
public String getStorageProviderId() {
return storageProviderId;
}
public void setStorageProviderId(String storageProviderId) {
this.storageProviderId = storageProviderId;
}
public static class Key implements Serializable {
protected String userId;
protected String action;
public Key() {
}
public Key(String user, String action) {
this.userId = user;
this.action = action;
}
public String getUserId() {
return userId;
}
public String getAction() {
return action;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Key key = (Key) o;
if (action != key.action) return false;
if (userId != null ? !userId.equals(key.userId != null ? key.userId : null) : key.userId != null) return false;
return true;
}
@Override
public int hashCode() {
int result = userId != null ? userId.hashCode() : 0;
result = 31 * result + (action != null ? action.hashCode() : 0);
return result;
}
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null) return false;
if (!(o instanceof FederatedUserRequiredActionEntity)) return false;
FederatedUserRequiredActionEntity key = (FederatedUserRequiredActionEntity) o;
if (action != key.action) return false;
if (userId != null ? !userId.equals(key.userId != null ? key.userId : null) : key.userId != null) return false;
return true;
}
@Override
public int hashCode() {
int result = userId != null ? userId.hashCode() : 0;
result = 31 * result + (action != null ? action.hashCode() : 0);
return result;
}
}

View file

@ -0,0 +1,160 @@
/*
* 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.jpa.entity;
import org.keycloak.models.jpa.entities.UserEntity;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.IdClass;
import javax.persistence.NamedQueries;
import javax.persistence.NamedQuery;
import javax.persistence.Table;
import java.io.Serializable;
/**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $
*/
@NamedQueries({
@NamedQuery(name="feduserHasRole", query="select m from FederatedUserRoleMappingEntity m where m.userId = :userId and m.roleId = :roleId"),
@NamedQuery(name="feduserRoleMappings", query="select m from FederatedUserRoleMappingEntity m where m.userId = :userId"),
@NamedQuery(name="deleteFederatedUserRoleMappingsByRealm", query="delete from FederatedUserRoleMappingEntity mapping where mapping.realmId=:realmId"),
@NamedQuery(name="deleteFederatedUserRoleMappingsByStorageProvider", query="delete from FederatedUserRoleMappingEntity e where e.storageProviderId=:storageProviderId"),
@NamedQuery(name="deleteFederatedUserRoleMappingsByRealmAndLink", query="delete from FederatedUserRoleMappingEntity mapping where mapping.userId IN (select u.id from UserEntity u where u.realmId=:realmId and u.federationLink=:link)"),
@NamedQuery(name="deleteFederatedUserRoleMappingsByRole", query="delete from FederatedUserRoleMappingEntity m where m.roleId = :roleId"),
@NamedQuery(name="deleteFederatedUserRoleMappingsByUser", query="delete from FederatedUserRoleMappingEntity m where m.userId = :userId and m.realmId = :realmId"),
})
@Table(name="FED_USER_ROLE_MAPPING")
@Entity
@IdClass(FederatedUserRoleMappingEntity.Key.class)
public class FederatedUserRoleMappingEntity {
@Id
protected String userId;
@Id
@Column(name = "ROLE_ID")
protected String roleId;
@Column(name = "REALM_ID")
protected String realmId;
@Column(name = "STORAGE_PROVIDER_ID")
protected String storageProviderId;
public String getUserId() {
return userId;
}
public void setUserId(String userId) {
this.userId = userId;
}
public String getRealmId() {
return realmId;
}
public void setRealmId(String realmId) {
this.realmId = realmId;
}
public String getStorageProviderId() {
return storageProviderId;
}
public void setStorageProviderId(String storageProviderId) {
this.storageProviderId = storageProviderId;
}
public String getRoleId() {
return roleId;
}
public void setRoleId(String roleId) {
this.roleId = roleId;
}
public static class Key implements Serializable {
protected String userId;
protected String roleId;
public Key() {
}
public Key(String userId, String roleId) {
this.userId = userId;
this.roleId = roleId;
}
public String getUserId() {
return userId;
}
public String getRoleId() {
return roleId;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Key key = (Key) o;
if (!roleId.equals(key.roleId)) return false;
if (!userId.equals(key.userId)) return false;
return true;
}
@Override
public int hashCode() {
int result = userId.hashCode();
result = 31 * result + roleId.hashCode();
return result;
}
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null) return false;
if (!(o instanceof FederatedUserRoleMappingEntity)) return false;
FederatedUserRoleMappingEntity key = (FederatedUserRoleMappingEntity) o;
if (!roleId.equals(key.roleId)) return false;
if (!userId.equals(key.userId)) return false;
return true;
}
@Override
public int hashCode() {
int result = userId.hashCode();
result = 31 * result + roleId.hashCode();
return result;
}
}

View file

@ -28,22 +28,28 @@ 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.entities.FederatedIdentityEntity;
import org.keycloak.models.entities.UserConsentEntity;
import org.keycloak.models.mongo.keycloak.entities.MongoUserConsentEntity;
import org.keycloak.models.mongo.keycloak.entities.MongoUserEntity;
import org.keycloak.models.utils.CredentialValidation;
import org.keycloak.storage.StorageProviderModel;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;
@ -140,7 +146,7 @@ public class MongoUserProvider implements UserProvider {
}
@Override
public UserModel getUserByServiceAccountClient(ClientModel client) {
public UserModel getServiceAccount(ClientModel client) {
DBObject query = new QueryBuilder()
.and("serviceAccountClientLink").is(client.getId())
.and("realmId").is(client.getRealm().getId())
@ -157,6 +163,17 @@ public class MongoUserProvider implements UserProvider {
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) {
@ -509,4 +526,112 @@ public class MongoUserProvider implements UserProvider {
// Not supported yet
return null;
}
@Override
public void addConsent(RealmModel realm, UserModel user, UserConsentModel consent) {
String clientId = consent.getClient().getId();
if (getConsentEntityByClientId(user, clientId) != null) {
throw new ModelDuplicateException("Consent already exists for client [" + clientId + "] and user [" + user.getId() + "]");
}
MongoUserConsentEntity consentEntity = new MongoUserConsentEntity();
consentEntity.setUserId(user.getId());
consentEntity.setClientId(clientId);
fillEntityFromModel(consent, consentEntity);
getMongoStore().insertEntity(consentEntity, invocationContext);
}
@Override
public UserConsentModel getConsentByClient(RealmModel realm, UserModel user, String clientId) {
UserConsentEntity consentEntity = getConsentEntityByClientId(user, clientId);
return consentEntity!=null ? toConsentModel(realm, consentEntity) : null;
}
@Override
public List<UserConsentModel> getConsents(RealmModel realm, UserModel user) {
List<UserConsentModel> result = new ArrayList<UserConsentModel>();
DBObject query = new QueryBuilder()
.and("userId").is(user.getId())
.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(UserModel user, String clientId) {
DBObject query = new QueryBuilder()
.and("userId").is(user.getId())
.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);
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);
}
@Override
public void updateConsent(RealmModel realm, UserModel user, UserConsentModel consent) {
String clientId = consent.getClient().getId();
MongoUserConsentEntity consentEntity = getConsentEntityByClientId(user, clientId);
if (consentEntity == null) {
throw new ModelException("Consent not found for client [" + clientId + "] and user [" + user.getId() + "]");
} else {
fillEntityFromModel(consent, consentEntity);
getMongoStore().updateEntity(consentEntity, invocationContext);
}
}
@Override
public boolean revokeConsentForClient(RealmModel realm, UserModel user, String clientId) {
MongoUserConsentEntity entity = getConsentEntityByClientId(user, clientId);
if (entity == null) {
return false;
}
return getMongoStore().removeEntity(entity, invocationContext);
}
@Override
public void preRemove(RealmModel realm, StorageProviderModel link) {
}
}

View file

@ -50,6 +50,7 @@ import org.keycloak.models.entities.IdentityProviderEntity;
import org.keycloak.models.entities.IdentityProviderMapperEntity;
import org.keycloak.models.entities.RequiredActionProviderEntity;
import org.keycloak.models.entities.RequiredCredentialEntity;
import org.keycloak.models.entities.StorageProviderEntity;
import org.keycloak.models.entities.UserFederationMapperEntity;
import org.keycloak.models.entities.UserFederationProviderEntity;
import org.keycloak.models.mongo.keycloak.entities.MongoClientEntity;
@ -58,6 +59,7 @@ import org.keycloak.models.mongo.keycloak.entities.MongoGroupEntity;
import org.keycloak.models.mongo.keycloak.entities.MongoRealmEntity;
import org.keycloak.models.mongo.keycloak.entities.MongoRoleEntity;
import org.keycloak.models.utils.KeycloakModelUtils;
import org.keycloak.storage.StorageProviderModel;
import java.security.Key;
import java.security.PrivateKey;
@ -984,6 +986,14 @@ public class RealmAdapter extends AbstractMongoAdapter<MongoRealmEntity> impleme
updateRealm();
}
private void removeFederationMappersForProvider(String federationProviderId) {
Set<UserFederationMapperEntity> mappers = getUserFederationMapperEntitiesByFederationProvider(federationProviderId);
for (UserFederationMapperEntity mapper : mappers) {
getMongoEntity().getUserFederationMappers().remove(mapper);
}
}
@Override
public UserFederationProviderModel addUserFederationProvider(String providerName, Map<String, String> config, int priority, String displayName, int fullSyncPeriod, int changedSyncPeriod, int lastSync) {
KeycloakModelUtils.ensureUniqueDisplayName(displayName, null, getUserFederationProviders());
@ -1025,14 +1035,6 @@ public class RealmAdapter extends AbstractMongoAdapter<MongoRealmEntity> impleme
}
updateRealm();
}
private void removeFederationMappersForProvider(String federationProviderId) {
Set<UserFederationMapperEntity> mappers = getUserFederationMapperEntitiesByFederationProvider(federationProviderId);
for (UserFederationMapperEntity mapper : mappers) {
getMongoEntity().getUserFederationMappers().remove(mapper);
}
}
@Override
public void updateUserFederationProvider(UserFederationProviderModel model) {
KeycloakModelUtils.ensureUniqueDisplayName(model.getDisplayName(), model, getUserFederationProviders());
@ -1161,6 +1163,173 @@ public class RealmAdapter extends AbstractMongoAdapter<MongoRealmEntity> impleme
updateRealm();
}
@Override
public StorageProviderModel addStorageProvider(StorageProviderModel model) {
KeycloakModelUtils.ensureUniqueDisplayName(model.getDisplayName(), null, getStorageProviders());
StorageProviderEntity entity = new StorageProviderEntity();
entity.setId(KeycloakModelUtils.generateId());
entity.setPriority(model.getPriority());
entity.setProviderName(model.getProviderName());
entity.setConfig(model.getConfig());
String displayName = model.getDisplayName();
if (displayName == null) {
displayName = entity.getId();
}
entity.setDisplayName(displayName);
realm.getStorageProviders().add(entity);
updateRealm();
StorageProviderModel providerModel = new StorageProviderModel(entity.getId(), model.getProviderName(),
model.getConfig(), model.getPriority(), displayName);
return providerModel;
}
@Override
public void updateStorageProvider(StorageProviderModel provider) {
KeycloakModelUtils.ensureUniqueDisplayName(provider.getDisplayName(), provider, getStorageProviders());
Iterator<StorageProviderEntity> it = realm.getStorageProviders().iterator();
while (it.hasNext()) {
StorageProviderEntity entity = it.next();
if (entity.getId().equals(provider.getId())) {
entity.setProviderName(provider.getProviderName());
entity.setConfig(provider.getConfig());
entity.setPriority(provider.getPriority());
String displayName = provider.getDisplayName();
if (displayName != null) {
entity.setDisplayName(provider.getDisplayName());
}
}
}
updateRealm();
}
@Override
public void removeStorageProvider(StorageProviderModel provider) {
Iterator<StorageProviderEntity> it = realm.getStorageProviders().iterator();
while (it.hasNext()) {
StorageProviderEntity entity = it.next();
if (entity.getId().equals(provider.getId())) {
session.users().preRemove(this, new StorageProviderModel(entity.getId(), entity.getProviderName(), entity.getConfig(), entity.getPriority(), entity.getDisplayName()
));
it.remove();
}
}
updateRealm();
}
@Override
public void setStorageProviders(List<StorageProviderModel> providers) {
for (StorageProviderModel currentProvider : providers) {
KeycloakModelUtils.ensureUniqueDisplayName(currentProvider.getDisplayName(), currentProvider, providers);
}
List<StorageProviderEntity> existingProviders = realm.getStorageProviders();
List<StorageProviderEntity> toRemove = new LinkedList<>();
for (StorageProviderEntity entity : existingProviders) {
boolean found = false;
for (StorageProviderModel model : providers) {
if (entity.getId().equals(model.getId())) {
entity.setConfig(model.getConfig());
entity.setPriority(model.getPriority());
entity.setProviderName(model.getProviderName());
String displayName = model.getDisplayName();
if (displayName != null) {
entity.setDisplayName(displayName);
}
found = true;
break;
}
}
if (found) continue;
session.users().preRemove(this, new StorageProviderModel(entity.getId(), entity.getProviderName(),
entity.getConfig(), entity.getPriority(), entity.getDisplayName()));
toRemove.add(entity);
}
for (StorageProviderEntity entity : toRemove) {
realm.getStorageProviders().remove(entity);
}
List<StorageProviderModel> add = new LinkedList<>();
for (StorageProviderModel model : providers) {
boolean found = false;
for (StorageProviderEntity entity : realm.getStorageProviders()) {
if (entity.getId().equals(model.getId())) {
found = true;
break;
}
}
if (!found) add.add(model);
}
for (StorageProviderModel model : add) {
StorageProviderEntity entity = new StorageProviderEntity();
if (model.getId() != null) {
entity.setId(model.getId());
} else {
String id = KeycloakModelUtils.generateId();
entity.setId(id);
model.setId(id);
}
entity.setProviderName(model.getProviderName());
entity.setConfig(model.getConfig());
entity.setPriority(model.getPriority());
String displayName = model.getDisplayName();
if (displayName == null) {
displayName = entity.getId();
}
entity.setDisplayName(displayName);
realm.getStorageProviders().add(entity);
}
updateRealm();
}
@Override
public List<StorageProviderModel> getStorageProviders() {
List<StorageProviderEntity> entities = realm.getStorageProviders();
if (entities.isEmpty()) return Collections.EMPTY_LIST;
List<StorageProviderEntity> copy = new LinkedList<>();
for (StorageProviderEntity entity : entities) {
copy.add(entity);
}
Collections.sort(copy, new Comparator<StorageProviderEntity>() {
@Override
public int compare(StorageProviderEntity o1, StorageProviderEntity o2) {
return o1.getPriority() - o2.getPriority();
}
});
List<StorageProviderModel> result = new LinkedList<>();
for (StorageProviderEntity entity : copy) {
result.add(new StorageProviderModel(entity.getId(), entity.getProviderName(), entity.getConfig(), entity.getPriority(), entity.getDisplayName()
));
}
return Collections.unmodifiableList(result);
}
@Override
public StorageProviderModel getStorageProvider(String id) {
for (StorageProviderEntity entity : realm.getStorageProviders()) {
if (entity.getId().equals(id)) return new StorageProviderModel(entity.getId(), entity.getProviderName(),
entity.getConfig(), entity.getPriority(), entity.getDisplayName());
}
return null;
}
@Override
public boolean isEventsEnabled() {
return realm.isEventsEnabled();

View file

@ -566,108 +566,6 @@ public class UserAdapter extends AbstractMongoAdapter<MongoUserEntity> implement
updateUser();
}
@Override
public void addConsent(UserConsentModel consent) {
String clientId = consent.getClient().getId();
if (getConsentEntityByClientId(clientId) != null) {
throw new ModelDuplicateException("Consent already exists for client [" + clientId + "] and user [" + user.getId() + "]");
}
MongoUserConsentEntity consentEntity = new MongoUserConsentEntity();
consentEntity.setUserId(getId());
consentEntity.setClientId(clientId);
fillEntityFromModel(consent, consentEntity);
getMongoStore().insertEntity(consentEntity, invocationContext);
}
@Override
public UserConsentModel getConsentByClient(String clientId) {
UserConsentEntity consentEntity = getConsentEntityByClientId(clientId);
return consentEntity!=null ? toConsentModel(consentEntity) : null;
}
@Override
public List<UserConsentModel> getConsents() {
List<UserConsentModel> result = new ArrayList<UserConsentModel>();
DBObject query = new QueryBuilder()
.and("userId").is(getId())
.get();
List<MongoUserConsentEntity> grantedConsents = getMongoStore().loadEntities(MongoUserConsentEntity.class, query, invocationContext);
for (UserConsentEntity consentEntity : grantedConsents) {
UserConsentModel model = toConsentModel(consentEntity);
result.add(model);
}
return result;
}
private MongoUserConsentEntity getConsentEntityByClientId(String clientId) {
DBObject query = new QueryBuilder()
.and("userId").is(getId())
.and("clientId").is(clientId)
.get();
return getMongoStore().loadSingleEntity(MongoUserConsentEntity.class, query, invocationContext);
}
private UserConsentModel toConsentModel(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);
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);
}
@Override
public void updateConsent(UserConsentModel consent) {
String clientId = consent.getClient().getId();
MongoUserConsentEntity consentEntity = getConsentEntityByClientId(clientId);
if (consentEntity == null) {
throw new ModelException("Consent not found for client [" + clientId + "] and user [" + user.getId() + "]");
} else {
fillEntityFromModel(consent, consentEntity);
getMongoStore().updateEntity(consentEntity, invocationContext);
}
}
@Override
public boolean revokeConsentForClient(String clientId) {
MongoUserConsentEntity entity = getConsentEntityByClientId(clientId);
if (entity == null) {
return false;
}
return getMongoStore().removeEntity(entity, invocationContext);
}
@Override
public boolean equals(Object o) {

View file

@ -34,8 +34,8 @@ import org.keycloak.provider.Provider;
public interface UserFederationMapper extends Provider {
/**
* Sync data from federation storage to Keycloak. It's useful just if mapper needs some data preloaded from federation storage (For example
* load roles from federation provider and sync them to Keycloak database)
* Sync data from federated storage to Keycloak. It's useful just if mapper needs some data preloaded from federated storage (For example
* load roles from federated provider and sync them to Keycloak database)
*
* Applicable just if sync is supported (see UserFederationMapperFactory.getSyncConfig() )
*
@ -48,7 +48,7 @@ public interface UserFederationMapper extends Provider {
UserFederationSyncResult syncDataFromFederationProviderToKeycloak(UserFederationMapperModel mapperModel, UserFederationProvider federationProvider, KeycloakSession session, RealmModel realm);
/**
* Sync data from Keycloak back to federation storage
* Sync data from Keycloak back to federated storage
*
* @see UserFederationMapperFactory#getSyncConfig()
* @param mapperModel

View file

@ -32,7 +32,7 @@ import org.keycloak.representations.idm.UserFederationMapperSyncConfigRepresenta
public interface UserFederationMapperFactory extends ProviderFactory<UserFederationMapper>, ConfiguredProvider {
/**
* Refers to providerName (type) of the federation provider, which this mapper can be used for. For example "ldap" or "kerberos"
* Refers to providerName (type) of the federated provider, which this mapper can be used for. For example "ldap" or "kerberos"
*
* @return providerName
*/
@ -42,7 +42,7 @@ public interface UserFederationMapperFactory extends ProviderFactory<UserFederat
String getDisplayType();
/**
* Specifies if mapper supports sync data from federation storage to keycloak and viceversa.
* Specifies if mapper supports sync data from federated storage to keycloak and viceversa.
* Also specifies messages to be displayed in admin console UI (For example "Sync roles from LDAP" etc)
*
* @return syncConfig representation

View file

@ -56,7 +56,7 @@ public class MigrateTo1_3_0 {
if (fedProvider.getProviderName().equals(LDAPConstants.LDAP_PROVIDER)) {
Map<String, String> config = fedProvider.getConfig();
// Update config properties for LDAP federation provider
// Update config properties for LDAP federated provider
if (config.get(LDAPConstants.SEARCH_SCOPE) == null) {
config.put(LDAPConstants.SEARCH_SCOPE, String.valueOf(SearchControls.SUBTREE_SCOPE));
}

View file

@ -57,4 +57,25 @@ public class FederatedIdentityModel {
public void setToken(String token) {
this.token = token;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
FederatedIdentityModel that = (FederatedIdentityModel) o;
if (userId != null ? !userId.equals(that.userId) : that.userId != null) return false;
if (!identityProvider.equals(that.identityProvider)) return false;
return userName != null ? userName.equals(that.userName) : that.userName == null;
}
@Override
public int hashCode() {
int result = userId != null ? userId.hashCode() : 0;
result = 31 * result + identityProvider.hashCode();
result = 31 * result + (userName != null ? userName.hashCode() : 0);
return result;
}
}

View file

@ -19,6 +19,8 @@ package org.keycloak.models;
import org.keycloak.provider.Provider;
import org.keycloak.scripting.ScriptingProvider;
import org.keycloak.storage.federated.UserFederatedStorageProvider;
import org.keycloak.storage.federated.UserFederatedStorageProviderFactory;
import java.util.Set;
@ -73,11 +75,16 @@ public interface KeycloakSession {
*/
UserFederationManager users();
UserProvider userStorageManager();
/**
* Keycloak user storage. Non-federated, but possibly cache (if it is on) view of users.
*/
UserProvider userStorage();
UserFederatedStorageProvider userFederatedStorage();
UserProvider userLocalStorage();
/**
* Keycloak scripting support.
*/

View file

@ -19,6 +19,7 @@ package org.keycloak.models;
import org.keycloak.common.enums.SslRequired;
import org.keycloak.provider.ProviderEvent;
import org.keycloak.storage.StorageProviderModel;
import java.security.Key;
import java.security.PrivateKey;
@ -263,9 +264,16 @@ public interface RealmModel extends RoleContainerModel {
public IdentityProviderMapperModel getIdentityProviderMapperById(String id);
public IdentityProviderMapperModel getIdentityProviderMapperByName(String brokerAlias, String name);
StorageProviderModel addStorageProvider(StorageProviderModel model);
void updateStorageProvider(StorageProviderModel provider);
void removeStorageProvider(StorageProviderModel provider);
void setStorageProviders(List<StorageProviderModel> providers);
List<StorageProviderModel> getStorageProviders();
StorageProviderModel getStorageProvider(String id);
// Should return list sorted by UserFederationProviderModel.priority
List<UserFederationProviderModel> getUserFederationProviders();
UserFederationProviderModel addUserFederationProvider(String providerName, Map<String, String> config, int priority, String displayName, int fullSyncPeriod, int changedSyncPeriod, int lastSync);
void updateUserFederationProvider(UserFederationProviderModel provider);
void removeUserFederationProvider(UserFederationProviderModel provider);

View file

@ -0,0 +1,28 @@
/*
* 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;
import java.util.Set;
/**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $
*/
public interface UserCredentialAuthenticationProvider {
Set<String> getSupportedCredentialAuthenticationTypes();
CredentialValidationOutput validCredential(KeycloakSession session, RealmModel realm, UserCredentialModel input);
}

View file

@ -0,0 +1,28 @@
/*
* 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;
import java.util.List;
import java.util.Set;
/**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $
*/
public interface UserCredentialValidatorProvider {
boolean validCredentials(KeycloakSession session, RealmModel realm, UserModel user, List<UserCredentialModel> input);
}

View file

@ -25,7 +25,7 @@ import java.io.Serializable;
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
*/
public class UserCredentialValueModel implements Serializable {
private String id;
private String type;
private String value;
private String device;
@ -40,6 +40,14 @@ public class UserCredentialValueModel implements Serializable {
private int period;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getType() {
return type;
}

View file

@ -20,6 +20,7 @@ package org.keycloak.models;
import org.jboss.logging.Logger;
import org.keycloak.models.utils.KeycloakModelUtils;
import org.keycloak.services.managers.UserManager;
import org.keycloak.storage.StorageProviderModel;
import java.util.ArrayList;
import java.util.Arrays;
@ -174,6 +175,38 @@ public class UserFederationManager implements UserProvider {
return session.userStorage().removeFederatedIdentity(realm, user, socialProvider);
}
@Override
public void addConsent(RealmModel realm, UserModel user, UserConsentModel consent) {
validateUser(realm, user);
session.userStorage().addConsent(realm, user, consent);
}
@Override
public UserConsentModel getConsentByClient(RealmModel realm, UserModel user, String clientInternalId) {
validateUser(realm, user);
return session.userStorage().getConsentByClient(realm, user, clientInternalId);
}
@Override
public List<UserConsentModel> getConsents(RealmModel realm, UserModel user) {
validateUser(realm, user);
return session.userStorage().getConsents(realm, user);
}
@Override
public void updateConsent(RealmModel realm, UserModel user, UserConsentModel consent) {
validateUser(realm, user);
session.userStorage().updateConsent(realm, user, consent);
}
@Override
public boolean revokeConsentForClient(RealmModel realm, UserModel user, String clientInternalId) {
validateUser(realm, user);
return session.userStorage().revokeConsentForClient(realm, user, clientInternalId);
}
@Override
public UserModel getUserById(String id, RealmModel realm) {
UserModel user = session.userStorage().getUserById(id, realm);
@ -265,8 +298,8 @@ public class UserFederationManager implements UserProvider {
}
@Override
public UserModel getUserByServiceAccountClient(ClientModel client) {
UserModel user = session.userStorage().getUserByServiceAccountClient(client);
public UserModel getServiceAccount(ClientModel client) {
UserModel user = session.userStorage().getServiceAccount(client);
if (user != null) {
user = validateAndProxyUser(client.getRealm(), user);
}
@ -279,6 +312,16 @@ public class UserFederationManager implements UserProvider {
}
@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 int getUsersCount(RealmModel realm) {
return session.userStorage().getUsersCount(realm);
@ -442,6 +485,11 @@ public class UserFederationManager implements UserProvider {
session.userStorage().preRemove(protocolMapper);
}
@Override
public void preRemove(RealmModel realm, StorageProviderModel link) {
}
public void updateCredential(RealmModel realm, UserModel user, UserCredentialModel credential) {
if (credential.getType().equals(UserCredentialModel.PASSWORD)) {
if (realm.getPasswordPolicy() != null) {

View file

@ -0,0 +1,29 @@
/*
* 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;
/**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $
*/
public interface UserLookupProvider {
UserModel getUserById(String id, RealmModel realm);
UserModel getUserByUsername(String username, RealmModel realm);
UserModel getUserByEmail(String email, RealmModel realm);
}

View file

@ -122,12 +122,6 @@ public interface UserModel extends RoleMapperModel {
String getServiceAccountClientLink();
void setServiceAccountClientLink(String clientInternalId);
void addConsent(UserConsentModel consent);
UserConsentModel getConsentByClient(String clientInternalId);
List<UserConsentModel> getConsents();
void updateConsent(UserConsentModel consent);
boolean revokeConsentForClient(String clientInternalId);
public static enum RequiredAction {
VERIFY_EMAIL, UPDATE_PROFILE, CONFIGURE_TOTP, UPDATE_PASSWORD
}

View file

@ -18,56 +18,44 @@
package org.keycloak.models;
import org.keycloak.provider.Provider;
import org.keycloak.storage.StorageProviderModel;
import java.util.List;
import java.util.Map;
import java.util.Set;
/**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $
*/
public interface UserProvider extends Provider {
public interface UserProvider extends Provider, UserLookupProvider, UserQueryProvider, UserCredentialValidatorProvider, UserUpdateProvider {
// Note: The reason there are so many query methods here is for layering a cache on top of an persistent KeycloakSession
UserModel addUser(RealmModel realm, String id, String username, boolean addDefaultRoles, boolean addDefaultRequiredActions);
UserModel addUser(RealmModel realm, String username);
boolean removeUser(RealmModel realm, UserModel user);
public void addFederatedIdentity(RealmModel realm, UserModel user, FederatedIdentityModel socialLink);
public boolean removeFederatedIdentity(RealmModel realm, UserModel user, String socialProvider);
void updateFederatedIdentity(RealmModel realm, UserModel federatedUser, FederatedIdentityModel federatedIdentityModel);
UserModel getUserById(String id, RealmModel realm);
UserModel getUserByUsername(String username, RealmModel realm);
UserModel getUserByEmail(String email, RealmModel realm);
List<UserModel> getGroupMembers(RealmModel realm, GroupModel group, int firstResult, int maxResults);
Set<FederatedIdentityModel> getFederatedIdentities(UserModel user, RealmModel realm);
FederatedIdentityModel getFederatedIdentity(UserModel user, String socialProvider, RealmModel realm);
UserModel getUserByFederatedIdentity(FederatedIdentityModel socialLink, RealmModel realm);
UserModel getUserByServiceAccountClient(ClientModel client);
List<UserModel> getUsers(RealmModel realm, boolean includeServiceAccounts);
// Service account is included for counts
int getUsersCount(RealmModel realm);
List<UserModel> getGroupMembers(RealmModel realm, GroupModel group);
void addConsent(RealmModel realm, UserModel user, UserConsentModel consent);
UserConsentModel getConsentByClient(RealmModel realm, UserModel user, String clientInternalId);
List<UserConsentModel> getConsents(RealmModel realm, UserModel user);
void updateConsent(RealmModel realm, UserModel user, UserConsentModel consent);
boolean revokeConsentForClient(RealmModel realm, UserModel user, String clientInternalId);
UserModel getServiceAccount(ClientModel client);
List<UserModel> getUsers(RealmModel realm, boolean includeServiceAccounts);
List<UserModel> getUsers(RealmModel realm, int firstResult, int maxResults, boolean includeServiceAccounts);
List<UserModel> searchForUser(String search, RealmModel realm);
List<UserModel> searchForUser(String search, RealmModel realm, int firstResult, int maxResults);
List<UserModel> searchForUserByAttributes(Map<String, String> attributes, RealmModel realm);
List<UserModel> searchForUserByAttributes(Map<String, String> attributes, RealmModel realm, int firstResult, int maxResults);
// Searching by UserModel.attribute (not property)
List<UserModel> searchForUserByUserAttribute(String attrName, String attrValue, RealmModel realm);
Set<FederatedIdentityModel> getFederatedIdentities(UserModel user, RealmModel realm);
FederatedIdentityModel getFederatedIdentity(UserModel user, String socialProvider, RealmModel realm);
void grantToAllUsers(RealmModel realm, RoleModel role);
void preRemove(RealmModel realm);
void preRemove(RealmModel realm, UserFederationProviderModel link);
void preRemove(RealmModel realm, StorageProviderModel link);
void preRemove(RealmModel realm, RoleModel role);
void preRemove(RealmModel realm, GroupModel group);
@ -75,9 +63,10 @@ public interface UserProvider extends Provider {
void preRemove(RealmModel realm, ClientModel client);
void preRemove(ProtocolMapperModel protocolMapper);
boolean validCredentials(KeycloakSession session, RealmModel realm, UserModel user, List<UserCredentialModel> input);
boolean validCredentials(KeycloakSession session, RealmModel realm, UserModel user, UserCredentialModel... input);
CredentialValidationOutput validCredentials(KeycloakSession session, RealmModel realm, UserCredentialModel... input);
void close();
}

View file

@ -0,0 +1,44 @@
/*
* 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;
import java.util.List;
import java.util.Map;
/**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $
*/
public interface UserQueryProvider {
// Service account is included for counts
int getUsersCount(RealmModel realm);
List<UserModel> getUsers(RealmModel realm);
List<UserModel> searchForUserByAttributes(Map<String, String> attributes, RealmModel realm);
List<UserModel> getUsers(RealmModel realm, int firstResult, int maxResults);
List<UserModel> searchForUser(String search, RealmModel realm, int firstResult, int maxResults);
List<UserModel> searchForUserByAttributes(Map<String, String> attributes, RealmModel realm, int firstResult, int maxResults);
List<UserModel> getGroupMembers(RealmModel realm, GroupModel group, int firstResult, int maxResults);
List<UserModel> getGroupMembers(RealmModel realm, GroupModel group);
}

View file

@ -0,0 +1,32 @@
/*
* 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;
/**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $
*/
public interface UserUpdateProvider {
UserModel addUser(RealmModel realm, String id, String username, boolean addDefaultRoles, boolean addDefaultRequiredActions);
UserModel addUser(RealmModel realm, String username);
boolean removeUser(RealmModel realm, UserModel user);
void grantToAllUsers(RealmModel realm, RoleModel role);
}

View file

@ -19,6 +19,7 @@ package org.keycloak.models.entities;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
@ -80,13 +81,14 @@ public class RealmEntity extends AbstractIdentifiableEntity {
private String emailTheme;
// We are using names of defaultRoles (not ids)
private List<String> defaultRoles = new ArrayList<String>();
private List<String> defaultGroups = new ArrayList<String>();
private List<String> defaultRoles = new LinkedList<String>();
private List<String> defaultGroups = new LinkedList<String>();
private List<RequiredCredentialEntity> requiredCredentials = new ArrayList<RequiredCredentialEntity>();
private List<UserFederationProviderEntity> userFederationProviders = new ArrayList<UserFederationProviderEntity>();
private List<UserFederationMapperEntity> userFederationMappers = new ArrayList<UserFederationMapperEntity>();
private List<IdentityProviderEntity> identityProviders = new ArrayList<IdentityProviderEntity>();
private List<RequiredCredentialEntity> requiredCredentials = new LinkedList<>();
private List<StorageProviderEntity> storageProviders = new LinkedList<>();
private List<UserFederationProviderEntity> userFederationProviders = new LinkedList<UserFederationProviderEntity>();
private List<UserFederationMapperEntity> userFederationMappers = new LinkedList<UserFederationMapperEntity>();
private List<IdentityProviderEntity> identityProviders = new LinkedList<IdentityProviderEntity>();
private Map<String, String> browserSecurityHeaders = new HashMap<String, String>();
private Map<String, String> smtpConfig = new HashMap<String, String>();
@ -682,6 +684,14 @@ public class RealmEntity extends AbstractIdentifiableEntity {
public void setDefaultGroups(List<String> defaultGroups) {
this.defaultGroups = defaultGroups;
}
public List<StorageProviderEntity> getStorageProviders() {
return storageProviders;
}
public void setStorageProviders(List<StorageProviderEntity> storageProviders) {
this.storageProviders = storageProviders;
}
}

View file

@ -0,0 +1,65 @@
/*
* 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.entities;
import java.util.Map;
/**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $
*/
public class StorageProviderEntity extends AbstractIdentifiableEntity {
protected String providerName;
protected Map<String, String> config;
protected int priority;
protected String displayName;
public String getProviderName() {
return providerName;
}
public void setProviderName(String providerName) {
this.providerName = providerName;
}
public Map<String, String> getConfig() {
return config;
}
public void setConfig(Map<String, String> config) {
this.config = config;
}
public int getPriority() {
return priority;
}
public void setPriority(int priority) {
this.priority = priority;
}
public String getDisplayName() {
return displayName;
}
public void setDisplayName(String displayName) {
this.displayName = displayName;
}
}

View file

@ -48,7 +48,7 @@ public class CredentialValidation {
}
/**
/**
* Will update password if hash iteration policy has changed
*
* @param realm
@ -195,7 +195,7 @@ public class CredentialValidation {
return true;
}
private static boolean validCredential(KeycloakSession session, RealmModel realm, UserModel user, UserCredentialModel credential) {
public static boolean validCredential(KeycloakSession session, RealmModel realm, UserModel user, UserCredentialModel credential) {
if (credential.getType().equals(UserCredentialModel.PASSWORD)) {
if (!validPassword(session, realm, user, credential.getValue())) {
return false;

View file

@ -0,0 +1,166 @@
/*
* 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.utils;
import org.keycloak.common.util.Time;
import org.keycloak.hash.PasswordHashManager;
import org.keycloak.jose.jws.JWSInput;
import org.keycloak.jose.jws.JWSInputException;
import org.keycloak.jose.jws.crypto.RSAProvider;
import org.keycloak.models.KeycloakSession;
import org.keycloak.models.OTPPolicy;
import org.keycloak.models.PasswordPolicy;
import org.keycloak.models.RealmModel;
import org.keycloak.models.UserCredentialModel;
import org.keycloak.models.UserCredentialValueModel;
import org.keycloak.models.UserModel;
import org.keycloak.representations.PasswordToken;
import java.util.List;
/**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $
*/
public class FederatedCredentialValidation {
private static int hashIterations(RealmModel realm) {
PasswordPolicy policy = realm.getPasswordPolicy();
if (policy != null) {
return policy.getHashIterations();
}
return -1;
}
/**
* Will update password if hash iteration policy has changed
*
* @param realm
* @param user
* @param password
* @return
*/
public static boolean validPassword(KeycloakSession session, RealmModel realm, UserModel user, String password, UserCredentialValueModel fedCred) {
return validateHashedCredential(session, realm, user, password, fedCred);
}
public static boolean validateHashedCredential(KeycloakSession session, RealmModel realm, UserModel user, String unhashedCredValue, UserCredentialValueModel credential) {
if (unhashedCredValue == null || unhashedCredValue.isEmpty()) {
return false;
}
boolean validated = PasswordHashManager.verify(session, realm, unhashedCredValue, credential);
if (validated) {
int iterations = hashIterations(realm);
if (iterations > -1 && iterations != credential.getHashIterations()) {
UserCredentialValueModel newCred = PasswordHashManager.encode(session, realm, unhashedCredValue);
session.userFederatedStorage().updateCredential(realm, user, newCred);
}
}
return validated;
}
public static boolean validPasswordToken(RealmModel realm, UserModel user, String encodedPasswordToken) {
try {
JWSInput jws = new JWSInput(encodedPasswordToken);
if (!RSAProvider.verify(jws, realm.getPublicKey())) {
return false;
}
PasswordToken passwordToken = jws.readJsonContent(PasswordToken.class);
if (!passwordToken.getRealm().equals(realm.getName())) {
return false;
}
if (!passwordToken.getUser().equals(user.getId())) {
return false;
}
if (Time.currentTime() - passwordToken.getTimestamp() > realm.getAccessCodeLifespanUserAction()) {
return false;
}
return true;
} catch (JWSInputException e) {
return false;
}
}
public static boolean validHOTP(KeycloakSession session, RealmModel realm, UserModel user, String otp, List<UserCredentialValueModel> fedCreds) {
UserCredentialValueModel passwordCred = null;
OTPPolicy policy = realm.getOTPPolicy();
HmacOTP validator = new HmacOTP(policy.getDigits(), policy.getAlgorithm(), policy.getLookAheadWindow());
for (UserCredentialValueModel cred : fedCreds) {
if (cred.getType().equals(UserCredentialModel.HOTP)) {
int counter = validator.validateHOTP(otp, cred.getValue(), cred.getCounter());
if (counter < 0) return false;
cred.setCounter(counter);
session.userFederatedStorage().updateCredential(realm, user, cred);
return true;
}
}
return false;
}
public static boolean validTOTP(RealmModel realm, UserModel user, String otp, List<UserCredentialValueModel> fedCreds) {
UserCredentialValueModel passwordCred = null;
OTPPolicy policy = realm.getOTPPolicy();
TimeBasedOTP validator = new TimeBasedOTP(policy.getAlgorithm(), policy.getDigits(), policy.getPeriod(), policy.getLookAheadWindow());
for (UserCredentialValueModel cred : fedCreds) {
if (validator.validateTOTP(otp, cred.getValue().getBytes())) {
return true;
}
}
return false;
}
public static boolean validSecret(RealmModel realm, UserModel user, String secret, UserCredentialValueModel cred) {
return cred.getValue().equals(secret);
}
public static boolean validCredential(KeycloakSession session, RealmModel realm, UserModel user, UserCredentialModel credential, List<UserCredentialValueModel> fedCreds) {
if (credential.getType().equals(UserCredentialModel.PASSWORD)) {
if (!validPassword(session, realm, user, credential.getValue(), fedCreds.get(0))) {
return false;
}
} else if (credential.getType().equals(UserCredentialModel.PASSWORD_TOKEN)) {
if (!validPasswordToken(realm, user, credential.getValue())) {
return false;
}
} else if (credential.getType().equals(UserCredentialModel.TOTP)) {
if (!validTOTP(realm, user, credential.getValue(), fedCreds)) {
return false;
}
} else if (credential.getType().equals(UserCredentialModel.HOTP)) {
if (!validHOTP(session, realm, user, credential.getValue(), fedCreds)) {
return false;
}
} else if (credential.getType().equals(UserCredentialModel.SECRET)) {
if (!validSecret(realm, user, credential.getValue(), fedCreds.get(0))) {
return false;
}
} else {
return false;
}
return true;
}
}

View file

@ -0,0 +1,186 @@
/*
* 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.utils;
import org.keycloak.common.util.Time;
import org.keycloak.hash.PasswordHashManager;
import org.keycloak.models.KeycloakSession;
import org.keycloak.models.OTPPolicy;
import org.keycloak.models.PasswordPolicy;
import org.keycloak.models.RealmModel;
import org.keycloak.models.UserCredentialModel;
import org.keycloak.models.UserCredentialValueModel;
import org.keycloak.models.UserModel;
import org.keycloak.storage.federated.UserFederatedStorageProvider;
import java.util.Collections;
import java.util.Comparator;
import java.util.LinkedList;
import java.util.List;
/**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $
*/
public class FederatedCredentials {
public static void updateCredential(KeycloakSession session, UserFederatedStorageProvider provider, RealmModel realm, UserModel user, UserCredentialModel cred) {
if (cred.getType().equals(UserCredentialModel.PASSWORD)) {
updatePasswordCredential(session, provider,realm, user, cred);
} else if (UserCredentialModel.isOtp(cred.getType())) {
updateOtpCredential(session, provider, realm, user, cred);
} else {
UserCredentialValueModel fedCred = getCredentialByType(provider, realm, user, cred.getType());
if (fedCred == null) {
fedCred.setCreatedDate(Time.toMillis(Time.currentTime()));
fedCred.setType(cred.getType());
fedCred.setDevice(cred.getDevice());
fedCred.setValue(cred.getValue());
} else {
fedCred.setValue(cred.getValue());
}
provider.updateCredential(realm, user, fedCred);
}
}
public static UserCredentialValueModel getCredentialByType(UserFederatedStorageProvider provider, RealmModel realm, UserModel user, String type) {
List<UserCredentialValueModel> creds = provider.getCredentials(realm, user);
for (UserCredentialValueModel cred : creds) {
if (cred.getType().equals(type)) return cred;
}
return null;
}
public static LinkedList<UserCredentialValueModel> getCredentialsByType(UserFederatedStorageProvider provider, RealmModel realm, UserModel user, String type) {
List<UserCredentialValueModel> creds = provider.getCredentials(realm, user);
LinkedList<UserCredentialValueModel> newCreds = new LinkedList<>();
for (UserCredentialValueModel cred : creds) {
if (cred.getType().equals(type)) newCreds.add(cred);
}
return newCreds;
}
public static void updatePasswordCredential(KeycloakSession session, UserFederatedStorageProvider provider, RealmModel realm, UserModel user, UserCredentialModel cred) {
UserCredentialValueModel fedCred = getCredentialByType(provider, realm, user, cred.getType());
if (fedCred == null) {
UserCredentialValueModel newCred = PasswordHashManager.encode(session, realm, cred.getValue());
newCred.setCreatedDate(Time.toMillis(Time.currentTime()));
newCred.setType(cred.getType());
newCred.setDevice(cred.getDevice());
provider.updateCredential(realm, user, newCred);
} else {
int expiredPasswordsPolicyValue = -1;
PasswordPolicy policy = realm.getPasswordPolicy();
if(policy != null) {
expiredPasswordsPolicyValue = policy.getExpiredPasswords();
}
if (expiredPasswordsPolicyValue != -1) {
fedCred.setType(UserCredentialModel.PASSWORD_HISTORY);
LinkedList<UserCredentialValueModel> credentialEntities = getCredentialsByType(provider, realm, user, UserCredentialModel.PASSWORD_HISTORY);
if (credentialEntities.size() > expiredPasswordsPolicyValue - 1) {
Collections.sort(credentialEntities, new Comparator<UserCredentialValueModel>() {
@Override
public int compare(UserCredentialValueModel o1, UserCredentialValueModel o2) {
if (o1.getCreatedDate().equals(o2.getCreatedDate())) return 0;
return o1.getCreatedDate() < o2.getCreatedDate() ? -1 : 1;
}
});
while (credentialEntities.size() > expiredPasswordsPolicyValue - 1) {
UserCredentialValueModel model = credentialEntities.removeFirst();
provider.removeCredential(realm, user, model);
}
}
provider.updateCredential(realm, user, fedCred);
fedCred = PasswordHashManager.encode(session, realm, cred.getValue());
fedCred.setCreatedDate(Time.toMillis(Time.currentTime()));
fedCred.setType(cred.getType());
fedCred.setDevice(cred.getDevice());
provider.updateCredential(realm, user, fedCred);
} else {
// clear password history as it is not required anymore
for (UserCredentialValueModel model : getCredentialsByType(provider, realm, user, UserCredentialModel.PASSWORD_HISTORY)) {
provider.removeCredential(realm, user, model);
}
UserCredentialValueModel newCred = PasswordHashManager.encode(session, realm, cred.getValue());
newCred.setCreatedDate(Time.toMillis(Time.currentTime()));
newCred.setType(cred.getType());
newCred.setDevice(cred.getDevice());
newCred.setId(fedCred.getId());
provider.updateCredential(realm, user, newCred);
}
}
}
public static void updateOtpCredential(KeycloakSession session, UserFederatedStorageProvider provider, RealmModel realm, UserModel user, UserCredentialModel cred) {
LinkedList<UserCredentialValueModel> credentialEntities = getCredentialsByType(provider, realm, user, UserCredentialModel.PASSWORD_HISTORY);
if (credentialEntities.isEmpty()) {
UserCredentialValueModel fedCred = new UserCredentialValueModel();
fedCred.setCreatedDate(Time.toMillis(Time.currentTime()));
fedCred.setType(cred.getType());
fedCred.setDevice(cred.getDevice());
fedCred.setValue(cred.getValue());
OTPPolicy otpPolicy = realm.getOTPPolicy();
fedCred.setAlgorithm(otpPolicy.getAlgorithm());
fedCred.setDigits(otpPolicy.getDigits());
fedCred.setCounter(otpPolicy.getInitialCounter());
fedCred.setPeriod(otpPolicy.getPeriod());
provider.updateCredential(realm, user, fedCred);
} else {
OTPPolicy policy = realm.getOTPPolicy();
if (cred.getDevice() == null) {
for (UserCredentialValueModel model : credentialEntities) provider.removeCredential(realm, user, model);
UserCredentialValueModel fedCred = new UserCredentialValueModel();
fedCred.setCreatedDate(Time.toMillis(Time.currentTime()));
fedCred.setType(cred.getType());
fedCred.setDevice(cred.getDevice());
fedCred.setDigits(policy.getDigits());
fedCred.setCounter(policy.getInitialCounter());
fedCred.setAlgorithm(policy.getAlgorithm());
fedCred.setValue(cred.getValue());
fedCred.setPeriod(policy.getPeriod());
provider.updateCredential(realm, user, fedCred);
} else {
UserCredentialValueModel fedCred = new UserCredentialValueModel();
for (UserCredentialValueModel model : credentialEntities) {
if (cred.getDevice().equals(model.getDevice())) {
fedCred = model;
break;
}
}
fedCred.setCreatedDate(Time.toMillis(Time.currentTime()));
fedCred.setType(cred.getType());
fedCred.setDevice(cred.getDevice());
fedCred.setDigits(policy.getDigits());
fedCred.setCounter(policy.getInitialCounter());
fedCred.setAlgorithm(policy.getAlgorithm());
fedCred.setValue(cred.getValue());
fedCred.setPeriod(policy.getPeriod());
provider.updateCredential(realm, user, fedCred);
}
}
}
}

View file

@ -44,6 +44,7 @@ import org.keycloak.models.UserModel;
import org.keycloak.representations.idm.CertificateRepresentation;
import org.keycloak.common.util.CertificateUtils;
import org.keycloak.common.util.PemUtils;
import org.keycloak.storage.StorageProviderModel;
import javax.crypto.spec.SecretKeySpec;
import java.io.IOException;
@ -341,6 +342,43 @@ public final class KeycloakModelUtils {
}
// USER FEDERATION RELATED STUFF
/**
* Ensure that displayName of myProvider (if not null) is unique and there is no other provider with same displayName in the list.
*
* @param displayName to check for duplications
* @param myProvider provider, which is excluded from the list (if present)
* @param federationProviders
* @throws ModelDuplicateException if there is other provider with same displayName
*/
public static void ensureUniqueDisplayName(String displayName, StorageProviderModel myProvider, List<StorageProviderModel> federationProviders) throws ModelDuplicateException {
if (displayName != null) {
for (StorageProviderModel federationProvider : federationProviders) {
if (myProvider != null && (myProvider.equals(federationProvider) || (myProvider.getId() != null && myProvider.getId().equals(federationProvider.getId())))) {
continue;
}
if (displayName.equals(federationProvider.getDisplayName())) {
throw new ModelDuplicateException("There is already existing federation provider with display name: " + displayName);
}
}
}
}
public static StorageProviderModel findStorageProviderByDisplayName(String displayName, RealmModel realm) {
if (displayName == null) {
return null;
}
for (StorageProviderModel provider : realm.getStorageProviders()) {
if (displayName.equals(provider.getDisplayName())) {
return provider;
}
}
return null;
}
/**
* Ensure that displayName of myProvider (if not null) is unique and there is no other provider with same displayName in the list.
*
@ -378,7 +416,6 @@ public final class KeycloakModelUtils {
return null;
}
public static UserFederationProviderModel findUserFederationProviderById(String fedProviderId, RealmModel realm) {
for (UserFederationProviderModel fedProvider : realm.getUserFederationProviders()) {
if (fedProviderId.equals(fedProvider.getId())) {

View file

@ -1279,7 +1279,7 @@ public class RepresentationToModel {
if (userRep.getClientConsents() != null) {
for (UserConsentRepresentation consentRep : userRep.getClientConsents()) {
UserConsentModel consentModel = toModel(newRealm, consentRep);
user.addConsent(consentModel);
session.userStorage().addConsent(newRealm, user, consentModel);
}
}
if (userRep.getServiceAccountClientId() != null) {

View file

@ -235,31 +235,6 @@ public class UserModelDelegate implements UserModel {
delegate.setServiceAccountClientLink(clientInternalId);
}
@Override
public void addConsent(UserConsentModel consent) {
delegate.addConsent(consent);
}
@Override
public UserConsentModel getConsentByClient(String clientId) {
return delegate.getConsentByClient(clientId);
}
@Override
public List<UserConsentModel> getConsents() {
return delegate.getConsents();
}
@Override
public void updateConsent(UserConsentModel consent) {
delegate.updateConsent(consent);
}
@Override
public boolean revokeConsentForClient(String clientId) {
return delegate.revokeConsentForClient(clientId);
}
public UserModel getDelegate() {
return delegate;
}

View file

@ -0,0 +1,65 @@
/*
* 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;
import org.keycloak.models.UserModel;
import java.io.Serializable;
/**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $
*/
public class StorageId implements Serializable {
private String id;
private String providerId;
private String storageId;
public StorageId(String id) {
this.id = id;
if (!id.startsWith("f:")) {
storageId = id;
return;
}
int providerIndex = id.indexOf(':', 2);
providerId = id.substring(2, providerIndex);
storageId = id.substring(providerIndex + 1);
}
public static String resolveProviderId(UserModel user) {
return new StorageId(user.getId()).getProviderId();
}
public static boolean isLocalStorage(UserModel user) {
return new StorageId(user.getId()).getProviderId() == null;
}
public String getId() {
return id;
}
public String getProviderId() {
return providerId;
}
public String getStorageId() {
return storageId;
}
}

View file

@ -0,0 +1,40 @@
/*
* 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;
import org.keycloak.models.ClientModel;
import org.keycloak.models.GroupModel;
import org.keycloak.models.ProtocolMapperModel;
import org.keycloak.models.RealmModel;
import org.keycloak.models.RoleModel;
import org.keycloak.models.UserModel;
import org.keycloak.provider.Provider;
/**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $
*/
public interface StorageProvider extends Provider {
StorageProviderModel getModel();
void preRemove(RealmModel realm);
void preRemove(RealmModel realm, GroupModel group);
void preRemove(RealmModel realm, RoleModel role);
void preRemove(RealmModel realm, StorageProviderModel model);
}

View file

@ -0,0 +1,62 @@
/*
* 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;
import org.keycloak.models.KeycloakSession;
import org.keycloak.provider.ProviderFactory;
import java.util.Set;
/**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $
*/
public interface StorageProviderFactory extends ProviderFactory<StorageProvider> {
boolean supports(Class<?> type);
/**
* called per Keycloak transaction.
*
* @param session
* @param model
* @return
*/
StorageProvider getInstance(KeycloakSession session, StorageProviderModel model);
/**
* Config options to display in generic admin console page for federated
*
* @return
*/
Set<String> getConfigurationOptions();
/**
* This is the name of the provider and will be showed in the admin console as an option.
*
* @return
*/
@Override
String getId();
/**
* This method is never called and is only an artifact of ProviderFactory. Returning null with no implementation is recommended.
* @param session
* @return
*/
@Override
StorageProvider create(KeycloakSession session);
}

View file

@ -0,0 +1,89 @@
/*
* 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;
import java.io.Serializable;
import java.util.HashMap;
import java.util.Map;
/**
* Stored configuration of a User Storage provider instance.
*
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
* @author <a href="mailto:bburke@redhat.com">Bill Burke</a>
*/
public class StorageProviderModel implements Serializable {
private String id;
private String providerName;
private Map<String, String> config = new HashMap<String, String>();
private int priority;
private String displayName;
public StorageProviderModel() {}
public StorageProviderModel(String id, String providerName, Map<String, String> config, int priority, String displayName) {
this.id = id;
this.providerName = providerName;
if (config != null) {
this.config.putAll(config);
}
this.priority = priority;
this.displayName = displayName;
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getProviderName() {
return providerName;
}
public void setProviderName(String providerName) {
this.providerName = providerName;
}
public Map<String, String> getConfig() {
return config;
}
public void setConfig(Map<String, String> config) {
this.config = config;
}
public int getPriority() {
return priority;
}
public void setPriority(int priority) {
this.priority = priority;
}
public String getDisplayName() {
return displayName;
}
public void setDisplayName(String displayName) {
this.displayName = displayName;
}
}

View file

@ -0,0 +1,49 @@
/*
* 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;
import org.keycloak.provider.Provider;
import org.keycloak.provider.ProviderFactory;
import org.keycloak.provider.Spi;
/**
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
*/
public class StorageProviderSpi implements Spi {
@Override
public boolean isInternal() {
return true;
}
@Override
public String getName() {
return "userFederation";
}
@Override
public Class<? extends Provider> getProviderClass() {
return StorageProvider.class;
}
@Override
public Class<? extends ProviderFactory> getProviderFactoryClass() {
return StorageProviderFactory.class;
}
}

View file

@ -0,0 +1,549 @@
/*
* 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;
import org.jboss.logging.Logger;
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.ModelException;
import org.keycloak.models.ProtocolMapperModel;
import org.keycloak.models.RealmModel;
import org.keycloak.models.RoleModel;
import org.keycloak.models.UserConsentModel;
import org.keycloak.models.UserCredentialAuthenticationProvider;
import org.keycloak.models.UserCredentialModel;
import org.keycloak.models.UserCredentialValidatorProvider;
import org.keycloak.models.UserCredentialValueModel;
import org.keycloak.models.UserFederationProviderModel;
import org.keycloak.models.UserLookupProvider;
import org.keycloak.models.UserModel;
import org.keycloak.models.UserProvider;
import org.keycloak.models.UserQueryProvider;
import org.keycloak.models.UserUpdateProvider;
import org.keycloak.models.utils.CredentialValidation;
import org.keycloak.storage.federated.UserFederatedStorageProvider;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;
/**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $
*/
public class UserStorageManager implements UserProvider {
private static final Logger logger = Logger.getLogger(UserStorageManager.class);
protected KeycloakSession session;
// Set of already validated/proxied federation users during this session. Key is user ID
private Map<String, UserModel> managedUsers = new HashMap<>();
private UserProvider localStorage = null;
public UserStorageManager(KeycloakSession session) {
this.session = session;
}
protected UserProvider localStorage() {
return session.userLocalStorage();
}
protected List<StorageProviderModel> getStorageProviders(RealmModel realm) {
return realm.getStorageProviders();
}
protected <T> T getFirstStorageProvider(RealmModel realm, Class<T> type) {
for (StorageProviderModel model : getStorageProviders(realm)) {
StorageProviderFactory factory = (StorageProviderFactory)session.getKeycloakSessionFactory().getProviderFactory(StorageProvider.class, model.getProviderName());
if (factory.supports(type)) {
return type.cast(factory.getInstance(session, model));
}
}
return null;
}
protected <T> List<T> getStorageProviders(RealmModel realm, Class<T> type) {
List<T> list = new LinkedList<>();
for (StorageProviderModel model : getStorageProviders(realm)) {
StorageProviderFactory factory = (StorageProviderFactory) session.getKeycloakSessionFactory().getProviderFactory(StorageProvider.class, model.getProviderName());
if (factory.supports(type)) {
list.add(type.cast(factory.getInstance(session, model)));
}
}
return list;
}
@Override
public UserModel addUser(RealmModel realm, String id, String username, boolean addDefaultRoles, boolean addDefaultRequiredActions) {
UserUpdateProvider registry = getFirstStorageProvider(realm, UserUpdateProvider.class);
if (registry != null) {
return registry.addUser(realm, id, username, addDefaultRoles, addDefaultRequiredActions);
}
return localStorage().addUser(realm, id, username.toLowerCase(), addDefaultRoles, addDefaultRequiredActions);
}
@Override
public UserModel addUser(RealmModel realm, String username) {
UserUpdateProvider registry = getFirstStorageProvider(realm, UserUpdateProvider.class);
if (registry != null) {
return registry.addUser(realm, username);
}
return localStorage().addUser(realm, username.toLowerCase());
}
public StorageProvider getStorageProvider(StorageProviderModel model) {
StorageProviderFactory factory = (StorageProviderFactory)session.getKeycloakSessionFactory().getProviderFactory(StorageProvider.class, model.getProviderName());
return factory.getInstance(session, model);
}
public StorageProvider getStorageProvider(RealmModel realm, String providerId) {
StorageProviderModel model = realm.getStorageProvider(providerId);
if (model == null) return null;
StorageProviderFactory factory = (StorageProviderFactory)session.getKeycloakSessionFactory().getProviderFactory(StorageProvider.class, model.getProviderName());
if (factory == null) {
throw new ModelException("Could not find StorageProviderFactory for: " + model.getProviderName());
}
return factory.getInstance(session, model);
}
@Override
public boolean removeUser(RealmModel realm, UserModel user) {
StorageId storageId = new StorageId(user.getId());
if (storageId.getProviderId() == null) {
return localStorage().removeUser(realm, user);
}
UserUpdateProvider registry = (UserUpdateProvider)getStorageProvider(realm, storageId.getProviderId());
if (registry == null) {
throw new ModelException("Could not resolve StorageProvider: " + storageId.getProviderId());
}
return registry.removeUser(realm, user);
}
public UserFederatedStorageProvider getFederatedStorage() {
return session.userFederatedStorage();
}
@Override
public void addFederatedIdentity(RealmModel realm, UserModel user, FederatedIdentityModel socialLink) {
getFederatedStorage().addFederatedIdentity(realm, user, socialLink);
}
public void updateFederatedIdentity(RealmModel realm, UserModel federatedUser, FederatedIdentityModel federatedIdentityModel) {
getFederatedStorage().updateFederatedIdentity(realm, federatedUser, federatedIdentityModel);
}
@Override
public boolean removeFederatedIdentity(RealmModel realm, UserModel user, String socialProvider) {
return getFederatedStorage().removeFederatedIdentity(realm, user, socialProvider);
}
@Override
public void addConsent(RealmModel realm, UserModel user, UserConsentModel consent) {
getFederatedStorage().addConsent(realm, user, consent);
}
@Override
public UserConsentModel getConsentByClient(RealmModel realm, UserModel user, String clientInternalId) {
return getFederatedStorage().getConsentByClient(realm, user, clientInternalId);
}
@Override
public List<UserConsentModel> getConsents(RealmModel realm, UserModel user) {
return getFederatedStorage().getConsents(realm, user);
}
@Override
public void updateConsent(RealmModel realm, UserModel user, UserConsentModel consent) {
getFederatedStorage().updateConsent(realm, user, consent);
}
@Override
public boolean revokeConsentForClient(RealmModel realm, UserModel user, String clientInternalId) {
return getFederatedStorage().revokeConsentForClient(realm, user, clientInternalId);
}
@Override
public UserModel getUserById(String id, RealmModel realm) {
StorageId storageId = new StorageId(id);
if (storageId.getProviderId() == null) {
return localStorage().getUserById(id, realm);
}
UserLookupProvider provider = (UserLookupProvider)getStorageProvider(realm, storageId.getProviderId());
return provider.getUserById(id, realm);
}
@Override
public List<UserModel> getGroupMembers(RealmModel realm, GroupModel group) {
return getGroupMembers(realm, group, -1, -1);
}
@Override
public UserModel getUserByUsername(String username, RealmModel realm) {
UserModel user = localStorage().getUserByUsername(username, realm);
if (user != null) return user;
for (UserLookupProvider provider : getStorageProviders(realm, UserLookupProvider.class)) {
user = provider.getUserByUsername(username, realm);
if (user != null) return user;
}
return null;
}
@Override
public UserModel getUserByEmail(String email, RealmModel realm) {
UserModel user = localStorage().getUserByEmail(email, realm);
if (user != null) return user;
for (UserLookupProvider provider : getStorageProviders(realm, UserLookupProvider.class)) {
user = provider.getUserByEmail(email, realm);
if (user != null) return user;
}
return null;
}
@Override
public UserModel getUserByFederatedIdentity(FederatedIdentityModel socialLink, RealmModel realm) {
UserModel user = localStorage().getUserByFederatedIdentity(socialLink, realm);
if (user != null) {
return user;
}
String id = getFederatedStorage().getUserByFederatedIdentity(socialLink, realm);
if (id != null) return getUserById(id, realm);
return null;
}
@Override
public UserModel getServiceAccount(ClientModel client) {
return localStorage().getServiceAccount(client);
}
@Override
public List<UserModel> getUsers(RealmModel realm, boolean includeServiceAccounts) {
return getUsers(realm, 0, Integer.MAX_VALUE - 1, includeServiceAccounts);
}
@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 int getUsersCount(RealmModel realm) {
int size = localStorage().getUsersCount(realm);
for (UserQueryProvider provider : getStorageProviders(realm, UserQueryProvider.class)) {
size += provider.getUsersCount(realm);
}
return size;
}
interface PaginatedQuery {
List<UserModel> query(UserQueryProvider provider, int first, int max);
}
protected List<UserModel> query(PaginatedQuery pagedQuery, RealmModel realm, int firstResult, int maxResults) {
List<UserModel> results = new LinkedList<UserModel>();
if (maxResults == 0) return results;
List<UserQueryProvider> storageProviders = getStorageProviders(realm, UserQueryProvider.class);
LinkedList<UserQueryProvider> providers = new LinkedList<>();
if (providers.isEmpty()) {
return pagedQuery.query(localStorage(), firstResult, maxResults);
}
providers.add(localStorage());
providers.addAll(storageProviders);
int leftToRead = maxResults;
int leftToFirstResult = firstResult;
Iterator<UserQueryProvider> it = providers.iterator();
while (it.hasNext() && leftToRead != 0) {
UserQueryProvider provider = it.next();
boolean exhausted = false;
int index = 0;
if (leftToFirstResult > 0) {
do {
int toRead = Math.min(50, leftToFirstResult);
List<UserModel> tmp = pagedQuery.query(provider, index, toRead);
leftToFirstResult -= tmp.size();
index += tmp.size();
if (tmp.size() < toRead) {
exhausted = true;
break;
}
} while (leftToFirstResult > 0);
}
if (exhausted) continue;
List<UserModel> tmp = pagedQuery.query(provider, index, leftToRead);
results.addAll(tmp);
if (leftToRead > 0) leftToRead -= tmp.size();
}
return results;
}
@Override
public List<UserModel> getUsers(final RealmModel realm, int firstResult, int maxResults, final boolean includeServiceAccounts) {
return query(new PaginatedQuery() {
@Override
public List<UserModel> query(UserQueryProvider provider, int first, int max) {
if (provider instanceof UserProvider) { // it is local storage
return ((UserProvider)provider).getUsers(realm, first, max, includeServiceAccounts);
}
return provider.getUsers(realm, first, max);
}
}, realm, firstResult, maxResults);
}
@Override
public List<UserModel> searchForUser(String search, RealmModel realm) {
return searchForUser(search, realm, 0, Integer.MAX_VALUE - 1);
}
@Override
public List<UserModel> searchForUser(final String search, final RealmModel realm, int firstResult, int maxResults) {
final Map<String, String> attributes = new HashMap<String, String>();
int spaceIndex = search.lastIndexOf(' ');
if (spaceIndex > -1) {
String firstName = search.substring(0, spaceIndex).trim();
String lastName = search.substring(spaceIndex).trim();
attributes.put(UserModel.FIRST_NAME, firstName);
attributes.put(UserModel.LAST_NAME, lastName);
} else if (search.indexOf('@') > -1) {
attributes.put(UserModel.USERNAME, search.trim().toLowerCase());
attributes.put(UserModel.EMAIL, search.trim().toLowerCase());
} else {
attributes.put(UserModel.LAST_NAME, search.trim());
attributes.put(UserModel.USERNAME, search.trim().toLowerCase());
}
return query(new PaginatedQuery() {
@Override
public List<UserModel> query(UserQueryProvider provider, int first, int max) {
return provider.searchForUserByAttributes(attributes, realm, first, max);
}
}, realm, firstResult, maxResults);
}
@Override
public List<UserModel> searchForUserByAttributes(Map<String, String> attributes, RealmModel realm) {
return searchForUserByAttributes(attributes, realm, 0, Integer.MAX_VALUE - 1);
}
@Override
public List<UserModel> searchForUserByAttributes(final Map<String, String> attributes, final RealmModel realm, int firstResult, int maxResults) {
return query(new PaginatedQuery() {
@Override
public List<UserModel> query(UserQueryProvider provider, int first, int max) {
return provider.searchForUserByAttributes(attributes, realm, first, max);
}
}, realm, firstResult, maxResults);
}
@Override
public List<UserModel> searchForUserByUserAttribute(String attrName, String attrValue, RealmModel realm) {
Map<String, String> attributes = new HashMap<>();
attributes.put(attrName, attrValue);
return searchForUserByAttributes(attributes, realm);
}
@Override
public Set<FederatedIdentityModel> getFederatedIdentities(UserModel user, RealmModel realm) {
if (user == null) throw new IllegalStateException("Federated user no longer valid");
if (StorageId.isLocalStorage(user)) {
return localStorage().getFederatedIdentities(user, realm);
}
return getFederatedStorage().getFederatedIdentities(user, realm);
}
@Override
public FederatedIdentityModel getFederatedIdentity(UserModel user, String socialProvider, RealmModel realm) {
if (user == null) throw new IllegalStateException("Federated user no longer valid");
if (StorageId.isLocalStorage(user)) {
return localStorage().getFederatedIdentity(user, socialProvider, realm);
}
return getFederatedStorage().getFederatedIdentity(user, socialProvider, realm);
}
@Override
public void grantToAllUsers(RealmModel realm, RoleModel role) {
// not federation-aware for now
List<UserUpdateProvider> storageProviders = getStorageProviders(realm, UserUpdateProvider.class);
LinkedList<UserUpdateProvider> providers = new LinkedList<>();
providers.add(localStorage());
providers.addAll(storageProviders);
for (UserUpdateProvider provider : providers) {
provider.grantToAllUsers(realm, role);
}
}
@Override
public List<UserModel> getGroupMembers(final RealmModel realm, final GroupModel group, int firstResult, int maxResults) {
return query(new PaginatedQuery() {
@Override
public List<UserModel> query(UserQueryProvider provider, int first, int max) {
return provider.getGroupMembers(realm, group, first, max);
}
}, realm, firstResult, maxResults);
}
@Override
public void preRemove(RealmModel realm) {
localStorage().preRemove(realm);
getFederatedStorage().preRemove(realm);
for (StorageProvider provider : getStorageProviders(realm, StorageProvider.class)) {
provider.preRemove(realm);
}
}
@Override
public void preRemove(RealmModel realm, UserFederationProviderModel model) {
localStorage().preRemove(realm, model);
}
@Override
public void preRemove(RealmModel realm, GroupModel group) {
localStorage().preRemove(realm, group);
getFederatedStorage().preRemove(realm, group);
for (StorageProvider provider : getStorageProviders(realm, StorageProvider.class)) {
provider.preRemove(realm, group);
}
}
@Override
public void preRemove(RealmModel realm, RoleModel role) {
localStorage().preRemove(realm, role);
getFederatedStorage().preRemove(realm, role);
for (StorageProvider provider : getStorageProviders(realm, StorageProvider.class)) {
provider.preRemove(realm, role);
}
}
@Override
public void preRemove(RealmModel realm, ClientModel client) {
localStorage().preRemove(realm, client);
}
@Override
public void preRemove(ProtocolMapperModel protocolMapper) {
localStorage().preRemove(protocolMapper);
}
@Override
public boolean validCredentials(KeycloakSession session, RealmModel realm, UserModel user, List<UserCredentialModel> input) {
if (StorageId.isLocalStorage(user)) {
return localStorage().validCredentials(session, realm, user, input);
}
// make sure we hit the cache here!
List<UserCredentialValueModel> userCreds = user.getCredentialsDirectly();
LinkedList<UserCredentialModel> toValidate = new LinkedList<>();
toValidate.addAll(input);
Iterator<UserCredentialModel> it = toValidate.iterator();
boolean failedStoredCredential = false;
// we allow for multiple credentials of same type, i.e. multiple OTP devices
while (it.hasNext()) {
UserCredentialModel cred = it.next();
boolean credValidated = false;
for (UserCredentialValueModel userCred : userCreds) {
if (!userCred.getType().equals(cred.getType())) continue;
if (CredentialValidation.validCredential(session, realm, user, cred)) {
credValidated = true;
break;
} else {
failedStoredCredential = true;
}
}
if (credValidated) {
it.remove();
} else if (failedStoredCredential) {
return false;
}
}
if (toValidate.isEmpty()) return true;
StorageProvider provider = getStorageProvider(realm, StorageId.resolveProviderId(user));
if (!(provider instanceof UserCredentialValidatorProvider)) {
return false;
}
return ((UserCredentialValidatorProvider)provider).validCredentials(session, realm, user, toValidate);
}
@Override
public boolean validCredentials(KeycloakSession session, RealmModel realm, UserModel user, UserCredentialModel... input) {
return validCredentials(session, realm, user, Arrays.asList(input));
}
@Override
public CredentialValidationOutput validCredentials(KeycloakSession session, RealmModel realm, UserCredentialModel... input) {
List<UserCredentialAuthenticationProvider> providers = getStorageProviders(realm, UserCredentialAuthenticationProvider.class);
if (providers.isEmpty()) return CredentialValidationOutput.failed();
CredentialValidationOutput result = null;
for (UserCredentialModel cred : input) {
UserCredentialAuthenticationProvider providerSupportingCreds = null;
// Find first provider, which supports required credential type
for (UserCredentialAuthenticationProvider provider : providers) {
if (provider.getSupportedCredentialAuthenticationTypes().contains(cred.getType())) {
providerSupportingCreds = provider;
break;
}
}
if (providerSupportingCreds == null) {
logger.warn("Don't have provider supporting credentials of type " + cred.getType());
return CredentialValidationOutput.failed();
}
logger.debug("Found provider [" + providerSupportingCreds + "] supporting credentials of type " + cred.getType());
CredentialValidationOutput currentResult = providerSupportingCreds.validCredential(session, realm, cred);
result = (result == null) ? currentResult : result.merge(currentResult);
}
// For now, validCredentials(realm, input) is not supported for local userProviders
return (result != null) ? result : CredentialValidationOutput.failed();
}
@Override
public void preRemove(RealmModel realm, StorageProviderModel link) {
}
@Override
public void close() {
}
}

View file

@ -0,0 +1,28 @@
/*
* 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;
import org.keycloak.models.RealmModel;
/**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $
*/
public interface UserStorageProvider {
void preRemove(RealmModel realm);
}

View file

@ -0,0 +1,162 @@
/*
* 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.adapter;
import org.keycloak.models.ClientModel;
import org.keycloak.models.GroupModel;
import org.keycloak.models.KeycloakSession;
import org.keycloak.models.RealmModel;
import org.keycloak.models.RoleModel;
import org.keycloak.models.UserCredentialModel;
import org.keycloak.models.UserCredentialValueModel;
import org.keycloak.models.UserModel;
import org.keycloak.storage.federated.UserFederatedStorageProvider;
import java.util.List;
import java.util.Map;
import java.util.Set;
/**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $
*/
public abstract class AbstractUserAdapter implements UserModel {
protected KeycloakSession session;
protected RealmModel realm;
public UserFederatedStorageProvider getFederatedStorage() {
return null;
}
@Override
public Set<String> getRequiredActions() {
return getFederatedStorage().getRequiredActions(realm, this);
}
@Override
public void addRequiredAction(String action) {
getFederatedStorage().addRequiredAction(realm, this, action);
}
@Override
public void removeRequiredAction(String action) {
getFederatedStorage().removeRequiredAction(realm, this, action);
}
@Override
public void addRequiredAction(RequiredAction action) {
getFederatedStorage().addRequiredAction(realm, this, action.name());
}
@Override
public void removeRequiredAction(RequiredAction action) {
getFederatedStorage().removeRequiredAction(realm, this, action.name());
}
@Override
public Set<GroupModel> getGroups() {
return null;
}
@Override
public void joinGroup(GroupModel group) {
}
@Override
public void leaveGroup(GroupModel group) {
}
@Override
public boolean isMemberOf(GroupModel group) {
return false;
}
@Override
public String getFederationLink() {
return null;
}
@Override
public void setFederationLink(String link) {
}
@Override
public String getServiceAccountClientLink() {
return null;
}
@Override
public void setServiceAccountClientLink(String clientInternalId) {
}
@Override
public Set<RoleModel> getRealmRoleMappings() {
return null;
}
@Override
public Set<RoleModel> getClientRoleMappings(ClientModel app) {
return null;
}
@Override
public boolean hasRole(RoleModel role) {
return false;
}
@Override
public void grantRole(RoleModel role) {
}
@Override
public Set<RoleModel> getRoleMappings() {
return null;
}
@Override
public void deleteRoleMapping(RoleModel role) {
}
@Override
public boolean isEnabled() {
return false;
}
@Override
public void setEnabled(boolean enabled) {
}
@Override
public boolean isOtpEnabled() {
return false;
}
@Override
public void setOtpEnabled(boolean totp) {
}
}

View file

@ -0,0 +1,387 @@
/*
* 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.changeset;
import org.keycloak.common.util.MultivaluedHashMap;
import org.keycloak.models.UserCredentialValueModel;
import org.keycloak.models.entities.AbstractIdentifiableEntity;
import java.util.Collections;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;
/**
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
*/
public class UserData {
private String id;
private boolean idChanged;
private String username;
private boolean usernameChanged;
private Long createdTimestamp;
private boolean createdTimestampChanged;
private String firstName;
private boolean firstNameChanged;
private String lastName;
private boolean lastNameChanged;
private String email;
private boolean emailChanged;
private boolean emailVerified;
private boolean emailVerifiedChanged;
private boolean totp;
private boolean totpChanged;
private boolean enabled;
private boolean enabledChanged;
private Set<String> roleIds = new HashSet<>();
private boolean rolesChanged;
private Set<String> groupIds = new HashSet<>();
private boolean groupsChanged;
private MultivaluedHashMap<String, String> attributes = new MultivaluedHashMap<>();
private boolean attributesChanged;
private Set<String> requiredActions = new HashSet<>();
private boolean requiredActionsChanged;
private List<UserCredentialValueModel> credentials = new LinkedList<>();
private boolean credentialsChanged;
public void rememberState() {
original = new UserData();
original.id = id;
original.username = username;
original.createdTimestamp = createdTimestamp;
original.firstName = firstName;
original.lastName = lastName;
original.email = email;
original.emailVerified = emailVerified;
original.totp = totp;
original.enabled = enabled;
original.attributes.putAll(attributes);
original.requiredActions.addAll(requiredActions);
original.credentials.addAll(credentials);
}
private UserData original = null;
public void clearChangeFlags() {
original = null;
idChanged = false;
usernameChanged = false;
createdTimestampChanged = false;
firstNameChanged = false;
lastNameChanged = false;
emailChanged = false;
emailVerifiedChanged = false;
totpChanged = false;
enabledChanged = false;
rolesChanged = false;
groupsChanged = false;
attributesChanged = false;
requiredActionsChanged = false;
credentialsChanged = false;
}
public boolean isChanged() {
return !idChanged
&& !usernameChanged
&& !createdTimestampChanged
&& !firstNameChanged
&& !lastNameChanged
&& !emailChanged
&& !emailVerifiedChanged
&& !totpChanged
&& !enabledChanged
&& !rolesChanged
&& !groupsChanged
&& !attributesChanged
&& !requiredActionsChanged
&& !credentialsChanged;
}
public boolean isIdChanged() {
return idChanged;
}
public boolean isUsernameChanged() {
return usernameChanged;
}
public boolean isCreatedTimestampChanged() {
return createdTimestampChanged;
}
public boolean isFirstNameChanged() {
return firstNameChanged;
}
public boolean isLastNameChanged() {
return lastNameChanged;
}
public boolean isEmailChanged() {
return emailChanged;
}
public boolean isEmailVerifiedChanged() {
return emailVerifiedChanged;
}
public boolean isTotpChanged() {
return totpChanged;
}
public boolean isEnabledChanged() {
return enabledChanged;
}
public boolean isRolesChanged() {
return rolesChanged;
}
public boolean isGroupsChanged() {
return groupsChanged;
}
public boolean isAttributesChanged() {
return attributesChanged;
}
public boolean isRequiredActionsChanged() {
return requiredActionsChanged;
}
public boolean isCredentialsChanged() {
return credentialsChanged;
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
idChanged = true;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
usernameChanged = true;
}
public Long getCreatedTimestamp() {
return createdTimestamp;
}
public void setCreatedTimestamp(Long timestamp) {
this.createdTimestamp = timestamp;
createdTimestampChanged = true;
}
public String getFirstName() {
return firstName;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
firstNameChanged = true;
}
public String getLastName() {
return lastName;
}
public void setLastName(String lastName) {
this.lastName = lastName;
lastNameChanged = true;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
emailChanged = true;
}
public boolean isEmailVerified() {
return emailVerified;
}
public void setEmailVerified(boolean emailVerified) {
this.emailVerified = emailVerified;
emailVerifiedChanged = true;
}
public boolean isTotp() {
return totp;
}
public void setTotp(boolean totp) {
this.totp = totp;
totpChanged = true;
}
public boolean isEnabled() {
return enabled;
}
public void setEnabled(boolean enabled) {
this.enabled = enabled;
enabledChanged = true;
}
public Set<String> getRoleMappings() {
return Collections.unmodifiableSet(roleIds);
}
public void grantRole(String roleId) {
if (roleIds.contains(roleId)) return;
roleIds.add(roleId);
rolesChanged = true;
}
public void deleteRoleMapping(String roleId) {
if (!roleIds.contains(roleId)) return;
roleIds.remove(roleId);
rolesChanged = true;
}
public MultivaluedHashMap<String, String> getAttributes() {
return attributes;
}
public void setSingleAttribute(String name, String value) {
attributes.putSingle(name, value);
attributesChanged = true;
}
public void setAttribute(String name, List<String> values) {
attributes.put(name, values);
attributesChanged = true;
}
public void removeAttribute(String name) {
attributes.remove(name);
attributesChanged = true;
}
public Set<String> getRequiredActions() {
return Collections.unmodifiableSet(requiredActions);
}
public void addRequiredAction(String action) {
if (requiredActions.contains(action)) return;
requiredActions.add(action);
requiredActionsChanged = true;
}
public void removeRequiredAction(String action) {
if (!requiredActions.contains(action)) return;
requiredActions.remove(action);
requiredActionsChanged = true;
}
public List<UserCredentialValueModel> getCredentials() {
return Collections.unmodifiableList(credentials);
}
public void removeCredentialType(String type) {
Iterator<UserCredentialValueModel> it = credentials.iterator();
while (it.hasNext()) {
if (it.next().getType().equals(type)) {
it.remove();
credentialsChanged = true;
}
}
}
public void removeCredentialDevice(String type, String device) {
Iterator<UserCredentialValueModel> it = credentials.iterator();
while (it.hasNext()) {
UserCredentialValueModel next = it.next();
if (next.getType().equals(type) && next.getDevice().equals(device)) {
it.remove();
credentialsChanged = true;
}
}
}
public void setCredential(UserCredentialValueModel cred) {
removeCredentialType(cred.getType());
addCredential(cred);
}
public void addCredential(UserCredentialValueModel cred) {
credentials.add(cred);
credentialsChanged = true;
}
public Set<String> getGroupIds() {
return Collections.unmodifiableSet(groupIds);
}
public void joinGroup(String groupId) {
if (groupIds.contains(groupId)) return;
groupIds.add(groupId);
groupsChanged = true;
}
public void leaveGroup(String groupId) {
if (!groupIds.contains(groupId)) return;
groupIds.remove(groupId);
groupsChanged = true;
}
@Override
public boolean equals(Object o) {
if (o == this) return true;
if (this.id == null) return false;
if (o == null || getClass() != o.getClass()) return false;
AbstractIdentifiableEntity that = (AbstractIdentifiableEntity) o;
if (!getId().equals(that.getId())) return false;
return true;
}
@Override
public int hashCode() {
return id!=null ? id.hashCode() : super.hashCode();
}
@Override
public String toString() {
return String.format("%s [ id=%s ]", getClass().getSimpleName(), getId());
}
}

View file

@ -0,0 +1,340 @@
/*
* 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.changeset;
import org.keycloak.common.util.Time;
import org.keycloak.hash.PasswordHashManager;
import org.keycloak.models.ClientModel;
import org.keycloak.models.GroupModel;
import org.keycloak.models.KeycloakSession;
import org.keycloak.models.OTPPolicy;
import org.keycloak.models.PasswordPolicy;
import org.keycloak.models.RealmModel;
import org.keycloak.models.RoleContainerModel;
import org.keycloak.models.RoleModel;
import org.keycloak.models.UserCredentialModel;
import org.keycloak.models.UserCredentialValueModel;
import org.keycloak.models.UserModel;
import org.keycloak.models.utils.KeycloakModelUtils;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;
/**
*
*
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $
*/
public class UserDataAdapter implements UserModel {
protected UserData userData;
protected RealmModel realm;
protected KeycloakSession session;
protected Set<String> managedCredentialTypes;
protected List<UserCredentialModel> updatedManagedCredentials = new LinkedList<>();
public UserDataAdapter(KeycloakSession session, RealmModel realm, UserData userData) {
this.session = session;
this.realm = realm;
this.userData = userData;
this.userData.rememberState();
}
@Override
public String getId() {
return userData.getId();
}
@Override
public String getUsername() {
return userData.getUsername();
}
@Override
public void setUsername(String username) {
userData.setUsername(username);
}
@Override
public Long getCreatedTimestamp() {
return userData.getCreatedTimestamp();
}
@Override
public void setCreatedTimestamp(Long timestamp) {
userData.setCreatedTimestamp(timestamp);
}
@Override
public boolean isEnabled() {
return userData.isEnabled();
}
@Override
public boolean isOtpEnabled() {
return userData.isTotp();
}
@Override
public void setEnabled(boolean enabled) {
userData.setEnabled(enabled);
}
@Override
public void setSingleAttribute(String name, String value) {
userData.setSingleAttribute(name, value);
}
@Override
public void setAttribute(String name, List<String> values) {
userData.setAttribute(name, values);
}
@Override
public void removeAttribute(String name) {
userData.removeAttribute(name);
}
@Override
public String getFirstAttribute(String name) {
return userData.getAttributes().getFirst(name);
}
@Override
public List<String> getAttribute(String name) {
return userData.getAttributes().get(name);
}
@Override
public Map<String, List<String>> getAttributes() {
return userData.getAttributes();
}
@Override
public Set<String> getRequiredActions() {
return userData.getRequiredActions();
}
@Override
public void addRequiredAction(String action) {
userData.addRequiredAction(action);
}
@Override
public void removeRequiredAction(String action) {
userData.removeRequiredAction(action);
}
@Override
public void addRequiredAction(RequiredAction action) {
userData.addRequiredAction(action.name());
}
@Override
public void removeRequiredAction(RequiredAction action) {
userData.removeRequiredAction(action.name());
}
@Override
public String getFirstName() {
return userData.getFirstName();
}
@Override
public void setFirstName(String firstName) {
userData.setFirstName(firstName);
}
@Override
public String getLastName() {
return userData.getLastName();
}
@Override
public void setLastName(String lastName) {
userData.setLastName(lastName);
}
@Override
public String getEmail() {
return userData.getEmail();
}
@Override
public void setEmail(String email) {
userData.setEmail(email);
}
@Override
public boolean isEmailVerified() {
return userData.isEmailVerified();
}
@Override
public void setEmailVerified(boolean verified) {
userData.setEmailVerified(verified);
}
@Override
public void setOtpEnabled(boolean totp) {
userData.setTotp(totp);
}
@Override
public void updateCredential(UserCredentialModel cred) {
}
@Override
public List<UserCredentialValueModel> getCredentialsDirectly() {
return null;
}
@Override
public void updateCredentialDirectly(UserCredentialValueModel cred) {
}
@Override
public Set<GroupModel> getGroups() {
Set<String> groups = userData.getGroupIds();
Set<GroupModel> set = new HashSet<>();
for (String id : groups) {
GroupModel group = realm.getGroupById(id);
if (group != null) set.add(group);
}
return set;
}
@Override
public void joinGroup(GroupModel group) {
userData.joinGroup(group.getId());
}
@Override
public void leaveGroup(GroupModel group) {
userData.leaveGroup(group.getId());
}
@Override
public boolean isMemberOf(GroupModel group) {
Set<GroupModel> roles = getGroups();
return KeycloakModelUtils.isMember(roles, group);
}
@Override
public String getFederationLink() {
return null;
}
@Override
public void setFederationLink(String link) {
}
@Override
public String getServiceAccountClientLink() {
return null;
}
@Override
public void setServiceAccountClientLink(String clientInternalId) {
}
@Override
public Set<RoleModel> getRealmRoleMappings() {
Set<RoleModel> roleMappings = getRoleMappings();
Set<RoleModel> realmRoles = new HashSet<RoleModel>();
for (RoleModel role : roleMappings) {
RoleContainerModel container = role.getContainer();
if (container instanceof RealmModel) {
realmRoles.add(role);
}
}
return realmRoles;
}
@Override
public Set<RoleModel> getClientRoleMappings(ClientModel app) {
Set<RoleModel> roleMappings = getRoleMappings();
Set<RoleModel> roles = new HashSet<RoleModel>();
for (RoleModel role : roleMappings) {
RoleContainerModel container = role.getContainer();
if (container instanceof ClientModel) {
ClientModel appModel = (ClientModel)container;
if (appModel.getId().equals(app.getId())) {
roles.add(role);
}
}
}
return roles;
}
@Override
public boolean hasRole(RoleModel role) {
Set<RoleModel> roles = getRoleMappings();
return KeycloakModelUtils.hasRole(roles, role);
}
@Override
public void grantRole(RoleModel role) {
userData.grantRole(role.getId());
}
@Override
public Set<RoleModel> getRoleMappings() {
Set<String> roles = userData.getRoleMappings();
Set<RoleModel> set = new HashSet<>();
for (String id : roles) {
RoleModel role = realm.getRoleById(id);
if (role != null) set.add(role);
}
return set;
}
@Override
public void deleteRoleMapping(RoleModel role) {
userData.deleteRoleMapping(role.getId());
}
}

View file

@ -0,0 +1,33 @@
/*
* 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.changeset;
import org.keycloak.models.KeycloakSession;
import org.keycloak.models.RealmModel;
import org.keycloak.models.UserCredentialModel;
import org.keycloak.models.UserModel;
import java.util.List;
/**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $
*/
public interface UserDataCredentialValidator {
boolean validCredentials(KeycloakSession session, RealmModel realm, UserModel user, List<UserCredentialModel> input);
boolean validCredentials(KeycloakSession session, RealmModel realm, UserModel user, UserCredentialModel... input);
}

View file

@ -0,0 +1,31 @@
/*
* 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.changeset;
import org.keycloak.models.RealmModel;
import org.keycloak.models.entities.UserEntity;
import org.keycloak.storage.StorageId;
/**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $
*/
public interface UserDataLookup {
UserData getUserById(RealmModel realm, StorageId id);
UserData getUserByUsername(RealmModel realm, String username);
UserData getUserByEmail(RealmModel realm, String email);
}

View file

@ -0,0 +1,46 @@
/*
* 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.changeset;
import org.keycloak.models.RealmModel;
import org.keycloak.models.entities.UserEntity;
import java.util.List;
import java.util.Map;
/**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $
*/
public interface UserDataQuery {
// Service account is included for counts
int getUsersCount(RealmModel realm);
List<UserData> getUsers(RealmModel realm);
List<UserData> searchForUser(String search, RealmModel realm);
List<UserData> searchForUserByAttributes(Map<String, String> attributes, RealmModel realm);
List<UserData> getUsers(RealmModel realm, int firstResult, int maxResults);
List<UserData> searchForUser(String search, RealmModel realm, int firstResult, int maxResults);
List<UserData> searchForUserByAttributes(Map<String, String> attributes, RealmModel realm, int firstResult, int maxResults);
// Searching by UserModel.attribute (not property)
List<UserData> searchForUserByUserAttribute(String attrName, String attrValue, RealmModel realm);
}

View file

@ -0,0 +1,32 @@
/*
* 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.changeset;
import org.keycloak.models.RealmModel;
import org.keycloak.models.UserModel;
import org.keycloak.models.entities.UserEntity;
import org.keycloak.storage.StorageId;
/**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $
*/
public interface UserDataStore {
void updateUser(RealmModel realm, UserData user);
void addUser(RealmModel realm, UserData user);
boolean removeUser(RealmModel realm, StorageId store);
}

View file

@ -0,0 +1,341 @@
/*
* 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.changeset;
import org.jboss.logging.Logger;
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.ModelException;
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.UserFederationProviderModel;
import org.keycloak.models.UserModel;
import org.keycloak.models.UserProvider;
import org.keycloak.models.UserUpdateProvider;
import org.keycloak.storage.StorageId;
import org.keycloak.storage.StorageProvider;
import org.keycloak.storage.StorageProviderFactory;
import org.keycloak.storage.StorageProviderModel;
import org.keycloak.storage.federated.UserFederatedStorageProvider;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;
/**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $
*/
public class UserStorageManager implements UserProvider {
private static final Logger logger = Logger.getLogger(UserStorageManager.class);
protected KeycloakSession session;
// Set of already validated/proxied federation users during this session. Key is user ID
private Map<String, UserModel> managedUsers = new HashMap<>();
private UserProvider localStorage = null;
public UserStorageManager(KeycloakSession session) {
this.session = session;
}
protected UserProvider localStorage() {
if (localStorage == null) {
localStorage = session.getProvider(UserProvider.class);
}
return localStorage;
}
protected List<StorageProviderModel> getStorageProviders(RealmModel realm) {
return null;
}
protected <T> T getFirstStorageProvider(RealmModel realm, Class<T> type) {
for (StorageProviderModel model : getStorageProviders(realm)) {
StorageProviderFactory factory = (StorageProviderFactory)session.getKeycloakSessionFactory().getProviderFactory(StorageProvider.class, model.getProviderName());
if (factory.supports(type)) {
return type.cast(factory.getInstance(session, model));
}
}
return null;
}
protected <T> List<T> getStorageProviders(RealmModel realm, Class<T> type) {
List<T> list = new LinkedList<>();
for (StorageProviderModel model : getStorageProviders(realm)) {
StorageProviderFactory factory = (StorageProviderFactory) session.getKeycloakSessionFactory().getProviderFactory(StorageProvider.class, model.getProviderName());
if (factory.supports(type)) {
list.add(type.cast(factory.getInstance(session, model)));
}
}
return list;
}
@Override
public UserModel addUser(RealmModel realm, String id, String username, boolean addDefaultRoles, boolean addDefaultRequiredActions) {
UserDataStore store = getFirstStorageProvider(realm, UserDataStore.class);
if (store != null) {
UserData data = new UserData();
}
return localStorage().addUser(realm, id, username.toLowerCase(), addDefaultRoles, addDefaultRequiredActions);
}
@Override
public UserModel addUser(RealmModel realm, String username) {
UserUpdateProvider registry = getFirstStorageProvider(realm, UserUpdateProvider.class);
if (registry != null) {
return registry.addUser(realm, username);
}
return localStorage().addUser(realm, username.toLowerCase());
}
public StorageProvider getStorageProvider(StorageProviderModel model) {
StorageProviderFactory factory = (StorageProviderFactory)session.getKeycloakSessionFactory().getProviderFactory(StorageProvider.class, model.getProviderName());
return factory.getInstance(session, model);
}
public StorageProvider getStorageProvider(String providerId) {
return null;
}
@Override
public boolean removeUser(RealmModel realm, UserModel user) {
StorageId storageId = new StorageId(user.getId());
if (storageId.getProviderId() == null) {
return localStorage().removeUser(realm, user);
}
UserUpdateProvider registry = (UserUpdateProvider)getStorageProvider(storageId.getProviderId());
if (registry == null) {
throw new ModelException("Could not resolve StorageProvider: " + storageId.getProviderId());
}
return registry.removeUser(realm, user);
}
public UserFederatedStorageProvider getFederatedStorage() {
return null;
}
@Override
public void addFederatedIdentity(RealmModel realm, UserModel user, FederatedIdentityModel socialLink) {
getFederatedStorage().addFederatedIdentity(realm, user, socialLink);
}
public void updateFederatedIdentity(RealmModel realm, UserModel federatedUser, FederatedIdentityModel federatedIdentityModel) {
getFederatedStorage().updateFederatedIdentity(realm, federatedUser, federatedIdentityModel);
}
@Override
public boolean removeFederatedIdentity(RealmModel realm, UserModel user, String socialProvider) {
return getFederatedStorage().removeFederatedIdentity(realm, user, socialProvider);
}
@Override
public void addConsent(RealmModel realm, UserModel user, UserConsentModel consent) {
getFederatedStorage().addConsent(realm, user, consent);
}
@Override
public UserConsentModel getConsentByClient(RealmModel realm, UserModel user, String clientInternalId) {
return getFederatedStorage().getConsentByClient(realm, user, clientInternalId);
}
@Override
public List<UserConsentModel> getConsents(RealmModel realm, UserModel user) {
return getFederatedStorage().getConsents(realm, user);
}
@Override
public void updateConsent(RealmModel realm, UserModel user, UserConsentModel consent) {
getFederatedStorage().updateConsent(realm, user, consent);
}
@Override
public boolean revokeConsentForClient(RealmModel realm, UserModel user, String clientInternalId) {
return getFederatedStorage().revokeConsentForClient(realm, user, clientInternalId);
}
@Override
public Set<FederatedIdentityModel> getFederatedIdentities(UserModel user, RealmModel realm) {
return null;
}
@Override
public FederatedIdentityModel getFederatedIdentity(UserModel user, String socialProvider, RealmModel realm) {
return null;
}
@Override
public UserModel getUserByFederatedIdentity(FederatedIdentityModel socialLink, RealmModel realm) {
return null;
}
@Override
public List<UserModel> getGroupMembers(RealmModel realm, GroupModel group, int firstResult, int maxResults) {
return null;
}
@Override
public List<UserModel> getGroupMembers(RealmModel realm, GroupModel group) {
return null;
}
@Override
public UserModel getServiceAccount(ClientModel client) {
return null;
}
@Override
public List<UserModel> getUsers(RealmModel realm, boolean includeServiceAccounts) {
return null;
}
@Override
public List<UserModel> getUsers(RealmModel realm, int firstResult, int maxResults, boolean includeServiceAccounts) {
return null;
}
@Override
public void grantToAllUsers(RealmModel realm, RoleModel role) {
}
@Override
public void preRemove(RealmModel realm) {
}
@Override
public void preRemove(RealmModel realm, UserFederationProviderModel link) {
}
@Override
public void preRemove(RealmModel realm, RoleModel role) {
}
@Override
public void preRemove(RealmModel realm, GroupModel group) {
}
@Override
public void preRemove(RealmModel realm, ClientModel client) {
}
@Override
public void preRemove(ProtocolMapperModel protocolMapper) {
}
@Override
public void preRemove(RealmModel realm, StorageProviderModel link) {
}
@Override
public CredentialValidationOutput validCredentials(KeycloakSession session, RealmModel realm, UserCredentialModel... input) {
return null;
}
@Override
public void close() {
}
@Override
public boolean validCredentials(KeycloakSession session, RealmModel realm, UserModel user, List<UserCredentialModel> input) {
return false;
}
@Override
public boolean validCredentials(KeycloakSession session, RealmModel realm, UserModel user, UserCredentialModel... input) {
return false;
}
@Override
public UserModel getUserById(String id, RealmModel realm) {
return null;
}
@Override
public UserModel getUserByUsername(String username, RealmModel realm) {
return null;
}
@Override
public UserModel getUserByEmail(String email, RealmModel realm) {
return null;
}
@Override
public int getUsersCount(RealmModel realm) {
return 0;
}
@Override
public List<UserModel> getUsers(RealmModel realm) {
return null;
}
@Override
public List<UserModel> searchForUser(String search, RealmModel realm) {
return null;
}
@Override
public List<UserModel> searchForUserByAttributes(Map<String, String> attributes, RealmModel realm) {
return null;
}
@Override
public List<UserModel> getUsers(RealmModel realm, int firstResult, int maxResults) {
return null;
}
@Override
public List<UserModel> searchForUser(String search, RealmModel realm, int firstResult, int maxResults) {
return null;
}
@Override
public List<UserModel> searchForUserByAttributes(Map<String, String> attributes, RealmModel realm, int firstResult, int maxResults) {
return null;
}
@Override
public List<UserModel> searchForUserByUserAttribute(String attrName, String attrValue, RealmModel realm) {
return null;
}
}

View file

@ -0,0 +1,24 @@
/*
* 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.federated;
/**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $
*/
public class CredentialModel {
}

View file

@ -0,0 +1,35 @@
/*
* 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.federated;
import org.keycloak.common.util.MultivaluedHashMap;
import org.keycloak.models.RealmModel;
import org.keycloak.models.UserModel;
import java.util.List;
import java.util.Map;
/**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $
*/
public interface UserAttributeFederatedStorage {
void setSingleAttribute(RealmModel realm, UserModel user, String name, String value);
void setAttribute(RealmModel realm, UserModel user, String name, List<String> values);
void removeAttribute(RealmModel realm, UserModel user, String name);
MultivaluedHashMap<String, String> getAttributes(RealmModel realm, UserModel user);
}

View file

@ -0,0 +1,36 @@
/*
* 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.federated;
import org.keycloak.models.FederatedIdentityModel;
import org.keycloak.models.RealmModel;
import org.keycloak.models.UserModel;
import java.util.Set;
/**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $
*/
public interface UserBrokerLinkFederatedStorage {
String getUserByFederatedIdentity(FederatedIdentityModel socialLink, RealmModel realm);
public void addFederatedIdentity(RealmModel realm, UserModel user, FederatedIdentityModel socialLink);
public boolean removeFederatedIdentity(RealmModel realm, UserModel user, String socialProvider);
void updateFederatedIdentity(RealmModel realm, UserModel federatedUser, FederatedIdentityModel federatedIdentityModel);
Set<FederatedIdentityModel> getFederatedIdentities(UserModel user, RealmModel realm);
FederatedIdentityModel getFederatedIdentity(UserModel user, String socialProvider, RealmModel realm);
}

View file

@ -0,0 +1,35 @@
/*
* 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.federated;
import org.keycloak.models.RealmModel;
import org.keycloak.models.UserConsentModel;
import org.keycloak.models.UserModel;
import java.util.List;
/**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $
*/
public interface UserConsentFederatedStorage {
void addConsent(RealmModel realm, UserModel user, UserConsentModel consent);
UserConsentModel getConsentByClient(RealmModel realm, UserModel user, String clientInternalId);
List<UserConsentModel> getConsents(RealmModel realm, UserModel user);
void updateConsent(RealmModel realm, UserModel user, UserConsentModel consent);
boolean revokeConsentForClient(RealmModel realm, UserModel user, String clientInternalId);
}

View file

@ -0,0 +1,35 @@
/*
* 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.federated;
import org.keycloak.models.RealmModel;
import org.keycloak.models.UserCredentialModel;
import org.keycloak.models.UserCredentialValueModel;
import org.keycloak.models.UserModel;
import java.util.List;
/**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $
*/
public interface UserCredentialsFederatedStorage {
void updateCredential(RealmModel realm, UserModel user, UserCredentialModel cred);
void updateCredential(RealmModel realm, UserModel user, UserCredentialValueModel cred);
void removeCredential(RealmModel realm, UserModel user, UserCredentialValueModel cred);
List<UserCredentialValueModel> getCredentials(RealmModel realm, UserModel user);
}

View file

@ -0,0 +1,58 @@
/*
* 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.federated;
import org.keycloak.models.ClientModel;
import org.keycloak.models.GroupModel;
import org.keycloak.models.ProtocolMapperModel;
import org.keycloak.models.RealmModel;
import org.keycloak.models.RoleModel;
import org.keycloak.models.UserFederationProviderModel;
import org.keycloak.models.UserModel;
import org.keycloak.provider.Provider;
import org.keycloak.storage.StorageProviderModel;
/**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $
*/
public interface UserFederatedStorageProvider extends Provider,
UserAttributeFederatedStorage,
UserBrokerLinkFederatedStorage,
UserConsentFederatedStorage,
UserCredentialsFederatedStorage,
UserGroupMembershipFederatedStorage,
UserRequiredActionsFederatedStorage,
UserRoleMappingsFederatedStorage {
void preRemove(RealmModel realm);
void preRemove(RealmModel realm, UserFederationProviderModel link);
public void preRemove(RealmModel realm, GroupModel group);
void preRemove(RealmModel realm, RoleModel role);
void preRemove(RealmModel realm, ClientModel client);
void preRemove(ProtocolMapperModel protocolMapper);
void preRemove(RealmModel realm, UserModel user);
void preRemove(RealmModel realm, StorageProviderModel model);
}

View file

@ -0,0 +1,26 @@
/*
* 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.federated;
import org.keycloak.provider.ProviderFactory;
/**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $
*/
public interface UserFederatedStorageProviderFactory extends ProviderFactory<UserFederatedStorageProvider> {
}

View file

@ -0,0 +1,51 @@
/*
* 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.federated;
import org.keycloak.provider.Provider;
import org.keycloak.provider.ProviderFactory;
import org.keycloak.provider.Spi;
import org.keycloak.storage.StorageProvider;
import org.keycloak.storage.StorageProviderFactory;
/**
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
*/
public class UserFederatedStorageProviderSpi implements Spi {
@Override
public boolean isInternal() {
return true;
}
@Override
public String getName() {
return "userFederatedStorage";
}
@Override
public Class<? extends Provider> getProviderClass() {
return UserFederatedStorageProvider.class;
}
@Override
public Class<? extends ProviderFactory> getProviderFactoryClass() {
return UserFederatedStorageProviderFactory.class;
}
}

View file

@ -0,0 +1,36 @@
/*
* 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.federated;
import org.keycloak.models.GroupModel;
import org.keycloak.models.RealmModel;
import org.keycloak.models.UserModel;
import java.util.Set;
/**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $
*/
public interface UserGroupMembershipFederatedStorage {
Set<GroupModel> getGroups(RealmModel realm, UserModel user);
void joinGroup(RealmModel realm,UserModel user, GroupModel group);
void leaveGroup(RealmModel realm,UserModel user, GroupModel group);
}

View file

@ -0,0 +1,32 @@
/*
* 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.federated;
import org.keycloak.models.RealmModel;
import org.keycloak.models.UserModel;
import java.util.Set;
/**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $
*/
public interface UserRequiredActionsFederatedStorage {
Set<String> getRequiredActions(RealmModel realm, UserModel user);
void addRequiredAction(RealmModel realm,UserModel user, String action);
void removeRequiredAction(RealmModel realm,UserModel user, String action);
}

View file

@ -0,0 +1,36 @@
/*
* 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.federated;
import org.keycloak.models.RealmModel;
import org.keycloak.models.RoleModel;
import org.keycloak.models.UserModel;
import java.util.Set;
/**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $
*/
public interface UserRoleMappingsFederatedStorage {
void grantRole(RealmModel realm,UserModel user, RoleModel role);
Set<RoleModel> getRoleMappings(RealmModel realm,UserModel user);
void deleteRoleMapping(RealmModel realm, UserModel user, RoleModel role);
}

View file

@ -16,6 +16,7 @@
#
org.keycloak.models.UserFederationSpi
org.keycloak.storage.federated.UserFederatedStorageProviderSpi
org.keycloak.mappers.UserFederationMapperSpi
org.keycloak.models.RealmSpi
org.keycloak.models.UserSessionSpi

View file

@ -319,7 +319,7 @@ public class ExportUtils {
userRep.setFederationLink(user.getFederationLink());
// Grants
List<UserConsentModel> consents = user.getConsents();
List<UserConsentModel> consents = session.users().getConsents(realm, user);
LinkedList<UserConsentRepresentation> consentReps = new LinkedList<UserConsentRepresentation>();
for (UserConsentModel consent : consents) {
UserConsentRepresentation consentRep = ModelToRepresentation.toRepresentation(consent);

View file

@ -64,7 +64,7 @@ public class ApplicationsBean {
MultivaluedHashMap<String, ClientRoleEntry> resourceRolesGranted = new MultivaluedHashMap<String, ClientRoleEntry>();
List<String> claimsGranted = new LinkedList<String>();
if (client.isConsentRequired()) {
UserConsentModel consent = user.getConsentByClient(client.getId());
UserConsentModel consent = session.users().getConsentByClient(realm, user, client.getId());
if (consent != null) {
processRoles(consent.getGrantedRoles(), realmRolesGranted, resourceRolesGranted);

View file

@ -420,13 +420,13 @@ public class TokenEndpoint {
throw new ErrorResponseException("unauthorized_client", "Client not enabled to retrieve service account", Response.Status.UNAUTHORIZED);
}
UserModel clientUser = session.users().getUserByServiceAccountClient(client);
UserModel clientUser = session.users().getServiceAccount(client);
if (clientUser == null || client.getProtocolMapperByName(OIDCLoginProtocol.LOGIN_PROTOCOL, ServiceAccountConstants.CLIENT_ID_PROTOCOL_MAPPER) == null) {
// May need to handle bootstrap here as well
logger.debugf("Service account user for client '%s' not found or default protocol mapper for service account not found. Creating now", client.getClientId());
new ClientManager(new RealmManager(session)).enableServiceAccount(client);
clientUser = session.users().getUserByServiceAccountClient(client);
clientUser = session.users().getServiceAccount(client);
}
String clientUsername = clientUser.getUsername();

View file

@ -22,6 +22,8 @@ import org.keycloak.models.cache.CacheUserProvider;
import org.keycloak.provider.Provider;
import org.keycloak.provider.ProviderFactory;
import org.keycloak.scripting.ScriptingProvider;
import org.keycloak.storage.UserStorageManager;
import org.keycloak.storage.federated.UserFederatedStorageProvider;
import java.util.*;
@ -36,6 +38,7 @@ public class DefaultKeycloakSession implements KeycloakSession {
private final DefaultKeycloakTransactionManager transactionManager;
private RealmProvider model;
private UserProvider userModel;
private UserStorageManager userStorageManager;
private ScriptingProvider scriptingProvider;
private UserSessionProvider sessionProvider;
private UserFederationManager federationManager;
@ -86,6 +89,22 @@ public class DefaultKeycloakSession implements KeycloakSession {
return factory;
}
@Override
public UserFederatedStorageProvider userFederatedStorage() {
return null;
}
@Override
public UserProvider userLocalStorage() {
return getProvider(UserProvider.class);
}
@Override
public UserProvider userStorageManager() {
if (userStorageManager == null) userStorageManager = new UserStorageManager(this);
return userStorageManager;
}
@Override
public UserProvider userStorage() {
if (userModel == null) {

View file

@ -443,7 +443,7 @@ public class AuthenticationManager {
if (client.isConsentRequired()) {
UserConsentModel grantedConsent = user.getConsentByClient(client.getId());
UserConsentModel grantedConsent = session.users().getConsentByClient(realm, user, client.getId());
ClientSessionCode accessCode = new ClientSessionCode(realm, clientSession);
for (RoleModel r : accessCode.getRequestedRoles()) {
@ -497,7 +497,7 @@ public class AuthenticationManager {
if (client.isConsentRequired()) {
UserConsentModel grantedConsent = user.getConsentByClient(client.getId());
UserConsentModel grantedConsent = session.users().getConsentByClient(realm, user, client.getId());
List<RoleModel> realmRoles = new LinkedList<>();
MultivaluedMap<String, RoleModel> resourceRoles = new MultivaluedMapImpl<>();

View file

@ -102,7 +102,7 @@ public class ClientManager {
sessionsPersister.onClientRemoved(realm, client);
}
UserModel serviceAccountUser = realmManager.getSession().users().getUserByServiceAccountClient(client);
UserModel serviceAccountUser = realmManager.getSession().users().getServiceAccount(client);
if (serviceAccountUser != null) {
new UserManager(realmManager.getSession()).removeUser(realm, serviceAccountUser);
}
@ -149,7 +149,7 @@ public class ClientManager {
client.setServiceAccountsEnabled(true);
// Add dedicated user for this service account
if (realmManager.getSession().users().getUserByServiceAccountClient(client) == null) {
if (realmManager.getSession().users().getServiceAccount(client) == null) {
String username = ServiceAccountConstants.SERVICE_ACCOUNT_USER_PREFIX + client.getClientId();
logger.debugf("Creating service account user '%s'", username);

View file

@ -500,7 +500,7 @@ public class AccountService extends AbstractSecuredLocalService {
// Revoke grant in UserModel
UserModel user = auth.getUser();
user.revokeConsentForClient(client.getId());
session.users().revokeConsentForClient(realm, user, client.getId());
new UserSessionManager(session).revokeOfflineToken(user, client);
// Logout clientSessions for this user and client

View file

@ -667,10 +667,10 @@ public class LoginActionsService {
return response;
}
UserConsentModel grantedConsent = user.getConsentByClient(client.getId());
UserConsentModel grantedConsent = session.users().getConsentByClient(realm, user, client.getId());
if (grantedConsent == null) {
grantedConsent = new UserConsentModel(client);
user.addConsent(grantedConsent);
session.users().addConsent(realm, user, grantedConsent);
}
for (RoleModel role : accessCode.getRequestedRoles()) {
grantedConsent.addGrantedRole(role);
@ -680,7 +680,7 @@ public class LoginActionsService {
grantedConsent.addGrantedProtocolMapper(protocolMapper);
}
}
user.updateConsent(grantedConsent);
session.users().updateConsent(realm, user, grantedConsent);
event.detail(Details.CONSENT, Details.CONSENT_VALUE_CONSENT_GRANTED);
event.success();

View file

@ -304,11 +304,11 @@ public class ClientResource {
throw new NotFoundException("Could not find client");
}
UserModel user = session.users().getUserByServiceAccountClient(client);
UserModel user = session.users().getServiceAccount(client);
if (user == null) {
if (client.isServiceAccountsEnabled()) {
new ClientManager(new RealmManager(session)).enableServiceAccount(client);
user = session.users().getUserByServiceAccountClient(client);
user = session.users().getServiceAccount(client);
} else {
throw new BadRequestException("Service account not enabled for the client '" + client.getClientId() + "'");
}

View file

@ -527,7 +527,7 @@ public class UsersResource {
Set<ClientModel> offlineClients = new UserSessionManager(session).findClientsWithOfflineToken(realm, user);
for (ClientModel client : realm.getClients()) {
UserConsentModel consent = user.getConsentByClient(client.getId());
UserConsentModel consent = session.users().getConsentByClient(realm, user, client.getId());
boolean hasOfflineToken = offlineClients.contains(client);
if (consent == null && !hasOfflineToken) {
@ -576,7 +576,7 @@ public class UsersResource {
}
ClientModel client = realm.getClientByClientId(clientId);
boolean revokedConsent = user.revokeConsentForClient(client.getId());
boolean revokedConsent = session.users().revokeConsentForClient(realm, user, client.getId());
boolean revokedOfflineToken = new UserSessionManager(session).revokeOfflineToken(user, client);
if (revokedConsent) {

View file

@ -351,15 +351,15 @@ public class ImportTest extends AbstractModelTest {
// Test user consents
admin = session.users().getUserByUsername("admin", realm);
Assert.assertEquals(2, admin.getConsents().size());
Assert.assertEquals(2, session.users().getConsents(realm, admin).size());
UserConsentModel appAdminConsent = admin.getConsentByClient(application.getId());
UserConsentModel appAdminConsent = session.users().getConsentByClient(realm, admin, application.getId());
Assert.assertEquals(2, appAdminConsent.getGrantedRoles().size());
Assert.assertTrue(appAdminConsent.getGrantedProtocolMappers() == null || appAdminConsent.getGrantedProtocolMappers().isEmpty());
Assert.assertTrue(appAdminConsent.isRoleGranted(realm.getRole("admin")));
Assert.assertTrue(appAdminConsent.isRoleGranted(application.getRole("app-admin")));
UserConsentModel otherAppAdminConsent = admin.getConsentByClient(otherApp.getId());
UserConsentModel otherAppAdminConsent = session.users().getConsentByClient(realm, admin, otherApp.getId());
Assert.assertEquals(1, otherAppAdminConsent.getGrantedRoles().size());
Assert.assertEquals(1, otherAppAdminConsent.getGrantedProtocolMappers().size());
Assert.assertTrue(otherAppAdminConsent.isRoleGranted(realm.getRole("admin")));
@ -376,8 +376,8 @@ public class ImportTest extends AbstractModelTest {
// Test service accounts
Assert.assertFalse(application.isServiceAccountsEnabled());
Assert.assertTrue(otherApp.isServiceAccountsEnabled());
Assert.assertNull(session.users().getUserByServiceAccountClient(application));
UserModel linked = session.users().getUserByServiceAccountClient(otherApp);
Assert.assertNull(session.users().getServiceAccount(application));
UserModel linked = session.users().getServiceAccount(otherApp);
Assert.assertNotNull(linked);
Assert.assertEquals("my-service-user", linked.getUsername());
}

View file

@ -67,7 +67,7 @@ public class UserConsentModelTest extends AbstractModelTest {
johnFooGrant.addGrantedRole(realmRole);
johnFooGrant.addGrantedRole(barClientRole);
johnFooGrant.addGrantedProtocolMapper(fooMapper);
john.addConsent(johnFooGrant);
realmManager.getSession().users().addConsent(realm, john, johnFooGrant);
UserConsentModel johnBarGrant = new UserConsentModel(barClient);
johnBarGrant.addGrantedProtocolMapper(barMapper);
@ -75,17 +75,17 @@ public class UserConsentModelTest extends AbstractModelTest {
// Update should fail as grant doesn't yet exists
try {
john.updateConsent(johnBarGrant);
realmManager.getSession().users().updateConsent(realm, john, johnBarGrant);
Assert.fail("Not expected to end here");
} catch (ModelException expected) {
}
john.addConsent(johnBarGrant);
realmManager.getSession().users().addConsent(realm, john, johnBarGrant);
UserConsentModel maryFooGrant = new UserConsentModel(fooClient);
maryFooGrant.addGrantedRole(realmRole);
maryFooGrant.addGrantedProtocolMapper(fooMapper);
mary.addConsent(maryFooGrant);
realmManager.getSession().users().addConsent(realm, mary, maryFooGrant);
commit();
}
@ -99,27 +99,27 @@ public class UserConsentModelTest extends AbstractModelTest {
UserModel john = session.users().getUserByUsername("john", realm);
UserModel mary = session.users().getUserByUsername("mary", realm);
UserConsentModel johnFooConsent = john.getConsentByClient(fooClient.getId());
UserConsentModel johnFooConsent = realmManager.getSession().users().getConsentByClient(realm, john, fooClient.getId());
Assert.assertEquals(johnFooConsent.getGrantedRoles().size(), 2);
Assert.assertEquals(johnFooConsent.getGrantedProtocolMappers().size(), 1);
Assert.assertTrue(isRoleGranted(realm, "realm-role", johnFooConsent));
Assert.assertTrue(isRoleGranted(barClient, "bar-client-role", johnFooConsent));
Assert.assertTrue(isMapperGranted(fooClient, "foo", johnFooConsent));
UserConsentModel johnBarConsent = john.getConsentByClient(barClient.getId());
UserConsentModel johnBarConsent = realmManager.getSession().users().getConsentByClient(realm, john, barClient.getId());
Assert.assertEquals(johnBarConsent.getGrantedRoles().size(), 1);
Assert.assertEquals(johnBarConsent.getGrantedProtocolMappers().size(), 1);
Assert.assertTrue(isRoleGranted(realm, "realm-role", johnBarConsent));
Assert.assertTrue(isMapperGranted(barClient, "bar", johnBarConsent));
UserConsentModel maryConsent = mary.getConsentByClient(fooClient.getId());
UserConsentModel maryConsent = realmManager.getSession().users().getConsentByClient(realm, mary, fooClient.getId());
Assert.assertEquals(maryConsent.getGrantedRoles().size(), 1);
Assert.assertEquals(maryConsent.getGrantedProtocolMappers().size(), 1);
Assert.assertTrue(isRoleGranted(realm, "realm-role", maryConsent));
Assert.assertFalse(isRoleGranted(barClient, "bar-client-role", maryConsent));
Assert.assertTrue(isMapperGranted(fooClient, "foo", maryConsent));
Assert.assertNull(mary.getConsentByClient(barClient.getId()));
Assert.assertNull(realmManager.getSession().users().getConsentByClient(realm, mary, barClient.getId()));
}
@Test
@ -130,10 +130,10 @@ public class UserConsentModelTest extends AbstractModelTest {
UserModel john = session.users().getUserByUsername("john", realm);
UserModel mary = session.users().getUserByUsername("mary", realm);
List<UserConsentModel> johnConsents = john.getConsents();
List<UserConsentModel> johnConsents = realmManager.getSession().users().getConsents(realm, john);
Assert.assertEquals(2, johnConsents.size());
List<UserConsentModel> maryConsents = mary.getConsents();
List<UserConsentModel> maryConsents = realmManager.getSession().users().getConsents(realm, mary);
Assert.assertEquals(1, maryConsents.size());
UserConsentModel maryConsent = maryConsents.get(0);
Assert.assertEquals(maryConsent.getClient().getId(), fooClient.getId());
@ -149,7 +149,7 @@ public class UserConsentModelTest extends AbstractModelTest {
ClientModel fooClient = realm.getClientByClientId("foo-client");
UserModel john = session.users().getUserByUsername("john", realm);
UserConsentModel johnConsent = john.getConsentByClient(fooClient.getId());
UserConsentModel johnConsent = realmManager.getSession().users().getConsentByClient(realm, john, fooClient.getId());
// Remove foo protocol mapper from johnConsent
ProtocolMapperModel protMapperModel = fooClient.getProtocolMapperByName(OIDCLoginProtocol.LOGIN_PROTOCOL, "foo");
@ -162,14 +162,14 @@ public class UserConsentModelTest extends AbstractModelTest {
RoleModel newRealmRole = realm.addRole("new-realm-role");
johnConsent.addGrantedRole(newRealmRole);
john.updateConsent(johnConsent);
realmManager.getSession().users().updateConsent(realm, john, johnConsent);
commit();
realm = realmManager.getRealm("original");
fooClient = realm.getClientByClientId("foo-client");
john = session.users().getUserByUsername("john", realm);
johnConsent = john.getConsentByClient(fooClient.getId());
johnConsent = realmManager.getSession().users().getConsentByClient(realm, john, fooClient.getId());
Assert.assertEquals(johnConsent.getGrantedRoles().size(), 2);
Assert.assertEquals(johnConsent.getGrantedProtocolMappers().size(), 0);
@ -184,13 +184,13 @@ public class UserConsentModelTest extends AbstractModelTest {
ClientModel fooClient = realm.getClientByClientId("foo-client");
UserModel john = session.users().getUserByUsername("john", realm);
john.revokeConsentForClient(fooClient.getId());
realmManager.getSession().users().revokeConsentForClient(realm, john, fooClient.getId());
commit();
realm = realmManager.getRealm("original");
john = session.users().getUserByUsername("john", realm);
Assert.assertNull(john.getConsentByClient(fooClient.getId()));
Assert.assertNull(realmManager.getSession().users().getConsentByClient(realm, john, fooClient.getId()));
}
@Test
@ -213,7 +213,7 @@ public class UserConsentModelTest extends AbstractModelTest {
realm = realmManager.getRealm("original");
fooClient = realm.getClientByClientId("foo-client");
UserModel john = session.users().getUserByUsername("john", realm);
UserConsentModel johnConsent = john.getConsentByClient(fooClient.getId());
UserConsentModel johnConsent = realmManager.getSession().users().getConsentByClient(realm, john, fooClient.getId());
Assert.assertEquals(johnConsent.getGrantedRoles().size(), 2);
Assert.assertEquals(johnConsent.getGrantedProtocolMappers().size(), 0);
@ -232,7 +232,7 @@ public class UserConsentModelTest extends AbstractModelTest {
ClientModel fooClient = realm.getClientByClientId("foo-client");
ClientModel barClient = realm.getClientByClientId("bar-client");
UserModel john = session.users().getUserByUsername("john", realm);
UserConsentModel johnConsent = john.getConsentByClient(fooClient.getId());
UserConsentModel johnConsent = realmManager.getSession().users().getConsentByClient(realm, john, fooClient.getId());
Assert.assertEquals(johnConsent.getGrantedRoles().size(), 1);
Assert.assertEquals(johnConsent.getGrantedProtocolMappers().size(), 1);
@ -254,13 +254,13 @@ public class UserConsentModelTest extends AbstractModelTest {
UserModel john = session.users().getUserByUsername("john", realm);
UserConsentModel johnFooConsent = john.getConsentByClient(fooClient.getId());
UserConsentModel johnFooConsent = realmManager.getSession().users().getConsentByClient(realm, john, fooClient.getId());
Assert.assertEquals(johnFooConsent.getGrantedRoles().size(), 1);
Assert.assertEquals(johnFooConsent.getGrantedProtocolMappers().size(), 1);
Assert.assertTrue(isRoleGranted(realm, "realm-role", johnFooConsent));
Assert.assertTrue(isMapperGranted(fooClient, "foo", johnFooConsent));
Assert.assertNull(john.getConsentByClient(barClient.getId()));
Assert.assertNull(realmManager.getSession().users().getConsentByClient(realm, john, barClient.getId()));
}
private boolean isRoleGranted(RoleContainerModel roleContainer, String roleName, UserConsentModel consentModel) {

View file

@ -271,7 +271,7 @@ public class UserModelTest extends AbstractModelTest {
user2.setLastName("Doe");
// Search
Assert.assertNull(session.users().getUserByServiceAccountClient(client));
Assert.assertNull(session.users().getServiceAccount(client));
List<UserModel> users = session.users().searchForUser("John Doe", realm);
Assert.assertEquals(2, users.size());
Assert.assertTrue(users.contains(user1));
@ -284,7 +284,7 @@ public class UserModelTest extends AbstractModelTest {
// Search and assert service account user not found
realm = realmManager.getRealmByName("original");
UserModel searched = session.users().getUserByServiceAccountClient(client);
UserModel searched = session.users().getServiceAccount(client);
Assert.assertEquals(searched, user1);
users = session.users().searchForUser("John Doe", realm);
Assert.assertEquals(1, users.size());