From 38ca4b39806878d286016b1b087988dc35902306 Mon Sep 17 00:00:00 2001 From: Steve Hawkins Date: Thu, 11 Jul 2024 13:03:42 -0400 Subject: [PATCH] fix: fail to start if the admin user can't be added also allowing the bootstrap options to be used by the cli, which requires hidden options to stay hidden and a minor refactoring for clarity closes: #31160 Signed-off-by: Steve Hawkins --- .../keycloak/quarkus/runtime/cli/Help.java | 33 ++++++------------- .../cli/command/BootstrapAdminService.java | 7 +++- .../cli/command/BootstrapAdminUser.java | 7 +++- .../mappers/PropertyMappers.java | 1 + .../jaxrs/QuarkusKeycloakApplication.java | 29 +++------------- .../it/cli/dist/BootstrapAdminDistTest.java | 7 ++++ .../keycloak/it/cli/dist/FipsDistTest.java | 19 +++-------- ...andDistTest.testExportHelpAll.approved.txt | 8 +---- ...andDistTest.testImportHelpAll.approved.txt | 8 +---- ...dDistTest.testStartDevHelpAll.approved.txt | 12 +------ ...mandDistTest.testStartHelpAll.approved.txt | 12 +------ ...est.testStartOptimizedHelpAll.approved.txt | 12 +------ 12 files changed, 43 insertions(+), 112 deletions(-) diff --git a/quarkus/runtime/src/main/java/org/keycloak/quarkus/runtime/cli/Help.java b/quarkus/runtime/src/main/java/org/keycloak/quarkus/runtime/cli/Help.java index dda1e0d9caac..2b085c5df415 100644 --- a/quarkus/runtime/src/main/java/org/keycloak/quarkus/runtime/cli/Help.java +++ b/quarkus/runtime/src/main/java/org/keycloak/quarkus/runtime/cli/Help.java @@ -157,10 +157,14 @@ private void configureUsageMessage(CommandLine.Model.CommandSpec commandSpec) { } private boolean isVisible(OptionSpec option) { - if (option.description().length == 0) { - // do not show options without a description + if (option.description().length == 0 || option.hidden()) { + // do not show options without a description nor hidden return false; } + + if (ALL_OPTIONS) { + return true; + } String optionName = undecorateDuplicitOptionName(option.longestName()); @@ -172,30 +176,13 @@ private boolean isVisible(OptionSpec option) { if (mapper == null) { final var disabledMapper = PropertyMappers.getDisabledMapper(optionName); - final var isDisabledMapper = disabledMapper.isPresent(); - + // Show disabled mappers, which do not have a description when they're enabled - final var isEnabledWhenEmpty = isDisabledMapper && disabledMapper.get().getEnabledWhen().isEmpty(); - if (isEnabledWhenEmpty) { - return true; - } - - if (ALL_OPTIONS && isDisabledMapper) { - return true; - } - - // only filter mapped options, defaults to the hidden marker - return !option.hidden() && !isDisabledMapper; - } - - boolean isUnsupportedOption = !PropertyMappers.isSupported(mapper); - - if (isUnsupportedOption) { - // unsupported options removed from help if all options are not requested - return !option.hidden() && ALL_OPTIONS; + return disabledMapper.flatMap(PropertyMapper::getEnabledWhen).isEmpty(); } - return !option.hidden(); + // unsupported options removed from help if all options are not requested + return PropertyMappers.isSupported(mapper); } public static void setAllOptions(boolean allOptions) { diff --git a/quarkus/runtime/src/main/java/org/keycloak/quarkus/runtime/cli/command/BootstrapAdminService.java b/quarkus/runtime/src/main/java/org/keycloak/quarkus/runtime/cli/command/BootstrapAdminService.java index 45d5eae07ad6..ad644e4e1af8 100644 --- a/quarkus/runtime/src/main/java/org/keycloak/quarkus/runtime/cli/command/BootstrapAdminService.java +++ b/quarkus/runtime/src/main/java/org/keycloak/quarkus/runtime/cli/command/BootstrapAdminService.java @@ -18,9 +18,12 @@ package org.keycloak.quarkus.runtime.cli.command; import org.keycloak.common.util.IoUtils; +import org.keycloak.models.KeycloakSessionFactory; +import org.keycloak.models.utils.KeycloakModelUtils; import org.keycloak.quarkus.runtime.cli.PropertyException; import org.keycloak.quarkus.runtime.integration.jaxrs.QuarkusKeycloakApplication; import org.keycloak.services.managers.ApplianceBootstrap; +import org.keycloak.services.resources.KeycloakApplication; import picocli.CommandLine.ArgGroup; import picocli.CommandLine.Command; @@ -97,7 +100,9 @@ private String getFromEnv(String envVar) { @Override public void onStart(QuarkusKeycloakApplication application) { //BootstrapAdmin bootstrap = spec.commandLine().getParent().getCommand(); - application.createTemporaryMasterRealmAdminService(clientId, clientSecret, /*bootstrap.expiration,*/ null); + KeycloakSessionFactory sessionFactory = KeycloakApplication.getSessionFactory(); + KeycloakModelUtils.runJobInTransaction(sessionFactory, session -> application + .createTemporaryMasterRealmAdminService(clientId, clientSecret, /* bootstrap.expiration, */ session)); } } diff --git a/quarkus/runtime/src/main/java/org/keycloak/quarkus/runtime/cli/command/BootstrapAdminUser.java b/quarkus/runtime/src/main/java/org/keycloak/quarkus/runtime/cli/command/BootstrapAdminUser.java index b5a7a9f6703a..ce20e941eb38 100644 --- a/quarkus/runtime/src/main/java/org/keycloak/quarkus/runtime/cli/command/BootstrapAdminUser.java +++ b/quarkus/runtime/src/main/java/org/keycloak/quarkus/runtime/cli/command/BootstrapAdminUser.java @@ -18,9 +18,12 @@ package org.keycloak.quarkus.runtime.cli.command; import org.keycloak.common.util.IoUtils; +import org.keycloak.models.KeycloakSessionFactory; +import org.keycloak.models.utils.KeycloakModelUtils; import org.keycloak.quarkus.runtime.cli.PropertyException; import org.keycloak.quarkus.runtime.integration.jaxrs.QuarkusKeycloakApplication; import org.keycloak.services.managers.ApplianceBootstrap; +import org.keycloak.services.resources.KeycloakApplication; import picocli.CommandLine.ArgGroup; import picocli.CommandLine.Command; @@ -97,7 +100,9 @@ private String getFromEnv(String envVar) { @Override public void onStart(QuarkusKeycloakApplication application) { //BootstrapAdmin bootstrap = spec.commandLine().getParent().getCommand(); - application.createTemporaryMasterRealmAdminUser(username, password, /*bootstrap.expiration,*/ null); + KeycloakSessionFactory sessionFactory = KeycloakApplication.getSessionFactory(); + KeycloakModelUtils.runJobInTransaction(sessionFactory, session -> application + .createTemporaryMasterRealmAdminUser(username, password, /* bootstrap.expiration, */ session)); } } diff --git a/quarkus/runtime/src/main/java/org/keycloak/quarkus/runtime/configuration/mappers/PropertyMappers.java b/quarkus/runtime/src/main/java/org/keycloak/quarkus/runtime/configuration/mappers/PropertyMappers.java index c31904ab1d24..40248db7d76d 100644 --- a/quarkus/runtime/src/main/java/org/keycloak/quarkus/runtime/configuration/mappers/PropertyMappers.java +++ b/quarkus/runtime/src/main/java/org/keycloak/quarkus/runtime/configuration/mappers/PropertyMappers.java @@ -64,6 +64,7 @@ private PropertyMappers(){} MAPPERS.addAll(ExportPropertyMappers.getMappers()); MAPPERS.addAll(ImportPropertyMappers.getMappers()); MAPPERS.addAll(TruststorePropertyMappers.getMappers()); + MAPPERS.addAll(BootstrapAdminPropertyMappers.getMappers()); } public static ConfigValue getValue(ConfigSourceInterceptorContext context, String name) { diff --git a/quarkus/runtime/src/main/java/org/keycloak/quarkus/runtime/integration/jaxrs/QuarkusKeycloakApplication.java b/quarkus/runtime/src/main/java/org/keycloak/quarkus/runtime/integration/jaxrs/QuarkusKeycloakApplication.java index 04a6a0db43aa..89c1d313ef2b 100644 --- a/quarkus/runtime/src/main/java/org/keycloak/quarkus/runtime/integration/jaxrs/QuarkusKeycloakApplication.java +++ b/quarkus/runtime/src/main/java/org/keycloak/quarkus/runtime/integration/jaxrs/QuarkusKeycloakApplication.java @@ -98,33 +98,12 @@ protected void createTemporaryAdmin(KeycloakSession session) { } } - public void createTemporaryMasterRealmAdminUser(String adminUserName, String adminPassword, /*Integer adminExpiration,*/ KeycloakSession existingSession) { - KeycloakSessionTask task = session -> { - new ApplianceBootstrap(session).createTemporaryMasterRealmAdminUser(adminUserName, adminPassword /*, adminExpiration*/, false); - }; - - runAdminTask(adminUserName, existingSession, task); - } - - public void createTemporaryMasterRealmAdminService(String clientId, String clientSecret, /*Integer adminExpiration,*/ KeycloakSession existingSession) { - KeycloakSessionTask task = session -> { - new ApplianceBootstrap(session).createTemporaryMasterRealmAdminService(clientId, clientSecret /*, adminExpiration*/); - }; - - runAdminTask(clientId, existingSession, task); + public void createTemporaryMasterRealmAdminUser(String adminUserName, String adminPassword, /*Integer adminExpiration,*/ KeycloakSession session) { + new ApplianceBootstrap(session).createTemporaryMasterRealmAdminUser(adminUserName, adminPassword /*, adminExpiration*/, false); } - private void runAdminTask(String adminUserName, KeycloakSession existingSession, KeycloakSessionTask task) { - try { - if (existingSession == null) { - KeycloakSessionFactory sessionFactory = KeycloakApplication.getSessionFactory(); - KeycloakModelUtils.runJobInTransaction(sessionFactory, task); - } else { - task.run(existingSession); - } - } catch (Throwable t) { - ServicesLogger.LOGGER.addUserFailed(t, adminUserName, Config.getAdminRealm()); - } + public void createTemporaryMasterRealmAdminService(String clientId, String clientSecret, /*Integer adminExpiration,*/ KeycloakSession session) { + new ApplianceBootstrap(session).createTemporaryMasterRealmAdminService(clientId, clientSecret /*, adminExpiration*/); } private String getEnvOrProp(String envKey, String propKey) { diff --git a/quarkus/tests/integration/src/test/java/org/keycloak/it/cli/dist/BootstrapAdminDistTest.java b/quarkus/tests/integration/src/test/java/org/keycloak/it/cli/dist/BootstrapAdminDistTest.java index dceea055b77d..4809f9db6e2b 100644 --- a/quarkus/tests/integration/src/test/java/org/keycloak/it/cli/dist/BootstrapAdminDistTest.java +++ b/quarkus/tests/integration/src/test/java/org/keycloak/it/cli/dist/BootstrapAdminDistTest.java @@ -63,6 +63,13 @@ void failEnvNotSet(LaunchResult result) { void createAdmin(LaunchResult result) { assertTrue(result.getErrorOutput().isEmpty(), result.getErrorOutput()); } + + @Test + @Launch({ "start-dev", "--bootstrap-admin-password=MY_PASSWORD" }) + void createAdminWithCliOptions(LaunchResult result) { + assertTrue(result.getErrorOutput().isEmpty(), result.getErrorOutput()); + result.getOutput().contains("Created temporary admin user with username temp-admin"); + } @Test @Launch({ "bootstrap-admin", "service", "--no-prompt" }) diff --git a/quarkus/tests/integration/src/test/java/org/keycloak/it/cli/dist/FipsDistTest.java b/quarkus/tests/integration/src/test/java/org/keycloak/it/cli/dist/FipsDistTest.java index 2b90cb961129..26786c0281e0 100644 --- a/quarkus/tests/integration/src/test/java/org/keycloak/it/cli/dist/FipsDistTest.java +++ b/quarkus/tests/integration/src/test/java/org/keycloak/it/cli/dist/FipsDistTest.java @@ -48,30 +48,19 @@ void testFipsNonApprovedMode(KeycloakDistribution dist) { } @Test - void testFipsApprovedModePasswordFails(KeycloakDistribution dist) { + void testFipsApprovedMode(KeycloakDistribution dist) { runOnFipsEnabledDistribution(dist, () -> { dist.setEnvVar("KC_BOOTSTRAP_ADMIN_USERNAME", "admin"); dist.setEnvVar("KC_BOOTSTRAP_ADMIN_PASSWORD", "admin"); CLIResult cliResult = dist.run("start", "--fips-mode=strict"); - cliResult.assertStarted(); - cliResult.assertMessage( - "org.bouncycastle.crypto.fips.FipsUnapprovedOperationError: password must be at least 112 bits"); + cliResult.assertMessage("password must be at least 112 bits"); cliResult.assertMessage("Java security providers: [ \n" + " KC(" + BCFIPS_VERSION + " Approved Mode, FIPS-JVM: " + KeycloakFipsSecurityProvider.isSystemFipsEnabled() + ") version 1.0 - class org.keycloak.crypto.fips.KeycloakFipsSecurityProvider"); - }); - } - - @Test - void testFipsApprovedModePasswordSucceeds(KeycloakDistribution dist) { - runOnFipsEnabledDistribution(dist, () -> { - dist.setEnvVar("KC_BOOTSTRAP_ADMIN_USERNAME", "admin"); + dist.setEnvVar("KC_BOOTSTRAP_ADMIN_PASSWORD", "adminadminadmin"); - - CLIResult cliResult = dist.run("start", "--fips-mode=strict"); + cliResult = dist.run("start", "--fips-mode=strict"); cliResult.assertStarted(); - cliResult.assertMessage("Java security providers: [ \n" - + " KC(" + BCFIPS_VERSION + " Approved Mode, FIPS-JVM: " + KeycloakFipsSecurityProvider.isSystemFipsEnabled() + ") version 1.0 - class org.keycloak.crypto.fips.KeycloakFipsSecurityProvider"); cliResult.assertMessage("Created temporary admin user with username admin"); }); } diff --git a/quarkus/tests/integration/src/test/resources/org/keycloak/it/cli/dist/approvals/cli/help/HelpCommandDistTest.testExportHelpAll.approved.txt b/quarkus/tests/integration/src/test/resources/org/keycloak/it/cli/dist/approvals/cli/help/HelpCommandDistTest.testExportHelpAll.approved.txt index 3090fad2ccf5..8798eae4625b 100644 --- a/quarkus/tests/integration/src/test/resources/org/keycloak/it/cli/dist/approvals/cli/help/HelpCommandDistTest.testExportHelpAll.approved.txt +++ b/quarkus/tests/integration/src/test/resources/org/keycloak/it/cli/dist/approvals/cli/help/HelpCommandDistTest.testExportHelpAll.approved.txt @@ -171,16 +171,10 @@ Logging: DEPRECATED. Set the format for the GELF timestamp field. Uses Java SimpleDateFormat pattern. Default: yyyy-MM-dd HH:mm:ss,SSS. Available only when GELF is activated. ---log-gelf-version - The GELF version to be used. Possible values are: 1.0, 1.1. Default: 1.1. - Available only when GELF is activated. --log-level The log level of the root category or a comma-separated list of individual categories and their levels. For the root category, you don't need to specify a category. Default: info. ---log-syslog-app-name - The app name used when formatting the message in RFC5424 format. Default: - keycloak. Available only when Syslog is activated. --log-syslog-endpoint The IP address and port of the syslog server. Default: localhost:514. Available only when Syslog is activated. @@ -217,4 +211,4 @@ Export: --users-per-file Set the number of users per file. It is used only if 'users' is set to 'different_files'. Increasing this number leads to exponentially increasing - export times. Default: 50. + export times. Default: 50. \ No newline at end of file diff --git a/quarkus/tests/integration/src/test/resources/org/keycloak/it/cli/dist/approvals/cli/help/HelpCommandDistTest.testImportHelpAll.approved.txt b/quarkus/tests/integration/src/test/resources/org/keycloak/it/cli/dist/approvals/cli/help/HelpCommandDistTest.testImportHelpAll.approved.txt index 1486b7a98791..10b9f14eaf17 100644 --- a/quarkus/tests/integration/src/test/resources/org/keycloak/it/cli/dist/approvals/cli/help/HelpCommandDistTest.testImportHelpAll.approved.txt +++ b/quarkus/tests/integration/src/test/resources/org/keycloak/it/cli/dist/approvals/cli/help/HelpCommandDistTest.testImportHelpAll.approved.txt @@ -171,16 +171,10 @@ Logging: DEPRECATED. Set the format for the GELF timestamp field. Uses Java SimpleDateFormat pattern. Default: yyyy-MM-dd HH:mm:ss,SSS. Available only when GELF is activated. ---log-gelf-version - The GELF version to be used. Possible values are: 1.0, 1.1. Default: 1.1. - Available only when GELF is activated. --log-level The log level of the root category or a comma-separated list of individual categories and their levels. For the root category, you don't need to specify a category. Default: info. ---log-syslog-app-name - The app name used when formatting the message in RFC5424 format. Default: - keycloak. Available only when Syslog is activated. --log-syslog-endpoint The IP address and port of the syslog server. Default: localhost:514. Available only when Syslog is activated. @@ -211,4 +205,4 @@ Import: --file Set the path to a file that will be read. --override Set if existing data should be overwritten. If set to false, data will be - ignored. Default: true. + ignored. Default: true. \ No newline at end of file diff --git a/quarkus/tests/integration/src/test/resources/org/keycloak/it/cli/dist/approvals/cli/help/HelpCommandDistTest.testStartDevHelpAll.approved.txt b/quarkus/tests/integration/src/test/resources/org/keycloak/it/cli/dist/approvals/cli/help/HelpCommandDistTest.testStartDevHelpAll.approved.txt index 4d39bb15558f..7d4d18061eb2 100644 --- a/quarkus/tests/integration/src/test/resources/org/keycloak/it/cli/dist/approvals/cli/help/HelpCommandDistTest.testStartDevHelpAll.approved.txt +++ b/quarkus/tests/integration/src/test/resources/org/keycloak/it/cli/dist/approvals/cli/help/HelpCommandDistTest.testStartDevHelpAll.approved.txt @@ -191,10 +191,6 @@ Hostname v1 (Deprecated): headers to allow internal and external applications. If all applications use the public URL this option should be enabled. Default: false. Available only when hostname:v1 feature is enabled. ---hostname-strict-https - DEPRECATED. Forces frontend URLs to use the 'https' scheme. If set to false, - the HTTP scheme is inferred from requests. Default: true. Available only - when hostname:v1 feature is enabled. --hostname-url DEPRECATED. Set the base URL for frontend URLs, including scheme, host, port and path. Available only when hostname:v1 feature is enabled. @@ -385,16 +381,10 @@ Logging: DEPRECATED. Set the format for the GELF timestamp field. Uses Java SimpleDateFormat pattern. Default: yyyy-MM-dd HH:mm:ss,SSS. Available only when GELF is activated. ---log-gelf-version - The GELF version to be used. Possible values are: 1.0, 1.1. Default: 1.1. - Available only when GELF is activated. --log-level The log level of the root category or a comma-separated list of individual categories and their levels. For the root category, you don't need to specify a category. Default: info. ---log-syslog-app-name - The app name used when formatting the message in RFC5424 format. Default: - keycloak. Available only when Syslog is activated. --log-syslog-endpoint The IP address and port of the syslog server. Default: localhost:514. Available only when Syslog is activated. @@ -431,4 +421,4 @@ Security: Do NOT start the server using this command when deploying to production. Use 'kc.sh start-dev --help-all' to list all available options, including build -options. +options. \ No newline at end of file diff --git a/quarkus/tests/integration/src/test/resources/org/keycloak/it/cli/dist/approvals/cli/help/HelpCommandDistTest.testStartHelpAll.approved.txt b/quarkus/tests/integration/src/test/resources/org/keycloak/it/cli/dist/approvals/cli/help/HelpCommandDistTest.testStartHelpAll.approved.txt index 3c3d0b723b30..44531fbec965 100644 --- a/quarkus/tests/integration/src/test/resources/org/keycloak/it/cli/dist/approvals/cli/help/HelpCommandDistTest.testStartHelpAll.approved.txt +++ b/quarkus/tests/integration/src/test/resources/org/keycloak/it/cli/dist/approvals/cli/help/HelpCommandDistTest.testStartHelpAll.approved.txt @@ -192,10 +192,6 @@ Hostname v1 (Deprecated): headers to allow internal and external applications. If all applications use the public URL this option should be enabled. Default: false. Available only when hostname:v1 feature is enabled. ---hostname-strict-https - DEPRECATED. Forces frontend URLs to use the 'https' scheme. If set to false, - the HTTP scheme is inferred from requests. Default: true. Available only - when hostname:v1 feature is enabled. --hostname-url DEPRECATED. Set the base URL for frontend URLs, including scheme, host, port and path. Available only when hostname:v1 feature is enabled. @@ -386,16 +382,10 @@ Logging: DEPRECATED. Set the format for the GELF timestamp field. Uses Java SimpleDateFormat pattern. Default: yyyy-MM-dd HH:mm:ss,SSS. Available only when GELF is activated. ---log-gelf-version - The GELF version to be used. Possible values are: 1.0, 1.1. Default: 1.1. - Available only when GELF is activated. --log-level The log level of the root category or a comma-separated list of individual categories and their levels. For the root category, you don't need to specify a category. Default: info. ---log-syslog-app-name - The app name used when formatting the message in RFC5424 format. Default: - keycloak. Available only when Syslog is activated. --log-syslog-endpoint The IP address and port of the syslog server. Default: localhost:514. Available only when Syslog is activated. @@ -436,4 +426,4 @@ By default, this command tries to update the server configuration by running a $ kc.sh start '--optimized' By doing that, the server should start faster based on any previous -configuration you have set when manually running the 'build' command. +configuration you have set when manually running the 'build' command. \ No newline at end of file diff --git a/quarkus/tests/integration/src/test/resources/org/keycloak/it/cli/dist/approvals/cli/help/HelpCommandDistTest.testStartOptimizedHelpAll.approved.txt b/quarkus/tests/integration/src/test/resources/org/keycloak/it/cli/dist/approvals/cli/help/HelpCommandDistTest.testStartOptimizedHelpAll.approved.txt index b54b396a1f61..b9a1d45f0ff9 100644 --- a/quarkus/tests/integration/src/test/resources/org/keycloak/it/cli/dist/approvals/cli/help/HelpCommandDistTest.testStartOptimizedHelpAll.approved.txt +++ b/quarkus/tests/integration/src/test/resources/org/keycloak/it/cli/dist/approvals/cli/help/HelpCommandDistTest.testStartOptimizedHelpAll.approved.txt @@ -177,10 +177,6 @@ Hostname v1 (Deprecated): headers to allow internal and external applications. If all applications use the public URL this option should be enabled. Default: false. Available only when hostname:v1 feature is enabled. ---hostname-strict-https - DEPRECATED. Forces frontend URLs to use the 'https' scheme. If set to false, - the HTTP scheme is inferred from requests. Default: true. Available only - when hostname:v1 feature is enabled. --hostname-url DEPRECATED. Set the base URL for frontend URLs, including scheme, host, port and path. Available only when hostname:v1 feature is enabled. @@ -337,16 +333,10 @@ Logging: DEPRECATED. Set the format for the GELF timestamp field. Uses Java SimpleDateFormat pattern. Default: yyyy-MM-dd HH:mm:ss,SSS. Available only when GELF is activated. ---log-gelf-version - The GELF version to be used. Possible values are: 1.0, 1.1. Default: 1.1. - Available only when GELF is activated. --log-level The log level of the root category or a comma-separated list of individual categories and their levels. For the root category, you don't need to specify a category. Default: info. ---log-syslog-app-name - The app name used when formatting the message in RFC5424 format. Default: - keycloak. Available only when Syslog is activated. --log-syslog-endpoint The IP address and port of the syslog server. Default: localhost:514. Available only when Syslog is activated. @@ -378,4 +368,4 @@ By default, this command tries to update the server configuration by running a $ kc.sh start '--optimized' By doing that, the server should start faster based on any previous -configuration you have set when manually running the 'build' command. +configuration you have set when manually running the 'build' command. \ No newline at end of file