KEYCLOAK-5926
This commit is contained in:
parent
64f8d7ce25
commit
0dee393071
14 changed files with 498 additions and 69 deletions
|
@ -48,6 +48,7 @@ import org.keycloak.models.cache.infinispan.events.UserFederationLinkRemovedEven
|
|||
import org.keycloak.models.cache.infinispan.events.UserFederationLinkUpdatedEvent;
|
||||
import org.keycloak.models.cache.infinispan.events.UserFullInvalidationEvent;
|
||||
import org.keycloak.models.cache.infinispan.events.UserUpdatedEvent;
|
||||
import org.keycloak.models.utils.ReadOnlyUserModelDelegate;
|
||||
import org.keycloak.storage.StorageId;
|
||||
import org.keycloak.storage.UserStorageProvider;
|
||||
import org.keycloak.storage.UserStorageProviderModel;
|
||||
|
@ -296,36 +297,41 @@ public class UserCacheSession implements UserCache {
|
|||
if (!storageId.isLocal()) {
|
||||
ComponentModel component = realm.getComponent(storageId.getProviderId());
|
||||
UserStorageProviderModel model = new UserStorageProviderModel(component);
|
||||
UserStorageProviderModel.CachePolicy policy = model.getCachePolicy();
|
||||
|
||||
// although we do set a timeout, Infinispan has no guarantees when the user will be evicted
|
||||
// its also hard to test stuff
|
||||
boolean invalidate = false;
|
||||
if (policy != null) {
|
||||
//String currentTime = DateFormat.getDateTimeInstance(DateFormat.FULL, DateFormat.FULL).format(new Date(Time.currentTimeMillis()));
|
||||
if (policy == UserStorageProviderModel.CachePolicy.NO_CACHE) {
|
||||
invalidate = true;
|
||||
} else if (cached.getCacheTimestamp() < model.getCacheInvalidBefore()) {
|
||||
invalidate = true;
|
||||
} else if (policy == UserStorageProviderModel.CachePolicy.MAX_LIFESPAN) {
|
||||
if (cached.getCacheTimestamp() + model.getMaxLifespan() < Time.currentTimeMillis()) {
|
||||
if (!model.isEnabled()) {
|
||||
invalidate = true;
|
||||
} else {
|
||||
UserStorageProviderModel.CachePolicy policy = model.getCachePolicy();
|
||||
if (policy != null) {
|
||||
//String currentTime = DateFormat.getDateTimeInstance(DateFormat.FULL, DateFormat.FULL).format(new Date(Time.currentTimeMillis()));
|
||||
if (policy == UserStorageProviderModel.CachePolicy.NO_CACHE) {
|
||||
invalidate = true;
|
||||
}
|
||||
} else if (policy == UserStorageProviderModel.CachePolicy.EVICT_DAILY) {
|
||||
long dailyTimeout = dailyTimeout(model.getEvictionHour(), model.getEvictionMinute());
|
||||
dailyTimeout = dailyTimeout - (24 * 60 * 60 * 1000);
|
||||
//String timeout = DateFormat.getDateTimeInstance(DateFormat.FULL, DateFormat.FULL).format(new Date(dailyTimeout));
|
||||
//String stamp = DateFormat.getDateTimeInstance(DateFormat.FULL, DateFormat.FULL).format(new Date(cached.getCacheTimestamp()));
|
||||
if (cached.getCacheTimestamp() <= dailyTimeout) {
|
||||
invalidate = true;
|
||||
}
|
||||
} else if (policy == UserStorageProviderModel.CachePolicy.EVICT_WEEKLY) {
|
||||
int oneWeek = 7 * 24 * 60 * 60 * 1000;
|
||||
long weeklyTimeout = weeklyTimeout(model.getEvictionDay(), model.getEvictionHour(), model.getEvictionMinute());
|
||||
long lastTimeout = weeklyTimeout - oneWeek;
|
||||
//String timeout = DateFormat.getDateTimeInstance(DateFormat.FULL, DateFormat.FULL).format(new Date(weeklyTimeout));
|
||||
//String stamp = DateFormat.getDateTimeInstance(DateFormat.FULL, DateFormat.FULL).format(new Date(cached.getCacheTimestamp()));
|
||||
if (cached.getCacheTimestamp() <= lastTimeout) {
|
||||
} else if (cached.getCacheTimestamp() < model.getCacheInvalidBefore()) {
|
||||
invalidate = true;
|
||||
} else if (policy == UserStorageProviderModel.CachePolicy.MAX_LIFESPAN) {
|
||||
if (cached.getCacheTimestamp() + model.getMaxLifespan() < Time.currentTimeMillis()) {
|
||||
invalidate = true;
|
||||
}
|
||||
} else if (policy == UserStorageProviderModel.CachePolicy.EVICT_DAILY) {
|
||||
long dailyTimeout = dailyTimeout(model.getEvictionHour(), model.getEvictionMinute());
|
||||
dailyTimeout = dailyTimeout - (24 * 60 * 60 * 1000);
|
||||
//String timeout = DateFormat.getDateTimeInstance(DateFormat.FULL, DateFormat.FULL).format(new Date(dailyTimeout));
|
||||
//String stamp = DateFormat.getDateTimeInstance(DateFormat.FULL, DateFormat.FULL).format(new Date(cached.getCacheTimestamp()));
|
||||
if (cached.getCacheTimestamp() <= dailyTimeout) {
|
||||
invalidate = true;
|
||||
}
|
||||
} else if (policy == UserStorageProviderModel.CachePolicy.EVICT_WEEKLY) {
|
||||
int oneWeek = 7 * 24 * 60 * 60 * 1000;
|
||||
long weeklyTimeout = weeklyTimeout(model.getEvictionDay(), model.getEvictionHour(), model.getEvictionMinute());
|
||||
long lastTimeout = weeklyTimeout - oneWeek;
|
||||
//String timeout = DateFormat.getDateTimeInstance(DateFormat.FULL, DateFormat.FULL).format(new Date(weeklyTimeout));
|
||||
//String stamp = DateFormat.getDateTimeInstance(DateFormat.FULL, DateFormat.FULL).format(new Date(cached.getCacheTimestamp()));
|
||||
if (cached.getCacheTimestamp() <= lastTimeout) {
|
||||
invalidate = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -346,6 +352,14 @@ public class UserCacheSession implements UserCache {
|
|||
if (!storageId.isLocal()) {
|
||||
ComponentModel component = realm.getComponent(storageId.getProviderId());
|
||||
UserStorageProviderModel model = new UserStorageProviderModel(component);
|
||||
if (!model.isEnabled()) {
|
||||
return new ReadOnlyUserModelDelegate(delegate) {
|
||||
@Override
|
||||
public boolean isEnabled() {
|
||||
return false;
|
||||
}
|
||||
};
|
||||
}
|
||||
UserStorageProviderModel.CachePolicy policy = model.getCachePolicy();
|
||||
if (policy != null && policy == UserStorageProviderModel.CachePolicy.NO_CACHE) {
|
||||
return delegate;
|
||||
|
@ -845,7 +859,7 @@ public class UserCacheSession implements UserCache {
|
|||
|
||||
@Override
|
||||
public boolean removeUser(RealmModel realm, UserModel user) {
|
||||
fullyInvalidateUser(realm, user);
|
||||
fullyInvalidateUser(realm, user);
|
||||
return getDelegate().removeUser(realm, user);
|
||||
}
|
||||
|
||||
|
|
|
@ -38,6 +38,7 @@ public class UserStorageProviderModel extends PrioritizedComponentModel {
|
|||
public static final String FULL_SYNC_PERIOD = "fullSyncPeriod";
|
||||
public static final String CHANGED_SYNC_PERIOD = "changedSyncPeriod";
|
||||
public static final String LAST_SYNC = "lastSync";
|
||||
public static final String ENABLED = "enabled";
|
||||
|
||||
public static enum CachePolicy {
|
||||
NO_CACHE,
|
||||
|
@ -59,6 +60,7 @@ public class UserStorageProviderModel extends PrioritizedComponentModel {
|
|||
private transient Integer changedSyncPeriod;
|
||||
private transient Integer lastSync;
|
||||
private transient Boolean importEnabled;
|
||||
private transient Boolean enabled;
|
||||
private transient CachePolicy cachePolicy;
|
||||
private transient long maxLifespan = -1;
|
||||
private transient int evictionHour = -1;
|
||||
|
@ -171,13 +173,30 @@ public class UserStorageProviderModel extends PrioritizedComponentModel {
|
|||
|
||||
}
|
||||
|
||||
|
||||
|
||||
public void setImportEnabled(boolean flag) {
|
||||
importEnabled = flag;
|
||||
getConfig().putSingle(IMPORT_ENABLED, Boolean.toString(flag));
|
||||
}
|
||||
|
||||
public void setEnabled(boolean flag) {
|
||||
enabled = flag;
|
||||
getConfig().putSingle(ENABLED, Boolean.toString(flag));
|
||||
}
|
||||
|
||||
|
||||
public boolean isEnabled() {
|
||||
if (enabled == null) {
|
||||
String val = getConfig().getFirst(ENABLED);
|
||||
if (val == null) {
|
||||
enabled = true;
|
||||
} else {
|
||||
enabled = Boolean.valueOf(val);
|
||||
}
|
||||
}
|
||||
return enabled;
|
||||
|
||||
}
|
||||
|
||||
public int getFullSyncPeriod() {
|
||||
if (fullSyncPeriod == null) {
|
||||
String val = getConfig().getFirst(FULL_SYNC_PERIOD);
|
||||
|
|
|
@ -55,6 +55,8 @@ public class UserStorageProviderSpi implements Spi {
|
|||
|
||||
static {
|
||||
List<ProviderConfigProperty> config = ProviderConfigurationBuilder.create()
|
||||
.property()
|
||||
.name("enabled").type(ProviderConfigProperty.BOOLEAN_TYPE).add()
|
||||
.property()
|
||||
.name("priority").type(ProviderConfigProperty.STRING_TYPE).add()
|
||||
.property()
|
||||
|
|
|
@ -30,6 +30,7 @@ import org.keycloak.storage.UserStorageManager;
|
|||
import org.keycloak.storage.UserStorageProvider;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
import java.util.LinkedList;
|
||||
|
@ -49,9 +50,9 @@ public class UserCredentialStoreManager implements UserCredentialManager, OnUser
|
|||
|
||||
protected UserCredentialStore getStoreForUser(UserModel user) {
|
||||
if (StorageId.isLocalStorage(user)) {
|
||||
return (UserCredentialStore)session.userLocalStorage();
|
||||
return (UserCredentialStore) session.userLocalStorage();
|
||||
} else {
|
||||
return (UserCredentialStore)session.userFederatedStorage();
|
||||
return (UserCredentialStore) session.userFederatedStorage();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -105,10 +106,11 @@ public class UserCredentialStoreManager implements UserCredentialManager, OnUser
|
|||
String providerId = StorageId.resolveProviderId(user);
|
||||
UserStorageProvider provider = UserStorageManager.getStorageProvider(session, realm, providerId);
|
||||
if (provider instanceof CredentialInputValidator) {
|
||||
if (!UserStorageManager.isStorageProviderEnabled(realm, providerId)) return false;
|
||||
Iterator<CredentialInput> it = toValidate.iterator();
|
||||
while (it.hasNext()) {
|
||||
CredentialInput input = it.next();
|
||||
CredentialInputValidator validator = (CredentialInputValidator)provider;
|
||||
CredentialInputValidator validator = (CredentialInputValidator) provider;
|
||||
if (validator.supportsCredentialType(input.getType()) && validator.isValid(realm, user, input)) {
|
||||
it.remove();
|
||||
}
|
||||
|
@ -118,6 +120,7 @@ public class UserCredentialStoreManager implements UserCredentialManager, OnUser
|
|||
if (user.getFederationLink() != null) {
|
||||
UserStorageProvider provider = UserStorageManager.getStorageProvider(session, realm, user.getFederationLink());
|
||||
if (provider != null && provider instanceof CredentialInputValidator) {
|
||||
if (!UserStorageManager.isStorageProviderEnabled(realm, user.getFederationLink())) return false;
|
||||
validate(realm, user, toValidate, ((CredentialInputValidator)provider));
|
||||
}
|
||||
}
|
||||
|
@ -147,7 +150,7 @@ public class UserCredentialStoreManager implements UserCredentialManager, OnUser
|
|||
List<T> list = new LinkedList<T>();
|
||||
for (ProviderFactory f : session.getKeycloakSessionFactory().getProviderFactories(CredentialProvider.class)) {
|
||||
if (!Types.supports(type, f, CredentialProviderFactory.class)) continue;
|
||||
list.add((T)session.getProvider(CredentialProvider.class, f.getId()));
|
||||
list.add((T) session.getProvider(CredentialProvider.class, f.getId()));
|
||||
}
|
||||
return list;
|
||||
|
||||
|
@ -159,16 +162,19 @@ public class UserCredentialStoreManager implements UserCredentialManager, OnUser
|
|||
String providerId = StorageId.resolveProviderId(user);
|
||||
UserStorageProvider provider = UserStorageManager.getStorageProvider(session, realm, providerId);
|
||||
if (provider instanceof CredentialInputUpdater) {
|
||||
CredentialInputUpdater updater = (CredentialInputUpdater)provider;
|
||||
if (!UserStorageManager.isStorageProviderEnabled(realm, providerId)) return;
|
||||
CredentialInputUpdater updater = (CredentialInputUpdater) provider;
|
||||
if (updater.supportsCredentialType(input.getType())) {
|
||||
if (updater.updateCredential(realm, user, input)) return;
|
||||
}
|
||||
|
||||
}
|
||||
} else {
|
||||
if (user.getFederationLink() != null) {
|
||||
UserStorageProvider provider = UserStorageManager.getStorageProvider(session, realm, user.getFederationLink());
|
||||
if (provider != null && provider instanceof CredentialInputUpdater) {
|
||||
if (((CredentialInputUpdater)provider).updateCredential(realm, user, input)) return;
|
||||
if (!UserStorageManager.isStorageProviderEnabled(realm, user.getFederationLink())) return;
|
||||
if (((CredentialInputUpdater) provider).updateCredential(realm, user, input)) return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -180,22 +186,26 @@ public class UserCredentialStoreManager implements UserCredentialManager, OnUser
|
|||
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void disableCredentialType(RealmModel realm, UserModel user, String credentialType) {
|
||||
if (!StorageId.isLocalStorage(user)) {
|
||||
String providerId = StorageId.resolveProviderId(user);
|
||||
UserStorageProvider provider = UserStorageManager.getStorageProvider(session, realm, providerId);
|
||||
if (provider instanceof CredentialInputUpdater) {
|
||||
CredentialInputUpdater updater = (CredentialInputUpdater)provider;
|
||||
if (!UserStorageManager.isStorageProviderEnabled(realm, providerId)) return;
|
||||
CredentialInputUpdater updater = (CredentialInputUpdater) provider;
|
||||
if (updater.supportsCredentialType(credentialType)) {
|
||||
updater.disableCredentialType(realm, user, credentialType);
|
||||
}
|
||||
|
||||
}
|
||||
} else {
|
||||
if (user.getFederationLink() != null) {
|
||||
UserStorageProvider provider = UserStorageManager.getStorageProvider(session, realm, user.getFederationLink());
|
||||
if (provider != null && provider instanceof CredentialInputUpdater) {
|
||||
((CredentialInputUpdater)provider).disableCredentialType(realm, user, credentialType);
|
||||
if (!UserStorageManager.isStorageProviderEnabled(realm, user.getFederationLink())) return;
|
||||
((CredentialInputUpdater) provider).disableCredentialType(realm, user, credentialType);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -218,14 +228,16 @@ public class UserCredentialStoreManager implements UserCredentialManager, OnUser
|
|||
String providerId = StorageId.resolveProviderId(user);
|
||||
UserStorageProvider provider = UserStorageManager.getStorageProvider(session, realm, providerId);
|
||||
if (provider instanceof CredentialInputUpdater) {
|
||||
CredentialInputUpdater updater = (CredentialInputUpdater)provider;
|
||||
if (!UserStorageManager.isStorageProviderEnabled(realm, providerId)) return Collections.EMPTY_SET;
|
||||
CredentialInputUpdater updater = (CredentialInputUpdater) provider;
|
||||
types.addAll(updater.getDisableableCredentialTypes(realm, user));
|
||||
}
|
||||
} else {
|
||||
if (user.getFederationLink() != null) {
|
||||
UserStorageProvider provider = UserStorageManager.getStorageProvider(session, realm, user.getFederationLink());
|
||||
if (provider != null && provider instanceof CredentialInputUpdater) {
|
||||
types.addAll(((CredentialInputUpdater)provider).getDisableableCredentialTypes(realm, user));
|
||||
if (!UserStorageManager.isStorageProviderEnabled(realm, user.getFederationLink())) return Collections.EMPTY_SET;
|
||||
types.addAll(((CredentialInputUpdater) provider).getDisableableCredentialTypes(realm, user));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -244,7 +256,8 @@ public class UserCredentialStoreManager implements UserCredentialManager, OnUser
|
|||
String providerId = StorageId.resolveProviderId(user);
|
||||
UserStorageProvider provider = UserStorageManager.getStorageProvider(session, realm, providerId);
|
||||
if (provider instanceof CredentialInputValidator) {
|
||||
CredentialInputValidator validator = (CredentialInputValidator)provider;
|
||||
if (!UserStorageManager.isStorageProviderEnabled(realm, providerId)) return false;
|
||||
CredentialInputValidator validator = (CredentialInputValidator) provider;
|
||||
if (validator.supportsCredentialType(type) && validator.isConfiguredFor(realm, user, type)) {
|
||||
return true;
|
||||
}
|
||||
|
@ -253,7 +266,8 @@ public class UserCredentialStoreManager implements UserCredentialManager, OnUser
|
|||
if (user.getFederationLink() != null) {
|
||||
UserStorageProvider provider = UserStorageManager.getStorageProvider(session, realm, user.getFederationLink());
|
||||
if (provider != null && provider instanceof CredentialInputValidator) {
|
||||
if (((CredentialInputValidator)provider).isConfiguredFor(realm, user, type)) return true;
|
||||
if (!UserStorageManager.isStorageProviderEnabled(realm, user.getFederationLink())) return false;
|
||||
if (((CredentialInputValidator) provider).isConfiguredFor(realm, user, type)) return true;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -276,7 +290,7 @@ public class UserCredentialStoreManager implements UserCredentialManager, OnUser
|
|||
|
||||
@Override
|
||||
public CredentialValidationOutput authenticate(KeycloakSession session, RealmModel realm, CredentialInput input) {
|
||||
List<CredentialAuthentication> list = UserStorageManager.getStorageProviders(session, realm, CredentialAuthentication.class);
|
||||
List<CredentialAuthentication> list = UserStorageManager.getEnabledStorageProviders(session, realm, CredentialAuthentication.class);
|
||||
for (CredentialAuthentication auth : list) {
|
||||
if (auth.supportsCredentialAuthenticationFor(input.getType())) {
|
||||
CredentialValidationOutput output = auth.authenticate(realm, input);
|
||||
|
|
|
@ -38,6 +38,7 @@ import org.keycloak.models.cache.CachedUserModel;
|
|||
import org.keycloak.models.cache.OnUserCache;
|
||||
import org.keycloak.models.cache.UserCache;
|
||||
import org.keycloak.models.utils.ComponentUtil;
|
||||
import org.keycloak.models.utils.ReadOnlyUserModelDelegate;
|
||||
import org.keycloak.services.managers.UserStorageSyncManager;
|
||||
import org.keycloak.storage.federated.UserFederatedStorageProvider;
|
||||
import org.keycloak.storage.user.ImportedUserValidation;
|
||||
|
@ -70,6 +71,11 @@ public class UserStorageManager implements UserProvider, OnUserCache, OnCreateCo
|
|||
this.session = session;
|
||||
}
|
||||
|
||||
public static boolean isStorageProviderEnabled(RealmModel realm, String providerId) {
|
||||
UserStorageProviderModel model = getStorageProviderModel(realm, providerId);
|
||||
return model.isEnabled();
|
||||
}
|
||||
|
||||
protected UserProvider localStorage() {
|
||||
return session.userLocalStorage();
|
||||
}
|
||||
|
@ -109,6 +115,25 @@ public class UserStorageManager implements UserProvider, OnUserCache, OnCreateCo
|
|||
}
|
||||
|
||||
|
||||
public static <T> List<T> getEnabledStorageProviders(KeycloakSession session, RealmModel realm, Class<T> type) {
|
||||
List<T> list = new LinkedList<>();
|
||||
for (UserStorageProviderModel model : getStorageProviders(realm)) {
|
||||
if (!model.isEnabled()) continue;
|
||||
UserStorageProviderFactory factory = (UserStorageProviderFactory) session.getKeycloakSessionFactory().getProviderFactory(UserStorageProvider.class, model.getProviderId());
|
||||
if (factory == null) {
|
||||
logger.warnv("Configured UserStorageProvider {0} of provider id {1} does not exist in realm {2}", model.getName(), model.getProviderId(), realm.getName());
|
||||
continue;
|
||||
}
|
||||
if (Types.supports(type, factory, UserStorageProviderFactory.class)) {
|
||||
list.add(type.cast(getStorageProviderInstance(session, model, factory)));
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public UserModel addUser(RealmModel realm, String id, String username, boolean addDefaultRoles, boolean addDefaultRequiredActions) {
|
||||
return localStorage().addUser(realm, id, username.toLowerCase(), addDefaultRoles, addDefaultRequiredActions);
|
||||
|
@ -116,7 +141,7 @@ public class UserStorageManager implements UserProvider, OnUserCache, OnCreateCo
|
|||
|
||||
@Override
|
||||
public UserModel addUser(RealmModel realm, String username) {
|
||||
for (UserRegistrationProvider provider : getStorageProviders(session, realm, UserRegistrationProvider.class)) {
|
||||
for (UserRegistrationProvider provider : getEnabledStorageProviders(session, realm, UserRegistrationProvider.class)) {
|
||||
UserModel user = provider.addUser(realm, username);
|
||||
if (user != null) return user;
|
||||
}
|
||||
|
@ -124,14 +149,21 @@ public class UserStorageManager implements UserProvider, OnUserCache, OnCreateCo
|
|||
return localStorage().addUser(realm, username.toLowerCase());
|
||||
}
|
||||
|
||||
public static UserStorageProviderModel getStorageProviderModel(RealmModel realm, String componentId) {
|
||||
ComponentModel model = realm.getComponent(componentId);
|
||||
if (model == null) return null;
|
||||
return new UserStorageProviderModel(model);
|
||||
}
|
||||
|
||||
public static UserStorageProvider getStorageProvider(KeycloakSession session, RealmModel realm, String componentId) {
|
||||
ComponentModel model = realm.getComponent(componentId);
|
||||
if (model == null) return null;
|
||||
UserStorageProviderModel storageModel = new UserStorageProviderModel(model);
|
||||
UserStorageProviderFactory factory = (UserStorageProviderFactory)session.getKeycloakSessionFactory().getProviderFactory(UserStorageProvider.class, model.getProviderId());
|
||||
if (factory == null) {
|
||||
throw new ModelException("Could not find UserStorageProviderFactory for: " + model.getProviderId());
|
||||
}
|
||||
return getStorageProviderInstance(session, new UserStorageProviderModel(model), factory);
|
||||
return getStorageProviderInstance(session, storageModel, factory);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -139,13 +171,18 @@ public class UserStorageManager implements UserProvider, OnUserCache, OnCreateCo
|
|||
if (getFederatedStorage() != null) getFederatedStorage().preRemove(realm, user);
|
||||
StorageId storageId = new StorageId(user.getId());
|
||||
if (storageId.getProviderId() == null) {
|
||||
boolean linkRemoved = true;
|
||||
if (user.getFederationLink() != null) {
|
||||
UserStorageProvider provider = getStorageProvider(session, realm, user.getFederationLink());
|
||||
if (provider != null && provider instanceof UserRegistrationProvider) {
|
||||
((UserRegistrationProvider)provider).removeUser(realm, user);
|
||||
if (isStorageProviderEnabled(realm, user.getFederationLink())) {
|
||||
UserStorageProvider provider = getStorageProvider(session, realm, user.getFederationLink());
|
||||
if (provider != null && provider instanceof UserRegistrationProvider) {
|
||||
((UserRegistrationProvider) provider).removeUser(realm, user);
|
||||
}
|
||||
} else {
|
||||
linkRemoved = false;
|
||||
}
|
||||
}
|
||||
return localStorage().removeUser(realm, user);
|
||||
return localStorage().removeUser(realm, user) && linkRemoved;
|
||||
}
|
||||
UserRegistrationProvider registry = (UserRegistrationProvider)getStorageProvider(session, realm, storageId.getProviderId());
|
||||
if (registry == null) {
|
||||
|
@ -264,6 +301,14 @@ public class UserStorageManager implements UserProvider, OnUserCache, OnCreateCo
|
|||
if (user == null || user.getFederationLink() == null) return user;
|
||||
UserStorageProvider provider = getStorageProvider(session, realm, user.getFederationLink());
|
||||
if (provider != null && provider instanceof ImportedUserValidation) {
|
||||
if (!isStorageProviderEnabled(realm, user.getFederationLink())) {
|
||||
return new ReadOnlyUserModelDelegate(user) {
|
||||
@Override
|
||||
public boolean isEnabled() {
|
||||
return false;
|
||||
}
|
||||
};
|
||||
}
|
||||
UserModel validated = ((ImportedUserValidation) provider).validate(realm, user);
|
||||
if (validated == null) {
|
||||
deleteInvalidUser(realm, user);
|
||||
|
@ -324,6 +369,7 @@ public class UserStorageManager implements UserProvider, OnUserCache, OnCreateCo
|
|||
}
|
||||
UserLookupProvider provider = (UserLookupProvider)getStorageProvider(session, realm, storageId.getProviderId());
|
||||
if (provider == null) return null;
|
||||
if (!isStorageProviderEnabled(realm, storageId.getProviderId())) return null;
|
||||
return provider.getUserById(id, realm);
|
||||
}
|
||||
|
||||
|
@ -343,7 +389,7 @@ public class UserStorageManager implements UserProvider, OnUserCache, OnCreateCo
|
|||
if (user != null) {
|
||||
return importValidation(realm, user);
|
||||
}
|
||||
for (UserLookupProvider provider : getStorageProviders(session, realm, UserLookupProvider.class)) {
|
||||
for (UserLookupProvider provider : getEnabledStorageProviders(session, realm, UserLookupProvider.class)) {
|
||||
user = provider.getUserByUsername(username, realm);
|
||||
if (user != null) return user;
|
||||
}
|
||||
|
@ -356,7 +402,7 @@ public class UserStorageManager implements UserProvider, OnUserCache, OnCreateCo
|
|||
if (user != null) {
|
||||
return importValidation(realm, user);
|
||||
}
|
||||
for (UserLookupProvider provider : getStorageProviders(session, realm, UserLookupProvider.class)) {
|
||||
for (UserLookupProvider provider : getEnabledStorageProviders(session, realm, UserLookupProvider.class)) {
|
||||
user = provider.getUserByEmail(email, realm);
|
||||
if (user != null) {
|
||||
return user;
|
||||
|
@ -401,7 +447,7 @@ public class UserStorageManager implements UserProvider, OnUserCache, OnCreateCo
|
|||
@Override
|
||||
public int getUsersCount(RealmModel realm, boolean includeServiceAccount) {
|
||||
int size = localStorage().getUsersCount(realm, includeServiceAccount);
|
||||
for (UserQueryProvider provider : getStorageProviders(session, realm, UserQueryProvider.class)) {
|
||||
for (UserQueryProvider provider : getEnabledStorageProviders(session, realm, UserQueryProvider.class)) {
|
||||
size += provider.getUsersCount(realm);
|
||||
}
|
||||
return size;
|
||||
|
@ -422,7 +468,7 @@ public class UserStorageManager implements UserProvider, OnUserCache, OnCreateCo
|
|||
if (firstResult < 0) firstResult = 0;
|
||||
if (maxResults < 0) maxResults = Integer.MAX_VALUE - 1;
|
||||
|
||||
List<UserQueryProvider> storageProviders = getStorageProviders(session, realm, UserQueryProvider.class);
|
||||
List<UserQueryProvider> storageProviders = getEnabledStorageProviders(session, realm, UserQueryProvider.class);
|
||||
// we can skip rest of method if there are no storage providers
|
||||
if (storageProviders.isEmpty()) {
|
||||
return pagedQuery.query(localStorage(), firstResult, maxResults);
|
||||
|
@ -560,7 +606,7 @@ public class UserStorageManager implements UserProvider, OnUserCache, OnCreateCo
|
|||
|
||||
@Override
|
||||
public void grantToAllUsers(RealmModel realm, RoleModel role) {
|
||||
List<UserBulkUpdateProvider> storageProviders = getStorageProviders(session, realm, UserBulkUpdateProvider.class);
|
||||
List<UserBulkUpdateProvider> storageProviders = getEnabledStorageProviders(session, realm, UserBulkUpdateProvider.class);
|
||||
LinkedList<UserBulkUpdateProvider> providers = new LinkedList<>();
|
||||
providers.add(localStorage());
|
||||
providers.addAll(storageProviders);
|
||||
|
@ -607,7 +653,7 @@ public class UserStorageManager implements UserProvider, OnUserCache, OnCreateCo
|
|||
localStorage().preRemove(realm);
|
||||
if (getFederatedStorage() != null) {
|
||||
getFederatedStorage().preRemove(realm);
|
||||
for (UserStorageProvider provider : getStorageProviders(session, realm, UserStorageProvider.class)) {
|
||||
for (UserStorageProvider provider : getEnabledStorageProviders(session, realm, UserStorageProvider.class)) {
|
||||
provider.preRemove(realm);
|
||||
}
|
||||
}
|
||||
|
@ -618,7 +664,7 @@ public class UserStorageManager implements UserProvider, OnUserCache, OnCreateCo
|
|||
localStorage().preRemove(realm, group);
|
||||
if (getFederatedStorage() != null) {
|
||||
getFederatedStorage().preRemove(realm, group);
|
||||
for (UserStorageProvider provider : getStorageProviders(session, realm, UserStorageProvider.class)) {
|
||||
for (UserStorageProvider provider : getEnabledStorageProviders(session, realm, UserStorageProvider.class)) {
|
||||
provider.preRemove(realm, group);
|
||||
}
|
||||
}
|
||||
|
@ -629,7 +675,7 @@ public class UserStorageManager implements UserProvider, OnUserCache, OnCreateCo
|
|||
localStorage().preRemove(realm, role);
|
||||
if (getFederatedStorage() != null) {
|
||||
getFederatedStorage().preRemove(realm, role);
|
||||
for (UserStorageProvider provider : getStorageProviders(session, realm, UserStorageProvider.class)) {
|
||||
for (UserStorageProvider provider : getEnabledStorageProviders(session, realm, UserStorageProvider.class)) {
|
||||
provider.preRemove(realm, role);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -22,6 +22,7 @@ import org.keycloak.credential.CredentialInput;
|
|||
import org.keycloak.credential.CredentialInputUpdater;
|
||||
import org.keycloak.credential.CredentialInputValidator;
|
||||
import org.keycloak.credential.CredentialModel;
|
||||
import org.keycloak.models.GroupModel;
|
||||
import org.keycloak.models.KeycloakSession;
|
||||
import org.keycloak.models.RealmModel;
|
||||
import org.keycloak.models.UserCredentialModel;
|
||||
|
@ -30,9 +31,11 @@ import org.keycloak.models.utils.UserModelDelegate;
|
|||
import org.keycloak.storage.UserStorageProvider;
|
||||
import org.keycloak.storage.user.ImportedUserValidation;
|
||||
import org.keycloak.storage.user.UserLookupProvider;
|
||||
import org.keycloak.storage.user.UserQueryProvider;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
@ -41,7 +44,7 @@ import java.util.Set;
|
|||
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
||||
* @version $Revision: 1 $
|
||||
*/
|
||||
public class FailableHardcodedStorageProvider implements UserStorageProvider, UserLookupProvider, ImportedUserValidation, CredentialInputUpdater, CredentialInputValidator {
|
||||
public class FailableHardcodedStorageProvider implements UserStorageProvider, UserLookupProvider, UserQueryProvider, ImportedUserValidation, CredentialInputUpdater, CredentialInputValidator {
|
||||
|
||||
public static String username = "billb";
|
||||
public static String password = "password";
|
||||
|
@ -64,13 +67,13 @@ public class FailableHardcodedStorageProvider implements UserStorageProvider, Us
|
|||
|
||||
@Override
|
||||
public boolean supportsCredentialType(String credentialType) {
|
||||
if (fail || componentFail) throw new RuntimeException("FORCED FAILURE");
|
||||
checkForceFail();
|
||||
return CredentialModel.PASSWORD.equals(credentialType);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean updateCredential(RealmModel realm, UserModel user, CredentialInput input) {
|
||||
if (fail || componentFail) throw new RuntimeException("FORCED FAILURE");
|
||||
checkForceFail();
|
||||
if (!(input instanceof UserCredentialModel)) return false;
|
||||
if (!user.getUsername().equals(username)) throw new RuntimeException("UNKNOWN USER!");
|
||||
|
||||
|
@ -85,25 +88,25 @@ public class FailableHardcodedStorageProvider implements UserStorageProvider, Us
|
|||
|
||||
@Override
|
||||
public void disableCredentialType(RealmModel realm, UserModel user, String credentialType) {
|
||||
if (fail || componentFail) throw new RuntimeException("FORCED FAILURE");
|
||||
checkForceFail();
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<String> getDisableableCredentialTypes(RealmModel realm, UserModel user) {
|
||||
if (fail || componentFail) throw new RuntimeException("FORCED FAILURE");
|
||||
checkForceFail();
|
||||
return Collections.EMPTY_SET;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isConfiguredFor(RealmModel realm, UserModel user, String credentialType) {
|
||||
if (fail || componentFail) throw new RuntimeException("FORCED FAILURE");
|
||||
checkForceFail();
|
||||
return CredentialModel.PASSWORD.equals(credentialType);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isValid(RealmModel realm, UserModel user, CredentialInput input) {
|
||||
if (fail || componentFail) throw new RuntimeException("FORCED FAILURE");
|
||||
checkForceFail();
|
||||
if (!(input instanceof UserCredentialModel)) return false;
|
||||
if (!user.getUsername().equals("billb")) throw new RuntimeException("UNKNOWN USER!");
|
||||
if (input.getType().equals(UserCredentialModel.PASSWORD)) {
|
||||
|
@ -163,19 +166,19 @@ public class FailableHardcodedStorageProvider implements UserStorageProvider, Us
|
|||
|
||||
@Override
|
||||
public UserModel validate(RealmModel realm, UserModel user) {
|
||||
if (fail || componentFail) throw new RuntimeException("FORCED FAILURE");
|
||||
checkForceFail();
|
||||
return new Delegate(user);
|
||||
}
|
||||
|
||||
@Override
|
||||
public UserModel getUserById(String id, RealmModel realm) {
|
||||
if (fail || componentFail) throw new RuntimeException("FORCED FAILURE");
|
||||
checkForceFail();
|
||||
throw new RuntimeException("THIS IMPORTS SHOULD NEVER BE CALLED");
|
||||
}
|
||||
|
||||
@Override
|
||||
public UserModel getUserByUsername(String uname, RealmModel realm) {
|
||||
if (fail || componentFail) throw new RuntimeException("FORCED FAILURE");
|
||||
checkForceFail();
|
||||
if (!username.equals(uname)) return null;
|
||||
UserModel local = session.userLocalStorage().getUserByUsername(uname, realm);
|
||||
if (local != null && !model.getId().equals(local.getFederationLink())) {
|
||||
|
@ -198,10 +201,96 @@ public class FailableHardcodedStorageProvider implements UserStorageProvider, Us
|
|||
|
||||
@Override
|
||||
public UserModel getUserByEmail(String email, RealmModel realm) {
|
||||
if (fail || componentFail) throw new RuntimeException("FORCED FAILURE");
|
||||
checkForceFail();
|
||||
return null;
|
||||
}
|
||||
|
||||
protected void checkForceFail() {
|
||||
if (fail || componentFail) throw new RuntimeException("FORCED FAILURE");
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getUsersCount(RealmModel realm) {
|
||||
checkForceFail();
|
||||
return 1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<UserModel> getUsers(RealmModel realm) {
|
||||
checkForceFail();
|
||||
UserModel hardcoded = getUserByUsername(username, realm);
|
||||
List<UserModel> list = new LinkedList<>();
|
||||
list.add(hardcoded);
|
||||
return list;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<UserModel> getUsers(RealmModel realm, int firstResult, int maxResults) {
|
||||
checkForceFail();
|
||||
UserModel hardcoded = getUserByUsername(username, realm);
|
||||
List<UserModel> list = new LinkedList<>();
|
||||
list.add(hardcoded);
|
||||
return list;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<UserModel> searchForUser(String search, RealmModel realm) {
|
||||
checkForceFail();
|
||||
if (!search.equals(username)) return Collections.EMPTY_LIST;
|
||||
UserModel hardcoded = getUserByUsername(username, realm);
|
||||
List<UserModel> list = new LinkedList<>();
|
||||
list.add(hardcoded);
|
||||
return list;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<UserModel> searchForUser(String search, RealmModel realm, int firstResult, int maxResults) {
|
||||
checkForceFail();
|
||||
if (!search.equals(username)) return Collections.EMPTY_LIST;
|
||||
UserModel hardcoded = getUserByUsername(username, realm);
|
||||
List<UserModel> list = new LinkedList<>();
|
||||
list.add(hardcoded);
|
||||
return list;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<UserModel> searchForUser(Map<String, String> params, RealmModel realm) {
|
||||
checkForceFail();
|
||||
if (!username.equals(params.get("username")))return Collections.EMPTY_LIST;
|
||||
UserModel hardcoded = getUserByUsername(username, realm);
|
||||
List<UserModel> list = new LinkedList<>();
|
||||
list.add(hardcoded);
|
||||
return list;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<UserModel> searchForUser(Map<String, String> params, RealmModel realm, int firstResult, int maxResults) {
|
||||
checkForceFail();
|
||||
if (!username.equals(params.get("username")))return Collections.EMPTY_LIST;
|
||||
UserModel hardcoded = getUserByUsername(username, realm);
|
||||
List<UserModel> list = new LinkedList<>();
|
||||
list.add(hardcoded);
|
||||
return list;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<UserModel> getGroupMembers(RealmModel realm, GroupModel group, int firstResult, int maxResults) {
|
||||
checkForceFail();
|
||||
return Collections.EMPTY_LIST;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<UserModel> getGroupMembers(RealmModel realm, GroupModel group) {
|
||||
checkForceFail();
|
||||
return Collections.EMPTY_LIST;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<UserModel> searchForUserByUserAttribute(String attrName, String attrValue, RealmModel realm) {
|
||||
checkForceFail();
|
||||
return Collections.EMPTY_LIST;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
*/
|
||||
package org.keycloak.testsuite.federation.storage;
|
||||
|
||||
import freemarker.ext.beans.HashAdapter;
|
||||
import org.junit.After;
|
||||
import org.junit.Assert;
|
||||
import org.junit.ClassRule;
|
||||
|
@ -59,8 +60,10 @@ import org.keycloak.testsuite.rule.WebRule;
|
|||
import org.openqa.selenium.WebDriver;
|
||||
|
||||
import java.util.Calendar;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
|
@ -69,6 +72,8 @@ import java.util.Set;
|
|||
*/
|
||||
public class UserStorageFailureTest {
|
||||
public static ComponentModel memoryProvider = null;
|
||||
public static String realmName;
|
||||
public static final String LOCAL_USER = "localUser";
|
||||
@ClassRule
|
||||
public static KeycloakRule keycloakRule = new KeycloakRule(new KeycloakRule.KeycloakSetup() {
|
||||
|
||||
|
@ -80,6 +85,7 @@ public class UserStorageFailureTest {
|
|||
model.setProviderId(FailableHardcodedStorageProviderFactory.PROVIDER_ID);
|
||||
model.setParentId(appRealm.getId());
|
||||
memoryProvider = appRealm.addComponentModel(model);
|
||||
realmName = appRealm.getName();
|
||||
|
||||
ClientModel offlineClient = appRealm.addClient("offline-client");
|
||||
offlineClient.setEnabled(true);
|
||||
|
@ -98,6 +104,10 @@ public class UserStorageFailureTest {
|
|||
serviceAccount.grantRole(role);
|
||||
serviceAccount.setServiceAccountClientLink(offlineClient.getClientId());
|
||||
|
||||
UserModel localUser = manager.getSession().userLocalStorage().addUser(appRealm, LOCAL_USER);
|
||||
localUser.setEnabled(true);
|
||||
|
||||
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -131,7 +141,7 @@ public class UserStorageFailureTest {
|
|||
oauth.scope(OAuth2Constants.OFFLINE_ACCESS);
|
||||
oauth.clientId("offline-client");
|
||||
oauth.redirectUri(Constants.AUTH_SERVER_ROOT + "/offline-client");
|
||||
oauth.doLogin("billb", "password");
|
||||
oauth.doLogin(FailableHardcodedStorageProvider.username, "password");
|
||||
|
||||
Event loginEvent = events.expectLogin()
|
||||
.client("offline-client")
|
||||
|
@ -149,18 +159,215 @@ public class UserStorageFailureTest {
|
|||
RefreshToken offlineToken = oauth.verifyRefreshToken(offlineTokenString);
|
||||
events.clear();
|
||||
|
||||
FailableHardcodedStorageProvider.fail = true;
|
||||
evictUser(FailableHardcodedStorageProvider.username);
|
||||
|
||||
KeycloakSession session;
|
||||
RealmModel realm;
|
||||
UserModel user;
|
||||
|
||||
toggleForceFail(true);
|
||||
|
||||
// make sure failure is turned on
|
||||
session = keycloakRule.startSession();
|
||||
realm = session.realms().getRealmByName(realmName);
|
||||
try {
|
||||
user = session.users().getUserByUsername(FailableHardcodedStorageProvider.username, realm);
|
||||
Assert.fail();
|
||||
} catch (Exception e) {
|
||||
Assert.assertEquals("FORCED FAILURE", e.getMessage());
|
||||
|
||||
}
|
||||
keycloakRule.stopSession(session, false);
|
||||
|
||||
// restart server to make sure we can still boot if user storage is down
|
||||
keycloakRule.restartServer();
|
||||
|
||||
toggleForceFail(false);
|
||||
|
||||
|
||||
// test that once user storage provider is available again we can still access the token.
|
||||
FailableHardcodedStorageProvider.fail = false;
|
||||
tokenResponse = oauth.doRefreshTokenRequest(offlineTokenString, "secret");
|
||||
Assert.assertNotNull(tokenResponse.getAccessToken());
|
||||
token = oauth.verifyToken(tokenResponse.getAccessToken());
|
||||
offlineTokenString = tokenResponse.getRefreshToken();
|
||||
offlineToken = oauth.verifyRefreshToken(offlineTokenString);
|
||||
events.clear();
|
||||
|
||||
|
||||
}
|
||||
|
||||
protected void evictUser(String username) {
|
||||
KeycloakSession session = keycloakRule.startSession();
|
||||
RealmModel realm = session.realms().getRealmByName(realmName);
|
||||
UserModel user = session.users().getUserByUsername(username, realm);
|
||||
session.userCache().evict(realm, user);
|
||||
keycloakRule.stopSession(session, true);
|
||||
}
|
||||
|
||||
protected void toggleForceFail(boolean toggle) {
|
||||
KeycloakSession session;
|
||||
RealmModel realm;
|
||||
session = keycloakRule.startSession();
|
||||
memoryProvider.getConfig().putSingle("fail", Boolean.toString(toggle));
|
||||
realm = session.realms().getRealmByName(realmName);
|
||||
realm.updateComponent(memoryProvider);
|
||||
keycloakRule.stopSession(session, true);
|
||||
}
|
||||
|
||||
protected void toggleProviderEnabled(boolean toggle) {
|
||||
KeycloakSession session;
|
||||
RealmModel realm;
|
||||
session = keycloakRule.startSession();
|
||||
UserStorageProviderModel model = new UserStorageProviderModel(memoryProvider);
|
||||
model.setEnabled(toggle);
|
||||
realm = session.realms().getRealmByName(realmName);
|
||||
realm.updateComponent(model);
|
||||
keycloakRule.stopSession(session, true);
|
||||
}
|
||||
|
||||
private void loginSuccessAndLogout(String username, String password) {
|
||||
loginPage.open();
|
||||
loginPage.login(username, password);
|
||||
Assert.assertEquals(AppPage.RequestType.AUTH_RESPONSE, appPage.getRequestType());
|
||||
Assert.assertNotNull(oauth.getCurrentQuery().get(OAuth2Constants.CODE));
|
||||
oauth.openLogout();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testKeycloak5926() {
|
||||
// make sure local copy is deleted
|
||||
{
|
||||
KeycloakSession session = keycloakRule.startSession();
|
||||
RealmModel realm = session.realms().getRealmByName(realmName);
|
||||
UserModel user = session.userLocalStorage().getUserByUsername(FailableHardcodedStorageProvider.username, realm);
|
||||
if (user != null) {
|
||||
session.userLocalStorage().removeUser(realm, user);
|
||||
}
|
||||
keycloakRule.stopSession(session, true);
|
||||
}
|
||||
|
||||
// query user to make sure its imported
|
||||
{
|
||||
KeycloakSession session = keycloakRule.startSession();
|
||||
RealmModel realm = session.realms().getRealmByName(realmName);
|
||||
UserModel user = session.users().getUserByUsername(FailableHardcodedStorageProvider.username, realm);
|
||||
Assert.assertNotNull(user);
|
||||
keycloakRule.stopSession(session, true);
|
||||
}
|
||||
|
||||
|
||||
|
||||
evictUser(FailableHardcodedStorageProvider.username);
|
||||
evictUser(LOCAL_USER);
|
||||
|
||||
toggleForceFail(true);
|
||||
{
|
||||
KeycloakSession session = keycloakRule.startSession();
|
||||
// make sure we can still query local users
|
||||
RealmModel realm = session.realms().getRealmByName(realmName);
|
||||
UserModel local = session.users().getUserByUsername(LOCAL_USER, realm);
|
||||
Assert.assertNotNull(local);
|
||||
// assert that lookup of user storage user fails
|
||||
try {
|
||||
UserModel user = session.users().getUserByUsername(FailableHardcodedStorageProvider.username, realm);
|
||||
Assert.fail();
|
||||
} catch (Exception e) {
|
||||
Assert.assertEquals("FORCED FAILURE", e.getMessage());
|
||||
|
||||
}
|
||||
|
||||
keycloakRule.stopSession(session, false);
|
||||
}
|
||||
// test that we can still login to a user
|
||||
loginSuccessAndLogout("test-user@localhost", "password");
|
||||
|
||||
toggleProviderEnabled(false);
|
||||
{
|
||||
KeycloakSession session = keycloakRule.startSession();
|
||||
// make sure we can still query local users
|
||||
RealmModel realm = session.realms().getRealmByName(realmName);
|
||||
UserModel local = session.users().getUserByUsername(LOCAL_USER, realm);
|
||||
Assert.assertNotNull(local);
|
||||
List<UserModel> result;
|
||||
result = session.users().searchForUser(LOCAL_USER, realm);
|
||||
Assert.assertEquals(1, result.size());
|
||||
session.users().searchForUser(FailableHardcodedStorageProvider.username, realm);
|
||||
Assert.assertEquals(1, result.size());
|
||||
session.users().searchForUser(LOCAL_USER, realm, 0, 2);
|
||||
Assert.assertEquals(1, result.size());
|
||||
session.users().searchForUser(FailableHardcodedStorageProvider.username, realm, 0, 2);
|
||||
Assert.assertEquals(1, result.size());
|
||||
Map<String, String> localParam = new HashMap<>();
|
||||
localParam.put("username", LOCAL_USER);
|
||||
Map<String, String> hardcodedParam = new HashMap<>();
|
||||
hardcodedParam.put("username", FailableHardcodedStorageProvider.username);
|
||||
|
||||
result = session.users().searchForUser(localParam, realm);
|
||||
Assert.assertEquals(1, result.size());
|
||||
session.users().searchForUser(hardcodedParam, realm);
|
||||
Assert.assertEquals(1, result.size());
|
||||
session.users().searchForUser(localParam, realm, 0, 2);
|
||||
Assert.assertEquals(1, result.size());
|
||||
session.users().searchForUser(hardcodedParam, realm, 0, 2);
|
||||
Assert.assertEquals(1, result.size());
|
||||
|
||||
session.users().getUsers(realm);
|
||||
session.users().getUsersCount(realm);
|
||||
|
||||
|
||||
|
||||
UserModel user = session.users().getUserByUsername(FailableHardcodedStorageProvider.username, realm);
|
||||
Assert.assertFalse(user instanceof CachedUserModel);
|
||||
Assert.assertEquals(FailableHardcodedStorageProvider.username, user.getUsername());
|
||||
Assert.assertEquals(FailableHardcodedStorageProvider.email, user.getEmail());
|
||||
Assert.assertFalse(user.isEnabled());
|
||||
try {
|
||||
user.setEmail("error@error.com");
|
||||
Assert.fail();
|
||||
} catch (Exception ex) {
|
||||
|
||||
}
|
||||
keycloakRule.stopSession(session, true);
|
||||
}
|
||||
// make sure user isn't cached as provider is disabled
|
||||
{
|
||||
KeycloakSession session = keycloakRule.startSession();
|
||||
RealmModel realm = session.realms().getRealmByName(realmName);
|
||||
UserModel user = session.users().getUserByUsername(FailableHardcodedStorageProvider.username, realm);
|
||||
Assert.assertFalse(user instanceof CachedUserModel);
|
||||
Assert.assertEquals(FailableHardcodedStorageProvider.username, user.getUsername());
|
||||
Assert.assertEquals(FailableHardcodedStorageProvider.email, user.getEmail());
|
||||
keycloakRule.stopSession(session, true);
|
||||
}
|
||||
|
||||
// make ABSOLUTELY sure user isn't cached as provider is disabled
|
||||
{
|
||||
KeycloakSession session = keycloakRule.startSession();
|
||||
RealmModel realm = session.realms().getRealmByName(realmName);
|
||||
UserModel user = session.users().getUserByUsername(FailableHardcodedStorageProvider.username, realm);
|
||||
Assert.assertFalse(user instanceof CachedUserModel);
|
||||
Assert.assertEquals(FailableHardcodedStorageProvider.username, user.getUsername());
|
||||
Assert.assertEquals(FailableHardcodedStorageProvider.email, user.getEmail());
|
||||
keycloakRule.stopSession(session, true);
|
||||
}
|
||||
|
||||
|
||||
|
||||
toggleProviderEnabled(true);
|
||||
toggleForceFail(false);
|
||||
|
||||
// user should be cachable now
|
||||
{
|
||||
KeycloakSession session = keycloakRule.startSession();
|
||||
RealmModel realm = session.realms().getRealmByName(realmName);
|
||||
UserModel user = session.users().getUserByUsername(FailableHardcodedStorageProvider.username, realm);
|
||||
Assert.assertTrue(user instanceof CachedUserModel);
|
||||
Assert.assertEquals(FailableHardcodedStorageProvider.username, user.getUsername());
|
||||
Assert.assertEquals(FailableHardcodedStorageProvider.email, user.getEmail());
|
||||
keycloakRule.stopSession(session, true);
|
||||
}
|
||||
|
||||
events.clear();
|
||||
}
|
||||
|
||||
@After
|
||||
|
|
|
@ -748,6 +748,7 @@ console-display-name=Console Display Name
|
|||
console-display-name.tooltip=Display name of provider when linked in admin console.
|
||||
priority=Priority
|
||||
priority.tooltip=Priority of provider when doing a user lookup. Lowest first.
|
||||
user-storage.enabled.tooltip=If provider is disabled it will not be considered for queries and imported users will be disabled and read only until the provider is enabled again.
|
||||
sync-settings=Sync Settings
|
||||
periodic-full-sync=Periodic Full Sync
|
||||
periodic-full-sync.tooltip=Does periodic full synchronization of provider users to Keycloak should be enabled or not
|
||||
|
|
|
@ -648,6 +648,10 @@ module.controller('UserFederationCtrl', function($scope, $location, $route, real
|
|||
return instance.providerId;
|
||||
}
|
||||
|
||||
$scope.isProviderEnabled = function(instance) {
|
||||
return !instance.config['enabled'] || instance.config['enabled'][0] == 'true';
|
||||
}
|
||||
|
||||
$scope.getInstancePriority = function(instance) {
|
||||
if (!instance.config['priority']) {
|
||||
console.log('getInstancePriority is undefined');
|
||||
|
@ -711,6 +715,7 @@ module.controller('GenericUserStorageCtrl', function($scope, $location, Notifica
|
|||
|
||||
};
|
||||
instance.config['priority'] = ["0"];
|
||||
instance.config['enabled'] = ["true"];
|
||||
|
||||
$scope.fullSyncEnabled = false;
|
||||
$scope.changedSyncEnabled = false;
|
||||
|
@ -753,6 +758,9 @@ module.controller('GenericUserStorageCtrl', function($scope, $location, Notifica
|
|||
|
||||
}
|
||||
}
|
||||
if (!instance.config['enabled']) {
|
||||
instance.config['enabled'] = ['true'];
|
||||
}
|
||||
if (!instance.config['cachePolicy']) {
|
||||
instance.config['cachePolicy'] = ['DEFAULT'];
|
||||
|
||||
|
@ -1061,6 +1069,7 @@ module.controller('LDAPUserStorageCtrl', function($scope, $location, Notificatio
|
|||
instance.config = {
|
||||
|
||||
};
|
||||
instance.config['enabled'] = ["true"];
|
||||
instance.config['priority'] = ["0"];
|
||||
|
||||
$scope.fullSyncEnabled = false;
|
||||
|
@ -1098,6 +1107,9 @@ module.controller('LDAPUserStorageCtrl', function($scope, $location, Notificatio
|
|||
instance.config['fullSyncPeriod'] = ['-1'];
|
||||
|
||||
}
|
||||
if (!instance.config['enabled']) {
|
||||
instance.config['enabled'] = ['true'];
|
||||
}
|
||||
if (!instance.config['changedSyncPeriod']) {
|
||||
console.log('setting to -1');
|
||||
instance.config['changedSyncPeriod'] = ['-1'];
|
||||
|
|
|
@ -44,6 +44,7 @@
|
|||
</tr>
|
||||
<tr data-ng-show="instances && instances.length > 0">
|
||||
<th>{{:: 'id' | translate}}</th>
|
||||
<th>{{:: 'enabled' | translate}}</th>
|
||||
<th>{{:: 'provider-name' | translate}}</th>
|
||||
<th>{{:: 'priority' | translate}}</th>
|
||||
<th colspan="2">{{:: 'actions' | translate}}</th>
|
||||
|
@ -52,6 +53,7 @@
|
|||
<tbody>
|
||||
<tr ng-repeat="instance in instances">
|
||||
<td><a href="#{{getInstanceLink(instance)}}">{{getInstanceName(instance)}}</a></td>
|
||||
<td>{{isProviderEnabled(instance)}}</td>
|
||||
<td>{{getInstanceProvider(instance) | capitalize}}</td>
|
||||
<td>{{getInstancePriority(instance)}}</td>
|
||||
<td class="kc-action-cell" kc-open="{{getInstanceLink(instance)}}">{{:: 'edit' | translate}}</td>
|
||||
|
|
|
@ -16,6 +16,13 @@
|
|||
<input class="form-control" id="providerId" type="text" ng-model="instance.id" readonly>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group clearfix block">
|
||||
<label class="col-md-2 control-label" for="enabled">{{:: 'enabled' | translate}}</label>
|
||||
<div class="col-md-6">
|
||||
<input ng-model="instance.config['enabled'][0]" name="enabled" id="enabled" onoffswitchvalue on-text="{{:: 'onText' | translate}}" off-text="{{:: 'offText' | translate}}" />
|
||||
</div>
|
||||
<kc-tooltip>{{:: 'user-storage.enabled.tooltip' | translate}}</kc-tooltip>
|
||||
</div>
|
||||
<div class="form-group clearfix">
|
||||
<label class="col-md-2 control-label" for="consoleDisplayName">{{:: 'console-display-name' | translate}} </label>
|
||||
<div class="col-md-6">
|
||||
|
|
|
@ -16,6 +16,13 @@
|
|||
<input class="form-control" id="providerId" type="text" ng-model="instance.id" readonly>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group clearfix block">
|
||||
<label class="col-md-2 control-label" for="enabled">{{:: 'enabled' | translate}}</label>
|
||||
<div class="col-md-6">
|
||||
<input ng-model="instance.config['enabled'][0]" name="enabled" id="enabled" onoffswitchvalue on-text="{{:: 'onText' | translate}}" off-text="{{:: 'offText' | translate}}" />
|
||||
</div>
|
||||
<kc-tooltip>{{:: 'user-storage.enabled.tooltip' | translate}}</kc-tooltip>
|
||||
</div>
|
||||
<div class="form-group clearfix">
|
||||
<label class="col-md-2 control-label" for="consoleDisplayName">{{:: 'console-display-name' | translate}} </label>
|
||||
<div class="col-md-6">
|
||||
|
|
|
@ -19,6 +19,13 @@
|
|||
<input class="form-control" id="providerId" type="text" ng-model="instance.id" readonly>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group clearfix block">
|
||||
<label class="col-md-2 control-label" for="enabled">{{:: 'enabled' | translate}}</label>
|
||||
<div class="col-md-6">
|
||||
<input ng-model="instance.config['enabled'][0]" name="enabled" id="enabled" onoffswitchvalue on-text="{{:: 'onText' | translate}}" off-text="{{:: 'offText' | translate}}" />
|
||||
</div>
|
||||
<kc-tooltip>{{:: 'user-storage.enabled.tooltip' | translate}}</kc-tooltip>
|
||||
</div>
|
||||
<div class="form-group clearfix">
|
||||
<label class="col-md-2 control-label" for="consoleDisplayName">{{:: 'console-display-name' | translate}} </label>
|
||||
<div class="col-md-6">
|
||||
|
|
|
@ -21,6 +21,7 @@
|
|||
<tr data-ng-show="instances && instances.length > 0">
|
||||
<th>{{:: 'id' | translate}}</th>
|
||||
<th>{{:: 'provider-name' | translate}}</th>
|
||||
<th>{{:: 'enabled' | translate}}</th>
|
||||
<th>{{:: 'priority' | translate}}</th>
|
||||
<th colspan="2">{{:: 'actions' | translate}}</th>
|
||||
</tr>
|
||||
|
@ -29,6 +30,7 @@
|
|||
<tr ng-repeat="instance in instances">
|
||||
<td><a href="#/realms/{{realm.realm}}/user-storage/providers/{{instance.providerId}}/{{instance.id}}">{{instance.name}}</a></td>
|
||||
<td>{{instance.providerId|capitalize}}</td>
|
||||
<td>{{instance.config['enabled'][0]}}</td>
|
||||
<td>{{instance.config['priority'][0]}}</td>
|
||||
<td class="kc-action-cell" kc-open="/realms/{{realm.realm}}/user-storage/providers/{{instance.providerId}}/{{instance.id}}">{{:: 'edit' | translate}}</td>
|
||||
<td class="kc-action-cell" data-ng-click="removeUserStorage(instance)">{{:: 'delete' | translate}}</td>
|
||||
|
|
Loading…
Reference in a new issue