Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add configuration to disable bootstrap of admin account #165

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 24 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,17 @@ Use another Keycloak Docker image/version than used in this Testcontainer:
KeycloakContainer keycloak = new KeycloakContainer("quay.io/keycloak/keycloak:26.0");
```

### Initial admin user credentials

Use different admin credentials than the default internal (`admin`/`admin`) ones:

```java
@Container
KeycloakContainer keycloak = new KeycloakContainer()
.withAdminUsername("myKeycloakAdminUser")
.withAdminPassword("tops3cr3t");
```

### Realm Import

Power up a Keycloak instance with one or more existing realm JSON config files (from classpath):
Expand All @@ -56,13 +67,24 @@ or
.withRealmImportFiles("/test-realm-1.json", "/test-realm-2.json");
```

### Initial admin user credentials
If your realm JSON configuration file includes user definitions - particularly the admin user
for the master realm - ensure you disable the automatic bootstrapping of the admin user:

```java
@Container
KeycloakContainer keycloak = new KeycloakContainer()
.withBootstrapAdminDisabled()
.withRealmImportFile("/test-realm.json");
```

Use different admin credentials than the defaut internal (`admin`/`admin`) ones:
To retrieve a working Keycloak Admin Client from the container, make sure to override the admin
credentials to match those in your imported realm JSON configuration file:

```java
@Container
KeycloakContainer keycloak = new KeycloakContainer()
.withBootstrapAdminDisabled()
.withRealmImportFile("/test-realm.json")
.withAdminUsername("myKeycloakAdminUser")
.withAdminPassword("tops3cr3t");
```
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,8 @@ public abstract class ExtendableKeycloakContainer<SELF extends ExtendableKeycloa
private List<File> providerLibsLocations;
private List<String> customCommandParts;

private boolean bootstrapAdmin = true;

/**
* Create a KeycloakContainer with default image and version tag
*/
Expand Down Expand Up @@ -164,8 +166,11 @@ protected void configure() {
withEnv("KC_FEATURES_DISABLED", String.join(",", featuresDisabled));
}

withEnv("KC_BOOTSTRAP_ADMIN_USERNAME", adminUsername);
withEnv("KC_BOOTSTRAP_ADMIN_PASSWORD", adminPassword);
if (bootstrapAdmin) {
withEnv("KC_BOOTSTRAP_ADMIN_USERNAME", adminUsername);
withEnv("KC_BOOTSTRAP_ADMIN_PASSWORD", adminPassword);
}

withEnv("JAVA_OPTS_KC_HEAP", "-XX:InitialRAMPercentage=%d -XX:MaxRAMPercentage=%d".formatted(initialRamPercentage, maxRamPercentage));

if (useTls && isNotBlank(tlsCertificateFilename)) {
Expand Down Expand Up @@ -515,6 +520,16 @@ private SELF withDebug(int hostPort, boolean suspend) {
return self();
}

/** Disable default bootstrapping of the keycloak admin. Useful when realms are imported. */
public SELF withBootstrapAdminDisabled() {
this.bootstrapAdmin = false;
return self();
}

/**
* Returns the keycloak admin. Note that this may not return a functioning admin client
* if the master realm including users were imported.
*/
public Keycloak getKeycloakAdminClient() {
if (useTls) {
return Keycloak.getInstance(getAuthServerUrl(), MASTER_REALM, getAdminUsername(), getAdminPassword(), ADMIN_CLI_CLIENT, buildSslContext());
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package dasniko.testcontainers.keycloak;

import io.restassured.response.ValidatableResponse;
import jakarta.ws.rs.NotAuthorizedException;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.ValueSource;
Expand All @@ -23,6 +24,7 @@
import static org.hamcrest.Matchers.is;
import static org.hamcrest.Matchers.notNullValue;
import static org.hamcrest.Matchers.startsWith;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.junit.jupiter.api.Assertions.fail;

Expand All @@ -32,6 +34,7 @@
public class KeycloakContainerTest {

public static final String TEST_REALM_JSON = "/test-realm.json";
public static final String MASTER_REALM_WITH_ADMIN_USER_JSON = "/master-realm-with-admin-user.json";

@Test
public void shouldStartKeycloak() {
Expand All @@ -49,7 +52,7 @@ public void shouldConsiderConfiguredStartupTimeout() {
try (KeycloakContainer keycloak = new KeycloakContainer().withStartupTimeout(duration)) {
keycloak.start();
}
} catch(ContainerLaunchException ex) {
} catch (ContainerLaunchException ex) {
Duration observedDuration = Duration.between(start, Instant.now());
assertTrue(observedDuration.toSeconds() >= MAX_TIMEOUT && observedDuration.toSeconds() < 30,
String.format("Startup time should consider configured limit of %d seconds, but took %d seconds",
Expand Down Expand Up @@ -91,6 +94,22 @@ public void shouldImportMultipleRealms() {
}
}

@Test
public void shouldImportMasterRealmAdmin() {
try (KeycloakContainer keycloak = new KeycloakContainer()
.withBootstrapAdminDisabled()
.withRealmImportFiles(MASTER_REALM_WITH_ADMIN_USER_JSON)) {
keycloak.start();

// Throws because we have imported a different admin user with different password
assertThrows(NotAuthorizedException.class, () -> keycloak.getKeycloakAdminClient().tokenManager().getAccessToken());

// Set password from imported realm, see json file
keycloak.withAdminPassword("password");
keycloak.getKeycloakAdminClient().tokenManager().getAccessToken();
}
}

@Test
public void shouldReturnServerInfo() {
try (KeycloakContainer keycloak = new KeycloakContainer()) {
Expand Down
23 changes: 23 additions & 0 deletions src/test/resources/master-realm-with-admin-user.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
{
"realm": "master",
"enabled": true,
"users": [
{
"username": "admin",
"firstName": "Example",
"lastName": "User",
"email": "example@keycloak.org",
"enabled": true,
"credentials": [
{
"type": "password",
"value": "password"
}
],
"realmRoles": [
"admin",
"default-roles-master"
]
}
]
}
Loading