diff --git a/docs/documentation/server_admin/images/initial-welcome-page.png b/docs/documentation/server_admin/images/initial-welcome-page.png index 5338f5a7c9c..c9881bc728e 100644 Binary files a/docs/documentation/server_admin/images/initial-welcome-page.png and b/docs/documentation/server_admin/images/initial-welcome-page.png differ diff --git a/docs/documentation/upgrading/topics/changes/changes-26_4_0.adoc b/docs/documentation/upgrading/topics/changes/changes-26_4_0.adoc index cc9abe69ac9..8b8940ba67c 100644 --- a/docs/documentation/upgrading/topics/changes/changes-26_4_0.adoc +++ b/docs/documentation/upgrading/topics/changes/changes-26_4_0.adoc @@ -177,6 +177,11 @@ Configuration of the default cache configurations in `conf/cache-ispn.xml`, or i In a future major release, the start-up will fail if default cache configurations are stated in those files and the option is not specified. + +=== Welcome Page changes + +The Welcome Page creates regular Admin users instead of temporary ones. + // ------------------------ Removed features ------------------------ // == Removed features diff --git a/docs/guides/ui-customization/welcome-theme.adoc b/docs/guides/ui-customization/welcome-theme.adoc index 473fddfe6c2..7226dc3f25e 100644 --- a/docs/guides/ui-customization/welcome-theme.adoc +++ b/docs/guides/ui-customization/welcome-theme.adoc @@ -8,7 +8,7 @@ summary="Learn how to customize the welcome theme."> The welcome theme is the web page that is served when you request the default page from the {project_name} server. For instance, if your server is deployed on your local machine at port 8080, http://localhost:8080 serves the welcome theme. -By default, the welcome theme is only used to create the initial temporary admin user. Once that user is created, whenever users navigate to the welcome theme, they are redirected to the Admin Console. However, this behavior can be changed and the welcome theme can be completely customized or replaced. +By default, the welcome theme is only used during the initial setup to create the first admin user. Once an initial admin exists, navigating to the welcome page redirects to the Admin Console. However, this behavior can be changed and the welcome theme can be completely customized or replaced. Since the welcome theme is not associated with a realm, it cannot be selected in the admin console like other themes. 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 85d6a296f8d..dff9f7e2a07 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 @@ -103,7 +103,7 @@ public class QuarkusKeycloakApplication extends KeycloakApplication { } public boolean createTemporaryMasterRealmAdminUser(String adminUserName, String adminPassword, /*Integer adminExpiration,*/ KeycloakSession session) { - return new ApplianceBootstrap(session).createTemporaryMasterRealmAdminUser(adminUserName, adminPassword /*, adminExpiration*/, false); + return new ApplianceBootstrap(session).createMasterRealmAdminUser(adminUserName, adminPassword, true /*, adminExpiration*/, false); } public boolean createTemporaryMasterRealmAdminService(String clientId, String clientSecret, /*Integer adminExpiration,*/ KeycloakSession session) { diff --git a/services/src/main/java/org/keycloak/services/ServicesLogger.java b/services/src/main/java/org/keycloak/services/ServicesLogger.java index f4cc2260c16..e6a47b6f3a6 100644 --- a/services/src/main/java/org/keycloak/services/ServicesLogger.java +++ b/services/src/main/java/org/keycloak/services/ServicesLogger.java @@ -469,4 +469,8 @@ public interface ServicesLogger extends BasicLogger { @Message(id=110, value="Environment variable '%s' is deprecated, use '%s' instead") void usingDeprecatedEnvironmentVariable(String deprecated, String supported); + @LogMessage(level = INFO) + @Message(id=111, value="Created initial admin user with username %s") + void createdInitialAdminUser(String userName); + } diff --git a/services/src/main/java/org/keycloak/services/managers/ApplianceBootstrap.java b/services/src/main/java/org/keycloak/services/managers/ApplianceBootstrap.java index 3bab2d2c745..7b920319ca0 100755 --- a/services/src/main/java/org/keycloak/services/managers/ApplianceBootstrap.java +++ b/services/src/main/java/org/keycloak/services/managers/ApplianceBootstrap.java @@ -121,7 +121,7 @@ public class ApplianceBootstrap { * @param initialUser if true only create the user if no other users exist * @return false if the user could not be created */ - public boolean createTemporaryMasterRealmAdminUser(String username, String password, /*Integer expriationMinutes,*/ boolean initialUser) { + public boolean createMasterRealmAdminUser(String username, String password, boolean isTemporary, /*Integer expriationMinutes,*/ boolean initialUser) { RealmModel realm = session.realms().getRealmByName(Config.getAdminRealm()); session.getContext().setRealm(realm); @@ -136,8 +136,10 @@ public class ApplianceBootstrap { try { UserModel adminUser = session.users().addUser(realm, username); adminUser.setEnabled(true); - adminUser.setSingleAttribute(IS_TEMP_ADMIN_ATTR_NAME, Boolean.TRUE.toString()); - // also set the expiration - could be relative to a creation timestamp, or computed + if (isTemporary) { + adminUser.setSingleAttribute(IS_TEMP_ADMIN_ATTR_NAME, Boolean.TRUE.toString()); + // also set the expiration - could be relative to a creation timestamp, or computed + } UserCredentialModel usrCredModel = UserCredentialModel.password(password); adminUser.credentialManager().updateCredential(usrCredModel); @@ -145,7 +147,10 @@ public class ApplianceBootstrap { RoleModel adminRole = realm.getRole(AdminRoles.ADMIN); adminUser.grantRole(adminRole); - ServicesLogger.LOGGER.createdTemporaryAdminUser(username); + if (isTemporary) + ServicesLogger.LOGGER.createdTemporaryAdminUser(username); + else + ServicesLogger.LOGGER.createdInitialAdminUser(username); } catch (ModelDuplicateException e) { ServicesLogger.LOGGER.addUserFailedUserExists(username, Config.getAdminRealm()); return false; @@ -155,7 +160,7 @@ public class ApplianceBootstrap { /** * Create a temporary admin service account - * @param clientId the client ID + * @param clientId the client ID * @param clientSecret the client secret * @return false if the service account could not be created */ @@ -194,8 +199,8 @@ public class ApplianceBootstrap { return true; } - public void createMasterRealmUser(String username, String password) { - createTemporaryMasterRealmAdminUser(username, password, true); + public void createMasterRealmUser(String username, String password, boolean isTemporary) { + createMasterRealmAdminUser(username, password, isTemporary, true); } } diff --git a/services/src/main/java/org/keycloak/services/resources/WelcomeResource.java b/services/src/main/java/org/keycloak/services/resources/WelcomeResource.java index 1cf1d128834..681a85757db 100755 --- a/services/src/main/java/org/keycloak/services/resources/WelcomeResource.java +++ b/services/src/main/java/org/keycloak/services/resources/WelcomeResource.java @@ -39,6 +39,8 @@ import org.keycloak.common.Version; import org.keycloak.common.util.Base64Url; import org.keycloak.common.util.MimeTypeUtil; import org.keycloak.common.util.SecretGenerator; +import org.keycloak.common.util.SystemEnvProperties; +import org.keycloak.config.BootstrapAdminOptions; import org.keycloak.cookie.CookieProvider; import org.keycloak.cookie.CookieType; import org.keycloak.http.HttpRequest; @@ -133,9 +135,10 @@ public class WelcomeResource { return createWelcomePage(null, "Password and confirmation doesn't match"); } + try { ApplianceBootstrap applianceBootstrap = new ApplianceBootstrap(session); - applianceBootstrap.createMasterRealmUser(username, password); + applianceBootstrap.createMasterRealmUser(username, password, false); } catch (ModelException e) { session.getTransactionManager().rollback(); logger.error("Error creating the administrative user", e); @@ -145,7 +148,6 @@ public class WelcomeResource { expireCsrfCookie(); shouldBootstrap.set(false); - ServicesLogger.LOGGER.createdTemporaryAdminUser(username); return createWelcomePage("User created", null); } } @@ -301,5 +303,4 @@ public class WelcomeResource { throw new ForbiddenException(); } } - } diff --git a/tests/base/src/test/java/org/keycloak/tests/welcomepage/WelcomePageTest.java b/tests/base/src/test/java/org/keycloak/tests/welcomepage/WelcomePageTest.java index b215a427f8a..fce7e2c2934 100644 --- a/tests/base/src/test/java/org/keycloak/tests/welcomepage/WelcomePageTest.java +++ b/tests/base/src/test/java/org/keycloak/tests/welcomepage/WelcomePageTest.java @@ -53,8 +53,8 @@ public class WelcomePageTest { welcomePage.navigateTo(); - Assertions.assertEquals("Create a temporary administrative user", welcomePage.getWelcomeMessage()); - Assertions.assertTrue(welcomePage.getWelcomeDescription().startsWith("To get started with Keycloak, you first create a temporary administrative user")); + Assertions.assertEquals("Create an administrative user", welcomePage.getWelcomeMessage()); + Assertions.assertTrue(welcomePage.getWelcomeDescription().startsWith("To get started with Keycloak, you first create an administrative user")); Assertions.assertTrue(driver.getPageSource().contains("form")); } @@ -64,7 +64,7 @@ public class WelcomePageTest { driver.get(getPublicServerUrl().toString()); Assertions.assertEquals("Local access required", welcomePage.getWelcomeMessage()); - Assertions.assertTrue(welcomePage.getWelcomeDescription().startsWith("You will need local access to create the temporary administrative user.")); + Assertions.assertTrue(welcomePage.getWelcomeDescription().startsWith("You will need local access to create the administrative user.")); Assertions.assertFalse(driver.getPageSource().contains("form")); } diff --git a/testsuite/integration-arquillian/servers/auth-server/undertow/src/main/java/org/keycloak/testsuite/arquillian/undertow/KeycloakOnUndertow.java b/testsuite/integration-arquillian/servers/auth-server/undertow/src/main/java/org/keycloak/testsuite/arquillian/undertow/KeycloakOnUndertow.java index 0eadcec74e9..b3c11258675 100644 --- a/testsuite/integration-arquillian/servers/auth-server/undertow/src/main/java/org/keycloak/testsuite/arquillian/undertow/KeycloakOnUndertow.java +++ b/testsuite/integration-arquillian/servers/auth-server/undertow/src/main/java/org/keycloak/testsuite/arquillian/undertow/KeycloakOnUndertow.java @@ -226,7 +226,7 @@ public class KeycloakOnUndertow implements DeployableContainer
<#if localUser> -

Create a temporary administrative user

+

Create an administrative user

<#if !successMessage?has_content> - + <#else>

Local access required

- +
@@ -132,7 +132,7 @@
<#else> -

To create the temporary administrative user, access the Administration Console over localhost, or use a bootstrap-admin command.

+

To create the administrative user, access the Administration Console over localhost, or use a bootstrap-admin command.