keycloak-aplcache

Changes

Details

diff --git a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/UserCacheSession.java b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/UserCacheSession.java
index e100c29..6bed4cf 100755
--- a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/UserCacheSession.java
+++ b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/UserCacheSession.java
@@ -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);
     }
 
diff --git a/server-spi/src/main/java/org/keycloak/storage/UserStorageProviderModel.java b/server-spi/src/main/java/org/keycloak/storage/UserStorageProviderModel.java
index 55de181..1ec06a6 100755
--- a/server-spi/src/main/java/org/keycloak/storage/UserStorageProviderModel.java
+++ b/server-spi/src/main/java/org/keycloak/storage/UserStorageProviderModel.java
@@ -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);
diff --git a/server-spi/src/main/java/org/keycloak/storage/UserStorageProviderSpi.java b/server-spi/src/main/java/org/keycloak/storage/UserStorageProviderSpi.java
index 06bc256..9517b72 100755
--- a/server-spi/src/main/java/org/keycloak/storage/UserStorageProviderSpi.java
+++ b/server-spi/src/main/java/org/keycloak/storage/UserStorageProviderSpi.java
@@ -56,6 +56,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()
                 .name("fullSyncPeriod").type(ProviderConfigProperty.STRING_TYPE).add()
diff --git a/services/src/main/java/org/keycloak/credential/UserCredentialStoreManager.java b/services/src/main/java/org/keycloak/credential/UserCredentialStoreManager.java
index 0dd4aa7..16f789b 100644
--- a/services/src/main/java/org/keycloak/credential/UserCredentialStoreManager.java
+++ b/services/src/main/java/org/keycloak/credential/UserCredentialStoreManager.java
@@ -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);
diff --git a/services/src/main/java/org/keycloak/services/managers/UserStorageSyncManager.java b/services/src/main/java/org/keycloak/services/managers/UserStorageSyncManager.java
index 797301c..90d102a 100755
--- a/services/src/main/java/org/keycloak/services/managers/UserStorageSyncManager.java
+++ b/services/src/main/java/org/keycloak/services/managers/UserStorageSyncManager.java
@@ -81,7 +81,7 @@ public class UserStorageSyncManager {
 
     public SynchronizationResult syncAllUsers(final KeycloakSessionFactory sessionFactory, final String realmId, final UserStorageProviderModel provider) {
         UserStorageProviderFactory factory = (UserStorageProviderFactory) sessionFactory.getProviderFactory(UserStorageProvider.class, provider.getProviderId());
-        if (!(factory instanceof ImportSynchronization) || !provider.isImportEnabled()) {
+        if (!(factory instanceof ImportSynchronization) || !provider.isImportEnabled() || !provider.isEnabled()) {
             return SynchronizationResult.ignored();
 
         }
@@ -122,7 +122,7 @@ public class UserStorageSyncManager {
 
     public SynchronizationResult syncChangedUsers(final KeycloakSessionFactory sessionFactory, final String realmId, final UserStorageProviderModel provider) {
         UserStorageProviderFactory factory = (UserStorageProviderFactory) sessionFactory.getProviderFactory(UserStorageProvider.class, provider.getProviderId());
-        if (!(factory instanceof ImportSynchronization) || !provider.isImportEnabled()) {
+        if (!(factory instanceof ImportSynchronization) || !provider.isImportEnabled() || !provider.isEnabled()) {
             return SynchronizationResult.ignored();
 
         }
diff --git a/services/src/main/java/org/keycloak/storage/UserStorageManager.java b/services/src/main/java/org/keycloak/storage/UserStorageManager.java
index 7cbe67c..16d14e0 100755
--- a/services/src/main/java/org/keycloak/storage/UserStorageManager.java
+++ b/services/src/main/java/org/keycloak/storage/UserStorageManager.java
@@ -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);
             }
         }
diff --git a/testsuite/integration-deprecated/src/test/java/org/keycloak/testsuite/federation/storage/FailableHardcodedStorageProvider.java b/testsuite/integration-deprecated/src/test/java/org/keycloak/testsuite/federation/storage/FailableHardcodedStorageProvider.java
index 780d1c7..0c221ab 100644
--- a/testsuite/integration-deprecated/src/test/java/org/keycloak/testsuite/federation/storage/FailableHardcodedStorageProvider.java
+++ b/testsuite/integration-deprecated/src/test/java/org/keycloak/testsuite/federation/storage/FailableHardcodedStorageProvider.java
@@ -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";
@@ -59,18 +62,22 @@ public class FailableHardcodedStorageProvider implements UserStorageProvider, Us
     public FailableHardcodedStorageProvider(ComponentModel model, KeycloakSession session) {
         this.model = model;
         this.session = session;
-        componentFail = model.getConfig().getFirst("fail") != null && model.getConfig().getFirst("fail").equalsIgnoreCase("true");
+        componentFail = isInFailMode(model);
+    }
+
+    public static boolean isInFailMode(ComponentModel model) {
+        return model.getConfig().getFirst("fail") != null && model.getConfig().getFirst("fail").equalsIgnoreCase("true");
     }
 
     @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 +92,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 +170,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 +205,100 @@ 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) throwFailure();
+    }
+
+    public static  void throwFailure() {
+        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() {
 
diff --git a/testsuite/integration-deprecated/src/test/java/org/keycloak/testsuite/federation/storage/FailableHardcodedStorageProviderFactory.java b/testsuite/integration-deprecated/src/test/java/org/keycloak/testsuite/federation/storage/FailableHardcodedStorageProviderFactory.java
index 46faec0..de34096 100644
--- a/testsuite/integration-deprecated/src/test/java/org/keycloak/testsuite/federation/storage/FailableHardcodedStorageProviderFactory.java
+++ b/testsuite/integration-deprecated/src/test/java/org/keycloak/testsuite/federation/storage/FailableHardcodedStorageProviderFactory.java
@@ -18,9 +18,14 @@ package org.keycloak.testsuite.federation.storage;
 
 import org.keycloak.component.ComponentModel;
 import org.keycloak.models.KeycloakSession;
+import org.keycloak.models.KeycloakSessionFactory;
 import org.keycloak.provider.ProviderConfigProperty;
 import org.keycloak.storage.UserStorageProviderFactory;
+import org.keycloak.storage.UserStorageProviderModel;
+import org.keycloak.storage.user.ImportSynchronization;
+import org.keycloak.storage.user.SynchronizationResult;
 
+import java.util.Date;
 import java.util.LinkedList;
 import java.util.List;
 
@@ -28,7 +33,7 @@ import java.util.List;
  * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
  * @version $Revision: 1 $
  */
-public class FailableHardcodedStorageProviderFactory implements UserStorageProviderFactory<FailableHardcodedStorageProvider> {
+public class FailableHardcodedStorageProviderFactory implements UserStorageProviderFactory<FailableHardcodedStorageProvider>, ImportSynchronization {
 
     public static final String PROVIDER_ID = "failable-hardcoded-storage";
 
@@ -52,4 +57,15 @@ public class FailableHardcodedStorageProviderFactory implements UserStorageProvi
         return OPTIONS;
     }
 
+    @Override
+    public SynchronizationResult sync(KeycloakSessionFactory sessionFactory, String realmId, UserStorageProviderModel model) {
+        if (FailableHardcodedStorageProvider.isInFailMode(model)) FailableHardcodedStorageProvider.throwFailure();
+        return SynchronizationResult.empty();
+    }
+
+    @Override
+    public SynchronizationResult syncSince(Date lastSync, KeycloakSessionFactory sessionFactory, String realmId, UserStorageProviderModel model) {
+        if (FailableHardcodedStorageProvider.isInFailMode(model)) FailableHardcodedStorageProvider.throwFailure();
+        return SynchronizationResult.empty();
+    }
 }
diff --git a/testsuite/integration-deprecated/src/test/java/org/keycloak/testsuite/federation/storage/UserStorageFailureTest.java b/testsuite/integration-deprecated/src/test/java/org/keycloak/testsuite/federation/storage/UserStorageFailureTest.java
index d8d5fbd..daeb309 100644
--- a/testsuite/integration-deprecated/src/test/java/org/keycloak/testsuite/federation/storage/UserStorageFailureTest.java
+++ b/testsuite/integration-deprecated/src/test/java/org/keycloak/testsuite/federation/storage/UserStorageFailureTest.java
@@ -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;
@@ -48,6 +49,7 @@ import org.keycloak.representations.idm.UserRepresentation;
 import org.keycloak.services.managers.RealmManager;
 import org.keycloak.storage.StorageId;
 import org.keycloak.storage.UserStorageProviderModel;
+import org.keycloak.testsuite.ApplicationServlet;
 import org.keycloak.testsuite.AssertEvents;
 import org.keycloak.testsuite.Constants;
 import org.keycloak.testsuite.OAuthClient;
@@ -59,8 +61,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 +73,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 +86,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 +105,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 +142,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,26 +160,223 @@ 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();
+        keycloakRule.deployServlet("app", "/app", ApplicationServlet.class);
+
+        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();
+
+
     }
 
-    @After
-    public void resetTimeoffset() {
-        Time.setOffset(0);
+    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);
+        System.out.println(driver.getCurrentUrl());
+        System.out.println(driver.getPageSource());
+        Assert.assertTrue(appPage.isCurrent());
+        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, true);
+        }
+        // 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();
     }
 
+
     //@Test
     public void testIDE() throws Exception {
         Thread.sleep(100000000);
diff --git a/themes/src/main/resources/theme/base/admin/messages/admin-messages_en.properties b/themes/src/main/resources/theme/base/admin/messages/admin-messages_en.properties
index 61955d3..ca2c23f 100644
--- a/themes/src/main/resources/theme/base/admin/messages/admin-messages_en.properties
+++ b/themes/src/main/resources/theme/base/admin/messages/admin-messages_en.properties
@@ -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
diff --git a/themes/src/main/resources/theme/base/admin/resources/js/controllers/users.js b/themes/src/main/resources/theme/base/admin/resources/js/controllers/users.js
index c50b691..f1c0742 100755
--- a/themes/src/main/resources/theme/base/admin/resources/js/controllers/users.js
+++ b/themes/src/main/resources/theme/base/admin/resources/js/controllers/users.js
@@ -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'];
diff --git a/themes/src/main/resources/theme/base/admin/resources/partials/user-federation.html b/themes/src/main/resources/theme/base/admin/resources/partials/user-federation.html
index 8298a99..3b97f51 100755
--- a/themes/src/main/resources/theme/base/admin/resources/partials/user-federation.html
+++ b/themes/src/main/resources/theme/base/admin/resources/partials/user-federation.html
@@ -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>
diff --git a/themes/src/main/resources/theme/base/admin/resources/partials/user-storage.html b/themes/src/main/resources/theme/base/admin/resources/partials/user-storage.html
index aaf2158..93ca5a9 100755
--- a/themes/src/main/resources/theme/base/admin/resources/partials/user-storage.html
+++ b/themes/src/main/resources/theme/base/admin/resources/partials/user-storage.html
@@ -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>
diff --git a/themes/src/main/resources/theme/base/admin/resources/partials/user-storage-generic.html b/themes/src/main/resources/theme/base/admin/resources/partials/user-storage-generic.html
index b4a1fda..2b2456c 100755
--- a/themes/src/main/resources/theme/base/admin/resources/partials/user-storage-generic.html
+++ b/themes/src/main/resources/theme/base/admin/resources/partials/user-storage-generic.html
@@ -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">
diff --git a/themes/src/main/resources/theme/base/admin/resources/partials/user-storage-kerberos.html b/themes/src/main/resources/theme/base/admin/resources/partials/user-storage-kerberos.html
index 5dd0a67..b7fa6ef 100644
--- a/themes/src/main/resources/theme/base/admin/resources/partials/user-storage-kerberos.html
+++ b/themes/src/main/resources/theme/base/admin/resources/partials/user-storage-kerberos.html
@@ -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">
diff --git a/themes/src/main/resources/theme/base/admin/resources/partials/user-storage-ldap.html b/themes/src/main/resources/theme/base/admin/resources/partials/user-storage-ldap.html
index 9412839..0a391b9 100755
--- a/themes/src/main/resources/theme/base/admin/resources/partials/user-storage-ldap.html
+++ b/themes/src/main/resources/theme/base/admin/resources/partials/user-storage-ldap.html
@@ -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">