Move User Storage SPI, introduce ExportImportManager
This commit is contained in:
parent
703e868a51
commit
82094d113e
63 changed files with 1680 additions and 1482 deletions
|
@ -27,6 +27,7 @@ import org.keycloak.provider.ProviderFactory;
|
||||||
import org.keycloak.representations.idm.RealmRepresentation;
|
import org.keycloak.representations.idm.RealmRepresentation;
|
||||||
import org.keycloak.storage.UserStorageProvider;
|
import org.keycloak.storage.UserStorageProvider;
|
||||||
import org.keycloak.storage.UserStorageProviderModel;
|
import org.keycloak.storage.UserStorageProviderModel;
|
||||||
|
import org.keycloak.storage.UserStorageUtil;
|
||||||
|
|
||||||
import javax.naming.directory.SearchControls;
|
import javax.naming.directory.SearchControls;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
@ -52,7 +53,7 @@ public class MigrateTo1_3_0 implements Migration {
|
||||||
}
|
}
|
||||||
|
|
||||||
private void migrateLDAPProviders(KeycloakSession session, RealmModel realm) {
|
private void migrateLDAPProviders(KeycloakSession session, RealmModel realm) {
|
||||||
realm.getUserStorageProvidersStream().forEachOrdered(fedProvider -> {
|
UserStorageUtil.getUserStorageProvidersStream(realm).forEachOrdered(fedProvider -> {
|
||||||
if (fedProvider.getProviderId().equals(LDAPConstants.LDAP_PROVIDER)) {
|
if (fedProvider.getProviderId().equals(LDAPConstants.LDAP_PROVIDER)) {
|
||||||
fedProvider = new UserStorageProviderModel(fedProvider); // copy don't want to muck with cache
|
fedProvider = new UserStorageProviderModel(fedProvider); // copy don't want to muck with cache
|
||||||
MultivaluedHashMap<String, String> config = fedProvider.getConfig();
|
MultivaluedHashMap<String, String> config = fedProvider.getConfig();
|
|
@ -29,6 +29,7 @@ import org.keycloak.models.utils.DefaultAuthenticationFlows;
|
||||||
import org.keycloak.models.utils.DefaultRequiredActions;
|
import org.keycloak.models.utils.DefaultRequiredActions;
|
||||||
import org.keycloak.models.utils.KeycloakModelUtils;
|
import org.keycloak.models.utils.KeycloakModelUtils;
|
||||||
import org.keycloak.representations.idm.RealmRepresentation;
|
import org.keycloak.representations.idm.RealmRepresentation;
|
||||||
|
import org.keycloak.storage.UserStorageUtil;
|
||||||
|
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
@ -67,7 +68,7 @@ public class MigrateTo1_4_0 implements Migration {
|
||||||
|
|
||||||
private void migrateLDAPMappers(KeycloakSession session, RealmModel realm) {
|
private void migrateLDAPMappers(KeycloakSession session, RealmModel realm) {
|
||||||
List<String> mandatoryInLdap = Arrays.asList("username", "username-cn", "first name", "last name");
|
List<String> mandatoryInLdap = Arrays.asList("username", "username-cn", "first name", "last name");
|
||||||
realm.getUserStorageProvidersStream()
|
UserStorageUtil.getUserStorageProvidersStream(realm)
|
||||||
.filter(providerModel -> Objects.equals(providerModel.getProviderId(), LDAPConstants.LDAP_PROVIDER))
|
.filter(providerModel -> Objects.equals(providerModel.getProviderId(), LDAPConstants.LDAP_PROVIDER))
|
||||||
.forEachOrdered(providerModel -> realm.getComponentsStream(providerModel.getId())
|
.forEachOrdered(providerModel -> realm.getComponentsStream(providerModel.getId())
|
||||||
.filter(mapper -> mandatoryInLdap.contains(mapper.getName()))
|
.filter(mapper -> mandatoryInLdap.contains(mapper.getName()))
|
|
@ -25,6 +25,7 @@ import org.keycloak.models.RealmModel;
|
||||||
import org.keycloak.models.utils.KeycloakModelUtils;
|
import org.keycloak.models.utils.KeycloakModelUtils;
|
||||||
import org.keycloak.representations.idm.RealmRepresentation;
|
import org.keycloak.representations.idm.RealmRepresentation;
|
||||||
import org.keycloak.storage.UserStorageProviderModel;
|
import org.keycloak.storage.UserStorageProviderModel;
|
||||||
|
import org.keycloak.storage.UserStorageUtil;
|
||||||
|
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
|
|
||||||
|
@ -50,7 +51,7 @@ public class MigrateTo1_8_0 implements Migration {
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void migrateRealm(RealmModel realm) {
|
protected void migrateRealm(RealmModel realm) {
|
||||||
realm.getUserStorageProvidersStream()
|
UserStorageUtil.getUserStorageProvidersStream(realm)
|
||||||
.filter(fedProvider -> Objects.equals(fedProvider.getProviderId(), LDAPConstants.LDAP_PROVIDER))
|
.filter(fedProvider -> Objects.equals(fedProvider.getProviderId(), LDAPConstants.LDAP_PROVIDER))
|
||||||
.filter(this::isActiveDirectory)
|
.filter(this::isActiveDirectory)
|
||||||
.filter(fedProvider -> Objects.isNull(getMapperByName(realm, fedProvider, "MSAD account controls")))
|
.filter(fedProvider -> Objects.isNull(getMapperByName(realm, fedProvider, "MSAD account controls")))
|
|
@ -12,13 +12,14 @@ import org.keycloak.models.cache.UserCache;
|
||||||
import org.keycloak.storage.ClientScopeStorageManager;
|
import org.keycloak.storage.ClientScopeStorageManager;
|
||||||
import org.keycloak.storage.ClientStorageManager;
|
import org.keycloak.storage.ClientStorageManager;
|
||||||
import org.keycloak.storage.DatastoreProvider;
|
import org.keycloak.storage.DatastoreProvider;
|
||||||
|
import org.keycloak.storage.ExportImportManager;
|
||||||
import org.keycloak.storage.GroupStorageManager;
|
import org.keycloak.storage.GroupStorageManager;
|
||||||
import org.keycloak.storage.LegacyStoreManagers;
|
import org.keycloak.storage.LegacyStoreManagers;
|
||||||
|
import org.keycloak.storage.MigrationManager;
|
||||||
import org.keycloak.storage.RoleStorageManager;
|
import org.keycloak.storage.RoleStorageManager;
|
||||||
import org.keycloak.storage.UserStorageManager;
|
import org.keycloak.storage.UserStorageManager;
|
||||||
|
|
||||||
public class LegacyDatastoreProvider implements DatastoreProvider, LegacyStoreManagers {
|
public class LegacyDatastoreProvider implements DatastoreProvider, LegacyStoreManagers {
|
||||||
|
|
||||||
private final LegacyDatastoreProviderFactory factory;
|
private final LegacyDatastoreProviderFactory factory;
|
||||||
private final KeycloakSession session;
|
private final KeycloakSession session;
|
||||||
|
|
||||||
|
@ -184,4 +185,15 @@ public class LegacyDatastoreProvider implements DatastoreProvider, LegacyStoreMa
|
||||||
}
|
}
|
||||||
return userProvider;
|
return userProvider;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ExportImportManager getExportImportManager() {
|
||||||
|
return new LegacyExportImportManager(session);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public MigrationManager getMigrationManager() {
|
||||||
|
return new LegacyMigrationManager(session);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -0,0 +1,181 @@
|
||||||
|
package org.keycloak.storage.datastore;
|
||||||
|
|
||||||
|
import org.jboss.logging.Logger;
|
||||||
|
import org.keycloak.common.Version;
|
||||||
|
import org.keycloak.migration.MigrationModel;
|
||||||
|
import org.keycloak.migration.ModelVersion;
|
||||||
|
import org.keycloak.migration.migrators.MigrateTo12_0_0;
|
||||||
|
import org.keycloak.migration.migrators.MigrateTo14_0_0;
|
||||||
|
import org.keycloak.migration.migrators.MigrateTo18_0_0;
|
||||||
|
import org.keycloak.migration.migrators.MigrateTo1_2_0;
|
||||||
|
import org.keycloak.migration.migrators.MigrateTo1_3_0;
|
||||||
|
import org.keycloak.migration.migrators.MigrateTo1_4_0;
|
||||||
|
import org.keycloak.migration.migrators.MigrateTo1_5_0;
|
||||||
|
import org.keycloak.migration.migrators.MigrateTo1_6_0;
|
||||||
|
import org.keycloak.migration.migrators.MigrateTo1_7_0;
|
||||||
|
import org.keycloak.migration.migrators.MigrateTo1_8_0;
|
||||||
|
import org.keycloak.migration.migrators.MigrateTo1_9_0;
|
||||||
|
import org.keycloak.migration.migrators.MigrateTo1_9_2;
|
||||||
|
import org.keycloak.migration.migrators.MigrateTo2_0_0;
|
||||||
|
import org.keycloak.migration.migrators.MigrateTo2_1_0;
|
||||||
|
import org.keycloak.migration.migrators.MigrateTo2_2_0;
|
||||||
|
import org.keycloak.migration.migrators.MigrateTo2_3_0;
|
||||||
|
import org.keycloak.migration.migrators.MigrateTo2_5_0;
|
||||||
|
import org.keycloak.migration.migrators.MigrateTo3_0_0;
|
||||||
|
import org.keycloak.migration.migrators.MigrateTo3_1_0;
|
||||||
|
import org.keycloak.migration.migrators.MigrateTo3_2_0;
|
||||||
|
import org.keycloak.migration.migrators.MigrateTo3_4_0;
|
||||||
|
import org.keycloak.migration.migrators.MigrateTo3_4_1;
|
||||||
|
import org.keycloak.migration.migrators.MigrateTo3_4_2;
|
||||||
|
import org.keycloak.migration.migrators.MigrateTo4_0_0;
|
||||||
|
import org.keycloak.migration.migrators.MigrateTo4_2_0;
|
||||||
|
import org.keycloak.migration.migrators.MigrateTo4_6_0;
|
||||||
|
import org.keycloak.migration.migrators.MigrateTo6_0_0;
|
||||||
|
import org.keycloak.migration.migrators.MigrateTo8_0_0;
|
||||||
|
import org.keycloak.migration.migrators.MigrateTo8_0_2;
|
||||||
|
import org.keycloak.migration.migrators.MigrateTo9_0_0;
|
||||||
|
import org.keycloak.migration.migrators.MigrateTo9_0_4;
|
||||||
|
import org.keycloak.migration.migrators.Migration;
|
||||||
|
import org.keycloak.models.Constants;
|
||||||
|
import org.keycloak.models.DeploymentStateProvider;
|
||||||
|
import org.keycloak.models.KeycloakSession;
|
||||||
|
import org.keycloak.models.RealmModel;
|
||||||
|
import org.keycloak.representations.idm.RealmRepresentation;
|
||||||
|
import org.keycloak.storage.MigrationManager;
|
||||||
|
|
||||||
|
import java.util.LinkedHashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This wraps the functionality for migrations of the legacy storage. This will be handled differently for the new map storage,
|
||||||
|
* therefore, it has been extracted.
|
||||||
|
*
|
||||||
|
* @author Alexander Schwartz
|
||||||
|
*/
|
||||||
|
public class LegacyMigrationManager implements MigrationManager {
|
||||||
|
private static final Logger logger = Logger.getLogger(LegacyMigrationManager.class);
|
||||||
|
|
||||||
|
private static final Migration[] migrations = {
|
||||||
|
new MigrateTo1_2_0(),
|
||||||
|
new MigrateTo1_3_0(),
|
||||||
|
new MigrateTo1_4_0(),
|
||||||
|
new MigrateTo1_5_0(),
|
||||||
|
new MigrateTo1_6_0(),
|
||||||
|
new MigrateTo1_7_0(),
|
||||||
|
new MigrateTo1_8_0(),
|
||||||
|
new MigrateTo1_9_0(),
|
||||||
|
new MigrateTo1_9_2(),
|
||||||
|
new MigrateTo2_0_0(),
|
||||||
|
new MigrateTo2_1_0(),
|
||||||
|
new MigrateTo2_2_0(),
|
||||||
|
new MigrateTo2_3_0(),
|
||||||
|
new MigrateTo2_5_0(),
|
||||||
|
new MigrateTo3_0_0(),
|
||||||
|
new MigrateTo3_1_0(),
|
||||||
|
new MigrateTo3_2_0(),
|
||||||
|
new MigrateTo3_4_0(),
|
||||||
|
new MigrateTo3_4_1(),
|
||||||
|
new MigrateTo3_4_2(),
|
||||||
|
new MigrateTo4_0_0(),
|
||||||
|
new MigrateTo4_2_0(),
|
||||||
|
new MigrateTo4_6_0(),
|
||||||
|
new MigrateTo6_0_0(),
|
||||||
|
new MigrateTo8_0_0(),
|
||||||
|
new MigrateTo8_0_2(),
|
||||||
|
new MigrateTo9_0_0(),
|
||||||
|
new MigrateTo9_0_4(),
|
||||||
|
new MigrateTo12_0_0(),
|
||||||
|
new MigrateTo14_0_0(),
|
||||||
|
new MigrateTo18_0_0()
|
||||||
|
};
|
||||||
|
|
||||||
|
private final KeycloakSession session;
|
||||||
|
|
||||||
|
public LegacyMigrationManager(KeycloakSession session) {
|
||||||
|
this.session = session;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void migrate() {
|
||||||
|
session.setAttribute(Constants.STORAGE_BATCH_ENABLED, Boolean.getBoolean("keycloak.migration.batch-enabled"));
|
||||||
|
session.setAttribute(Constants.STORAGE_BATCH_SIZE, Integer.getInteger("keycloak.migration.batch-size"));
|
||||||
|
MigrationModel model = session.getProvider(DeploymentStateProvider.class).getMigrationModel();
|
||||||
|
|
||||||
|
ModelVersion currentVersion = new ModelVersion(Version.VERSION_KEYCLOAK);
|
||||||
|
ModelVersion latestUpdate = migrations[migrations.length-1].getVersion();
|
||||||
|
ModelVersion databaseVersion = model.getStoredVersion() != null ? new ModelVersion(model.getStoredVersion()) : null;
|
||||||
|
|
||||||
|
if (databaseVersion == null || databaseVersion.lessThan(latestUpdate)) {
|
||||||
|
for (Migration m : migrations) {
|
||||||
|
if (databaseVersion == null || databaseVersion.lessThan(m.getVersion())) {
|
||||||
|
if (databaseVersion != null) {
|
||||||
|
logger.debugf("Migrating older model to %s", m.getVersion());
|
||||||
|
}
|
||||||
|
m.migrate(session);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (databaseVersion == null || databaseVersion.lessThan(currentVersion)) {
|
||||||
|
model.setStoredVersion(currentVersion.toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
Version.RESOURCES_VERSION = model.getResourcesTag();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static final ModelVersion RHSSO_VERSION_7_0_KEYCLOAK_VERSION = new ModelVersion("1.9.8");
|
||||||
|
public static final ModelVersion RHSSO_VERSION_7_1_KEYCLOAK_VERSION = new ModelVersion("2.5.5");
|
||||||
|
public static final ModelVersion RHSSO_VERSION_7_2_KEYCLOAK_VERSION = new ModelVersion("3.4.3");
|
||||||
|
public static final ModelVersion RHSSO_VERSION_7_3_KEYCLOAK_VERSION = new ModelVersion("4.8.3");
|
||||||
|
public static final ModelVersion RHSSO_VERSION_7_4_KEYCLOAK_VERSION = new ModelVersion("9.0.3");
|
||||||
|
|
||||||
|
private static final Map<Pattern, ModelVersion> PATTERN_MATCHER = new LinkedHashMap<>();
|
||||||
|
static {
|
||||||
|
PATTERN_MATCHER.put(Pattern.compile("^7\\.0\\.\\d+\\.GA$"), RHSSO_VERSION_7_0_KEYCLOAK_VERSION);
|
||||||
|
PATTERN_MATCHER.put(Pattern.compile("^7\\.1\\.\\d+\\.GA$"), RHSSO_VERSION_7_1_KEYCLOAK_VERSION);
|
||||||
|
PATTERN_MATCHER.put(Pattern.compile("^7\\.2\\.\\d+\\.GA$"), RHSSO_VERSION_7_2_KEYCLOAK_VERSION);
|
||||||
|
PATTERN_MATCHER.put(Pattern.compile("^7\\.3\\.\\d+\\.GA$"), RHSSO_VERSION_7_3_KEYCLOAK_VERSION);
|
||||||
|
PATTERN_MATCHER.put(Pattern.compile("^7\\.4\\.\\d+\\.GA$"), RHSSO_VERSION_7_4_KEYCLOAK_VERSION);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void migrate(RealmModel realm, RealmRepresentation rep, boolean skipUserDependent) {
|
||||||
|
ModelVersion stored = null;
|
||||||
|
if (rep.getKeycloakVersion() != null) {
|
||||||
|
stored = convertRHSSOVersionToKeycloakVersion(rep.getKeycloakVersion());
|
||||||
|
if (stored == null) {
|
||||||
|
stored = new ModelVersion(rep.getKeycloakVersion());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (stored == null) {
|
||||||
|
stored = migrations[0].getVersion();
|
||||||
|
}
|
||||||
|
|
||||||
|
for (Migration m : migrations) {
|
||||||
|
if (stored == null || stored.lessThan(m.getVersion())) {
|
||||||
|
if (stored != null) {
|
||||||
|
logger.debugf("Migrating older json representation to %s", m.getVersion());
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
m.migrateImport(session, realm, rep, skipUserDependent);
|
||||||
|
} catch (Exception e) {
|
||||||
|
logger.error("Failed to migrate json representation for version: " + m.getVersion(), e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static ModelVersion convertRHSSOVersionToKeycloakVersion(String version) {
|
||||||
|
// look for the keycloakVersion pattern to identify it as RH SSO
|
||||||
|
for (Pattern pattern : PATTERN_MATCHER.keySet()) {
|
||||||
|
if (pattern.matcher(version).find()) {
|
||||||
|
return PATTERN_MATCHER.get(pattern);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// chceck if the version is in format for CD releases, e.g.: "keycloakVersion": "6"
|
||||||
|
if (Pattern.compile("^[0-9]*$").matcher(version).find()) {
|
||||||
|
return new ModelVersion(Integer.parseInt(version), 0, 0);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -31,6 +31,7 @@ import org.keycloak.models.utils.KeycloakModelUtils;
|
||||||
import org.keycloak.storage.UserStorageProvider;
|
import org.keycloak.storage.UserStorageProvider;
|
||||||
import org.keycloak.storage.UserStorageProviderFactory;
|
import org.keycloak.storage.UserStorageProviderFactory;
|
||||||
import org.keycloak.storage.UserStorageProviderModel;
|
import org.keycloak.storage.UserStorageProviderModel;
|
||||||
|
import org.keycloak.storage.UserStorageUtil;
|
||||||
import org.keycloak.storage.user.ImportSynchronization;
|
import org.keycloak.storage.user.ImportSynchronization;
|
||||||
import org.keycloak.storage.user.SynchronizationResult;
|
import org.keycloak.storage.user.SynchronizationResult;
|
||||||
import org.keycloak.timer.TimerProvider;
|
import org.keycloak.timer.TimerProvider;
|
||||||
|
@ -61,7 +62,7 @@ public class UserStorageSyncManager {
|
||||||
public void run(KeycloakSession session) {
|
public void run(KeycloakSession session) {
|
||||||
Stream<RealmModel> realms = session.realms().getRealmsWithProviderTypeStream(UserStorageProvider.class);
|
Stream<RealmModel> realms = session.realms().getRealmsWithProviderTypeStream(UserStorageProvider.class);
|
||||||
realms.forEach(realm -> {
|
realms.forEach(realm -> {
|
||||||
Stream<UserStorageProviderModel> providers = realm.getUserStorageProvidersStream();
|
Stream<UserStorageProviderModel> providers = UserStorageUtil.getUserStorageProvidersStream(realm);
|
||||||
providers.forEachOrdered(provider -> {
|
providers.forEachOrdered(provider -> {
|
||||||
UserStorageProviderFactory factory = (UserStorageProviderFactory) session.getKeycloakSessionFactory().getProviderFactory(UserStorageProvider.class, provider.getProviderId());
|
UserStorageProviderFactory factory = (UserStorageProviderFactory) session.getKeycloakSessionFactory().getProviderFactory(UserStorageProvider.class, provider.getProviderId());
|
||||||
if (factory instanceof ImportSynchronization && provider.isImportEnabled()) {
|
if (factory instanceof ImportSynchronization && provider.isImportEnabled()) {
|
||||||
|
@ -165,7 +166,7 @@ public class UserStorageSyncManager {
|
||||||
|
|
||||||
|
|
||||||
public static void notifyToRefreshPeriodicSyncAll(KeycloakSession session, RealmModel realm, boolean removed) {
|
public static void notifyToRefreshPeriodicSyncAll(KeycloakSession session, RealmModel realm, boolean removed) {
|
||||||
realm.getUserStorageProvidersStream().forEachOrdered(fedProvider ->
|
UserStorageUtil.getUserStorageProvidersStream(realm).forEachOrdered(fedProvider ->
|
||||||
notifyToRefreshPeriodicSync(session, realm, fedProvider, removed));
|
notifyToRefreshPeriodicSync(session, realm, fedProvider, removed));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -267,7 +268,7 @@ public class UserStorageSyncManager {
|
||||||
@Override
|
@Override
|
||||||
public void run(KeycloakSession session) {
|
public void run(KeycloakSession session) {
|
||||||
RealmModel persistentRealm = session.realms().getRealm(realmId);
|
RealmModel persistentRealm = session.realms().getRealm(realmId);
|
||||||
persistentRealm.getUserStorageProvidersStream()
|
UserStorageUtil.getUserStorageProvidersStream(persistentRealm)
|
||||||
.filter(persistentFedProvider -> Objects.equals(provider.getId(), persistentFedProvider.getId()))
|
.filter(persistentFedProvider -> Objects.equals(provider.getId(), persistentFedProvider.getId()))
|
||||||
.forEachOrdered(persistentFedProvider -> {
|
.forEachOrdered(persistentFedProvider -> {
|
||||||
// Update persistent provider in DB
|
// Update persistent provider in DB
|
||||||
|
|
|
@ -0,0 +1,71 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2016 Red Hat, Inc. and/or its affiliates
|
||||||
|
* and other contributors as indicated by the @author tags.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.keycloak.models.datastore;
|
||||||
|
|
||||||
|
import org.junit.Assert;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.keycloak.migration.ModelVersion;
|
||||||
|
|
||||||
|
import static org.keycloak.storage.datastore.LegacyMigrationManager.RHSSO_VERSION_7_0_KEYCLOAK_VERSION;
|
||||||
|
import static org.keycloak.storage.datastore.LegacyMigrationManager.RHSSO_VERSION_7_1_KEYCLOAK_VERSION;
|
||||||
|
import static org.keycloak.storage.datastore.LegacyMigrationManager.RHSSO_VERSION_7_2_KEYCLOAK_VERSION;
|
||||||
|
import static org.keycloak.storage.datastore.LegacyMigrationManager.RHSSO_VERSION_7_3_KEYCLOAK_VERSION;
|
||||||
|
import static org.keycloak.storage.datastore.LegacyMigrationManager.RHSSO_VERSION_7_4_KEYCLOAK_VERSION;
|
||||||
|
import static org.keycloak.storage.datastore.LegacyMigrationManager.convertRHSSOVersionToKeycloakVersion;
|
||||||
|
import static org.hamcrest.CoreMatchers.equalTo;
|
||||||
|
import static org.hamcrest.CoreMatchers.is;
|
||||||
|
import static org.hamcrest.CoreMatchers.nullValue;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
||||||
|
* @version $Revision: 1 $
|
||||||
|
*/
|
||||||
|
public class LegacyMigrationManagerTest {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testRHSSOVersionToKeycloakVersionConversion() {
|
||||||
|
Assert.assertThat(convertRHSSOVersionToKeycloakVersion("7.0.0.GA"), is(equalTo(RHSSO_VERSION_7_0_KEYCLOAK_VERSION)));
|
||||||
|
Assert.assertThat(convertRHSSOVersionToKeycloakVersion("7.0.1.GA"), is(equalTo(RHSSO_VERSION_7_0_KEYCLOAK_VERSION)));
|
||||||
|
Assert.assertThat(convertRHSSOVersionToKeycloakVersion("7.0.2.GA"), is(equalTo(RHSSO_VERSION_7_0_KEYCLOAK_VERSION)));
|
||||||
|
|
||||||
|
Assert.assertThat(convertRHSSOVersionToKeycloakVersion("7.1.0.GA"), is(equalTo(RHSSO_VERSION_7_1_KEYCLOAK_VERSION)));
|
||||||
|
Assert.assertThat(convertRHSSOVersionToKeycloakVersion("7.1.1.GA"), is(equalTo(RHSSO_VERSION_7_1_KEYCLOAK_VERSION)));
|
||||||
|
Assert.assertThat(convertRHSSOVersionToKeycloakVersion("7.1.2.GA"), is(equalTo(RHSSO_VERSION_7_1_KEYCLOAK_VERSION)));
|
||||||
|
|
||||||
|
Assert.assertThat(convertRHSSOVersionToKeycloakVersion("7.2.0.GA"), is(equalTo(RHSSO_VERSION_7_2_KEYCLOAK_VERSION)));
|
||||||
|
Assert.assertThat(convertRHSSOVersionToKeycloakVersion("7.2.1.GA"), is(equalTo(RHSSO_VERSION_7_2_KEYCLOAK_VERSION)));
|
||||||
|
Assert.assertThat(convertRHSSOVersionToKeycloakVersion("7.2.2.GA"), is(equalTo(RHSSO_VERSION_7_2_KEYCLOAK_VERSION)));
|
||||||
|
|
||||||
|
Assert.assertThat(convertRHSSOVersionToKeycloakVersion("7.3.0.GA"), is(equalTo(RHSSO_VERSION_7_3_KEYCLOAK_VERSION)));
|
||||||
|
Assert.assertThat(convertRHSSOVersionToKeycloakVersion("7.3.1.GA"), is(equalTo(RHSSO_VERSION_7_3_KEYCLOAK_VERSION)));
|
||||||
|
Assert.assertThat(convertRHSSOVersionToKeycloakVersion("7.3.2.GA"), is(equalTo(RHSSO_VERSION_7_3_KEYCLOAK_VERSION)));
|
||||||
|
Assert.assertThat(convertRHSSOVersionToKeycloakVersion("7.3.10.GA"), is(equalTo(RHSSO_VERSION_7_3_KEYCLOAK_VERSION)));
|
||||||
|
|
||||||
|
Assert.assertThat(convertRHSSOVersionToKeycloakVersion("7.4.0.GA"), is(equalTo(RHSSO_VERSION_7_4_KEYCLOAK_VERSION)));
|
||||||
|
Assert.assertThat(convertRHSSOVersionToKeycloakVersion("7.4.15.GA"), is(equalTo(RHSSO_VERSION_7_4_KEYCLOAK_VERSION)));
|
||||||
|
|
||||||
|
// check the conversion doesn't change version for keycloak
|
||||||
|
Assert.assertThat(convertRHSSOVersionToKeycloakVersion("7.0.0"), is(nullValue()));
|
||||||
|
Assert.assertThat(convertRHSSOVersionToKeycloakVersion("8.0.0"), is(nullValue()));
|
||||||
|
|
||||||
|
// check for CD releases
|
||||||
|
Assert.assertThat(convertRHSSOVersionToKeycloakVersion("6"), is(equalTo(new ModelVersion("6.0.0"))));
|
||||||
|
Assert.assertThat(convertRHSSOVersionToKeycloakVersion("7"), is(equalTo(new ModelVersion("7.0.0"))));
|
||||||
|
Assert.assertThat(convertRHSSOVersionToKeycloakVersion("10"), is(equalTo(new ModelVersion("10.0.0"))));
|
||||||
|
}
|
||||||
|
}
|
|
@ -25,7 +25,7 @@ import org.keycloak.events.admin.OperationType;
|
||||||
import org.keycloak.models.KeycloakSession;
|
import org.keycloak.models.KeycloakSession;
|
||||||
import org.keycloak.models.RealmModel;
|
import org.keycloak.models.RealmModel;
|
||||||
import org.keycloak.services.ServicesLogger;
|
import org.keycloak.services.ServicesLogger;
|
||||||
import org.keycloak.services.managers.UserStorageSyncManager;
|
import org.keycloak.storage.managers.UserStorageSyncManager;
|
||||||
import org.keycloak.services.resources.admin.permissions.AdminPermissionEvaluator;
|
import org.keycloak.services.resources.admin.permissions.AdminPermissionEvaluator;
|
||||||
import org.keycloak.storage.UserStorageProvider;
|
import org.keycloak.storage.UserStorageProvider;
|
||||||
import org.keycloak.storage.UserStorageProviderModel;
|
import org.keycloak.storage.UserStorageProviderModel;
|
||||||
|
|
|
@ -0,0 +1,21 @@
|
||||||
|
package org.keycloak.storage;
|
||||||
|
|
||||||
|
import org.keycloak.models.RealmModel;
|
||||||
|
|
||||||
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Alexander Schwartz
|
||||||
|
*/
|
||||||
|
public class UserStorageUtil {
|
||||||
|
/**
|
||||||
|
* Returns sorted {@link UserStorageProviderModel UserStorageProviderModel} as a stream.
|
||||||
|
* It should be used with forEachOrdered if the ordering is required.
|
||||||
|
* @return Sorted stream of {@link UserStorageProviderModel}. Never returns {@code null}.
|
||||||
|
*/
|
||||||
|
public static Stream<UserStorageProviderModel> getUserStorageProvidersStream(RealmModel realm) {
|
||||||
|
return realm.getComponentsStream(realm.getId(), UserStorageProvider.class.getName())
|
||||||
|
.map(UserStorageProviderModel::new)
|
||||||
|
.sorted(UserStorageProviderModel.comparator);
|
||||||
|
}
|
||||||
|
}
|
|
@ -21,7 +21,6 @@ import org.keycloak.Config;
|
||||||
import org.keycloak.common.util.MultivaluedHashMap;
|
import org.keycloak.common.util.MultivaluedHashMap;
|
||||||
import org.keycloak.models.LDAPConstants;
|
import org.keycloak.models.LDAPConstants;
|
||||||
import org.keycloak.models.map.storage.ldap.role.config.LdapMapRoleMapperConfig;
|
import org.keycloak.models.map.storage.ldap.role.config.LdapMapRoleMapperConfig;
|
||||||
import org.keycloak.storage.UserStorageProvider;
|
|
||||||
|
|
||||||
import javax.naming.directory.SearchControls;
|
import javax.naming.directory.SearchControls;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
|
@ -271,15 +270,6 @@ public class LdapMapConfig {
|
||||||
return Boolean.parseBoolean(config.getFirst(LDAPConstants.START_TLS));
|
return Boolean.parseBoolean(config.getFirst(LDAPConstants.START_TLS));
|
||||||
}
|
}
|
||||||
|
|
||||||
public UserStorageProvider.EditMode getEditMode() {
|
|
||||||
String editModeString = config.getFirst(LDAPConstants.EDIT_MODE);
|
|
||||||
if (editModeString == null) {
|
|
||||||
return UserStorageProvider.EditMode.READ_ONLY;
|
|
||||||
} else {
|
|
||||||
return UserStorageProvider.EditMode.valueOf(editModeString);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void addBinaryAttribute(String attrName) {
|
public void addBinaryAttribute(String attrName) {
|
||||||
binaryAttributeNames.add(attrName);
|
binaryAttributeNames.add(attrName);
|
||||||
}
|
}
|
||||||
|
|
|
@ -48,7 +48,6 @@ import org.keycloak.models.map.storage.ModelCriteriaBuilder.Operator;
|
||||||
import org.keycloak.models.map.storage.criteria.DefaultModelCriteria;
|
import org.keycloak.models.map.storage.criteria.DefaultModelCriteria;
|
||||||
import org.keycloak.models.utils.KeycloakModelUtils;
|
import org.keycloak.models.utils.KeycloakModelUtils;
|
||||||
import org.keycloak.storage.StorageId;
|
import org.keycloak.storage.StorageId;
|
||||||
import org.keycloak.storage.UserStorageProvider;
|
|
||||||
import org.keycloak.storage.client.ClientStorageProvider;
|
import org.keycloak.storage.client.ClientStorageProvider;
|
||||||
|
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
|
@ -456,9 +455,6 @@ public class MapUserProvider implements UserProvider.Streams, UserCredentialStor
|
||||||
public void preRemove(RealmModel realm, ComponentModel component) {
|
public void preRemove(RealmModel realm, ComponentModel component) {
|
||||||
String componentId = component.getId();
|
String componentId = component.getId();
|
||||||
LOG.tracef("preRemove[ComponentModel](%s, %s)%s", realm, componentId, getShortStackTrace());
|
LOG.tracef("preRemove[ComponentModel](%s, %s)%s", realm, componentId, getShortStackTrace());
|
||||||
if (component.getProviderType().equals(UserStorageProvider.class.getName())) {
|
|
||||||
removeImportedUsers(realm, componentId);
|
|
||||||
}
|
|
||||||
if (component.getProviderType().equals(ClientStorageProvider.class.getName())) {
|
if (component.getProviderType().equals(ClientStorageProvider.class.getName())) {
|
||||||
DefaultModelCriteria<UserModel> mcb = criteria();
|
DefaultModelCriteria<UserModel> mcb = criteria();
|
||||||
mcb = mcb.compare(SearchableFields.REALM_ID, Operator.EQ, realm.getId())
|
mcb = mcb.compare(SearchableFields.REALM_ID, Operator.EQ, realm.getId())
|
||||||
|
|
|
@ -17,169 +17,25 @@
|
||||||
|
|
||||||
package org.keycloak.migration;
|
package org.keycloak.migration;
|
||||||
|
|
||||||
import java.util.LinkedHashMap;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.regex.Pattern;
|
|
||||||
import org.jboss.logging.Logger;
|
|
||||||
import org.keycloak.common.Version;
|
|
||||||
import org.keycloak.migration.migrators.MigrateTo12_0_0;
|
|
||||||
import org.keycloak.migration.migrators.MigrateTo14_0_0;
|
|
||||||
import org.keycloak.migration.migrators.MigrateTo18_0_0;
|
|
||||||
import org.keycloak.migration.migrators.MigrateTo1_2_0;
|
|
||||||
import org.keycloak.migration.migrators.MigrateTo1_3_0;
|
|
||||||
import org.keycloak.migration.migrators.MigrateTo1_4_0;
|
|
||||||
import org.keycloak.migration.migrators.MigrateTo1_5_0;
|
|
||||||
import org.keycloak.migration.migrators.MigrateTo1_6_0;
|
|
||||||
import org.keycloak.migration.migrators.MigrateTo1_7_0;
|
|
||||||
import org.keycloak.migration.migrators.MigrateTo1_8_0;
|
|
||||||
import org.keycloak.migration.migrators.MigrateTo1_9_0;
|
|
||||||
import org.keycloak.migration.migrators.MigrateTo1_9_2;
|
|
||||||
import org.keycloak.migration.migrators.MigrateTo2_0_0;
|
|
||||||
import org.keycloak.migration.migrators.MigrateTo2_1_0;
|
|
||||||
import org.keycloak.migration.migrators.MigrateTo2_2_0;
|
|
||||||
import org.keycloak.migration.migrators.MigrateTo2_3_0;
|
|
||||||
import org.keycloak.migration.migrators.MigrateTo2_5_0;
|
|
||||||
import org.keycloak.migration.migrators.MigrateTo3_0_0;
|
|
||||||
import org.keycloak.migration.migrators.MigrateTo3_1_0;
|
|
||||||
import org.keycloak.migration.migrators.MigrateTo3_2_0;
|
|
||||||
import org.keycloak.migration.migrators.MigrateTo3_4_0;
|
|
||||||
import org.keycloak.migration.migrators.MigrateTo3_4_1;
|
|
||||||
import org.keycloak.migration.migrators.MigrateTo3_4_2;
|
|
||||||
import org.keycloak.migration.migrators.MigrateTo4_0_0;
|
|
||||||
import org.keycloak.migration.migrators.MigrateTo4_2_0;
|
|
||||||
import org.keycloak.migration.migrators.MigrateTo4_6_0;
|
|
||||||
import org.keycloak.migration.migrators.MigrateTo6_0_0;
|
|
||||||
import org.keycloak.migration.migrators.MigrateTo8_0_0;
|
|
||||||
import org.keycloak.migration.migrators.MigrateTo8_0_2;
|
|
||||||
import org.keycloak.migration.migrators.MigrateTo9_0_0;
|
|
||||||
import org.keycloak.migration.migrators.MigrateTo9_0_4;
|
|
||||||
import org.keycloak.migration.migrators.Migration;
|
|
||||||
import org.keycloak.models.Constants;
|
|
||||||
import org.keycloak.models.DeploymentStateProvider;
|
|
||||||
import org.keycloak.models.KeycloakSession;
|
import org.keycloak.models.KeycloakSession;
|
||||||
import org.keycloak.models.RealmModel;
|
import org.keycloak.models.RealmModel;
|
||||||
import org.keycloak.representations.idm.RealmRepresentation;
|
import org.keycloak.representations.idm.RealmRepresentation;
|
||||||
|
import org.keycloak.storage.DatastoreProvider;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
||||||
* @version $Revision: 1 $
|
* @version $Revision: 1 $
|
||||||
*/
|
*/
|
||||||
|
@Deprecated // as this will be moved to a legacy module
|
||||||
public class MigrationModelManager {
|
public class MigrationModelManager {
|
||||||
private static Logger logger = Logger.getLogger(MigrationModelManager.class);
|
|
||||||
|
|
||||||
private static final Migration[] migrations = {
|
|
||||||
new MigrateTo1_2_0(),
|
|
||||||
new MigrateTo1_3_0(),
|
|
||||||
new MigrateTo1_4_0(),
|
|
||||||
new MigrateTo1_5_0(),
|
|
||||||
new MigrateTo1_6_0(),
|
|
||||||
new MigrateTo1_7_0(),
|
|
||||||
new MigrateTo1_8_0(),
|
|
||||||
new MigrateTo1_9_0(),
|
|
||||||
new MigrateTo1_9_2(),
|
|
||||||
new MigrateTo2_0_0(),
|
|
||||||
new MigrateTo2_1_0(),
|
|
||||||
new MigrateTo2_2_0(),
|
|
||||||
new MigrateTo2_3_0(),
|
|
||||||
new MigrateTo2_5_0(),
|
|
||||||
new MigrateTo3_0_0(),
|
|
||||||
new MigrateTo3_1_0(),
|
|
||||||
new MigrateTo3_2_0(),
|
|
||||||
new MigrateTo3_4_0(),
|
|
||||||
new MigrateTo3_4_1(),
|
|
||||||
new MigrateTo3_4_2(),
|
|
||||||
new MigrateTo4_0_0(),
|
|
||||||
new MigrateTo4_2_0(),
|
|
||||||
new MigrateTo4_6_0(),
|
|
||||||
new MigrateTo6_0_0(),
|
|
||||||
new MigrateTo8_0_0(),
|
|
||||||
new MigrateTo8_0_2(),
|
|
||||||
new MigrateTo9_0_0(),
|
|
||||||
new MigrateTo9_0_4(),
|
|
||||||
new MigrateTo12_0_0(),
|
|
||||||
new MigrateTo14_0_0(),
|
|
||||||
new MigrateTo18_0_0()
|
|
||||||
};
|
|
||||||
|
|
||||||
public static void migrate(KeycloakSession session) {
|
public static void migrate(KeycloakSession session) {
|
||||||
session.setAttribute(Constants.STORAGE_BATCH_ENABLED, Boolean.getBoolean("keycloak.migration.batch-enabled"));
|
session.getProvider(DatastoreProvider.class).getMigrationManager().migrate();
|
||||||
session.setAttribute(Constants.STORAGE_BATCH_SIZE, Integer.getInteger("keycloak.migration.batch-size"));
|
|
||||||
MigrationModel model = session.getProvider(DeploymentStateProvider.class).getMigrationModel();
|
|
||||||
|
|
||||||
ModelVersion currentVersion = new ModelVersion(Version.VERSION_KEYCLOAK);
|
|
||||||
ModelVersion latestUpdate = migrations[migrations.length-1].getVersion();
|
|
||||||
ModelVersion databaseVersion = model.getStoredVersion() != null ? new ModelVersion(model.getStoredVersion()) : null;
|
|
||||||
|
|
||||||
if (databaseVersion == null || databaseVersion.lessThan(latestUpdate)) {
|
|
||||||
for (Migration m : migrations) {
|
|
||||||
if (databaseVersion == null || databaseVersion.lessThan(m.getVersion())) {
|
|
||||||
if (databaseVersion != null) {
|
|
||||||
logger.debugf("Migrating older model to %s", m.getVersion());
|
|
||||||
}
|
|
||||||
m.migrate(session);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (databaseVersion == null || databaseVersion.lessThan(currentVersion)) {
|
|
||||||
model.setStoredVersion(currentVersion.toString());
|
|
||||||
}
|
|
||||||
|
|
||||||
Version.RESOURCES_VERSION = model.getResourcesTag();
|
|
||||||
}
|
|
||||||
|
|
||||||
public static final ModelVersion RHSSO_VERSION_7_0_KEYCLOAK_VERSION = new ModelVersion("1.9.8");
|
|
||||||
public static final ModelVersion RHSSO_VERSION_7_1_KEYCLOAK_VERSION = new ModelVersion("2.5.5");
|
|
||||||
public static final ModelVersion RHSSO_VERSION_7_2_KEYCLOAK_VERSION = new ModelVersion("3.4.3");
|
|
||||||
public static final ModelVersion RHSSO_VERSION_7_3_KEYCLOAK_VERSION = new ModelVersion("4.8.3");
|
|
||||||
public static final ModelVersion RHSSO_VERSION_7_4_KEYCLOAK_VERSION = new ModelVersion("9.0.3");
|
|
||||||
|
|
||||||
private static final Map<Pattern, ModelVersion> PATTERN_MATCHER = new LinkedHashMap<>();
|
|
||||||
static {
|
|
||||||
PATTERN_MATCHER.put(Pattern.compile("^7\\.0\\.\\d+\\.GA$"), RHSSO_VERSION_7_0_KEYCLOAK_VERSION);
|
|
||||||
PATTERN_MATCHER.put(Pattern.compile("^7\\.1\\.\\d+\\.GA$"), RHSSO_VERSION_7_1_KEYCLOAK_VERSION);
|
|
||||||
PATTERN_MATCHER.put(Pattern.compile("^7\\.2\\.\\d+\\.GA$"), RHSSO_VERSION_7_2_KEYCLOAK_VERSION);
|
|
||||||
PATTERN_MATCHER.put(Pattern.compile("^7\\.3\\.\\d+\\.GA$"), RHSSO_VERSION_7_3_KEYCLOAK_VERSION);
|
|
||||||
PATTERN_MATCHER.put(Pattern.compile("^7\\.4\\.\\d+\\.GA$"), RHSSO_VERSION_7_4_KEYCLOAK_VERSION);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void migrateImport(KeycloakSession session, RealmModel realm, RealmRepresentation rep, boolean skipUserDependent) {
|
public static void migrateImport(KeycloakSession session, RealmModel realm, RealmRepresentation rep, boolean skipUserDependent) {
|
||||||
ModelVersion stored = null;
|
session.getProvider(DatastoreProvider.class).getMigrationManager().migrate(realm, rep, skipUserDependent);
|
||||||
if (rep.getKeycloakVersion() != null) {
|
|
||||||
stored = convertRHSSOVersionToKeycloakVersion(rep.getKeycloakVersion());
|
|
||||||
if (stored == null) {
|
|
||||||
stored = new ModelVersion(rep.getKeycloakVersion());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (stored == null) {
|
|
||||||
stored = migrations[0].getVersion();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for (Migration m : migrations) {
|
|
||||||
if (stored == null || stored.lessThan(m.getVersion())) {
|
|
||||||
if (stored != null) {
|
|
||||||
logger.debugf("Migrating older json representation to %s", m.getVersion());
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
m.migrateImport(session, realm, rep, skipUserDependent);
|
|
||||||
} catch (Exception e) {
|
|
||||||
logger.error("Failed to migrate json representation for version: " + m.getVersion(), e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static ModelVersion convertRHSSOVersionToKeycloakVersion(String version) {
|
|
||||||
// look for the keycloakVersion pattern to identify it as RH SSO
|
|
||||||
for (Pattern pattern : PATTERN_MATCHER.keySet()) {
|
|
||||||
if (pattern.matcher(version).find()) {
|
|
||||||
return PATTERN_MATCHER.get(pattern);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// chceck if the version is in format for CD releases, e.g.: "keycloakVersion": "6"
|
|
||||||
if (Pattern.compile("^[0-9]*$").matcher(version).find()) {
|
|
||||||
return new ModelVersion(Integer.parseInt(version), 0, 0);
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -45,7 +45,6 @@ import org.keycloak.models.RoleModel;
|
||||||
import org.keycloak.models.ScopeContainerModel;
|
import org.keycloak.models.ScopeContainerModel;
|
||||||
import org.keycloak.models.UserModel;
|
import org.keycloak.models.UserModel;
|
||||||
import org.keycloak.representations.idm.CertificateRepresentation;
|
import org.keycloak.representations.idm.CertificateRepresentation;
|
||||||
import org.keycloak.storage.UserStorageProviderModel;
|
|
||||||
import org.keycloak.transaction.JtaTransactionManagerLookup;
|
import org.keycloak.transaction.JtaTransactionManagerLookup;
|
||||||
|
|
||||||
import javax.crypto.spec.SecretKeySpec;
|
import javax.crypto.spec.SecretKeySpec;
|
||||||
|
@ -392,24 +391,6 @@ public final class KeycloakModelUtils {
|
||||||
// USER FEDERATION RELATED STUFF
|
// USER FEDERATION RELATED STUFF
|
||||||
|
|
||||||
|
|
||||||
public static UserStorageProviderModel findUserStorageProviderByName(String displayName, RealmModel realm) {
|
|
||||||
if (displayName == null) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
return realm.getUserStorageProvidersStream()
|
|
||||||
.filter(fedProvider -> Objects.equals(fedProvider.getName(), displayName))
|
|
||||||
.findFirst()
|
|
||||||
.orElse(null);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static UserStorageProviderModel findUserStorageProviderById(String fedProviderId, RealmModel realm) {
|
|
||||||
return realm.getUserStorageProvidersStream()
|
|
||||||
.filter(fedProvider -> Objects.equals(fedProvider.getId(), fedProviderId))
|
|
||||||
.findFirst()
|
|
||||||
.orElse(null);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static ComponentModel createComponentModel(String name, String parentId, String providerId, String providerType, String... config) {
|
public static ComponentModel createComponentModel(String name, String parentId, String providerId, String providerType, String... config) {
|
||||||
ComponentModel mapperModel = new ComponentModel();
|
ComponentModel mapperModel = new ComponentModel();
|
||||||
mapperModel.setParentId(parentId);
|
mapperModel.setParentId(parentId);
|
||||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -22,4 +22,7 @@ public interface DatastoreProvider extends Provider {
|
||||||
|
|
||||||
public UserProvider users();
|
public UserProvider users();
|
||||||
|
|
||||||
|
ExportImportManager getExportImportManager();
|
||||||
|
|
||||||
|
MigrationManager getMigrationManager();
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,16 @@
|
||||||
|
package org.keycloak.storage;
|
||||||
|
|
||||||
|
import org.keycloak.models.KeycloakSession;
|
||||||
|
import org.keycloak.models.RealmModel;
|
||||||
|
import org.keycloak.representations.idm.RealmRepresentation;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Manage importing and updating of realms for the legacy store.
|
||||||
|
*
|
||||||
|
* @author Alexander Schwartz
|
||||||
|
*/
|
||||||
|
public interface ExportImportManager {
|
||||||
|
void importRealm(RealmRepresentation rep, RealmModel newRealm, boolean skipUserDependent);
|
||||||
|
|
||||||
|
void updateRealm(RealmRepresentation rep, RealmModel realm);
|
||||||
|
}
|
|
@ -0,0 +1,18 @@
|
||||||
|
package org.keycloak.storage;
|
||||||
|
|
||||||
|
import org.keycloak.models.RealmModel;
|
||||||
|
import org.keycloak.representations.idm.RealmRepresentation;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handle the migration of the datastore and an imported realm representation.
|
||||||
|
* Will eventually be handled by the store directly.
|
||||||
|
*
|
||||||
|
* @author Alexander Schwartz
|
||||||
|
*/
|
||||||
|
@Deprecated
|
||||||
|
public interface MigrationManager {
|
||||||
|
|
||||||
|
void migrate();
|
||||||
|
|
||||||
|
void migrate(RealmModel realm, RealmRepresentation rep, boolean skipUserDependent);
|
||||||
|
}
|
|
@ -21,11 +21,6 @@ import org.junit.Assert;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.keycloak.migration.ModelVersion;
|
import org.keycloak.migration.ModelVersion;
|
||||||
|
|
||||||
import static org.hamcrest.CoreMatchers.equalTo;
|
|
||||||
import static org.hamcrest.CoreMatchers.is;
|
|
||||||
import static org.hamcrest.CoreMatchers.nullValue;
|
|
||||||
import static org.keycloak.migration.MigrationModelManager.*;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
||||||
* @version $Revision: 1 $
|
* @version $Revision: 1 $
|
||||||
|
@ -100,35 +95,4 @@ public class MigrationVersionTest {
|
||||||
Assert.assertNull(versionProduct.getQualifier());
|
Assert.assertNull(versionProduct.getQualifier());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testRHSSOVersionToKeycloakVersionConversion() {
|
|
||||||
Assert.assertThat(convertRHSSOVersionToKeycloakVersion("7.0.0.GA"), is(equalTo(RHSSO_VERSION_7_0_KEYCLOAK_VERSION)));
|
|
||||||
Assert.assertThat(convertRHSSOVersionToKeycloakVersion("7.0.1.GA"), is(equalTo(RHSSO_VERSION_7_0_KEYCLOAK_VERSION)));
|
|
||||||
Assert.assertThat(convertRHSSOVersionToKeycloakVersion("7.0.2.GA"), is(equalTo(RHSSO_VERSION_7_0_KEYCLOAK_VERSION)));
|
|
||||||
|
|
||||||
Assert.assertThat(convertRHSSOVersionToKeycloakVersion("7.1.0.GA"), is(equalTo(RHSSO_VERSION_7_1_KEYCLOAK_VERSION)));
|
|
||||||
Assert.assertThat(convertRHSSOVersionToKeycloakVersion("7.1.1.GA"), is(equalTo(RHSSO_VERSION_7_1_KEYCLOAK_VERSION)));
|
|
||||||
Assert.assertThat(convertRHSSOVersionToKeycloakVersion("7.1.2.GA"), is(equalTo(RHSSO_VERSION_7_1_KEYCLOAK_VERSION)));
|
|
||||||
|
|
||||||
Assert.assertThat(convertRHSSOVersionToKeycloakVersion("7.2.0.GA"), is(equalTo(RHSSO_VERSION_7_2_KEYCLOAK_VERSION)));
|
|
||||||
Assert.assertThat(convertRHSSOVersionToKeycloakVersion("7.2.1.GA"), is(equalTo(RHSSO_VERSION_7_2_KEYCLOAK_VERSION)));
|
|
||||||
Assert.assertThat(convertRHSSOVersionToKeycloakVersion("7.2.2.GA"), is(equalTo(RHSSO_VERSION_7_2_KEYCLOAK_VERSION)));
|
|
||||||
|
|
||||||
Assert.assertThat(convertRHSSOVersionToKeycloakVersion("7.3.0.GA"), is(equalTo(RHSSO_VERSION_7_3_KEYCLOAK_VERSION)));
|
|
||||||
Assert.assertThat(convertRHSSOVersionToKeycloakVersion("7.3.1.GA"), is(equalTo(RHSSO_VERSION_7_3_KEYCLOAK_VERSION)));
|
|
||||||
Assert.assertThat(convertRHSSOVersionToKeycloakVersion("7.3.2.GA"), is(equalTo(RHSSO_VERSION_7_3_KEYCLOAK_VERSION)));
|
|
||||||
Assert.assertThat(convertRHSSOVersionToKeycloakVersion("7.3.10.GA"), is(equalTo(RHSSO_VERSION_7_3_KEYCLOAK_VERSION)));
|
|
||||||
|
|
||||||
Assert.assertThat(convertRHSSOVersionToKeycloakVersion("7.4.0.GA"), is(equalTo(RHSSO_VERSION_7_4_KEYCLOAK_VERSION)));
|
|
||||||
Assert.assertThat(convertRHSSOVersionToKeycloakVersion("7.4.15.GA"), is(equalTo(RHSSO_VERSION_7_4_KEYCLOAK_VERSION)));
|
|
||||||
|
|
||||||
// check the conversion doesn't change version for keycloak
|
|
||||||
Assert.assertThat(convertRHSSOVersionToKeycloakVersion("7.0.0"), is(nullValue()));
|
|
||||||
Assert.assertThat(convertRHSSOVersionToKeycloakVersion("8.0.0"), is(nullValue()));
|
|
||||||
|
|
||||||
// check for CD releases
|
|
||||||
Assert.assertThat(convertRHSSOVersionToKeycloakVersion("6"), is(equalTo(new ModelVersion("6.0.0"))));
|
|
||||||
Assert.assertThat(convertRHSSOVersionToKeycloakVersion("7"), is(equalTo(new ModelVersion("7.0.0"))));
|
|
||||||
Assert.assertThat(convertRHSSOVersionToKeycloakVersion("10"), is(equalTo(new ModelVersion("10.0.0"))));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,8 +23,6 @@ import org.keycloak.component.ComponentModel;
|
||||||
import org.keycloak.provider.Provider;
|
import org.keycloak.provider.Provider;
|
||||||
import org.keycloak.provider.ProviderEvent;
|
import org.keycloak.provider.ProviderEvent;
|
||||||
import org.keycloak.storage.SearchableModelField;
|
import org.keycloak.storage.SearchableModelField;
|
||||||
import org.keycloak.storage.UserStorageProvider;
|
|
||||||
import org.keycloak.storage.UserStorageProviderModel;
|
|
||||||
import org.keycloak.storage.client.ClientStorageProvider;
|
import org.keycloak.storage.client.ClientStorageProvider;
|
||||||
import org.keycloak.storage.client.ClientStorageProviderModel;
|
import org.keycloak.storage.client.ClientStorageProviderModel;
|
||||||
import org.keycloak.storage.role.RoleStorageProvider;
|
import org.keycloak.storage.role.RoleStorageProvider;
|
||||||
|
@ -662,25 +660,6 @@ public interface RealmModel extends RoleContainerModel {
|
||||||
|
|
||||||
ComponentModel getComponent(String id);
|
ComponentModel getComponent(String id);
|
||||||
|
|
||||||
/**
|
|
||||||
* @deprecated Use {@link #getUserStorageProvidersStream() getUserStorageProvidersStream} instead.
|
|
||||||
*/
|
|
||||||
@Deprecated
|
|
||||||
default List<UserStorageProviderModel> getUserStorageProviders() {
|
|
||||||
return getUserStorageProvidersStream().collect(Collectors.toList());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns sorted {@link UserStorageProviderModel UserStorageProviderModel} as a stream.
|
|
||||||
* It should be used with forEachOrdered if the ordering is required.
|
|
||||||
* @return Sorted stream of {@link UserStorageProviderModel}. Never returns {@code null}.
|
|
||||||
*/
|
|
||||||
default Stream<UserStorageProviderModel> getUserStorageProvidersStream() {
|
|
||||||
return getComponentsStream(getId(), UserStorageProvider.class.getName())
|
|
||||||
.map(UserStorageProviderModel::new)
|
|
||||||
.sorted(UserStorageProviderModel.comparator);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @deprecated Use {@link #getClientStorageProvidersStream() getClientStorageProvidersStream} instead.
|
* @deprecated Use {@link #getClientStorageProvidersStream() getClientStorageProvidersStream} instead.
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -162,9 +162,9 @@ public class CacheableStorageProviderModel extends PrioritizedComponentModel {
|
||||||
}
|
}
|
||||||
|
|
||||||
public long getLifespan() {
|
public long getLifespan() {
|
||||||
UserStorageProviderModel.CachePolicy policy = getCachePolicy();
|
CachePolicy policy = getCachePolicy();
|
||||||
long lifespan = -1;
|
long lifespan = -1;
|
||||||
if (policy == null || policy == UserStorageProviderModel.CachePolicy.DEFAULT) {
|
if (policy == null || policy == CachePolicy.DEFAULT) {
|
||||||
lifespan = -1;
|
lifespan = -1;
|
||||||
} else if (policy == CacheableStorageProviderModel.CachePolicy.EVICT_DAILY) {
|
} else if (policy == CacheableStorageProviderModel.CachePolicy.EVICT_DAILY) {
|
||||||
if (getEvictionHour() > -1 && getEvictionMinute() > -1) {
|
if (getEvictionHour() > -1 && getEvictionMinute() > -1) {
|
||||||
|
|
|
@ -21,7 +21,7 @@ import org.keycloak.models.RoleModel;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This is an optional capability interface that is intended to be implemented by any
|
* This is an optional capability interface that is intended to be implemented by any
|
||||||
* {@link org.keycloak.storage.UserStorageProvider UserStorageProvider} that supports bulk operations.
|
* <code>UserStorageProvider</code> that supports bulk operations.
|
||||||
*
|
*
|
||||||
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
||||||
* @version $Revision: 1 $
|
* @version $Revision: 1 $
|
||||||
|
|
|
@ -21,7 +21,7 @@ import org.keycloak.models.UserModel;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This is an optional capability interface that is intended to be implemented by any
|
* This is an optional capability interface that is intended to be implemented by any
|
||||||
* {@link org.keycloak.storage.UserStorageProvider UserStorageProvider} that supports basic user querying. You must
|
* <code>UserStorageProvider</code> that supports basic user querying. You must
|
||||||
* implement this interface if you want to be able to log in to keycloak using users from your storage.
|
* implement this interface if you want to be able to log in to keycloak using users from your storage.
|
||||||
* <p/>
|
* <p/>
|
||||||
* Note that all methods in this interface should limit search only to data available within the storage that is
|
* Note that all methods in this interface should limit search only to data available within the storage that is
|
||||||
|
|
|
@ -31,7 +31,7 @@ import java.util.stream.Stream;
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* This is an optional capability interface that is intended to be implemented by any
|
* This is an optional capability interface that is intended to be implemented by any
|
||||||
* {@link org.keycloak.storage.UserStorageProvider UserStorageProvider} that supports complex user querying. You must
|
* <code>UserStorageProvider</code> that supports complex user querying. You must
|
||||||
* implement this interface if you want to view and manage users from the administration console.
|
* implement this interface if you want to view and manage users from the administration console.
|
||||||
* <p/>
|
* <p/>
|
||||||
* Note that all methods in this interface should limit search only to data available within the storage that is
|
* Note that all methods in this interface should limit search only to data available within the storage that is
|
||||||
|
|
|
@ -22,7 +22,7 @@ import org.keycloak.models.UserModel;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This is an optional capability interface that is intended to be implemented by any
|
* This is an optional capability interface that is intended to be implemented by any
|
||||||
* {@link org.keycloak.storage.UserStorageProvider UserStorageProvider} that supports addition of new users. You must
|
* <code>UserStorageProvider</code> that supports addition of new users. You must
|
||||||
* implement this interface if you want to use this storage for registering new users.
|
* implement this interface if you want to use this storage for registering new users.
|
||||||
*
|
*
|
||||||
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
||||||
|
|
|
@ -25,11 +25,11 @@ import org.keycloak.models.UserModel;
|
||||||
import org.keycloak.models.cache.CachedUserModel;
|
import org.keycloak.models.cache.CachedUserModel;
|
||||||
import org.keycloak.models.cache.OnUserCache;
|
import org.keycloak.models.cache.OnUserCache;
|
||||||
import org.keycloak.models.cache.UserCache;
|
import org.keycloak.models.cache.UserCache;
|
||||||
|
import org.keycloak.provider.Provider;
|
||||||
|
import org.keycloak.provider.ProviderFactory;
|
||||||
import org.keycloak.storage.AbstractStorageManager;
|
import org.keycloak.storage.AbstractStorageManager;
|
||||||
|
import org.keycloak.storage.CacheableStorageProviderModel;
|
||||||
import org.keycloak.storage.StorageId;
|
import org.keycloak.storage.StorageId;
|
||||||
import org.keycloak.storage.UserStorageProvider;
|
|
||||||
import org.keycloak.storage.UserStorageProviderFactory;
|
|
||||||
import org.keycloak.storage.UserStorageProviderModel;
|
|
||||||
|
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.LinkedList;
|
import java.util.LinkedList;
|
||||||
|
@ -41,11 +41,11 @@ import java.util.stream.Stream;
|
||||||
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
||||||
* @version $Revision: 1 $
|
* @version $Revision: 1 $
|
||||||
*/
|
*/
|
||||||
public class UserCredentialStoreManager extends AbstractStorageManager<UserStorageProvider, UserStorageProviderModel>
|
public class UserCredentialStoreManager extends AbstractStorageManager<Provider, CacheableStorageProviderModel>
|
||||||
implements UserCredentialManager.Streams, OnUserCache {
|
implements UserCredentialManager.Streams, OnUserCache {
|
||||||
|
|
||||||
public UserCredentialStoreManager(KeycloakSession session) {
|
public UserCredentialStoreManager(KeycloakSession session) {
|
||||||
super(session, UserStorageProviderFactory.class, UserStorageProvider.class, UserStorageProviderModel::new, "user");
|
super(session, ProviderFactory.class, Provider.class, componentModel -> null, "user");
|
||||||
}
|
}
|
||||||
|
|
||||||
protected UserCredentialStore getStoreForUser(UserModel user) {
|
protected UserCredentialStore getStoreForUser(UserModel user) {
|
||||||
|
@ -143,6 +143,7 @@ public class UserCredentialStoreManager extends AbstractStorageManager<UserStora
|
||||||
List<CredentialInput> toValidate = new LinkedList<>(inputs);
|
List<CredentialInput> toValidate = new LinkedList<>(inputs);
|
||||||
String providerId = StorageId.isLocalStorage(user) ? user.getFederationLink() : StorageId.resolveProviderId(user);
|
String providerId = StorageId.isLocalStorage(user) ? user.getFederationLink() : StorageId.resolveProviderId(user);
|
||||||
if (providerId != null) {
|
if (providerId != null) {
|
||||||
|
/*
|
||||||
UserStorageProviderModel model = getStorageProviderModel(realm, providerId);
|
UserStorageProviderModel model = getStorageProviderModel(realm, providerId);
|
||||||
if (model == null || !model.isEnabled()) return false;
|
if (model == null || !model.isEnabled()) return false;
|
||||||
|
|
||||||
|
@ -150,6 +151,7 @@ public class UserCredentialStoreManager extends AbstractStorageManager<UserStora
|
||||||
if (validator != null) {
|
if (validator != null) {
|
||||||
validate(realm, user, toValidate, validator);
|
validate(realm, user, toValidate, validator);
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
}
|
}
|
||||||
|
|
||||||
if (toValidate.isEmpty()) return true;
|
if (toValidate.isEmpty()) return true;
|
||||||
|
@ -176,6 +178,7 @@ public class UserCredentialStoreManager extends AbstractStorageManager<UserStora
|
||||||
if (!StorageId.isLocalStorage(user)) throwExceptionIfInvalidUser(user);
|
if (!StorageId.isLocalStorage(user)) throwExceptionIfInvalidUser(user);
|
||||||
|
|
||||||
if (providerId != null) {
|
if (providerId != null) {
|
||||||
|
/*
|
||||||
UserStorageProviderModel model = getStorageProviderModel(realm, providerId);
|
UserStorageProviderModel model = getStorageProviderModel(realm, providerId);
|
||||||
if (model == null || !model.isEnabled()) return false;
|
if (model == null || !model.isEnabled()) return false;
|
||||||
|
|
||||||
|
@ -183,6 +186,7 @@ public class UserCredentialStoreManager extends AbstractStorageManager<UserStora
|
||||||
if (updater != null && updater.supportsCredentialType(input.getType())) {
|
if (updater != null && updater.supportsCredentialType(input.getType())) {
|
||||||
if (updater.updateCredential(realm, user, input)) return true;
|
if (updater.updateCredential(realm, user, input)) return true;
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
}
|
}
|
||||||
|
|
||||||
return getCredentialProviders(session, CredentialInputUpdater.class)
|
return getCredentialProviders(session, CredentialInputUpdater.class)
|
||||||
|
@ -195,6 +199,7 @@ public class UserCredentialStoreManager extends AbstractStorageManager<UserStora
|
||||||
String providerId = StorageId.isLocalStorage(user) ? user.getFederationLink() : StorageId.resolveProviderId(user);
|
String providerId = StorageId.isLocalStorage(user) ? user.getFederationLink() : StorageId.resolveProviderId(user);
|
||||||
if (!StorageId.isLocalStorage(user)) throwExceptionIfInvalidUser(user);
|
if (!StorageId.isLocalStorage(user)) throwExceptionIfInvalidUser(user);
|
||||||
if (providerId != null) {
|
if (providerId != null) {
|
||||||
|
/*
|
||||||
UserStorageProviderModel model = getStorageProviderModel(realm, providerId);
|
UserStorageProviderModel model = getStorageProviderModel(realm, providerId);
|
||||||
if (model == null || !model.isEnabled()) return;
|
if (model == null || !model.isEnabled()) return;
|
||||||
|
|
||||||
|
@ -202,6 +207,8 @@ public class UserCredentialStoreManager extends AbstractStorageManager<UserStora
|
||||||
if (updater.supportsCredentialType(credentialType)) {
|
if (updater.supportsCredentialType(credentialType)) {
|
||||||
updater.disableCredentialType(realm, user, credentialType);
|
updater.disableCredentialType(realm, user, credentialType);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
*/
|
||||||
}
|
}
|
||||||
|
|
||||||
getCredentialProviders(session, CredentialInputUpdater.class)
|
getCredentialProviders(session, CredentialInputUpdater.class)
|
||||||
|
@ -214,11 +221,13 @@ public class UserCredentialStoreManager extends AbstractStorageManager<UserStora
|
||||||
Stream<String> types = Stream.empty();
|
Stream<String> types = Stream.empty();
|
||||||
String providerId = StorageId.isLocalStorage(user) ? user.getFederationLink() : StorageId.resolveProviderId(user);
|
String providerId = StorageId.isLocalStorage(user) ? user.getFederationLink() : StorageId.resolveProviderId(user);
|
||||||
if (providerId != null) {
|
if (providerId != null) {
|
||||||
|
/*
|
||||||
UserStorageProviderModel model = getStorageProviderModel(realm, providerId);
|
UserStorageProviderModel model = getStorageProviderModel(realm, providerId);
|
||||||
if (model == null || !model.isEnabled()) return types;
|
if (model == null || !model.isEnabled()) return types;
|
||||||
|
|
||||||
CredentialInputUpdater updater = getStorageProviderInstance(model, CredentialInputUpdater.class);
|
CredentialInputUpdater updater = getStorageProviderInstance(model, CredentialInputUpdater.class);
|
||||||
if (updater != null) types = updater.getDisableableCredentialTypesStream(realm, user);
|
if (updater != null) types = updater.getDisableableCredentialTypesStream(realm, user);
|
||||||
|
*/
|
||||||
}
|
}
|
||||||
|
|
||||||
return Stream.concat(types, getCredentialProviders(session, CredentialInputUpdater.class)
|
return Stream.concat(types, getCredentialProviders(session, CredentialInputUpdater.class)
|
||||||
|
@ -251,6 +260,7 @@ public class UserCredentialStoreManager extends AbstractStorageManager<UserStora
|
||||||
private UserStorageCredentialConfigured isConfiguredThroughUserStorage(RealmModel realm, UserModel user, String type) {
|
private UserStorageCredentialConfigured isConfiguredThroughUserStorage(RealmModel realm, UserModel user, String type) {
|
||||||
String providerId = StorageId.isLocalStorage(user) ? user.getFederationLink() : StorageId.resolveProviderId(user);
|
String providerId = StorageId.isLocalStorage(user) ? user.getFederationLink() : StorageId.resolveProviderId(user);
|
||||||
if (providerId != null) {
|
if (providerId != null) {
|
||||||
|
/*
|
||||||
UserStorageProviderModel model = getStorageProviderModel(realm, providerId);
|
UserStorageProviderModel model = getStorageProviderModel(realm, providerId);
|
||||||
if (model == null || !model.isEnabled()) return UserStorageCredentialConfigured.USER_STORAGE_DISABLED;
|
if (model == null || !model.isEnabled()) return UserStorageCredentialConfigured.USER_STORAGE_DISABLED;
|
||||||
|
|
||||||
|
@ -258,6 +268,7 @@ public class UserCredentialStoreManager extends AbstractStorageManager<UserStora
|
||||||
if (validator != null && validator.supportsCredentialType(type) && validator.isConfiguredFor(realm, user, type)) {
|
if (validator != null && validator.supportsCredentialType(type) && validator.isConfiguredFor(realm, user, type)) {
|
||||||
return UserStorageCredentialConfigured.CONFIGURED;
|
return UserStorageCredentialConfigured.CONFIGURED;
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
}
|
}
|
||||||
|
|
||||||
return UserStorageCredentialConfigured.NOT_CONFIGURED;
|
return UserStorageCredentialConfigured.NOT_CONFIGURED;
|
||||||
|
|
|
@ -148,7 +148,7 @@ public class LDAPSyncTest extends AbstractLDAPTest {
|
||||||
|
|
||||||
// Assert lastSync time updated
|
// Assert lastSync time updated
|
||||||
Assert.assertTrue(ctx.getLdapModel().getLastSync() > 0);
|
Assert.assertTrue(ctx.getLdapModel().getLastSync() > 0);
|
||||||
testRealm.getUserStorageProvidersStream().forEachOrdered(persistentFedModel -> {
|
UserStorageUtil.getUserStorageProvidersStream(testRealm).forEachOrdered(persistentFedModel -> {
|
||||||
if (LDAPStorageProviderFactory.PROVIDER_NAME.equals(persistentFedModel.getProviderId())) {
|
if (LDAPStorageProviderFactory.PROVIDER_NAME.equals(persistentFedModel.getProviderId())) {
|
||||||
Assert.assertTrue(persistentFedModel.getLastSync() > 0);
|
Assert.assertTrue(persistentFedModel.getLastSync() > 0);
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -9,6 +9,7 @@ import org.keycloak.models.RealmModel;
|
||||||
import org.keycloak.storage.UserStorageProvider;
|
import org.keycloak.storage.UserStorageProvider;
|
||||||
import org.keycloak.storage.UserStorageProviderFactory;
|
import org.keycloak.storage.UserStorageProviderFactory;
|
||||||
import org.keycloak.storage.UserStorageProviderModel;
|
import org.keycloak.storage.UserStorageProviderModel;
|
||||||
|
import org.keycloak.storage.UserStorageUtil;
|
||||||
|
|
||||||
import java.util.stream.Stream;
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
|
@ -22,10 +23,6 @@ public class UserStorageProvidersTestUtils {
|
||||||
return model.isEnabled();
|
return model.isEnabled();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Stream<UserStorageProviderModel> getStorageProviders(RealmModel realm) {
|
|
||||||
return realm.getUserStorageProvidersStream();
|
|
||||||
}
|
|
||||||
|
|
||||||
private static UserStorageProviderFactory getUserStorageProviderFactory(UserStorageProviderModel model, KeycloakSession session) {
|
private static UserStorageProviderFactory getUserStorageProviderFactory(UserStorageProviderModel model, KeycloakSession session) {
|
||||||
return (UserStorageProviderFactory) session.getKeycloakSessionFactory()
|
return (UserStorageProviderFactory) session.getKeycloakSessionFactory()
|
||||||
.getProviderFactory(UserStorageProvider.class, model.getProviderId());
|
.getProviderFactory(UserStorageProvider.class, model.getProviderId());
|
||||||
|
@ -50,7 +47,7 @@ public class UserStorageProvidersTestUtils {
|
||||||
}
|
}
|
||||||
|
|
||||||
public static <T> Stream<UserStorageProviderModel> getStorageProviders(RealmModel realm, KeycloakSession session, Class<T> type) {
|
public static <T> Stream<UserStorageProviderModel> getStorageProviders(RealmModel realm, KeycloakSession session, Class<T> type) {
|
||||||
return realm.getUserStorageProvidersStream()
|
return UserStorageUtil.getUserStorageProvidersStream(realm)
|
||||||
.filter(model -> {
|
.filter(model -> {
|
||||||
UserStorageProviderFactory factory = getUserStorageProviderFactory(model, session);
|
UserStorageProviderFactory factory = getUserStorageProviderFactory(model, session);
|
||||||
if (factory == null) {
|
if (factory == null) {
|
||||||
|
|
|
@ -25,7 +25,7 @@ import org.junit.runners.MethodSorters;
|
||||||
import org.keycloak.component.ComponentModel;
|
import org.keycloak.component.ComponentModel;
|
||||||
import org.keycloak.models.KeycloakSessionFactory;
|
import org.keycloak.models.KeycloakSessionFactory;
|
||||||
import org.keycloak.models.RealmModel;
|
import org.keycloak.models.RealmModel;
|
||||||
import org.keycloak.services.managers.UserStorageSyncManager;
|
import org.keycloak.storage.managers.UserStorageSyncManager;
|
||||||
import org.keycloak.storage.UserStorageProvider;
|
import org.keycloak.storage.UserStorageProvider;
|
||||||
import org.keycloak.storage.UserStorageProviderModel;
|
import org.keycloak.storage.UserStorageProviderModel;
|
||||||
import org.keycloak.storage.user.SynchronizationResult;
|
import org.keycloak.storage.user.SynchronizationResult;
|
||||||
|
|
|
@ -20,9 +20,11 @@ package org.keycloak.testsuite.util.cli;
|
||||||
import org.keycloak.common.util.MultivaluedHashMap;
|
import org.keycloak.common.util.MultivaluedHashMap;
|
||||||
import org.keycloak.models.KeycloakSession;
|
import org.keycloak.models.KeycloakSession;
|
||||||
import org.keycloak.models.RealmModel;
|
import org.keycloak.models.RealmModel;
|
||||||
import org.keycloak.models.utils.KeycloakModelUtils;
|
import org.keycloak.storage.managers.UserStorageSyncManager;
|
||||||
import org.keycloak.services.managers.UserStorageSyncManager;
|
|
||||||
import org.keycloak.storage.UserStorageProviderModel;
|
import org.keycloak.storage.UserStorageProviderModel;
|
||||||
|
import org.keycloak.storage.UserStorageUtil;
|
||||||
|
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
|
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
|
||||||
|
@ -35,7 +37,7 @@ public class SyncDummyFederationProviderCommand extends AbstractCommand {
|
||||||
int changedSyncPeriod = getIntArg(1);
|
int changedSyncPeriod = getIntArg(1);
|
||||||
|
|
||||||
RealmModel realm = session.realms().getRealmByName("master");
|
RealmModel realm = session.realms().getRealmByName("master");
|
||||||
UserStorageProviderModel fedProviderModel = KeycloakModelUtils.findUserStorageProviderByName("cluster-dummy", realm);
|
UserStorageProviderModel fedProviderModel = findUserStorageProviderByName(session, "cluster-dummy", realm);
|
||||||
if (fedProviderModel == null) {
|
if (fedProviderModel == null) {
|
||||||
MultivaluedHashMap<String, String> cfg = fedProviderModel.getConfig();
|
MultivaluedHashMap<String, String> cfg = fedProviderModel.getConfig();
|
||||||
updateConfig(cfg, waitTime);
|
updateConfig(cfg, waitTime);
|
||||||
|
@ -64,6 +66,16 @@ public class SyncDummyFederationProviderCommand extends AbstractCommand {
|
||||||
cfg.putSingle("wait-time", String.valueOf(waitTime));
|
cfg.putSingle("wait-time", String.valueOf(waitTime));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static UserStorageProviderModel findUserStorageProviderByName(KeycloakSession session, String displayName, RealmModel realm) {
|
||||||
|
if (displayName == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return UserStorageUtil.getUserStorageProvidersStream(realm)
|
||||||
|
.filter(fedProvider -> Objects.equals(fedProvider.getName(), displayName))
|
||||||
|
.findFirst()
|
||||||
|
.orElse(null);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getName() {
|
public String getName() {
|
||||||
|
|
Loading…
Reference in a new issue