fix: removing KeycloakApplication usage of keycloak-add-user.json (#39460)

* fix: removing KeycloakApplication usage of keycloak-add-user.json

closes:#39428

Signed-off-by: Steve Hawkins <shawkins@redhat.com>

* Removing the test keycloak-add-user.json

Signed-off-by: Steve Hawkins <shawkins@redhat.com>

---------

Signed-off-by: Steve Hawkins <shawkins@redhat.com>
This commit is contained in:
Steven Hawkins 2025-05-08 03:58:09 -04:00 committed by GitHub
parent 8716d2425d
commit f40cb88db4
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
12 changed files with 44 additions and 175 deletions

View File

@ -70,18 +70,6 @@ public interface ServicesLogger extends BasicLogger {
@Message(id=5, value="Unable to import realm %s from %s.")
void unableToImportRealm(@Cause Throwable t, String realmName, String from);
@LogMessage(level = INFO)
@Message(id=6, value="Importing users from '%s'")
void imprtingUsersFrom(Object from);
@LogMessage(level = ERROR)
@Message(id=7, value="Failed to load 'keycloak-add-user.json'")
void failedToLoadUsers(@Cause Throwable t);
@LogMessage(level = ERROR)
@Message(id=8, value="Failed to add user %s to realm %s: realm not found")
void addUserFailedRealmNotFound(String user, String realm);
@LogMessage(level = INFO)
@Message(id=9, value="Added user '%s' to realm '%s'")
void addUserSuccess(String user, String realm);
@ -89,7 +77,7 @@ public interface ServicesLogger extends BasicLogger {
@LogMessage(level = ERROR)
@Message(id=10, value="Failed to add user '%s' to realm '%s': user with username exists")
void addUserFailedUserExists(String user, String realm);
@LogMessage(level = ERROR)
@Message(id=11, value="Failed to add user '%s' to realm '%s'")
void addUserFailed(@Cause Throwable t, String user, String realm);
@ -472,11 +460,11 @@ public interface ServicesLogger extends BasicLogger {
@LogMessage(level = WARN)
@Message(id=108, value="URI '%s' doesn't match any trustedHost or trustedDomain")
void uriDoesntMatch(String uri);
@LogMessage(level = ERROR)
@Message(id=109, value="Failed to add client '%s' to realm '%s': client with client ID exists")
void addClientFailedClientExists(String clientId, String realm);
@LogMessage(level = WARN)
@Message(id=110, value="Environment variable '%s' is deprecated, use '%s' instead")
void usingDeprecatedEnvironmentVariable(String deprecated, String supported);

View File

@ -25,34 +25,18 @@ import org.keycloak.exportimport.ExportImportManager;
import org.keycloak.models.KeycloakSession;
import org.keycloak.models.KeycloakSessionFactory;
import org.keycloak.models.KeycloakSessionTask;
import org.keycloak.models.ModelDuplicateException;
import org.keycloak.models.RealmModel;
import org.keycloak.models.UserModel;
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.PostMigrationEvent;
import org.keycloak.models.utils.RepresentationToModel;
import org.keycloak.platform.Platform;
import org.keycloak.platform.PlatformProvider;
import org.keycloak.representations.idm.RealmRepresentation;
import org.keycloak.representations.idm.UserRepresentation;
import org.keycloak.services.ServicesLogger;
import org.keycloak.services.managers.ApplianceBootstrap;
import org.keycloak.services.managers.RealmManager;
import org.keycloak.transaction.JtaTransactionManagerLookup;
import org.keycloak.util.JsonSerialization;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.util.List;
import java.util.NoSuchElementException;
import java.util.ServiceLoader;
import com.fasterxml.jackson.core.type.TypeReference;
import jakarta.transaction.SystemException;
import jakarta.transaction.Transaction;
import jakarta.ws.rs.core.Application;
@ -173,8 +157,6 @@ public abstract class KeycloakApplication extends Application {
bootstrapState.exportImportManager.runImport();
}
importAddUser();
return bootstrapState.exportImportManager;
}
@ -200,54 +182,4 @@ public abstract class KeycloakApplication extends Application {
return sessionFactory;
}
public void importAddUser() {
String configDir = System.getProperty("jboss.server.config.dir");
if (configDir != null) {
File addUserFile = new File(configDir + File.separator + "keycloak-add-user.json");
if (addUserFile.isFile()) {
ServicesLogger.LOGGER.imprtingUsersFrom(addUserFile);
List<RealmRepresentation> realms;
try {
realms = JsonSerialization.readValue(new FileInputStream(addUserFile), new TypeReference<List<RealmRepresentation>>() {
});
} catch (IOException e) {
ServicesLogger.LOGGER.failedToLoadUsers(e);
return;
}
for (RealmRepresentation realmRep : realms) {
for (UserRepresentation userRep : realmRep.getUsers()) {
try {
KeycloakModelUtils.runJobInTransaction(sessionFactory, session -> {
RealmModel realm = session.realms().getRealmByName(realmRep.getRealm());
if (realm == null) {
ServicesLogger.LOGGER.addUserFailedRealmNotFound(userRep.getUsername(), realmRep.getRealm());
}
session.getContext().setRealm(realm);
UserProvider users = session.users();
if (users.getUserByUsername(realm, userRep.getUsername()) != null) {
ServicesLogger.LOGGER.notCreatingExistingUser(userRep.getUsername());
} else {
UserModel user = RepresentationToModel.createUser(session, realm, userRep);
ServicesLogger.LOGGER.addUserSuccess(userRep.getUsername(), realmRep.getRealm());
}
});
} catch (ModelDuplicateException e) {
ServicesLogger.LOGGER.addUserFailedUserExists(userRep.getUsername(), realmRep.getRealm());
} catch (Throwable t) {
ServicesLogger.LOGGER.addUserFailed(t, userRep.getUsername(), realmRep.getRealm());
}
}
}
if (!addUserFile.delete()) {
ServicesLogger.LOGGER.failedToDeleteFile(addUserFile.getAbsolutePath());
}
}
}
}
}

View File

@ -63,6 +63,14 @@ public class Config {
return "mysecret";
}
public static String getAdminUsername() {
return "admin";
}
public static String getAdminPassword() {
return "admin";
}
public static SmallRyeConfig initConfig() {
SmallRyeConfigBuilder configBuilder = new SmallRyeConfigBuilder()
.addDefaultSources()

View File

@ -22,7 +22,8 @@ public abstract class AbstractKeycloakServerSupplier implements Supplier<Keycloa
KeycloakServerConfigBuilder command = KeycloakServerConfigBuilder.startDev()
.cache("local")
.bootstrapAdminClient(Config.getAdminClientId(), Config.getAdminClientSecret());
.bootstrapAdminClient(Config.getAdminClientId(), Config.getAdminClientSecret())
.bootstrapAdminUser(Config.getAdminUsername(), Config.getAdminPassword());
command.log().handlers(KeycloakServerConfigBuilder.LogHandlers.CONSOLE);

View File

@ -43,6 +43,11 @@ public class KeycloakServerConfigBuilder {
.option("bootstrap-admin-client-secret", clientSecret);
}
public KeycloakServerConfigBuilder bootstrapAdminUser(String username, String password) {
return option("bootstrap-admin-username", username)
.option("bootstrap-admin-password", password);
}
public KeycloakServerConfigBuilder cache(String cache) {
return option("cache", cache);
}

View File

@ -46,6 +46,11 @@ public class WelcomePageTest {
@Test
@Order(1)
public void localAccessNoAdmin() {
// get rid of the bootstrap admin added for db compatibility with the older test framework
// it will get added by in subsequent tests
var users = adminClient.realms().realm("master").users();
users.searchByUsername("admin", true).stream().findFirst().ifPresent(admin -> users.delete(admin.getId()));
welcomePage.navigateTo();
Assertions.assertEquals("Create a temporary administrative user", welcomePage.getWelcomeMessage());

View File

@ -316,26 +316,6 @@
</resources>
</configuration>
</execution>
<execution>
<id>copy-admin-user-json-file</id>
<phase>process-resources</phase>
<goals>
<goal>copy-resources</goal>
</goals>
<configuration>
<skip>${skip.add.user.json}</skip>
<outputDirectory>${auth.server.config.dir}</outputDirectory>
<resources>
<resource>
<directory>src/test/resources</directory>
<includes>
<include>keycloak-add-user.json</include>
</includes>
<filtering>true</filtering>
</resource>
</resources>
</configuration>
</execution>
</executions>
</plugin>

View File

@ -65,6 +65,7 @@ import org.keycloak.common.Profile.Feature.Type;
import org.keycloak.common.crypto.FipsMode;
import org.keycloak.testsuite.ProfileAssume;
import org.keycloak.testsuite.arquillian.SuiteContext;
import org.keycloak.testsuite.auth.page.AuthRealm;
import org.keycloak.testsuite.model.StoreProvider;
import org.keycloak.utils.StringUtil;
@ -167,7 +168,7 @@ public abstract class AbstractQuarkusDeployableContainer implements DeployableCo
commands.add("--http-port=" + configuration.getBindHttpPort());
commands.add("--https-port=" + configuration.getBindHttpsPort());
commands.add("--http-relative-path=/auth");
commands.add("--health-enabled=true"); // expose something to management interface to turn it on
@ -209,8 +210,9 @@ public abstract class AbstractQuarkusDeployableContainer implements DeployableCo
commands.add("--cache-config-file=cluster-" + cacheMode + ".xml");
var stack = System.getProperty("auth.server.quarkus.cluster.stack");
if (stack != null)
if (stack != null) {
commands.add("--cache-stack=" + stack);
}
}
log.debugf("FIPS Mode: %s", configuration.getFipsMode());
@ -221,7 +223,7 @@ public abstract class AbstractQuarkusDeployableContainer implements DeployableCo
addStorageOptions(storeProvider, commands);
addFeaturesOption(commands);
spis.values().forEach(commands::addAll);
var features = getDefaultFeatures();
@ -235,13 +237,18 @@ public abstract class AbstractQuarkusDeployableContainer implements DeployableCo
System.setProperty("kc.cache-remote-create-caches", "true");
}
if (!suiteContext.get().isAuthServerMigrationEnabled()) {
commands.add("--bootstrap-admin-username=" + AuthRealm.ADMIN);
commands.add("--bootstrap-admin-password=" + AuthRealm.ADMIN);
}
return commands;
}
protected void addFeaturesOption(List<String> commands) {
String enabledFeatures = Optional.ofNullable(configuration.getEnabledFeatures()).orElse("");
String disabledFeatures = Optional.ofNullable(configuration.getDisabledFeatures()).orElse("");
var disabled = ProfileAssume.getDisabledFeatures();
// TODO: this is not ideal, we're trying to infer what should be enabled / disabled from what was captured
// as the disabled features. This at least does not understand the profile and may not age well.
@ -386,12 +393,15 @@ public abstract class AbstractQuarkusDeployableContainer implements DeployableCo
private SSLSocketFactory createInsecureSslSocketFactory() throws IOException {
TrustManager[] trustAllCerts = new TrustManager[]{new X509TrustManager() {
@Override
public void checkClientTrusted(final X509Certificate[] chain, final String authType) {
}
@Override
public void checkServerTrusted(final X509Certificate[] chain, final String authType) {
}
@Override
public X509Certificate[] getAcceptedIssuers() {
return null;
}
@ -456,7 +466,7 @@ public abstract class AbstractQuarkusDeployableContainer implements DeployableCo
public void setSpiConfig(String spi, List<String> args) {
this.spis.put(spi, args);
}
public void removeSpiConfig(String spi) {
this.spis.remove(spi);
}

View File

@ -117,7 +117,9 @@ public class KeycloakQuarkusServerDeployableContainer extends AbstractQuarkusDep
log.infof("Importing realm from file '%s'", importFileName);
final URL url = getClass().getResource("/migration-test/" + importFileName);
if (url == null) throw new IllegalArgumentException("Cannot find migration import file");
if (url == null) {
throw new IllegalArgumentException("Cannot find migration import file");
}
final Path path = Paths.get(url.toURI());
final File wrkDir = configuration.getProvidersPath().resolve("bin").toFile();
@ -166,11 +168,6 @@ public class KeycloakQuarkusServerDeployableContainer extends AbstractQuarkusDep
builder.environment().put("JAVA_OPTS", javaOpts);
}
if (!StoreProvider.JPA.equals(StoreProvider.getCurrentProvider())) {
builder.environment().put("KC_BOOTSTRAP_ADMIN_USERNAME", "admin");
builder.environment().put("KC_BOOTSTRAP_ADMIN_PASSWORD", "admin");
}
if (restart.compareAndSet(false, true)) {
deleteDirectory(configuration.getProvidersPath().resolve("data"));
}
@ -245,6 +242,7 @@ public class KeycloakQuarkusServerDeployableContainer extends AbstractQuarkusDep
public static void deleteDirectory(final Path directory) throws IOException {
if (Files.isDirectory(directory, new LinkOption[0])) {
Files.walkFileTree(directory, new SimpleFileVisitor<Path>() {
@Override
public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
try {
Files.delete(file);
@ -254,6 +252,7 @@ public class KeycloakQuarkusServerDeployableContainer extends AbstractQuarkusDep
return FileVisitResult.CONTINUE;
}
@Override
public FileVisitResult postVisitDirectory(Path dir, IOException exc) throws IOException {
try {
Files.delete(dir);

View File

@ -1,13 +0,0 @@
[ {
"realm" : "master",
"users" : [ {
"username" : "admin",
"enabled" : true,
"credentials" : [ {
"type" : "password",
"secretData" : "{\"value\":\"Rned5xhMiQffs44bqm6B6VSCyedQn0hg2hnyuTTQNCcd1GxlDQbbKNFIPESgeQws0WYoQs+8kAWuD/wfBcBFaA==\",\"salt\":\"0K637Dy0FG+sBlXbHA7ioA==\"}",
"credentialData" : "{\"hashIterations\":100000,\"algorithm\":\"pbkdf2-sha256\"}"
} ],
"realmRoles" : [ "admin" ]
} ]
} ]

View File

@ -59,38 +59,13 @@
<artifactId>integration-arquillian-tests-base</artifactId>
<version>${project.version}</version>
<classifier>tests</classifier>
<includes>arquillian.xml,wildfly-config.xml,keycloak-add-user.json,test-constants.properties,kerberos/*,keystore/*,password-blacklists/*,log4j.properties,vault/*</includes>
<includes>arquillian.xml,wildfly-config.xml,test-constants.properties,kerberos/*,keystore/*,password-blacklists/*,log4j.properties,vault/*</includes>
</artifactItem>
</artifactItems>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<artifactId>maven-resources-plugin</artifactId>
<executions>
<execution>
<id>copy-admin-user-json-file</id>
<phase>process-test-resources</phase>
<goals>
<goal>copy-resources</goal>
</goals>
<configuration>
<skip>${skip.add.user.json}</skip>
<outputDirectory>${auth.server.config.dir}</outputDirectory>
<resources>
<resource>
<directory>${project.build.directory}/dependency</directory>
<includes>
<include>keycloak-add-user.json</include>
</includes>
<filtering>true</filtering>
</resource>
</resources>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</pluginManagement>
</build>

View File

@ -332,26 +332,6 @@
<plugin>
<artifactId>maven-resources-plugin</artifactId>
<executions>
<execution>
<id>copy-admin-user-json-file</id>
<phase>generate-resources</phase>
<goals>
<goal>copy-resources</goal>
</goals>
<configuration>
<skip>${skip.add.user.json}</skip>
<outputDirectory>${auth.server.config.dir}</outputDirectory>
<resources>
<resource>
<directory>src/test/resources</directory>
<includes>
<include>keycloak-add-user.json</include>
</includes>
<filtering>true</filtering>
</resource>
</resources>
</configuration>
</execution>
<execution>
<id>copy-truststore</id>
<phase>generate-resources</phase>
@ -803,7 +783,6 @@
<auth.server.crossdc11.home>${containers.home}/auth-server-${auth.server}-crossdc11</auth.server.crossdc11.home>
<auth.server.crossdc12.home>${containers.home}/auth-server-${auth.server}-crossdc12</auth.server.crossdc12.home>
<!-- property specifies keycloak-add-user.json file destination -->
<auth.server.config.dir>${auth.server.crossdc01.home}/standalone/configuration</auth.server.config.dir>
<cache.server.crossdc1.jvm.debug.port>6001</cache.server.crossdc1.jvm.debug.port>