KEYCLOAK-17615 Move database initialization from KeycloakApplication to JpaConnectionProviderFactory
This commit is contained in:
parent
515bfb5064
commit
162043beec
16 changed files with 267 additions and 104 deletions
2
.github/workflows/ci.yml
vendored
2
.github/workflows/ci.yml
vendored
|
@ -160,7 +160,7 @@ jobs:
|
||||||
run: |
|
run: |
|
||||||
declare -A PARAMS TESTGROUP
|
declare -A PARAMS TESTGROUP
|
||||||
PARAMS["quarkus"]="-Pauth-server-quarkus"
|
PARAMS["quarkus"]="-Pauth-server-quarkus"
|
||||||
PARAMS["undertow-map"]="-Pauth-server-undertow -Dkeycloak.client.provider=map -Dkeycloak.group.provider=map -Dkeycloak.role.provider=map -Dkeycloak.authSession.provider=map -Dkeycloak.userSession.provider=map -Dkeycloak.loginFailure.provider=map -Dkeycloak.user.provider=map -Dkeycloak.clientScope.provider=map -Dkeycloak.realm.provider=map -Dkeycloak.authorization.provider=map"
|
PARAMS["undertow-map"]="-Pauth-server-undertow -Dkeycloak.client.provider=map -Dkeycloak.group.provider=map -Dkeycloak.role.provider=map -Dkeycloak.authSession.provider=map -Dkeycloak.userSession.provider=map -Dkeycloak.loginFailure.provider=map -Dkeycloak.user.provider=map -Dkeycloak.clientScope.provider=map -Dkeycloak.realm.provider=map -Dkeycloak.authorization.provider=map -Dkeycloak.serverInfo.provider=map"
|
||||||
PARAMS["wildfly"]="-Pauth-server-wildfly"
|
PARAMS["wildfly"]="-Pauth-server-wildfly"
|
||||||
TESTGROUP["group1"]="-Dtest=!**.crossdc.**,!**.cluster.**,%regex[org.keycloak.testsuite.(a[abc]|ad[a-l]|[^a-q]).*]" # Tests alphabetically before admin tests and those after "r"
|
TESTGROUP["group1"]="-Dtest=!**.crossdc.**,!**.cluster.**,%regex[org.keycloak.testsuite.(a[abc]|ad[a-l]|[^a-q]).*]" # Tests alphabetically before admin tests and those after "r"
|
||||||
TESTGROUP["group2"]="-Dtest=!**.crossdc.**,!**.cluster.**,%regex[org.keycloak.testsuite.(ad[^a-l]|a[^a-d]|b).*]" # Admin tests and those starting with "b"
|
TESTGROUP["group2"]="-Dtest=!**.crossdc.**,!**.cluster.**,%regex[org.keycloak.testsuite.(ad[^a-l]|a[^a-d]|b).*]" # Admin tests and those starting with "b"
|
||||||
|
|
|
@ -25,6 +25,7 @@ import org.keycloak.ServerStartupError;
|
||||||
import org.keycloak.common.util.StringPropertyReplacer;
|
import org.keycloak.common.util.StringPropertyReplacer;
|
||||||
import org.keycloak.connections.jpa.updater.JpaUpdaterProvider;
|
import org.keycloak.connections.jpa.updater.JpaUpdaterProvider;
|
||||||
import org.keycloak.connections.jpa.util.JpaUtils;
|
import org.keycloak.connections.jpa.util.JpaUtils;
|
||||||
|
import org.keycloak.migration.MigrationModelManager;
|
||||||
import org.keycloak.models.KeycloakSession;
|
import org.keycloak.models.KeycloakSession;
|
||||||
import org.keycloak.models.KeycloakSessionFactory;
|
import org.keycloak.models.KeycloakSessionFactory;
|
||||||
import org.keycloak.models.KeycloakSessionTask;
|
import org.keycloak.models.KeycloakSessionTask;
|
||||||
|
@ -213,6 +214,18 @@ public class DefaultJpaConnectionProviderFactory implements JpaConnectionProvide
|
||||||
if (globalStatsInterval != -1) {
|
if (globalStatsInterval != -1) {
|
||||||
startGlobalStats(session, globalStatsInterval);
|
startGlobalStats(session, globalStatsInterval);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Migrate model is executed just in case following providers are "jpa".
|
||||||
|
* In Map Storage, there is an assumption that migrateModel is not needed.
|
||||||
|
*/
|
||||||
|
if ((Config.getProvider("realm") == null || "jpa".equals(Config.getProvider("realm"))) &&
|
||||||
|
(Config.getProvider("client") == null || "jpa".equals(Config.getProvider("client"))) &&
|
||||||
|
(Config.getProvider("clientScope") == null || "jpa".equals(Config.getProvider("clientScope")))) {
|
||||||
|
|
||||||
|
logger.debug("Calling migrateModel");
|
||||||
|
migrateModel(session);
|
||||||
|
}
|
||||||
} finally {
|
} finally {
|
||||||
// Close after creating EntityManagerFactory to prevent in-mem databases from closing
|
// Close after creating EntityManagerFactory to prevent in-mem databases from closing
|
||||||
if (connection != null) {
|
if (connection != null) {
|
||||||
|
@ -402,4 +415,7 @@ public class DefaultJpaConnectionProviderFactory implements JpaConnectionProvide
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void migrateModel(KeycloakSession session) {
|
||||||
|
KeycloakModelUtils.runJobInTransaction(session.getKeycloakSessionFactory(), MigrationModelManager::migrate);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -48,6 +48,7 @@ public class MigrationModelAdapter implements MigrationModel {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@Deprecated
|
||||||
public String getResourcesTag() {
|
public String getResourcesTag() {
|
||||||
return latest != null ? latest.getId() : null;
|
return latest != null ? latest.getId() : null;
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,87 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2021 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.map.serverinfo;
|
||||||
|
|
||||||
|
import java.security.MessageDigest;
|
||||||
|
import java.security.NoSuchAlgorithmException;
|
||||||
|
import org.jboss.logging.Logger;
|
||||||
|
import org.keycloak.Config;
|
||||||
|
import org.keycloak.common.Version;
|
||||||
|
import org.keycloak.common.util.Base64Url;
|
||||||
|
import org.keycloak.common.util.RandomString;
|
||||||
|
import org.keycloak.migration.MigrationModel;
|
||||||
|
import org.keycloak.migration.ModelVersion;
|
||||||
|
import org.keycloak.models.KeycloakSession;
|
||||||
|
import org.keycloak.models.ServerInfoProvider;
|
||||||
|
import org.keycloak.models.ServerInfoProviderFactory;
|
||||||
|
import org.keycloak.models.map.common.AbstractMapProviderFactory;
|
||||||
|
|
||||||
|
public class MapServerInfoProviderFactory extends AbstractMapProviderFactory<ServerInfoProvider> implements ServerInfoProviderFactory {
|
||||||
|
|
||||||
|
private static final String RESOURCES_VERSION_SEED = "resourcesVersionSeed";
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void init(Config.Scope config) {
|
||||||
|
String seed = config.get(RESOURCES_VERSION_SEED);
|
||||||
|
if (seed == null) {
|
||||||
|
Logger.getLogger(ServerInfoProviderFactory.class).warnf("It is recommended to set '%s' property in the %s provider config of serverInfo SPI", RESOURCES_VERSION_SEED, PROVIDER_ID);
|
||||||
|
//generate random string for this installation
|
||||||
|
seed = RandomString.randomCode(10);
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
Version.RESOURCES_VERSION = Base64Url.encode(MessageDigest.getInstance("MD5")
|
||||||
|
.digest((seed + new ModelVersion(Version.VERSION_KEYCLOAK).toString()).getBytes()))
|
||||||
|
.substring(0, 5);
|
||||||
|
} catch (NoSuchAlgorithmException e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ServerInfoProvider create(KeycloakSession session) {
|
||||||
|
return INSTANCE;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static final ServerInfoProvider INSTANCE = new ServerInfoProvider() {
|
||||||
|
|
||||||
|
private final MigrationModel INSTANCE = new MigrationModel() {
|
||||||
|
@Override
|
||||||
|
public String getStoredVersion() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
@Override
|
||||||
|
public String getResourcesTag() {
|
||||||
|
throw new UnsupportedOperationException("Not supported.");
|
||||||
|
}
|
||||||
|
@Override
|
||||||
|
public void setStoredVersion(String version) {
|
||||||
|
throw new UnsupportedOperationException("Not supported.");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public MigrationModel getMigrationModel() {
|
||||||
|
return INSTANCE;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void close() {
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
}
|
|
@ -0,0 +1,18 @@
|
||||||
|
#
|
||||||
|
# Copyright 2021 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.
|
||||||
|
#
|
||||||
|
|
||||||
|
org.keycloak.models.map.serverinfo.MapServerInfoProviderFactory
|
|
@ -184,8 +184,18 @@ public final class QuarkusJpaConnectionProviderFactory implements JpaConnectionP
|
||||||
|
|
||||||
private void initSchemaOrExport(KeycloakSession session) {
|
private void initSchemaOrExport(KeycloakSession session) {
|
||||||
ExportImportManager exportImportManager = new ExportImportManager(session);
|
ExportImportManager exportImportManager = new ExportImportManager(session);
|
||||||
logger.debug("Calling migrateModel");
|
|
||||||
migrateModel(session);
|
/*
|
||||||
|
* Migrate model is executed just in case following providers are "jpa".
|
||||||
|
* In Map Storage, there is an assumption that migrateModel is not needed.
|
||||||
|
*/
|
||||||
|
if ((Config.getProvider("realm") == null || "jpa".equals(Config.getProvider("realm"))) &&
|
||||||
|
(Config.getProvider("client") == null || "jpa".equals(Config.getProvider("client"))) &&
|
||||||
|
(Config.getProvider("clientScope") == null || "jpa".equals(Config.getProvider("clientScope")))) {
|
||||||
|
|
||||||
|
logger.debug("Calling migrateModel");
|
||||||
|
migrateModel(session);
|
||||||
|
}
|
||||||
|
|
||||||
DBLockManager dbLockManager = new DBLockManager(session);
|
DBLockManager dbLockManager = new DBLockManager(session);
|
||||||
dbLockManager.checkForcedUnlock();
|
dbLockManager.checkForcedUnlock();
|
||||||
|
|
|
@ -24,6 +24,7 @@ package org.keycloak.migration;
|
||||||
*/
|
*/
|
||||||
public interface MigrationModel {
|
public interface MigrationModel {
|
||||||
String getStoredVersion();
|
String getStoredVersion();
|
||||||
|
@Deprecated
|
||||||
String getResourcesTag();
|
String getResourcesTag();
|
||||||
void setStoredVersion(String version);
|
void setStoredVersion(String version);
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,7 +22,6 @@ import org.keycloak.Config;
|
||||||
import org.keycloak.common.util.Resteasy;
|
import org.keycloak.common.util.Resteasy;
|
||||||
import org.keycloak.config.ConfigProviderFactory;
|
import org.keycloak.config.ConfigProviderFactory;
|
||||||
import org.keycloak.exportimport.ExportImportManager;
|
import org.keycloak.exportimport.ExportImportManager;
|
||||||
import org.keycloak.migration.MigrationModelManager;
|
|
||||||
import org.keycloak.models.KeycloakSession;
|
import org.keycloak.models.KeycloakSession;
|
||||||
import org.keycloak.models.KeycloakSessionFactory;
|
import org.keycloak.models.KeycloakSessionFactory;
|
||||||
import org.keycloak.models.KeycloakSessionTask;
|
import org.keycloak.models.KeycloakSessionTask;
|
||||||
|
@ -30,8 +29,6 @@ import org.keycloak.models.ModelDuplicateException;
|
||||||
import org.keycloak.models.RealmModel;
|
import org.keycloak.models.RealmModel;
|
||||||
import org.keycloak.models.UserModel;
|
import org.keycloak.models.UserModel;
|
||||||
import org.keycloak.models.UserProvider;
|
import org.keycloak.models.UserProvider;
|
||||||
import org.keycloak.models.dblock.DBLockManager;
|
|
||||||
import org.keycloak.models.dblock.DBLockProvider;
|
|
||||||
import org.keycloak.models.utils.KeycloakModelUtils;
|
import org.keycloak.models.utils.KeycloakModelUtils;
|
||||||
import org.keycloak.models.utils.PostMigrationEvent;
|
import org.keycloak.models.utils.PostMigrationEvent;
|
||||||
import org.keycloak.models.utils.RepresentationToModel;
|
import org.keycloak.models.utils.RepresentationToModel;
|
||||||
|
@ -86,8 +83,8 @@ public class KeycloakApplication extends Application {
|
||||||
|
|
||||||
protected final PlatformProvider platform = Platform.getPlatform();
|
protected final PlatformProvider platform = Platform.getPlatform();
|
||||||
|
|
||||||
protected Set<Object> singletons = new HashSet<Object>();
|
protected Set<Object> singletons = new HashSet<>();
|
||||||
protected Set<Class<?>> classes = new HashSet<Class<?>>();
|
protected Set<Class<?>> classes = new HashSet<>();
|
||||||
|
|
||||||
protected static KeycloakSessionFactory sessionFactory;
|
protected static KeycloakSessionFactory sessionFactory;
|
||||||
|
|
||||||
|
@ -124,28 +121,10 @@ public class KeycloakApplication extends Application {
|
||||||
protected void startup() {
|
protected void startup() {
|
||||||
this.sessionFactory = createSessionFactory();
|
this.sessionFactory = createSessionFactory();
|
||||||
|
|
||||||
ExportImportManager[] exportImportManager = new ExportImportManager[1];
|
ExportImportManager exportImportManager = bootstrap();
|
||||||
|
|
||||||
KeycloakModelUtils.runJobInTransaction(sessionFactory, new KeycloakSessionTask() {
|
if (exportImportManager.isRunExport()) {
|
||||||
|
exportImportManager.runExport();
|
||||||
@Override
|
|
||||||
public void run(KeycloakSession lockSession) {
|
|
||||||
DBLockManager dbLockManager = new DBLockManager(lockSession);
|
|
||||||
dbLockManager.checkForcedUnlock();
|
|
||||||
DBLockProvider dbLock = dbLockManager.getDBLock();
|
|
||||||
dbLock.waitForLock(DBLockProvider.Namespace.KEYCLOAK_BOOT);
|
|
||||||
try {
|
|
||||||
exportImportManager[0] = migrateAndBootstrap();
|
|
||||||
} finally {
|
|
||||||
dbLock.releaseLock();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
if (exportImportManager[0].isRunExport()) {
|
|
||||||
exportImportManager[0].runExport();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
KeycloakModelUtils.runJobInTransaction(sessionFactory, new KeycloakSessionTask() {
|
KeycloakModelUtils.runJobInTransaction(sessionFactory, new KeycloakSessionTask() {
|
||||||
|
@ -168,78 +147,56 @@ public class KeycloakApplication extends Application {
|
||||||
sessionFactory.close();
|
sessionFactory.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Migrate model, bootstrap master realm, import realms and create admin user. This is done with acquired dbLock
|
// Bootstrap master realm, import realms and create admin user.
|
||||||
protected ExportImportManager migrateAndBootstrap() {
|
protected ExportImportManager bootstrap() {
|
||||||
ExportImportManager exportImportManager;
|
ExportImportManager[] exportImportManager = new ExportImportManager[1];
|
||||||
logger.debug("Calling migrateModel");
|
|
||||||
migrateModel();
|
|
||||||
|
|
||||||
logger.debug("bootstrap");
|
logger.debug("bootstrap");
|
||||||
KeycloakSession session = sessionFactory.create();
|
KeycloakModelUtils.runJobInTransaction(sessionFactory, new KeycloakSessionTask() {
|
||||||
try {
|
@Override
|
||||||
session.getTransactionManager().begin();
|
public void run(KeycloakSession session) {
|
||||||
JtaTransactionManagerLookup lookup = (JtaTransactionManagerLookup) sessionFactory.getProviderFactory(JtaTransactionManagerLookup.class);
|
// TODO what is the purpose of following piece of code? Leaving it as is for now.
|
||||||
if (lookup != null) {
|
JtaTransactionManagerLookup lookup = (JtaTransactionManagerLookup) sessionFactory.getProviderFactory(JtaTransactionManagerLookup.class);
|
||||||
if (lookup.getTransactionManager() != null) {
|
if (lookup != null) {
|
||||||
try {
|
if (lookup.getTransactionManager() != null) {
|
||||||
Transaction transaction = lookup.getTransactionManager().getTransaction();
|
try {
|
||||||
logger.debugv("bootstrap current transaction? {0}", transaction != null);
|
Transaction transaction = lookup.getTransactionManager().getTransaction();
|
||||||
if (transaction != null) {
|
logger.debugv("bootstrap current transaction? {0}", transaction != null);
|
||||||
logger.debugv("bootstrap current transaction status? {0}", transaction.getStatus());
|
if (transaction != null) {
|
||||||
|
logger.debugv("bootstrap current transaction status? {0}", transaction.getStatus());
|
||||||
|
}
|
||||||
|
} catch (SystemException e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
}
|
}
|
||||||
} catch (SystemException e) {
|
|
||||||
throw new RuntimeException(e);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// TODO up here ^^
|
||||||
|
|
||||||
|
session.clientPolicy().setupClientPoliciesOnKeycloakApp("/keycloak-default-client-profiles.json", "/keycloak-default-client-policies.json");
|
||||||
|
|
||||||
|
ApplianceBootstrap applianceBootstrap = new ApplianceBootstrap(session);
|
||||||
|
exportImportManager[0] = new ExportImportManager(session);
|
||||||
|
|
||||||
|
boolean createMasterRealm = applianceBootstrap.isNewInstall();
|
||||||
|
if (exportImportManager[0].isRunImport() && exportImportManager[0].isImportMasterIncluded()) {
|
||||||
|
createMasterRealm = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (createMasterRealm) {
|
||||||
|
applianceBootstrap.createMasterRealm();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
});
|
||||||
|
|
||||||
session.clientPolicy().setupClientPoliciesOnKeycloakApp("/keycloak-default-client-profiles.json", "/keycloak-default-client-policies.json");
|
if (exportImportManager[0].isRunImport()) {
|
||||||
|
exportImportManager[0].runImport();
|
||||||
ApplianceBootstrap applianceBootstrap = new ApplianceBootstrap(session);
|
|
||||||
exportImportManager = new ExportImportManager(session);
|
|
||||||
|
|
||||||
boolean createMasterRealm = applianceBootstrap.isNewInstall();
|
|
||||||
if (exportImportManager.isRunImport() && exportImportManager.isImportMasterIncluded()) {
|
|
||||||
createMasterRealm = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (createMasterRealm) {
|
|
||||||
applianceBootstrap.createMasterRealm();
|
|
||||||
}
|
|
||||||
session.getTransactionManager().commit();
|
|
||||||
} catch (RuntimeException re) {
|
|
||||||
if (session.getTransactionManager().isActive()) {
|
|
||||||
session.getTransactionManager().rollback();
|
|
||||||
}
|
|
||||||
throw re;
|
|
||||||
} finally {
|
|
||||||
session.close();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (exportImportManager.isRunImport()) {
|
|
||||||
exportImportManager.runImport();
|
|
||||||
} else {
|
} else {
|
||||||
importRealms();
|
importRealms();
|
||||||
}
|
}
|
||||||
|
|
||||||
importAddUser();
|
importAddUser();
|
||||||
|
|
||||||
return exportImportManager;
|
return exportImportManager[0];
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
protected void migrateModel() {
|
|
||||||
KeycloakSession session = sessionFactory.create();
|
|
||||||
try {
|
|
||||||
session.getTransactionManager().begin();
|
|
||||||
MigrationModelManager.migrate(session);
|
|
||||||
session.getTransactionManager().commit();
|
|
||||||
} catch (Exception e) {
|
|
||||||
session.getTransactionManager().rollback();
|
|
||||||
throw e;
|
|
||||||
} finally {
|
|
||||||
session.close();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void loadConfig() {
|
protected void loadConfig() {
|
||||||
|
|
|
@ -66,7 +66,7 @@ public class ServerInfoTest extends AbstractKeycloakTest {
|
||||||
|
|
||||||
Map<String, ProviderRepresentation> jpaProviders = info.getProviders().get("connectionsJpa").getProviders();
|
Map<String, ProviderRepresentation> jpaProviders = info.getProviders().get("connectionsJpa").getProviders();
|
||||||
ProviderRepresentation jpaProvider = jpaProviders.values().iterator().next();
|
ProviderRepresentation jpaProvider = jpaProviders.values().iterator().next();
|
||||||
log.infof("JPA Connections provider info: %s", jpaProvider.getOperationalInfo().toString());
|
log.infof("JPA Connections provider info: %s", jpaProvider.getOperationalInfo());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -929,7 +929,7 @@ public abstract class AbstractMigrationTest extends AbstractKeycloakTest {
|
||||||
String response = SimpleHttp.doGet(url.toString(), client).asString();
|
String response = SimpleHttp.doGet(url.toString(), client).asString();
|
||||||
Matcher m = Pattern.compile("resources/([^/]*)/welcome").matcher(response);
|
Matcher m = Pattern.compile("resources/([^/]*)/welcome").matcher(response);
|
||||||
assertTrue(m.find());
|
assertTrue(m.find());
|
||||||
assertTrue(m.group(1).matches("[\\da-z]{5}"));
|
assertTrue(m.group(1).matches("[a-zA-Z0-9_\\-.~]{5}"));
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
fail(e.getMessage());
|
fail(e.getMessage());
|
||||||
}
|
}
|
||||||
|
|
|
@ -36,6 +36,13 @@
|
||||||
"event-queue": {}
|
"event-queue": {}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
"serverInfo": {
|
||||||
|
"provider": "${keycloak.serverInfo.provider:jpa}",
|
||||||
|
"map": {
|
||||||
|
"resourcesVersionSeed": "1JZ379bzyOCFA"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
"realm": {
|
"realm": {
|
||||||
"provider": "${keycloak.realm.provider:jpa}"
|
"provider": "${keycloak.realm.provider:jpa}"
|
||||||
},
|
},
|
||||||
|
|
|
@ -71,6 +71,8 @@ import org.junit.rules.TestRule;
|
||||||
import org.junit.runner.Description;
|
import org.junit.runner.Description;
|
||||||
import org.junit.runners.model.Statement;
|
import org.junit.runners.model.Statement;
|
||||||
import org.keycloak.timer.TimerSpi;
|
import org.keycloak.timer.TimerSpi;
|
||||||
|
import org.keycloak.models.ServerInfoProviderFactory;
|
||||||
|
import org.keycloak.models.ServerInfoSpi;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Base of testcases that operate on session level. The tests derived from this class
|
* Base of testcases that operate on session level. The tests derived from this class
|
||||||
|
@ -175,6 +177,7 @@ public abstract class KeycloakModelTest {
|
||||||
.add(GroupSpi.class)
|
.add(GroupSpi.class)
|
||||||
.add(RealmSpi.class)
|
.add(RealmSpi.class)
|
||||||
.add(RoleSpi.class)
|
.add(RoleSpi.class)
|
||||||
|
.add(ServerInfoSpi.class)
|
||||||
.add(StoreFactorySpi.class)
|
.add(StoreFactorySpi.class)
|
||||||
.add(TimerSpi.class)
|
.add(TimerSpi.class)
|
||||||
.add(UserLoginFailureSpi.class)
|
.add(UserLoginFailureSpi.class)
|
||||||
|
@ -185,6 +188,7 @@ public abstract class KeycloakModelTest {
|
||||||
private static final Set<Class<? extends ProviderFactory>> ALLOWED_FACTORIES = ImmutableSet.<Class<? extends ProviderFactory>>builder()
|
private static final Set<Class<? extends ProviderFactory>> ALLOWED_FACTORIES = ImmutableSet.<Class<? extends ProviderFactory>>builder()
|
||||||
.add(DefaultAuthorizationProviderFactory.class)
|
.add(DefaultAuthorizationProviderFactory.class)
|
||||||
.add(DefaultExecutorsProviderFactory.class)
|
.add(DefaultExecutorsProviderFactory.class)
|
||||||
|
.add(ServerInfoProviderFactory.class)
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
protected static final List<KeycloakModelParameters> MODEL_PARAMETERS;
|
protected static final List<KeycloakModelParameters> MODEL_PARAMETERS;
|
||||||
|
|
|
@ -1,33 +1,62 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2021 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.testsuite.model;
|
package org.keycloak.testsuite.model;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import javax.persistence.EntityManager;
|
||||||
|
import org.jboss.logging.Logger;
|
||||||
import org.junit.Assert;
|
import org.junit.Assert;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.keycloak.common.Version;
|
import org.keycloak.common.Version;
|
||||||
import org.keycloak.common.util.Time;
|
import org.keycloak.common.util.Time;
|
||||||
import org.keycloak.connections.jpa.JpaConnectionProvider;
|
import org.keycloak.connections.jpa.JpaConnectionProvider;
|
||||||
import org.keycloak.migration.MigrationModel;
|
import org.keycloak.migration.MigrationModel;
|
||||||
import org.keycloak.models.jpa.entities.MigrationModelEntity;
|
import org.keycloak.models.ClientProvider;
|
||||||
import org.keycloak.representations.idm.RealmRepresentation;
|
import org.keycloak.models.ClientScopeProvider;
|
||||||
import org.keycloak.testsuite.AbstractKeycloakTest;
|
import org.keycloak.models.Constants;
|
||||||
import org.keycloak.testsuite.arquillian.annotation.AuthServerContainerExclude;
|
import org.keycloak.models.KeycloakSession;
|
||||||
|
import org.keycloak.models.RealmModel;
|
||||||
import javax.persistence.EntityManager;
|
import org.keycloak.models.RealmProvider;
|
||||||
import java.util.List;
|
|
||||||
import org.jboss.logging.Logger;
|
|
||||||
import org.keycloak.models.ServerInfoProvider;
|
import org.keycloak.models.ServerInfoProvider;
|
||||||
|
import org.keycloak.models.jpa.entities.MigrationModelEntity;
|
||||||
|
|
||||||
import static org.keycloak.testsuite.arquillian.annotation.AuthServerContainerExclude.AuthServer.REMOTE;
|
@RequireProvider(value=RealmProvider.class, only="jpa")
|
||||||
|
@RequireProvider(value=ClientProvider.class, only="jpa")
|
||||||
|
@RequireProvider(value=ClientScopeProvider.class, only="jpa")
|
||||||
|
public class MigrationModelTest extends KeycloakModelTest {
|
||||||
|
|
||||||
@AuthServerContainerExclude(REMOTE)
|
private String realmId;
|
||||||
public class MigrationModelTest extends AbstractKeycloakTest {
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void addTestRealms(List<RealmRepresentation> testRealms) {
|
public void createEnvironment(KeycloakSession s) {
|
||||||
|
RealmModel realm = s.realms().createRealm("realm");
|
||||||
|
realm.setDefaultRole(s.roles().addRealmRole(realm, Constants.DEFAULT_ROLES_ROLE_PREFIX + "-" + realm.getName()));
|
||||||
|
this.realmId = realm.getId();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void cleanEnvironment(KeycloakSession s) {
|
||||||
|
s.realms().removeRealm(realmId);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void test() {
|
public void test() {
|
||||||
testingClient.server().run(session -> {
|
inComittedTransaction(1, (session , i) -> {
|
||||||
|
|
||||||
String currentVersion = Version.VERSION_KEYCLOAK.replaceAll("^(\\d+(?:\\.\\d+){0,2}).*$", "$1");
|
String currentVersion = Version.VERSION_KEYCLOAK.replaceAll("^(\\d+(?:\\.\\d+){0,2}).*$", "$1");
|
||||||
|
|
||||||
JpaConnectionProvider p = session.getProvider(JpaConnectionProvider.class);
|
JpaConnectionProvider p = session.getProvider(JpaConnectionProvider.class);
|
||||||
|
@ -64,7 +93,8 @@ public class MigrationModelTest extends AbstractKeycloakTest {
|
||||||
Assert.assertEquals(currentVersion, m.getStoredVersion());
|
Assert.assertEquals(currentVersion, m.getStoredVersion());
|
||||||
|
|
||||||
em.remove(l.get(1));
|
em.remove(l.get(1));
|
||||||
|
|
||||||
|
return null;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
|
@ -27,6 +27,8 @@ import org.keycloak.connections.jpa.updater.liquibase.lock.LiquibaseDBLockProvid
|
||||||
import org.keycloak.events.jpa.JpaEventStoreProviderFactory;
|
import org.keycloak.events.jpa.JpaEventStoreProviderFactory;
|
||||||
import org.keycloak.models.jpa.session.JpaUserSessionPersisterProviderFactory;
|
import org.keycloak.models.jpa.session.JpaUserSessionPersisterProviderFactory;
|
||||||
import org.keycloak.models.session.UserSessionPersisterSpi;
|
import org.keycloak.models.session.UserSessionPersisterSpi;
|
||||||
|
import org.keycloak.migration.MigrationProviderFactory;
|
||||||
|
import org.keycloak.migration.MigrationSpi;
|
||||||
import org.keycloak.testsuite.model.KeycloakModelParameters;
|
import org.keycloak.testsuite.model.KeycloakModelParameters;
|
||||||
import org.keycloak.models.dblock.DBLockSpi;
|
import org.keycloak.models.dblock.DBLockSpi;
|
||||||
import org.keycloak.models.jpa.JpaClientProviderFactory;
|
import org.keycloak.models.jpa.JpaClientProviderFactory;
|
||||||
|
@ -40,6 +42,8 @@ import org.keycloak.provider.Spi;
|
||||||
import org.keycloak.testsuite.model.Config;
|
import org.keycloak.testsuite.model.Config;
|
||||||
import com.google.common.collect.ImmutableSet;
|
import com.google.common.collect.ImmutableSet;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
import org.keycloak.protocol.LoginProtocolFactory;
|
||||||
|
import org.keycloak.protocol.LoginProtocolSpi;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
|
@ -55,6 +59,10 @@ public class Jpa extends KeycloakModelParameters {
|
||||||
.add(LiquibaseConnectionSpi.class)
|
.add(LiquibaseConnectionSpi.class)
|
||||||
.add(UserSessionPersisterSpi.class)
|
.add(UserSessionPersisterSpi.class)
|
||||||
|
|
||||||
|
//required for migrateModel
|
||||||
|
.add(MigrationSpi.class)
|
||||||
|
.add(LoginProtocolSpi.class)
|
||||||
|
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
static final Set<Class<? extends ProviderFactory>> ALLOWED_FACTORIES = ImmutableSet.<Class<? extends ProviderFactory>>builder()
|
static final Set<Class<? extends ProviderFactory>> ALLOWED_FACTORIES = ImmutableSet.<Class<? extends ProviderFactory>>builder()
|
||||||
|
@ -72,6 +80,11 @@ public class Jpa extends KeycloakModelParameters {
|
||||||
.add(LiquibaseConnectionProviderFactory.class)
|
.add(LiquibaseConnectionProviderFactory.class)
|
||||||
.add(LiquibaseDBLockProviderFactory.class)
|
.add(LiquibaseDBLockProviderFactory.class)
|
||||||
.add(JpaUserSessionPersisterProviderFactory.class)
|
.add(JpaUserSessionPersisterProviderFactory.class)
|
||||||
|
|
||||||
|
//required for migrateModel
|
||||||
|
.add(MigrationProviderFactory.class)
|
||||||
|
.add(LoginProtocolFactory.class)
|
||||||
|
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
public Jpa() {
|
public Jpa() {
|
||||||
|
@ -81,11 +94,17 @@ public class Jpa extends KeycloakModelParameters {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void updateConfig(Config cf) {
|
public void updateConfig(Config cf) {
|
||||||
|
updateConfigForJpa(cf);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void updateConfigForJpa(Config cf) {
|
||||||
cf.spi("client").defaultProvider("jpa")
|
cf.spi("client").defaultProvider("jpa")
|
||||||
.spi("clientScope").defaultProvider("jpa")
|
.spi("clientScope").defaultProvider("jpa")
|
||||||
.spi("group").defaultProvider("jpa")
|
.spi("group").defaultProvider("jpa")
|
||||||
.spi("role").defaultProvider("jpa")
|
.spi("role").defaultProvider("jpa")
|
||||||
.spi("user").defaultProvider("jpa")
|
.spi("user").defaultProvider("jpa")
|
||||||
|
.spi("realm").defaultProvider("jpa")
|
||||||
|
.spi("serverInfo").defaultProvider("jpa")
|
||||||
;
|
;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -31,6 +31,7 @@ import org.keycloak.storage.clientscope.ClientScopeStorageProviderFactory;
|
||||||
import org.keycloak.storage.clientscope.ClientScopeStorageProviderModel;
|
import org.keycloak.storage.clientscope.ClientScopeStorageProviderModel;
|
||||||
import org.keycloak.storage.clientscope.ClientScopeStorageProviderSpi;
|
import org.keycloak.storage.clientscope.ClientScopeStorageProviderSpi;
|
||||||
import org.keycloak.testsuite.federation.HardcodedClientScopeStorageProviderFactory;
|
import org.keycloak.testsuite.federation.HardcodedClientScopeStorageProviderFactory;
|
||||||
|
import org.keycloak.testsuite.model.Config;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
|
@ -70,4 +71,9 @@ public class JpaFederation extends KeycloakModelParameters {
|
||||||
return super.getParameters(clazz);
|
return super.getParameters(clazz);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void updateConfig(Config cf) {
|
||||||
|
Jpa.updateConfigForJpa(cf);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,6 +14,13 @@
|
||||||
"provider": "${keycloak.eventsStore.provider:}"
|
"provider": "${keycloak.eventsStore.provider:}"
|
||||||
},
|
},
|
||||||
|
|
||||||
|
"serverInfo": {
|
||||||
|
"provider": "${keycloak.serverInfo.provider:jpa}",
|
||||||
|
"map": {
|
||||||
|
"resourcesVersionSeed": "1JZ379bzyOCFA"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
"realm": {
|
"realm": {
|
||||||
"provider": "${keycloak.realm.provider:jpa}"
|
"provider": "${keycloak.realm.provider:jpa}"
|
||||||
},
|
},
|
||||||
|
|
Loading…
Reference in a new issue