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

Migrate Keycloak Admin Client from config classes to the @ConfigMapping #39342

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
Original file line number Diff line number Diff line change
@@ -1,19 +1,21 @@
package io.quarkus.keycloak.admin.client.common;

import io.quarkus.runtime.annotations.ConfigItem;
import io.quarkus.runtime.annotations.ConfigPhase;
import io.quarkus.runtime.annotations.ConfigRoot;
import io.smallrye.config.ConfigMapping;
import io.smallrye.config.WithDefault;

/**
* Keycloak Admin Client
*/
@ConfigRoot(phase = ConfigPhase.BUILD_TIME, name = "keycloak.admin-client")
public class KeycloakAdminClientBuildTimeConfig {
@ConfigMapping(prefix = "quarkus.keycloak.admin-client")
@ConfigRoot(phase = ConfigPhase.BUILD_TIME)
public interface KeycloakAdminClientBuildTimeConfig {

/**
* Set to true if Keycloak Admin Client injection is supported.
*/
@ConfigItem(defaultValue = "true")
public boolean enabled = true;
@WithDefault("true")
boolean enabled();

}
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,6 @@ public class KeycloakAdminClientInjectionEnabled implements BooleanSupplier {

@Override
public boolean getAsBoolean() {
return config.enabled;
return config.enabled();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,14 +16,14 @@ public void passwordGrantTypeTest() {

// username is required
Assertions.assertThrows(KeycloakAdminClientConfigUtil.KeycloakAdminClientException.class, () -> {
KeycloakAdminClientConfig config = createConfig();
KeycloakAdminClientConfigImpl config = createConfig();
config.username = Optional.empty();
validate(config);
});

// password is required
Assertions.assertThrows(KeycloakAdminClientConfigUtil.KeycloakAdminClientException.class, () -> {
KeycloakAdminClientConfig config = createConfig();
KeycloakAdminClientConfigImpl config = createConfig();
config.password = Optional.empty();
validate(config);
});
Expand All @@ -36,14 +36,14 @@ public void clientCredentialsGrantTypeTest() {

// client secret is required
Assertions.assertThrows(KeycloakAdminClientConfigUtil.KeycloakAdminClientException.class, () -> {
KeycloakAdminClientConfig config = createClientCredentialsConfig();
KeycloakAdminClientConfigImpl config = createClientCredentialsConfig();
config.clientSecret = Optional.empty();
validate(config);
});
}

private KeycloakAdminClientConfig createConfig() {
final KeycloakAdminClientConfig config = new KeycloakAdminClientConfig();
private KeycloakAdminClientConfigImpl createConfig() {
final KeycloakAdminClientConfigImpl config = new KeycloakAdminClientConfigImpl();
config.serverUrl = Optional.of("https://localhost:8081");
config.grantType = KeycloakAdminClientConfig.GrantType.PASSWORD;
config.clientId = "client id";
Expand All @@ -55,13 +55,65 @@ private KeycloakAdminClientConfig createConfig() {
return config;
}

private KeycloakAdminClientConfig createClientCredentialsConfig() {
final KeycloakAdminClientConfig config = createConfig();
private KeycloakAdminClientConfigImpl createClientCredentialsConfig() {
final KeycloakAdminClientConfigImpl config = createConfig();
config.grantType = KeycloakAdminClientConfig.GrantType.CLIENT_CREDENTIALS;
config.password = Optional.empty();
config.username = Optional.empty();
config.clientSecret = Optional.of("client secret");
return config;
}

private static final class KeycloakAdminClientConfigImpl implements KeycloakAdminClientConfig {

private Optional<String> password;
private Optional<String> username;
private Optional<String> clientSecret;
private Optional<String> scope;
private Optional<String> serverUrl;
private String realm;
private String clientId;
private KeycloakAdminClientConfig.GrantType grantType;

@Override
public Optional<String> serverUrl() {
return serverUrl;
}

@Override
public String realm() {
return realm;
}

@Override
public String clientId() {
return clientId;
}

@Override
public Optional<String> clientSecret() {
return clientSecret;
}

@Override
public Optional<String> username() {
return username;
}

@Override
public Optional<String> password() {
return password;
}

@Override
public Optional<String> scope() {
return scope;
}

@Override
public GrantType grantType() {
return grantType;
}
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -2,68 +2,67 @@

import java.util.Optional;

import io.quarkus.runtime.annotations.ConfigItem;
import io.quarkus.runtime.annotations.ConfigPhase;
import io.quarkus.runtime.annotations.ConfigRoot;
import io.smallrye.config.ConfigMapping;
import io.smallrye.config.WithDefault;

/**
* Keycloak Admin Client
*/
@ConfigRoot(phase = ConfigPhase.RUN_TIME, name = "keycloak.admin-client")
public class KeycloakAdminClientConfig {
@ConfigMapping(prefix = "quarkus.keycloak.admin-client")
@ConfigRoot(phase = ConfigPhase.RUN_TIME)
public interface KeycloakAdminClientConfig {

/**
* Keycloak server URL, for example, `https://host:port`.
* If this property is not set then the Keycloak Admin Client injection will fail - use
* {@linkplain org.keycloak.admin.client.KeycloakBuilder}
* to create it instead.
*/
@ConfigItem
public Optional<String> serverUrl;
Optional<String> serverUrl();

/**
* Realm.
*/
@ConfigItem(defaultValue = "master")
public String realm;
@WithDefault("master")
String realm();

/**
* Client id.
*/
@ConfigItem(defaultValue = "admin-cli")
public String clientId;
@WithDefault("admin-cli")
String clientId();

/**
* Client secret. Required with a `client_credentials` grant type.
*/
@ConfigItem
public Optional<String> clientSecret;
Optional<String> clientSecret();

/**
* Username. Required with a `password` grant type.
*/
@ConfigItem(defaultValue = "admin")
public Optional<String> username;
@WithDefault("admin")
Optional<String> username();

/**
* Password. Required with a `password` grant type.
*/
@ConfigItem(defaultValue = "admin")
public Optional<String> password;
@WithDefault("admin")
Optional<String> password();

/**
* OAuth 2.0 <a href="https://datatracker.ietf.org/doc/html/rfc6749#section-3.3">Access Token Scope</a>.
*/
@ConfigItem
public Optional<String> scope;
Optional<String> scope();

/**
* OAuth Grant Type.
*/
@ConfigItem(defaultValue = "PASSWORD")
public GrantType grantType;
@WithDefault("PASSWORD")
GrantType grantType();

public enum GrantType {
enum GrantType {
PASSWORD,
CLIENT_CREDENTIALS;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,20 +13,20 @@ public class KeycloakAdminClientConfigUtil {
*/
public static void validate(KeycloakAdminClientConfig config) {

if (config.serverUrl.isEmpty()) {
if (config.serverUrl().isEmpty()) {
LOG.debug(
"Configuration property 'server-url' is not set, 'Keycloak' admin client injection will fail, "
+ "use org.keycloak.admin.client.KeycloakBuilder to create it instead");
return;
}

// client id is also required in both cases, but since it's not nullable, we can skip its validation
if (config.grantType == PASSWORD) {
if (config.password.isEmpty() || config.username.isEmpty()) {
if (config.grantType() == PASSWORD) {
if (config.password().isEmpty() || config.username().isEmpty()) {
throw new KeycloakAdminClientException("grant type 'password' requires username and password");
}
} else {
if (config.clientSecret.isEmpty()) {
if (config.clientSecret().isEmpty()) {
throw new KeycloakAdminClientException("grant type 'client_credentials' requires client secret");
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ public Supplier<Keycloak> createAdminClient() {

final KeycloakAdminClientConfig config = keycloakAdminClientConfigRuntimeValue.getValue();
validate(config);
if (config.serverUrl.isEmpty()) {
if (config.serverUrl().isEmpty()) {
return new Supplier<>() {
@Override
public Keycloak get() {
Expand All @@ -40,14 +40,14 @@ public Keycloak get() {
}
final KeycloakBuilder keycloakBuilder = KeycloakBuilder
.builder()
.clientId(config.clientId)
.clientSecret(config.clientSecret.orElse(null))
.grantType(config.grantType.asString())
.username(config.username.orElse(null))
.password(config.password.orElse(null))
.realm(config.realm)
.serverUrl(config.serverUrl.get())
.scope(config.scope.orElse(null));
.clientId(config.clientId())
.clientSecret(config.clientSecret().orElse(null))
.grantType(config.grantType().asString())
.username(config.username().orElse(null))
.password(config.password().orElse(null))
.realm(config.realm())
.serverUrl(config.serverUrl().get())
.scope(config.scope().orElse(null));
return new Supplier<Keycloak>() {
@Override
public Keycloak get() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ public Supplier<Keycloak> createAdminClient() {

final KeycloakAdminClientConfig config = keycloakAdminClientConfigRuntimeValue.getValue();
validate(config);
if (config.serverUrl.isEmpty()) {
if (config.serverUrl().isEmpty()) {
return new Supplier<>() {
@Override
public Keycloak get() {
Expand All @@ -46,14 +46,14 @@ public Keycloak get() {
}
final KeycloakBuilder keycloakBuilder = KeycloakBuilder
.builder()
.clientId(config.clientId)
.clientSecret(config.clientSecret.orElse(null))
.grantType(config.grantType.asString())
.username(config.username.orElse(null))
.password(config.password.orElse(null))
.realm(config.realm)
.serverUrl(config.serverUrl.get())
.scope(config.scope.orElse(null));
.clientId(config.clientId())
.clientSecret(config.clientSecret().orElse(null))
.grantType(config.grantType().asString())
.username(config.username().orElse(null))
.password(config.password().orElse(null))
.realm(config.realm())
.serverUrl(config.serverUrl().get())
.scope(config.scope().orElse(null));
return new Supplier<Keycloak>() {
@Override
public Keycloak get() {
Expand Down
Loading