fix: adds a check for duplicate users/clients to simplify cmd errors (#31583)
also changes temp-admin-service to temp-admin closes: #31160 Signed-off-by: Steve Hawkins <shawkins@redhat.com>
This commit is contained in:
parent
e090b0d260
commit
7ce6f12fe3
3 changed files with 73 additions and 47 deletions
|
@ -17,27 +17,22 @@
|
||||||
|
|
||||||
package org.keycloak.quarkus.runtime.integration.jaxrs;
|
package org.keycloak.quarkus.runtime.integration.jaxrs;
|
||||||
|
|
||||||
import io.quarkus.runtime.ShutdownEvent;
|
|
||||||
import io.quarkus.runtime.StartupEvent;
|
|
||||||
import io.smallrye.common.annotation.Blocking;
|
|
||||||
|
|
||||||
import org.keycloak.Config;
|
|
||||||
import org.keycloak.config.BootstrapAdminOptions;
|
import org.keycloak.config.BootstrapAdminOptions;
|
||||||
import org.keycloak.models.KeycloakSession;
|
import org.keycloak.models.KeycloakSession;
|
||||||
import org.keycloak.models.KeycloakSessionFactory;
|
import org.keycloak.models.KeycloakSessionFactory;
|
||||||
import org.keycloak.models.KeycloakSessionTask;
|
|
||||||
import org.keycloak.models.utils.KeycloakModelUtils;
|
|
||||||
import org.keycloak.platform.Platform;
|
import org.keycloak.platform.Platform;
|
||||||
import org.keycloak.quarkus.runtime.Environment;
|
import org.keycloak.quarkus.runtime.Environment;
|
||||||
import org.keycloak.quarkus.runtime.cli.command.AbstractNonServerCommand;
|
import org.keycloak.quarkus.runtime.cli.command.AbstractNonServerCommand;
|
||||||
import org.keycloak.quarkus.runtime.configuration.Configuration;
|
import org.keycloak.quarkus.runtime.configuration.Configuration;
|
||||||
import org.keycloak.quarkus.runtime.integration.QuarkusKeycloakSessionFactory;
|
import org.keycloak.quarkus.runtime.integration.QuarkusKeycloakSessionFactory;
|
||||||
import org.keycloak.quarkus.runtime.integration.QuarkusPlatform;
|
import org.keycloak.quarkus.runtime.integration.QuarkusPlatform;
|
||||||
import org.keycloak.services.ServicesLogger;
|
|
||||||
import org.keycloak.services.managers.ApplianceBootstrap;
|
import org.keycloak.services.managers.ApplianceBootstrap;
|
||||||
import org.keycloak.services.resources.KeycloakApplication;
|
import org.keycloak.services.resources.KeycloakApplication;
|
||||||
import org.keycloak.utils.StringUtil;
|
import org.keycloak.utils.StringUtil;
|
||||||
|
|
||||||
|
import io.quarkus.runtime.ShutdownEvent;
|
||||||
|
import io.quarkus.runtime.StartupEvent;
|
||||||
|
import io.smallrye.common.annotation.Blocking;
|
||||||
import jakarta.enterprise.event.Observes;
|
import jakarta.enterprise.event.Observes;
|
||||||
import jakarta.ws.rs.ApplicationPath;
|
import jakarta.ws.rs.ApplicationPath;
|
||||||
|
|
||||||
|
@ -85,23 +80,23 @@ public class QuarkusKeycloakApplication extends KeycloakApplication {
|
||||||
|
|
||||||
try {
|
try {
|
||||||
//Integer expiration = Configuration.getOptionalKcValue(BootstrapAdminOptions.EXPIRATION.getKey()).map(Integer::valueOf).orElse(null);
|
//Integer expiration = Configuration.getOptionalKcValue(BootstrapAdminOptions.EXPIRATION.getKey()).map(Integer::valueOf).orElse(null);
|
||||||
if (StringUtil.isNotBlank(adminPassword)) {
|
if (StringUtil.isNotBlank(adminPassword) && !createTemporaryMasterRealmAdminUser(adminUsername, adminPassword, /*expiration,*/ session)) {
|
||||||
createTemporaryMasterRealmAdminUser(adminUsername, adminPassword, /*expiration,*/ session);
|
throw new RuntimeException("Aborting startup and the creation of the master realm, because the temporary admin user account could not be created.");
|
||||||
}
|
}
|
||||||
if (StringUtil.isNotBlank(clientSecret)) {
|
if (StringUtil.isNotBlank(clientSecret) && !createTemporaryMasterRealmAdminService(clientId, clientSecret, /*expiration,*/ session)) {
|
||||||
createTemporaryMasterRealmAdminService(clientId, clientSecret, /*expiration,*/ session);
|
throw new RuntimeException("Aborting startup and the creation of the master realm, because the temporary admin service account could not be created.");
|
||||||
}
|
}
|
||||||
} catch (NumberFormatException e) {
|
} catch (NumberFormatException e) {
|
||||||
throw new RuntimeException("Invalid admin expiration value provided. An integer is expected.", e);
|
throw new RuntimeException("Invalid admin expiration value provided. An integer is expected.", e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void createTemporaryMasterRealmAdminUser(String adminUserName, String adminPassword, /*Integer adminExpiration,*/ KeycloakSession session) {
|
public boolean createTemporaryMasterRealmAdminUser(String adminUserName, String adminPassword, /*Integer adminExpiration,*/ KeycloakSession session) {
|
||||||
new ApplianceBootstrap(session).createTemporaryMasterRealmAdminUser(adminUserName, adminPassword /*, adminExpiration*/, false);
|
return new ApplianceBootstrap(session).createTemporaryMasterRealmAdminUser(adminUserName, adminPassword /*, adminExpiration*/, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void createTemporaryMasterRealmAdminService(String clientId, String clientSecret, /*Integer adminExpiration,*/ KeycloakSession session) {
|
public boolean createTemporaryMasterRealmAdminService(String clientId, String clientSecret, /*Integer adminExpiration,*/ KeycloakSession session) {
|
||||||
new ApplianceBootstrap(session).createTemporaryMasterRealmAdminService(clientId, clientSecret /*, adminExpiration*/);
|
return new ApplianceBootstrap(session).createTemporaryMasterRealmAdminService(clientId, clientSecret /*, adminExpiration*/);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -88,7 +88,7 @@ public interface ServicesLogger extends BasicLogger {
|
||||||
@LogMessage(level = ERROR)
|
@LogMessage(level = ERROR)
|
||||||
@Message(id=10, value="Failed to add user '%s' to realm '%s': user with username exists")
|
@Message(id=10, value="Failed to add user '%s' to realm '%s': user with username exists")
|
||||||
void addUserFailedUserExists(String user, String realm);
|
void addUserFailedUserExists(String user, String realm);
|
||||||
|
|
||||||
@LogMessage(level = ERROR)
|
@LogMessage(level = ERROR)
|
||||||
@Message(id=11, value="Failed to add user '%s' to realm '%s'")
|
@Message(id=11, value="Failed to add user '%s' to realm '%s'")
|
||||||
void addUserFailed(@Cause Throwable t, String user, String realm);
|
void addUserFailed(@Cause Throwable t, String user, String realm);
|
||||||
|
@ -465,10 +465,15 @@ public interface ServicesLogger extends BasicLogger {
|
||||||
void scriptEngineCreated(String engineName, String engineVersion, String mimeType);
|
void scriptEngineCreated(String engineName, String engineVersion, String mimeType);
|
||||||
|
|
||||||
@LogMessage(level = DEBUG)
|
@LogMessage(level = DEBUG)
|
||||||
@Message(id=107, value="Skipping create admin user. Admin already exists in realm '%s'.")
|
@Message(id=107, value="Skipping create admin user. User(s) already exist in realm '%s'.")
|
||||||
void addAdminUserFailedAdminExists(String realm);
|
void addAdminUserFailedUsersExist(String realm);
|
||||||
|
|
||||||
@LogMessage(level = WARN)
|
@LogMessage(level = WARN)
|
||||||
@Message(id=108, value="URI '%s' doesn't match any trustedHost or trustedDomain")
|
@Message(id=108, value="URI '%s' doesn't match any trustedHost or trustedDomain")
|
||||||
void uriDoesntMatch(String uri);
|
void uriDoesntMatch(String uri);
|
||||||
|
|
||||||
|
@LogMessage(level = ERROR)
|
||||||
|
@Message(id=109, value="Failed to add client '%s' to realm '%s': client with client ID exists")
|
||||||
|
void addClientFailedClientExists(String clientId, String realm);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,6 +23,7 @@ import org.keycloak.models.AdminRoles;
|
||||||
import org.keycloak.models.ClientModel;
|
import org.keycloak.models.ClientModel;
|
||||||
import org.keycloak.models.Constants;
|
import org.keycloak.models.Constants;
|
||||||
import org.keycloak.models.KeycloakSession;
|
import org.keycloak.models.KeycloakSession;
|
||||||
|
import org.keycloak.models.ModelDuplicateException;
|
||||||
import org.keycloak.models.RealmModel;
|
import org.keycloak.models.RealmModel;
|
||||||
import org.keycloak.models.RoleModel;
|
import org.keycloak.models.RoleModel;
|
||||||
import org.keycloak.models.UserCredentialModel;
|
import org.keycloak.models.UserCredentialModel;
|
||||||
|
@ -113,7 +114,14 @@ public class ApplianceBootstrap {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void createTemporaryMasterRealmAdminUser(String username, String password, /*Integer expriationMinutes,*/ boolean initialUser) {
|
/**
|
||||||
|
* Create a temporary admin user
|
||||||
|
* @param username
|
||||||
|
* @param password
|
||||||
|
* @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) {
|
||||||
RealmModel realm = session.realms().getRealmByName(Config.getAdminRealm());
|
RealmModel realm = session.realms().getRealmByName(Config.getAdminRealm());
|
||||||
session.getContext().setRealm(realm);
|
session.getContext().setRealm(realm);
|
||||||
|
|
||||||
|
@ -121,26 +129,38 @@ public class ApplianceBootstrap {
|
||||||
//expriationMinutes = expriationMinutes == null ? DEFAULT_TEMP_ADMIN_EXPIRATION : expriationMinutes;
|
//expriationMinutes = expriationMinutes == null ? DEFAULT_TEMP_ADMIN_EXPIRATION : expriationMinutes;
|
||||||
|
|
||||||
if (initialUser && session.users().getUsersCount(realm) > 0) {
|
if (initialUser && session.users().getUsersCount(realm) > 0) {
|
||||||
ServicesLogger.LOGGER.addAdminUserFailedAdminExists(Config.getAdminRealm());
|
ServicesLogger.LOGGER.addAdminUserFailedUsersExist(Config.getAdminRealm());
|
||||||
return;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
UserModel adminUser = session.users().addUser(realm, username);
|
try {
|
||||||
adminUser.setEnabled(true);
|
UserModel adminUser = session.users().addUser(realm, username);
|
||||||
// TODO: is this appropriate, does it need to be managed?
|
adminUser.setEnabled(true);
|
||||||
// adminUser.setSingleAttribute("temporary_admin", Boolean.TRUE.toString());
|
// TODO: is this appropriate, does it need to be managed?
|
||||||
// also set the expiration - could be relative to a creation timestamp, or computed
|
// adminUser.setSingleAttribute("temporary_admin", 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);
|
UserCredentialModel usrCredModel = UserCredentialModel.password(password);
|
||||||
|
adminUser.credentialManager().updateCredential(usrCredModel);
|
||||||
RoleModel adminRole = realm.getRole(AdminRoles.ADMIN);
|
|
||||||
adminUser.grantRole(adminRole);
|
RoleModel adminRole = realm.getRole(AdminRoles.ADMIN);
|
||||||
|
adminUser.grantRole(adminRole);
|
||||||
ServicesLogger.LOGGER.createdTemporaryAdminUser(username);
|
|
||||||
|
ServicesLogger.LOGGER.createdTemporaryAdminUser(username);
|
||||||
|
} catch (ModelDuplicateException e) {
|
||||||
|
ServicesLogger.LOGGER.addUserFailedUserExists(username, Config.getAdminRealm());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void createTemporaryMasterRealmAdminService(String clientId, String clientSecret /*, Integer expriationMinutes*/) {
|
/**
|
||||||
|
* Create a temporary admin service account
|
||||||
|
* @param clientId the client ID
|
||||||
|
* @param clientSecret the client secret
|
||||||
|
* @return false if the service account could not be created
|
||||||
|
*/
|
||||||
|
public boolean createTemporaryMasterRealmAdminService(String clientId, String clientSecret /*, Integer expriationMinutes*/) {
|
||||||
RealmModel realm = session.realms().getRealmByName(Config.getAdminRealm());
|
RealmModel realm = session.realms().getRealmByName(Config.getAdminRealm());
|
||||||
session.getContext().setRealm(realm);
|
session.getContext().setRealm(realm);
|
||||||
|
|
||||||
|
@ -154,17 +174,23 @@ public class ApplianceBootstrap {
|
||||||
adminClient.setPublicClient(false);
|
adminClient.setPublicClient(false);
|
||||||
adminClient.setSecret(clientSecret);
|
adminClient.setSecret(clientSecret);
|
||||||
|
|
||||||
ClientModel adminClientModel = ClientManager.createClient(session, realm, adminClient);
|
try {
|
||||||
|
ClientModel adminClientModel = ClientManager.createClient(session, realm, adminClient);
|
||||||
new ClientManager(new RealmManager(session)).enableServiceAccount(adminClientModel);
|
|
||||||
UserModel serviceAccount = session.users().getServiceAccount(adminClientModel);
|
new ClientManager(new RealmManager(session)).enableServiceAccount(adminClientModel);
|
||||||
RoleModel adminRole = realm.getRole(AdminRoles.ADMIN);
|
UserModel serviceAccount = session.users().getServiceAccount(adminClientModel);
|
||||||
serviceAccount.grantRole(adminRole);
|
RoleModel adminRole = realm.getRole(AdminRoles.ADMIN);
|
||||||
|
serviceAccount.grantRole(adminRole);
|
||||||
// TODO: set temporary
|
|
||||||
// also set the expiration - could be relative to a creation timestamp, or computed
|
// TODO: set temporary
|
||||||
|
// also set the expiration - could be relative to a creation timestamp, or computed
|
||||||
ServicesLogger.LOGGER.createdTemporaryAdminService(clientId);
|
|
||||||
|
ServicesLogger.LOGGER.createdTemporaryAdminService(clientId);
|
||||||
|
} catch (ModelDuplicateException e) {
|
||||||
|
ServicesLogger.LOGGER.addClientFailedClientExists(clientId, Config.getAdminRealm());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void createMasterRealmUser(String username, String password) {
|
public void createMasterRealmUser(String username, String password) {
|
||||||
|
|
Loading…
Reference in a new issue