Allow Quarkus configuration to mix different storage providers

Closes #13312
This commit is contained in:
Alexander Schwartz 2022-07-25 18:58:43 +02:00 committed by Hynek Mlnařík
parent 4e83b9be9d
commit 67e2f342a9
9 changed files with 393 additions and 100 deletions

View file

@ -492,7 +492,7 @@ jobs:
- name: Run Quarkus Storage Tests - name: Run Quarkus Storage Tests
run: | run: |
./mvnw clean install -nsu -B -f quarkus/tests/pom.xml -Ptest-database -Dtest=PostgreSQLDistTest,DatabaseOptionsDistTest,JPAStoreDistTest,HotRodStoreDistTest | misc/log/trimmer.sh ./mvnw clean install -nsu -B -f quarkus/tests/pom.xml -Ptest-database -Dtest=PostgreSQLDistTest,DatabaseOptionsDistTest,JPAStoreDistTest,HotRodStoreDistTest,MixedStoreDistTest | misc/log/trimmer.sh
TEST_RESULT=${PIPESTATUS[0]} TEST_RESULT=${PIPESTATUS[0]}
find . -path '*/target/surefire-reports/*.xml' | zip -q reports-quarkus-tests.zip -@ find . -path '*/target/surefire-reports/*.xml' | zip -q reports-quarkus-tests.zip -@
exit $TEST_RESULT exit $TEST_RESULT

View file

@ -47,8 +47,7 @@ public class StorageOptions {
public static final Option<StorageType> STORAGE = new OptionBuilder<>("storage", StorageType.class) public static final Option<StorageType> STORAGE = new OptionBuilder<>("storage", StorageType.class)
.category(OptionCategory.STORAGE) .category(OptionCategory.STORAGE)
.description(String.format("Sets a storage mechanism. Possible values are: %s.", .description(String.format("Sets the default storage mechanism for all areas. Possible values are: %s.", storageAreas()))
String.join(",", String.join(", ", Arrays.stream(StorageType.values()).map(StorageType::name).collect(Collectors.toList())))))
.expectedValues(StorageType.values()) .expectedValues(StorageType.values())
.defaultValue(Optional.empty()) .defaultValue(Optional.empty())
.hidden() .hidden()
@ -60,18 +59,22 @@ public class StorageOptions {
.buildTime(true) .buildTime(true)
.build(); .build();
public static final Option<StorageType> STORAGE_EVENT_STORE = new OptionBuilder<>("storage-event-store", StorageType.class) public static final Option<String> STORAGE_EVENT_STORE_PROVIDER = new OptionBuilder<>("storage-event-store-provider", String.class)
.category(OptionCategory.STORAGE) .category(OptionCategory.STORAGE)
.buildTime(true) .buildTime(true)
.build(); .build();
public static final Option<StorageType> STORAGE_EVENT_ADMIN_STORE = new OptionBuilder<>("storage-event-admin", StorageType.class) public static final Option<StorageType> STORAGE_EVENT_ADMIN_STORE = new OptionBuilder<>("storage-event-admin", StorageType.class)
.category(OptionCategory.STORAGE) .category(OptionCategory.STORAGE)
.description(descriptionForStorageAreas("admin events"))
.expectedValues(StorageType.values())
.buildTime(true) .buildTime(true)
.build(); .build();
public static final Option<StorageType> STORAGE_EVENT_AUTH_STORE = new OptionBuilder<>("storage-event-auth", StorageType.class) public static final Option<StorageType> STORAGE_EVENT_AUTH_STORE = new OptionBuilder<>("storage-event-auth", StorageType.class)
.category(OptionCategory.STORAGE) .category(OptionCategory.STORAGE)
.description(descriptionForStorageAreas("authentication and authorization events"))
.expectedValues(StorageType.values())
.buildTime(true) .buildTime(true)
.build(); .build();
@ -80,123 +83,139 @@ public class StorageOptions {
.buildTime(true) .buildTime(true)
.build(); .build();
public static final Option<String> STORAGE_REALM = new OptionBuilder<>("storage-realm", String.class) public static final Option<String> STORAGE_REALM_PROVIDER = new OptionBuilder<>("storage-realm-provider", String.class)
.category(OptionCategory.STORAGE) .category(OptionCategory.STORAGE)
.hidden() .hidden()
.buildTime(true) .buildTime(true)
.build(); .build();
public static final Option<String> STORAGE_REALM_STORE = new OptionBuilder<>("storage-realm-store", String.class) public static final Option<StorageType> STORAGE_REALM_STORE = new OptionBuilder<>("storage-realm", StorageType.class)
.category(OptionCategory.STORAGE)
.description(descriptionForStorageAreas("realms"))
.expectedValues(StorageType.values())
.buildTime(true)
.build();
public static final Option<String> STORAGE_CLIENT_PROVIDER = new OptionBuilder<>("storage-client-provider", String.class)
.category(OptionCategory.STORAGE) .category(OptionCategory.STORAGE)
.hidden() .hidden()
.buildTime(true) .buildTime(true)
.build(); .build();
public static final Option<String> STORAGE_CLIENT = new OptionBuilder<>("storage-client", String.class) public static final Option<StorageType> STORAGE_CLIENT_STORE = new OptionBuilder<>("storage-client", StorageType.class)
.category(OptionCategory.STORAGE)
.description(descriptionForStorageAreas("clients"))
.expectedValues(StorageType.values())
.buildTime(true)
.build();
public static final Option<String> STORAGE_CLIENT_SCOPE_PROVIDER = new OptionBuilder<>("storage-client-scope-provider", String.class)
.category(OptionCategory.STORAGE) .category(OptionCategory.STORAGE)
.hidden() .hidden()
.buildTime(true) .buildTime(true)
.build(); .build();
public static final Option<String> STORAGE_CLIENT_STORE = new OptionBuilder<>("storage-client-store", String.class) public static final Option<StorageType> STORAGE_CLIENT_SCOPE_STORE = new OptionBuilder<>("storage-client-scope", StorageType.class)
.category(OptionCategory.STORAGE)
.description(descriptionForStorageAreas("client scopes"))
.expectedValues(StorageType.values())
.buildTime(true)
.build();
public static final Option<String> STORAGE_GROUP_PROVIDER = new OptionBuilder<>("storage-group-provider", String.class)
.category(OptionCategory.STORAGE) .category(OptionCategory.STORAGE)
.hidden() .hidden()
.buildTime(true) .buildTime(true)
.build(); .build();
public static final Option<String> STORAGE_CLIENT_SCOPE = new OptionBuilder<>("storage-client-scope", String.class) public static final Option<StorageType> STORAGE_GROUP_STORE = new OptionBuilder<>("storage-group", StorageType.class)
.category(OptionCategory.STORAGE)
.description(descriptionForStorageAreas("groups"))
.expectedValues(StorageType.values())
.buildTime(true)
.build();
public static final Option<String> STORAGE_ROLE_PROVIDER = new OptionBuilder<>("storage-role-provider", String.class)
.category(OptionCategory.STORAGE) .category(OptionCategory.STORAGE)
.hidden() .hidden()
.buildTime(true) .buildTime(true)
.build(); .build();
public static final Option<String> STORAGE_CLIENT_SCOPE_STORE = new OptionBuilder<>("storage-client-scope-store", String.class) public static final Option<StorageType> STORAGE_ROLE_STORE = new OptionBuilder<>("storage-role", StorageType.class)
.category(OptionCategory.STORAGE)
.description(descriptionForStorageAreas("roles"))
.expectedValues(StorageType.values())
.buildTime(true)
.build();
public static final Option<String> STORAGE_USER_PROVIDER = new OptionBuilder<>("storage-user-provider", String.class)
.category(OptionCategory.STORAGE) .category(OptionCategory.STORAGE)
.hidden() .hidden()
.buildTime(true) .buildTime(true)
.build(); .build();
public static final Option<String> STORAGE_GROUP = new OptionBuilder<>("storage-group", String.class) public static final Option<StorageType> STORAGE_USER_STORE = new OptionBuilder<>("storage-user", StorageType.class)
.category(OptionCategory.STORAGE)
.description(descriptionForStorageAreas("users"))
.expectedValues(StorageType.values())
.buildTime(true)
.build();
public static final Option<String> STORAGE_DEPLOYMENT_STATE_PROVIDER = new OptionBuilder<>("storage-deployment-state-provider", String.class)
.category(OptionCategory.STORAGE) .category(OptionCategory.STORAGE)
.hidden() .hidden()
.buildTime(true) .buildTime(true)
.build(); .build();
public static final Option<String> STORAGE_GROUP_STORE = new OptionBuilder<>("storage-group-store", String.class) public static final Option<String> STORAGE_AUTH_SESSION_PROVIDER = new OptionBuilder<>("storage-auth-session-provider", String.class)
.category(OptionCategory.STORAGE) .category(OptionCategory.STORAGE)
.hidden() .hidden()
.buildTime(true) .buildTime(true)
.build(); .build();
public static final Option<String> STORAGE_ROLE = new OptionBuilder<>("storage-role", String.class) public static final Option<StorageType> STORAGE_AUTH_SESSION_STORE = new OptionBuilder<>("storage-auth-session", StorageType.class)
.category(OptionCategory.STORAGE)
.description(descriptionForStorageAreas("authentication sessions"))
.expectedValues(StorageType.values())
.buildTime(true)
.build();
public static final Option<String> STORAGE_USER_SESSION_PROVIDER = new OptionBuilder<>("storage-user-session-provider", String.class)
.category(OptionCategory.STORAGE) .category(OptionCategory.STORAGE)
.hidden() .hidden()
.buildTime(true) .buildTime(true)
.build(); .build();
public static final Option<String> STORAGE_ROLE_STORE = new OptionBuilder<>("storage-role-store", String.class) public static final Option<StorageType> STORAGE_USER_SESSION_STORE = new OptionBuilder<>("storage-user-session", StorageType.class)
.category(OptionCategory.STORAGE)
.description(descriptionForStorageAreas("user and client sessions"))
.expectedValues(StorageType.values())
.buildTime(true)
.build();
public static final Option<String> STORAGE_LOGIN_FAILURE_PROVIDER = new OptionBuilder<>("storage-login-failure-provider", String.class)
.category(OptionCategory.STORAGE) .category(OptionCategory.STORAGE)
.hidden() .hidden()
.buildTime(true) .buildTime(true)
.build(); .build();
public static final Option<String> STORAGE_USER = new OptionBuilder<>("storage-user", String.class) public static final Option<StorageType> STORAGE_LOGIN_FAILURE_STORE = new OptionBuilder<>("storage-login-failure", StorageType.class)
.category(OptionCategory.STORAGE)
.description(descriptionForStorageAreas("login failures"))
.expectedValues(StorageType.values())
.buildTime(true)
.build();
public static final Option<String> STORAGE_AUTHORIZATION_PROVIDER = new OptionBuilder<>("storage-authorization-provider", String.class)
.category(OptionCategory.STORAGE) .category(OptionCategory.STORAGE)
.hidden() .hidden()
.buildTime(true) .buildTime(true)
.build(); .build();
public static final Option<String> STORAGE_USER_STORE = new OptionBuilder<>("storage-user-store", String.class) public static final Option<StorageType> STORAGE_AUTHORIZATION_STORE = new OptionBuilder<>("storage-authorization", StorageType.class)
.category(OptionCategory.STORAGE) .category(OptionCategory.STORAGE)
.hidden() .description(descriptionForStorageAreas("authorizations"))
.buildTime(true) .expectedValues(StorageType.values())
.build();
public static final Option<String> STORAGE_DEPLOYMENT_STATE = new OptionBuilder<>("storage-deployment-state", String.class)
.category(OptionCategory.STORAGE)
.hidden()
.buildTime(true)
.build();
public static final Option<String> STORAGE_AUTH_SESSION = new OptionBuilder<>("storage-auth-session", String.class)
.category(OptionCategory.STORAGE)
.hidden()
.buildTime(true)
.build();
public static final Option<String> STORAGE_AUTH_SESSION_STORE = new OptionBuilder<>("storage-auth-session-store", String.class)
.category(OptionCategory.STORAGE)
.hidden()
.buildTime(true)
.build();
public static final Option<String> STORAGE_USER_SESSION = new OptionBuilder<>("storage-user-session", String.class)
.category(OptionCategory.STORAGE)
.hidden()
.buildTime(true)
.build();
public static final Option<String> STORAGE_USER_SESSION_STORE = new OptionBuilder<>("storage-user-session-store", String.class)
.category(OptionCategory.STORAGE)
.hidden()
.buildTime(true)
.build();
public static final Option<String> STORAGE_LOGIN_FAILURE = new OptionBuilder<>("storage-login-failure", String.class)
.category(OptionCategory.STORAGE)
.hidden()
.buildTime(true)
.build();
public static final Option<String> STORAGE_LOGIN_FAILURE_STORE = new OptionBuilder<>("storage-login-failure-store", String.class)
.category(OptionCategory.STORAGE)
.hidden()
.buildTime(true)
.build();
public static final Option<String> STORAGE_AUTHORIZATION_PERSISTER = new OptionBuilder<>("storage-authorization-persister", String.class)
.category(OptionCategory.STORAGE)
.hidden()
.buildTime(true) .buildTime(true)
.build(); .build();
@ -206,15 +225,16 @@ public class StorageOptions {
.buildTime(true) .buildTime(true)
.build(); .build();
public static final Option<String> STORAGE_ACTION_TOKEN = new OptionBuilder<>("storage-action-token", String.class) public static final Option<String> STORAGE_ACTION_TOKEN_PROVIDER = new OptionBuilder<>("storage-action-token-provider", String.class)
.category(OptionCategory.STORAGE) .category(OptionCategory.STORAGE)
.hidden() .hidden()
.buildTime(true) .buildTime(true)
.build(); .build();
public static final Option<String> STORAGE_ACTION_TOKEN_STORE = new OptionBuilder<>("storage-action-token-store", String.class) public static final Option<StorageType> STORAGE_ACTION_TOKEN_STORE = new OptionBuilder<>("storage-action-token", StorageType.class)
.category(OptionCategory.STORAGE) .category(OptionCategory.STORAGE)
.hidden() .description(descriptionForStorageAreas("action tokens"))
.expectedValues(StorageType.values())
.buildTime(true) .buildTime(true)
.build(); .build();
@ -236,37 +256,38 @@ public class StorageOptions {
.buildTime(true) .buildTime(true)
.build(); .build();
public static final Option<String> STORAGE_CACHE_CLEAR_USER = new OptionBuilder<>("cache-clear-user", String.class) public static final Option<String> STORAGE_ADMIN_CACHE_CLEAR_USER = new OptionBuilder<>("cache-clear-user", String.class)
.category(OptionCategory.STORAGE) .category(OptionCategory.STORAGE)
.hidden() .hidden()
.buildTime(true) .buildTime(true)
.build(); .build();
public static final Option<String> STORAGE_CACHE_CLEAR_REALM = new OptionBuilder<>("cache-clear-realm", String.class) public static final Option<String> STORAGE_ADMIN_CACHE_CLEAR_REALM = new OptionBuilder<>("cache-clear-realm", String.class)
.category(OptionCategory.STORAGE) .category(OptionCategory.STORAGE)
.hidden() .hidden()
.buildTime(true) .buildTime(true)
.build(); .build();
public static final Option<String> STORAGE_CACHE_CLEAR_KEYS = new OptionBuilder<>("cache-clear-keys", String.class) public static final Option<String> STORAGE_ADMIN_CACHE_CLEAR_KEYS = new OptionBuilder<>("cache-clear-keys", String.class)
.category(OptionCategory.STORAGE) .category(OptionCategory.STORAGE)
.hidden() .hidden()
.buildTime(true) .buildTime(true)
.build(); .build();
public static final Option<String> STORAGE_SINGLE_USE_OBJECT = new OptionBuilder<>("storage-single-use-object", String.class) public static final Option<String> STORAGE_SINGLE_USE_OBJECT_PROVIDER = new OptionBuilder<>("storage-single-use-object-provider", String.class)
.category(OptionCategory.STORAGE) .category(OptionCategory.STORAGE)
.hidden() .hidden()
.buildTime(true) .buildTime(true)
.build(); .build();
public static final Option<String> STORAGE_SINGLE_USE_OBJECT_STORE = new OptionBuilder<>("storage-single-use-object-store", String.class) public static final Option<StorageType> STORAGE_SINGLE_USE_OBJECT_STORE = new OptionBuilder<>("storage-single-use-object", StorageType.class)
.category(OptionCategory.STORAGE) .category(OptionCategory.STORAGE)
.hidden() .description(descriptionForStorageAreas("single use objects"))
.expectedValues(StorageType.values())
.buildTime(true) .buildTime(true)
.build(); .build();
public static final Option<String> STORAGE_PUBLIC_KEY_STORE = new OptionBuilder<>("storage-public-key-store", String.class) public static final Option<String> STORAGE_PUBLIC_KEY_STORAGE_STORE = new OptionBuilder<>("storage-public-key-storage", String.class)
.category(OptionCategory.STORAGE) .category(OptionCategory.STORAGE)
.hidden() .hidden()
.buildTime(true) .buildTime(true)
@ -284,7 +305,7 @@ public class StorageOptions {
.buildTime(true) .buildTime(true)
.build(); .build();
public static final Option<String> STORAGE_USER_STORAGE = new OptionBuilder<>("storage-user-storage", String.class) public static final Option<String> STORAGE_ADMIN_USER_STORAGE = new OptionBuilder<>("storage-admin-user-storage", String.class)
.category(OptionCategory.STORAGE) .category(OptionCategory.STORAGE)
.hidden() .hidden()
.buildTime(true) .buildTime(true)
@ -332,6 +353,20 @@ public class StorageOptions {
public static final List<Option<?>> ALL_OPTIONS = List.of( public static final List<Option<?>> ALL_OPTIONS = List.of(
STORAGE, STORAGE,
STORAGE_EVENT_ADMIN_STORE,
STORAGE_EVENT_AUTH_STORE,
STORAGE_REALM_STORE,
STORAGE_CLIENT_STORE,
STORAGE_CLIENT_SCOPE_STORE,
STORAGE_GROUP_STORE,
STORAGE_ROLE_STORE,
STORAGE_USER_STORE,
STORAGE_AUTH_SESSION_STORE,
STORAGE_USER_SESSION_STORE,
STORAGE_LOGIN_FAILURE_STORE,
STORAGE_AUTHORIZATION_STORE,
STORAGE_ACTION_TOKEN_STORE,
STORAGE_SINGLE_USE_OBJECT_STORE,
STORAGE_HOTROD_HOST, STORAGE_HOTROD_HOST,
STORAGE_HOTROD_PORT, STORAGE_HOTROD_PORT,
STORAGE_HOTROD_USERNAME, STORAGE_HOTROD_USERNAME,
@ -339,4 +374,12 @@ public class StorageOptions {
STORAGE_HOTROD_CACHE_CONFIGURE, STORAGE_HOTROD_CACHE_CONFIGURE,
STORAGE_HOTROD_CACHE_REINDEX STORAGE_HOTROD_CACHE_REINDEX
); );
private static String descriptionForStorageAreas(String areaAsText) {
return String.format("Sets a storage mechanism for %s. Possible values are: %s.", areaAsText, storageAreas());
}
private static String storageAreas() {
return String.join(",", Arrays.stream(StorageType.values()).map(StorageType::name).collect(Collectors.joining(", ")));
}
} }

View file

@ -33,11 +33,14 @@ final class StoragePropertyMappers {
public static PropertyMapper[] getMappers() { public static PropertyMapper[] getMappers() {
return new PropertyMapper[] { return new PropertyMapper[] {
fromOption(StorageOptions.STORAGE) fromOption(StorageOptions.STORAGE)
.paramLabel("type")
.build(),
fromOption(StorageOptions.STORAGE_PROVIDER)
.to("kc.spi-map-storage-provider") .to("kc.spi-map-storage-provider")
.transformer(StoragePropertyMappers::resolveMapStorageProvider) .transformer(StoragePropertyMappers::resolveMapStorageProvider)
.paramLabel("type") .paramLabel("type")
.build(), .build(),
fromOption(StorageOptions.STORAGE_EVENT_STORE) fromOption(StorageOptions.STORAGE_EVENT_STORE_PROVIDER)
.mapFrom("storage") .mapFrom("storage")
.to("kc.spi-events-store-provider") .to("kc.spi-events-store-provider")
.transformer(StoragePropertyMappers::getAreaStorage) .transformer(StoragePropertyMappers::getAreaStorage)
@ -55,7 +58,7 @@ final class StoragePropertyMappers {
.transformer(StoragePropertyMappers::resolveMapStorageProvider) .transformer(StoragePropertyMappers::resolveMapStorageProvider)
.paramLabel("type") .paramLabel("type")
.build(), .build(),
fromOption(StorageOptions.STORAGE_REALM) fromOption(StorageOptions.STORAGE_REALM_PROVIDER)
.to("kc.spi-realm-provider") .to("kc.spi-realm-provider")
.mapFrom("storage") .mapFrom("storage")
.transformer(StoragePropertyMappers::getAreaStorage) .transformer(StoragePropertyMappers::getAreaStorage)
@ -67,7 +70,7 @@ final class StoragePropertyMappers {
.transformer(StoragePropertyMappers::resolveMapStorageProvider) .transformer(StoragePropertyMappers::resolveMapStorageProvider)
.paramLabel("type") .paramLabel("type")
.build(), .build(),
fromOption(StorageOptions.STORAGE_CLIENT) fromOption(StorageOptions.STORAGE_CLIENT_PROVIDER)
.to("kc.spi-client-provider") .to("kc.spi-client-provider")
.mapFrom("storage") .mapFrom("storage")
.transformer(StoragePropertyMappers::getAreaStorage) .transformer(StoragePropertyMappers::getAreaStorage)
@ -79,7 +82,7 @@ final class StoragePropertyMappers {
.transformer(StoragePropertyMappers::resolveMapStorageProvider) .transformer(StoragePropertyMappers::resolveMapStorageProvider)
.paramLabel("type") .paramLabel("type")
.build(), .build(),
fromOption(StorageOptions.STORAGE_CLIENT_SCOPE) fromOption(StorageOptions.STORAGE_CLIENT_SCOPE_PROVIDER)
.to("kc.spi-client-scope-provider") .to("kc.spi-client-scope-provider")
.mapFrom("storage") .mapFrom("storage")
.transformer(StoragePropertyMappers::getAreaStorage) .transformer(StoragePropertyMappers::getAreaStorage)
@ -91,7 +94,7 @@ final class StoragePropertyMappers {
.transformer(StoragePropertyMappers::resolveMapStorageProvider) .transformer(StoragePropertyMappers::resolveMapStorageProvider)
.paramLabel("type") .paramLabel("type")
.build(), .build(),
fromOption(StorageOptions.STORAGE_GROUP) fromOption(StorageOptions.STORAGE_GROUP_PROVIDER)
.to("kc.spi-group-provider") .to("kc.spi-group-provider")
.mapFrom("storage") .mapFrom("storage")
.transformer(StoragePropertyMappers::getAreaStorage) .transformer(StoragePropertyMappers::getAreaStorage)
@ -103,7 +106,7 @@ final class StoragePropertyMappers {
.transformer(StoragePropertyMappers::resolveMapStorageProvider) .transformer(StoragePropertyMappers::resolveMapStorageProvider)
.paramLabel("type") .paramLabel("type")
.build(), .build(),
fromOption(StorageOptions.STORAGE_ROLE) fromOption(StorageOptions.STORAGE_ROLE_PROVIDER)
.to("kc.spi-role-provider") .to("kc.spi-role-provider")
.mapFrom("storage") .mapFrom("storage")
.transformer(StoragePropertyMappers::getAreaStorage) .transformer(StoragePropertyMappers::getAreaStorage)
@ -115,7 +118,7 @@ final class StoragePropertyMappers {
.transformer(StoragePropertyMappers::resolveMapStorageProvider) .transformer(StoragePropertyMappers::resolveMapStorageProvider)
.paramLabel("type") .paramLabel("type")
.build(), .build(),
fromOption(StorageOptions.STORAGE_USER) fromOption(StorageOptions.STORAGE_USER_PROVIDER)
.to("kc.spi-user-provider") .to("kc.spi-user-provider")
.mapFrom("storage") .mapFrom("storage")
.transformer(StoragePropertyMappers::getAreaStorage) .transformer(StoragePropertyMappers::getAreaStorage)
@ -127,13 +130,13 @@ final class StoragePropertyMappers {
.transformer(StoragePropertyMappers::resolveMapStorageProvider) .transformer(StoragePropertyMappers::resolveMapStorageProvider)
.paramLabel("type") .paramLabel("type")
.build(), .build(),
fromOption(StorageOptions.STORAGE_DEPLOYMENT_STATE) fromOption(StorageOptions.STORAGE_DEPLOYMENT_STATE_PROVIDER)
.to("kc.spi-deployment-state-provider") .to("kc.spi-deployment-state-provider")
.mapFrom("storage") .mapFrom("storage")
.transformer(StoragePropertyMappers::getAreaStorage) .transformer(StoragePropertyMappers::getAreaStorage)
.paramLabel("type") .paramLabel("type")
.build(), .build(),
fromOption(StorageOptions.STORAGE_AUTH_SESSION) fromOption(StorageOptions.STORAGE_AUTH_SESSION_PROVIDER)
.to("kc.spi-authentication-sessions-provider") .to("kc.spi-authentication-sessions-provider")
.mapFrom("storage") .mapFrom("storage")
.transformer(StoragePropertyMappers::getCacheStorage) .transformer(StoragePropertyMappers::getCacheStorage)
@ -145,7 +148,7 @@ final class StoragePropertyMappers {
.transformer(StoragePropertyMappers::resolveMapStorageProvider) .transformer(StoragePropertyMappers::resolveMapStorageProvider)
.paramLabel("type") .paramLabel("type")
.build(), .build(),
fromOption(StorageOptions.STORAGE_USER_SESSION) fromOption(StorageOptions.STORAGE_USER_SESSION_PROVIDER)
.to("kc.spi-user-sessions-provider") .to("kc.spi-user-sessions-provider")
.mapFrom("storage") .mapFrom("storage")
.transformer(StoragePropertyMappers::getCacheStorage) .transformer(StoragePropertyMappers::getCacheStorage)
@ -157,7 +160,7 @@ final class StoragePropertyMappers {
.transformer(StoragePropertyMappers::resolveMapStorageProvider) .transformer(StoragePropertyMappers::resolveMapStorageProvider)
.paramLabel("type") .paramLabel("type")
.build(), .build(),
fromOption(StorageOptions.STORAGE_LOGIN_FAILURE) fromOption(StorageOptions.STORAGE_LOGIN_FAILURE_PROVIDER)
.to("kc.spi-login-failure-provider") .to("kc.spi-login-failure-provider")
.mapFrom("storage") .mapFrom("storage")
.transformer(StoragePropertyMappers::getCacheStorage) .transformer(StoragePropertyMappers::getCacheStorage)
@ -175,13 +178,19 @@ final class StoragePropertyMappers {
.transformer(StoragePropertyMappers::getUserSessionPersisterStorage) .transformer(StoragePropertyMappers::getUserSessionPersisterStorage)
.paramLabel("type") .paramLabel("type")
.build(), .build(),
fromOption(StorageOptions.STORAGE_AUTHORIZATION_PERSISTER) fromOption(StorageOptions.STORAGE_AUTHORIZATION_PROVIDER)
.to("kc.spi-authorization-persister-provider") .to("kc.spi-authorization-persister-provider")
.mapFrom("storage") .mapFrom("storage")
.transformer(StoragePropertyMappers::getAreaStorage) .transformer(StoragePropertyMappers::getAreaStorage)
.paramLabel("type") .paramLabel("type")
.build(), .build(),
fromOption(StorageOptions.STORAGE_ACTION_TOKEN) fromOption(StorageOptions.STORAGE_AUTHORIZATION_STORE)
.to("kc.spi-authorization-persister-map-storage-provider")
.mapFrom("storage")
.transformer(StoragePropertyMappers::resolveMapStorageProvider)
.paramLabel("type")
.build(),
fromOption(StorageOptions.STORAGE_ACTION_TOKEN_PROVIDER)
.to("kc.spi-action-token-provider") .to("kc.spi-action-token-provider")
.mapFrom("storage") .mapFrom("storage")
.transformer(StoragePropertyMappers::getCacheStorage) .transformer(StoragePropertyMappers::getCacheStorage)
@ -217,7 +226,7 @@ final class StoragePropertyMappers {
.transformer(StoragePropertyMappers::isCacheAreaEnabledForStorage) .transformer(StoragePropertyMappers::isCacheAreaEnabledForStorage)
.paramLabel(Boolean.TRUE + "|" + Boolean.FALSE) .paramLabel(Boolean.TRUE + "|" + Boolean.FALSE)
.build(), .build(),
fromOption(StorageOptions.STORAGE_SINGLE_USE_OBJECT) fromOption(StorageOptions.STORAGE_SINGLE_USE_OBJECT_PROVIDER)
.to("kc.spi-single-use-object-provider") .to("kc.spi-single-use-object-provider")
.mapFrom("storage") .mapFrom("storage")
.transformer(StoragePropertyMappers::getCacheStorage) .transformer(StoragePropertyMappers::getCacheStorage)
@ -229,10 +238,10 @@ final class StoragePropertyMappers {
.transformer(StoragePropertyMappers::resolveMapStorageProvider) .transformer(StoragePropertyMappers::resolveMapStorageProvider)
.paramLabel("type") .paramLabel("type")
.build(), .build(),
fromOption(StorageOptions.STORAGE_PUBLIC_KEY_STORE) fromOption(StorageOptions.STORAGE_PUBLIC_KEY_STORAGE_STORE)
.to("kc.spi-public-key-storage-map-storage-provider") .to("kc.spi-public-key-storage-map-storage-provider")
.mapFrom("storage") .mapFrom("storage")
.transformer(StoragePropertyMappers::resolveMapStorageProvider) .transformer(StoragePropertyMappers::resolveMapStorageProviderPublicKeyStorage)
.paramLabel("type") .paramLabel("type")
.build(), .build(),
fromOption(StorageOptions.STORAGE_EXCEPTION_CONVERTER) fromOption(StorageOptions.STORAGE_EXCEPTION_CONVERTER)
@ -241,19 +250,19 @@ final class StoragePropertyMappers {
.transformer(StoragePropertyMappers::isLegacyStoreEnabled) .transformer(StoragePropertyMappers::isLegacyStoreEnabled)
.paramLabel(Boolean.TRUE + "|" + Boolean.FALSE) .paramLabel(Boolean.TRUE + "|" + Boolean.FALSE)
.build(), .build(),
fromOption(StorageOptions.STORAGE_CACHE_CLEAR_REALM) fromOption(StorageOptions.STORAGE_ADMIN_CACHE_CLEAR_REALM)
.to("kc.spi-admin-realm-restapi-extension-clear-realm-cache-enabled") .to("kc.spi-admin-realm-restapi-extension-clear-realm-cache-enabled")
.mapFrom("storage") .mapFrom("storage")
.transformer(StoragePropertyMappers::isLegacyStoreEnabled) .transformer(StoragePropertyMappers::isLegacyStoreEnabled)
.paramLabel(Boolean.TRUE + "|" + Boolean.FALSE) .paramLabel(Boolean.TRUE + "|" + Boolean.FALSE)
.build(), .build(),
fromOption(StorageOptions.STORAGE_CACHE_CLEAR_USER) fromOption(StorageOptions.STORAGE_ADMIN_CACHE_CLEAR_USER)
.to("kc.spi-admin-realm-restapi-extension-clear-user-cache-enabled") .to("kc.spi-admin-realm-restapi-extension-clear-user-cache-enabled")
.mapFrom("storage") .mapFrom("storage")
.transformer(StoragePropertyMappers::isLegacyStoreEnabled) .transformer(StoragePropertyMappers::isLegacyStoreEnabled)
.paramLabel(Boolean.TRUE + "|" + Boolean.FALSE) .paramLabel(Boolean.TRUE + "|" + Boolean.FALSE)
.build(), .build(),
fromOption(StorageOptions.STORAGE_CACHE_CLEAR_KEYS) fromOption(StorageOptions.STORAGE_ADMIN_CACHE_CLEAR_KEYS)
.to("kc.spi-admin-realm-restapi-extension-clear-keys-cache-enabled") .to("kc.spi-admin-realm-restapi-extension-clear-keys-cache-enabled")
.mapFrom("storage") .mapFrom("storage")
.transformer(StoragePropertyMappers::isLegacyStoreEnabled) .transformer(StoragePropertyMappers::isLegacyStoreEnabled)
@ -265,7 +274,7 @@ final class StoragePropertyMappers {
.transformer(StoragePropertyMappers::isLegacyStoreEnabled) .transformer(StoragePropertyMappers::isLegacyStoreEnabled)
.paramLabel("type") .paramLabel("type")
.build(), .build(),
fromOption(StorageOptions.STORAGE_USER_STORAGE) fromOption(StorageOptions.STORAGE_ADMIN_USER_STORAGE)
.to("kc.spi-admin-realm-restapi-extension-user-storage-enabled") .to("kc.spi-admin-realm-restapi-extension-user-storage-enabled")
.mapFrom("storage") .mapFrom("storage")
.transformer(StoragePropertyMappers::isLegacyStoreEnabled) .transformer(StoragePropertyMappers::isLegacyStoreEnabled)
@ -343,6 +352,20 @@ final class StoragePropertyMappers {
return value; return value;
} }
private static Optional<String> resolveMapStorageProviderPublicKeyStorage(Optional<String> value, ConfigSourceInterceptorContext context) {
try {
if (value.isPresent()) {
// there is only one public key storage provider available
return of(StorageType.chm.getProvider());
}
} catch (IllegalArgumentException iae) {
throw new IllegalArgumentException("Invalid storage provider: " + value.orElse(null), iae);
}
return value;
}
private static Optional<String> isCacheAreaEnabledForStorage(Optional<String> storage, ConfigSourceInterceptorContext context) { private static Optional<String> isCacheAreaEnabledForStorage(Optional<String> storage, ConfigSourceInterceptorContext context) {
return of(storage.isEmpty() ? Boolean.TRUE.toString() : Boolean.FALSE.toString()); return of(storage.isEmpty() ? Boolean.TRUE.toString() : Boolean.FALSE.toString());
} }

View file

@ -18,6 +18,7 @@
package org.keycloak.quarkus.runtime.configuration.test; package org.keycloak.quarkus.runtime.configuration.test;
import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue; import static org.junit.Assert.assertTrue;
import static org.keycloak.quarkus.runtime.configuration.ConfigArgsConfigSource.CLI_ARGS; import static org.keycloak.quarkus.runtime.configuration.ConfigArgsConfigSource.CLI_ARGS;
@ -485,6 +486,30 @@ public class ConfigurationTest {
assertEquals("true", config4.getConfigValue("quarkus.log.handler.gelf.enabled").getValue()); assertEquals("true", config4.getConfigValue("quarkus.log.handler.gelf.enabled").getValue());
} }
@Test
public void testStorageMixedStorageOptions() {
System.setProperty(CLI_ARGS, "--storage=jpa" + ARG_SEPARATOR + "--storage-realm=chm");
SmallRyeConfig config = createConfig();
assertEquals("jpa", config.getConfigValue("kc.storage").getValue());
assertNull(config.getConfigValue("kc.spi-map-storage-provider").getValue());
assertEquals("map", config.getConfigValue("kc.spi-realm-provider").getValue());
assertEquals("concurrenthashmap", config.getConfigValue("kc.spi-realm-map-storage-provider").getValue());
assertEquals("map", config.getConfigValue("kc.spi-user-provider").getValue());
assertEquals("jpa", config.getConfigValue("kc.spi-user-map-storage-provider").getValue());
}
@Test
public void testStoragePureJpa() {
System.setProperty(CLI_ARGS, "--storage=jpa");
SmallRyeConfig config = createConfig();
assertEquals("jpa", config.getConfigValue("kc.storage").getValue());
assertNull(config.getConfigValue("kc.spi-map-storage-provider").getValue());
assertEquals("map", config.getConfigValue("kc.spi-realm-provider").getValue());
assertEquals("jpa", config.getConfigValue("kc.spi-realm-map-storage-provider").getValue());
assertEquals("map", config.getConfigValue("kc.spi-user-provider").getValue());
assertEquals("jpa", config.getConfigValue("kc.spi-user-map-storage-provider").getValue());
}
@Test @Test
public void testOptionValueWithEqualSign() { public void testOptionValueWithEqualSign() {
System.setProperty(CLI_ARGS, "--db=postgres" + ARG_SEPARATOR + "--db-password=my_secret="); System.setProperty(CLI_ARGS, "--db=postgres" + ARG_SEPARATOR + "--db-password=my_secret=");

View file

@ -0,0 +1,30 @@
package org.keycloak.it.storage.map;
import io.quarkus.test.junit.main.Launch;
import io.quarkus.test.junit.main.LaunchResult;
import org.junit.jupiter.api.Test;
import org.keycloak.it.junit5.extension.CLIResult;
import org.keycloak.it.junit5.extension.DistributionTest;
import org.keycloak.it.junit5.extension.RawDistOnly;
import org.keycloak.it.junit5.extension.WithDatabase;
import org.keycloak.it.utils.RawDistRootPath;
import java.io.File;
import java.nio.file.Paths;
import static org.junit.jupiter.api.Assertions.assertTrue;
@DistributionTest
@RawDistOnly(reason = "Containers are immutable")
@WithDatabase(alias = "postgres", buildOptions = {"storage=jpa", "storage-realm=chm"})
public class MixedStoreDistTest {
@Test
@Launch({ "start", "--http-enabled=true", "--hostname-strict=false" })
void testStartUsingMixedStorage(LaunchResult result, RawDistRootPath distRoot) {
CLIResult cliResult = (CLIResult) result;
cliResult.assertStarted();
File chmRealmsFile = Paths.get(distRoot.getDistRootPath().toString(), "data","chm", "map-realms.json").toFile();
assertTrue(chmRealmsFile.isFile(), "File for realms does not exist!");
}
}

View file

@ -29,7 +29,32 @@ Cache:
Storage (Experimental): Storage (Experimental):
--storage <type> Experimental: Sets a storage mechanism. Possible values are: jpa, chm, hotrod. --storage <type> Experimental: Sets the default storage mechanism for all areas. Possible
values are: jpa, chm, hotrod.
--storage-action-token <type>
Experimental: Sets a storage mechanism for action tokens. Possible values are:
jpa, chm, hotrod.
--storage-auth-session <type>
Experimental: Sets a storage mechanism for authentication sessions. Possible
values are: jpa, chm, hotrod.
--storage-authorization <type>
Experimental: Sets a storage mechanism for authorizations. Possible values
are: jpa, chm, hotrod.
--storage-client <type>
Experimental: Sets a storage mechanism for clients. Possible values are: jpa,
chm, hotrod.
--storage-client-scope <type>
Experimental: Sets a storage mechanism for client scopes. Possible values are:
jpa, chm, hotrod.
--storage-event-admin <type>
Experimental: Sets a storage mechanism for admin events. Possible values are:
jpa, chm, hotrod.
--storage-event-auth <type>
Experimental: Sets a storage mechanism for authentication and authorization
events. Possible values are: jpa, chm, hotrod.
--storage-group <type>
Experimental: Sets a storage mechanism for groups. Possible values are: jpa,
chm, hotrod.
--storage-hotrod-cache-configure <true|false> --storage-hotrod-cache-configure <true|false>
Experimental: When set to true, Keycloak will create and configure Infinispan Experimental: When set to true, Keycloak will create and configure Infinispan
caches on startup. Default: true. caches on startup. Default: true.
@ -44,6 +69,24 @@ Storage (Experimental):
Experimental: Sets the port of the Infinispan server. Experimental: Sets the port of the Infinispan server.
--storage-hotrod-username <username> --storage-hotrod-username <username>
Experimental: Sets the username of the Infinispan user. Experimental: Sets the username of the Infinispan user.
--storage-login-failure <type>
Experimental: Sets a storage mechanism for login failures. Possible values
are: jpa, chm, hotrod.
--storage-realm <type>
Experimental: Sets a storage mechanism for realms. Possible values are: jpa,
chm, hotrod.
--storage-role <type>
Experimental: Sets a storage mechanism for roles. Possible values are: jpa,
chm, hotrod.
--storage-single-use-object <type>
Experimental: Sets a storage mechanism for single use objects. Possible values
are: jpa, chm, hotrod.
--storage-user <type>
Experimental: Sets a storage mechanism for users. Possible values are: jpa,
chm, hotrod.
--storage-user-session <type>
Experimental: Sets a storage mechanism for user and client sessions. Possible
values are: jpa, chm, hotrod.
Database: Database:

View file

@ -29,7 +29,32 @@ Cache:
Storage (Experimental): Storage (Experimental):
--storage <type> Experimental: Sets a storage mechanism. Possible values are: jpa, chm, hotrod. --storage <type> Experimental: Sets the default storage mechanism for all areas. Possible
values are: jpa, chm, hotrod.
--storage-action-token <type>
Experimental: Sets a storage mechanism for action tokens. Possible values are:
jpa, chm, hotrod.
--storage-auth-session <type>
Experimental: Sets a storage mechanism for authentication sessions. Possible
values are: jpa, chm, hotrod.
--storage-authorization <type>
Experimental: Sets a storage mechanism for authorizations. Possible values
are: jpa, chm, hotrod.
--storage-client <type>
Experimental: Sets a storage mechanism for clients. Possible values are: jpa,
chm, hotrod.
--storage-client-scope <type>
Experimental: Sets a storage mechanism for client scopes. Possible values are:
jpa, chm, hotrod.
--storage-event-admin <type>
Experimental: Sets a storage mechanism for admin events. Possible values are:
jpa, chm, hotrod.
--storage-event-auth <type>
Experimental: Sets a storage mechanism for authentication and authorization
events. Possible values are: jpa, chm, hotrod.
--storage-group <type>
Experimental: Sets a storage mechanism for groups. Possible values are: jpa,
chm, hotrod.
--storage-hotrod-cache-configure <true|false> --storage-hotrod-cache-configure <true|false>
Experimental: When set to true, Keycloak will create and configure Infinispan Experimental: When set to true, Keycloak will create and configure Infinispan
caches on startup. Default: true. caches on startup. Default: true.
@ -44,6 +69,24 @@ Storage (Experimental):
Experimental: Sets the port of the Infinispan server. Experimental: Sets the port of the Infinispan server.
--storage-hotrod-username <username> --storage-hotrod-username <username>
Experimental: Sets the username of the Infinispan user. Experimental: Sets the username of the Infinispan user.
--storage-login-failure <type>
Experimental: Sets a storage mechanism for login failures. Possible values
are: jpa, chm, hotrod.
--storage-realm <type>
Experimental: Sets a storage mechanism for realms. Possible values are: jpa,
chm, hotrod.
--storage-role <type>
Experimental: Sets a storage mechanism for roles. Possible values are: jpa,
chm, hotrod.
--storage-single-use-object <type>
Experimental: Sets a storage mechanism for single use objects. Possible values
are: jpa, chm, hotrod.
--storage-user <type>
Experimental: Sets a storage mechanism for users. Possible values are: jpa,
chm, hotrod.
--storage-user-session <type>
Experimental: Sets a storage mechanism for user and client sessions. Possible
values are: jpa, chm, hotrod.
Database: Database:

View file

@ -35,7 +35,32 @@ Cache:
Storage (Experimental): Storage (Experimental):
--storage <type> Experimental: Sets a storage mechanism. Possible values are: jpa, chm, hotrod. --storage <type> Experimental: Sets the default storage mechanism for all areas. Possible
values are: jpa, chm, hotrod.
--storage-action-token <type>
Experimental: Sets a storage mechanism for action tokens. Possible values are:
jpa, chm, hotrod.
--storage-auth-session <type>
Experimental: Sets a storage mechanism for authentication sessions. Possible
values are: jpa, chm, hotrod.
--storage-authorization <type>
Experimental: Sets a storage mechanism for authorizations. Possible values
are: jpa, chm, hotrod.
--storage-client <type>
Experimental: Sets a storage mechanism for clients. Possible values are: jpa,
chm, hotrod.
--storage-client-scope <type>
Experimental: Sets a storage mechanism for client scopes. Possible values are:
jpa, chm, hotrod.
--storage-event-admin <type>
Experimental: Sets a storage mechanism for admin events. Possible values are:
jpa, chm, hotrod.
--storage-event-auth <type>
Experimental: Sets a storage mechanism for authentication and authorization
events. Possible values are: jpa, chm, hotrod.
--storage-group <type>
Experimental: Sets a storage mechanism for groups. Possible values are: jpa,
chm, hotrod.
--storage-hotrod-cache-configure <true|false> --storage-hotrod-cache-configure <true|false>
Experimental: When set to true, Keycloak will create and configure Infinispan Experimental: When set to true, Keycloak will create and configure Infinispan
caches on startup. Default: true. caches on startup. Default: true.
@ -50,6 +75,24 @@ Storage (Experimental):
Experimental: Sets the port of the Infinispan server. Experimental: Sets the port of the Infinispan server.
--storage-hotrod-username <username> --storage-hotrod-username <username>
Experimental: Sets the username of the Infinispan user. Experimental: Sets the username of the Infinispan user.
--storage-login-failure <type>
Experimental: Sets a storage mechanism for login failures. Possible values
are: jpa, chm, hotrod.
--storage-realm <type>
Experimental: Sets a storage mechanism for realms. Possible values are: jpa,
chm, hotrod.
--storage-role <type>
Experimental: Sets a storage mechanism for roles. Possible values are: jpa,
chm, hotrod.
--storage-single-use-object <type>
Experimental: Sets a storage mechanism for single use objects. Possible values
are: jpa, chm, hotrod.
--storage-user <type>
Experimental: Sets a storage mechanism for users. Possible values are: jpa,
chm, hotrod.
--storage-user-session <type>
Experimental: Sets a storage mechanism for user and client sessions. Possible
values are: jpa, chm, hotrod.
Database: Database:

View file

@ -35,7 +35,32 @@ Cache:
Storage (Experimental): Storage (Experimental):
--storage <type> Experimental: Sets a storage mechanism. Possible values are: jpa, chm, hotrod. --storage <type> Experimental: Sets the default storage mechanism for all areas. Possible
values are: jpa, chm, hotrod.
--storage-action-token <type>
Experimental: Sets a storage mechanism for action tokens. Possible values are:
jpa, chm, hotrod.
--storage-auth-session <type>
Experimental: Sets a storage mechanism for authentication sessions. Possible
values are: jpa, chm, hotrod.
--storage-authorization <type>
Experimental: Sets a storage mechanism for authorizations. Possible values
are: jpa, chm, hotrod.
--storage-client <type>
Experimental: Sets a storage mechanism for clients. Possible values are: jpa,
chm, hotrod.
--storage-client-scope <type>
Experimental: Sets a storage mechanism for client scopes. Possible values are:
jpa, chm, hotrod.
--storage-event-admin <type>
Experimental: Sets a storage mechanism for admin events. Possible values are:
jpa, chm, hotrod.
--storage-event-auth <type>
Experimental: Sets a storage mechanism for authentication and authorization
events. Possible values are: jpa, chm, hotrod.
--storage-group <type>
Experimental: Sets a storage mechanism for groups. Possible values are: jpa,
chm, hotrod.
--storage-hotrod-cache-configure <true|false> --storage-hotrod-cache-configure <true|false>
Experimental: When set to true, Keycloak will create and configure Infinispan Experimental: When set to true, Keycloak will create and configure Infinispan
caches on startup. Default: true. caches on startup. Default: true.
@ -50,6 +75,24 @@ Storage (Experimental):
Experimental: Sets the port of the Infinispan server. Experimental: Sets the port of the Infinispan server.
--storage-hotrod-username <username> --storage-hotrod-username <username>
Experimental: Sets the username of the Infinispan user. Experimental: Sets the username of the Infinispan user.
--storage-login-failure <type>
Experimental: Sets a storage mechanism for login failures. Possible values
are: jpa, chm, hotrod.
--storage-realm <type>
Experimental: Sets a storage mechanism for realms. Possible values are: jpa,
chm, hotrod.
--storage-role <type>
Experimental: Sets a storage mechanism for roles. Possible values are: jpa,
chm, hotrod.
--storage-single-use-object <type>
Experimental: Sets a storage mechanism for single use objects. Possible values
are: jpa, chm, hotrod.
--storage-user <type>
Experimental: Sets a storage mechanism for users. Possible values are: jpa,
chm, hotrod.
--storage-user-session <type>
Experimental: Sets a storage mechanism for user and client sessions. Possible
values are: jpa, chm, hotrod.
Database: Database: