From f9f81fde7bce7d69bc759f1da3171baa476f192b Mon Sep 17 00:00:00 2001 From: OZGCloud <ozgcloud@mgm-tp.com> Date: Fri, 21 Jul 2023 08:34:03 +0200 Subject: [PATCH] OZG-3961 OZG-4082 create Secret for User if password not exists(PoC) --- .../client/KeycloakClientService.java | 14 +++--- .../user/KeycloakUserRemoteService.java | 47 +++++++++++++++++++ .../keycloak/user/KeycloakUserService.java | 12 +++++ .../user/KeycloakUserRemoteServiceTest.java | 3 ++ .../user/KeycloakUserServiceTest.java | 13 +++++ .../user/OzgKeycloakUserSpecTestFactory.java | 2 +- 6 files changed, 83 insertions(+), 8 deletions(-) diff --git a/src/main/java/de/ozgcloud/operator/keycloak/client/KeycloakClientService.java b/src/main/java/de/ozgcloud/operator/keycloak/client/KeycloakClientService.java index 4357803..a059195 100644 --- a/src/main/java/de/ozgcloud/operator/keycloak/client/KeycloakClientService.java +++ b/src/main/java/de/ozgcloud/operator/keycloak/client/KeycloakClientService.java @@ -47,13 +47,6 @@ class KeycloakClientService { () -> createClient(spec, namespace)); } - void createClient(OzgKeycloakClientSpec spec, String realm) { - ClientRepresentation clientRepresentation = mapper.map(spec); - String realClientId = remoteService.createClient(clientRepresentation, realm); - - addOrUpdateClientRoles(spec, realm, realClientId); - } - void updateClient(ClientRepresentation existingClient, OzgKeycloakClientSpec spec, String realm) { ClientRepresentation clientRepresentation = mapper.update(existingClient, spec); remoteService.updateClient(clientRepresentation, realm); @@ -61,6 +54,13 @@ class KeycloakClientService { addOrUpdateClientRoles(spec, realm, existingClient.getId()); } + void createClient(OzgKeycloakClientSpec spec, String realm) { + ClientRepresentation clientRepresentation = mapper.map(spec); + String realClientId = remoteService.createClient(clientRepresentation, realm); + + addOrUpdateClientRoles(spec, realm, realClientId); + } + void addOrUpdateClientRoles(OzgKeycloakClientSpec spec, String realm, String realClientId) { spec.getClientRoles().forEach( roleSpec -> genericRemoteService.getClientRole(roleSpec.getName(), realClientId, realm) diff --git a/src/main/java/de/ozgcloud/operator/keycloak/user/KeycloakUserRemoteService.java b/src/main/java/de/ozgcloud/operator/keycloak/user/KeycloakUserRemoteService.java index 4e1d2f0..4430bc2 100644 --- a/src/main/java/de/ozgcloud/operator/keycloak/user/KeycloakUserRemoteService.java +++ b/src/main/java/de/ozgcloud/operator/keycloak/user/KeycloakUserRemoteService.java @@ -24,7 +24,10 @@ package de.ozgcloud.operator.keycloak.user; import java.util.Arrays; +import java.util.Map; +import java.util.Objects; import java.util.Optional; +import java.util.logging.Level; import org.keycloak.admin.client.CreatedResponseUtil; import org.keycloak.admin.client.Keycloak; @@ -38,12 +41,22 @@ import org.springframework.stereotype.Component; import de.ozgcloud.operator.keycloak.KeycloakException; import de.ozgcloud.operator.keycloak.KeycloakGenericRemoteService; import de.ozgcloud.operator.keycloak.KeycloakResultParser; +import io.fabric8.kubernetes.api.model.Secret; +import io.fabric8.kubernetes.api.model.SecretBuilder; +import io.fabric8.kubernetes.client.KubernetesClient; +import io.fabric8.kubernetes.client.dsl.Resource; +import lombok.extern.java.Log; +@Log @Component class KeycloakUserRemoteService { + private static final String SECRET_PASSWORD_FIELD = "password"; + @Autowired private Keycloak keycloak; + @Autowired + private KubernetesClient kubernetesClient; @Autowired private KeycloakGenericRemoteService keycloakGenericRemoteService; @@ -99,4 +112,38 @@ class KeycloakUserRemoteService { void addClientRoleToUser(RoleRepresentation clientRole, RealmResource realmResource, String userId, ClientRepresentation appClient) { realmResource.users().get(userId).roles().clientLevel(appClient.getId()).add(Arrays.asList(clientRole)); } + + // PoC + public String createSecret(OzgKeycloakUserSpec userSpec, String namespace) { + log.log(Level.INFO, "Create secret for user..."); + var secretName = userSpec.getKeycloakUser().getUsername() + "-credentials"; + + var secret = getSecret(secretName, namespace); + if (Objects.isNull(secret.get())) { + log.log(Level.INFO, "...secret does not exist, create one..."); + kubernetesClient.secrets().inNamespace(namespace).create(buildSecret()); + log.log(Level.INFO, "...secret created in " + namespace + " for user " + userSpec.getKeycloakUser().getUsername()); + log.log(Level.INFO, "...load created secret..."); + var createdSecret = getSecret(secretName, namespace); + var newPassword = getPassword(createdSecret); + log.log(Level.INFO, "return password from created secret:" + newPassword); + return newPassword; + } + var password = getPassword(secret); + log.log(Level.INFO, "secret exists, return password:" + password); + return password; + } + + private Resource<Secret> getSecret(String secretName, String namespace) { + return kubernetesClient.secrets().inNamespace(namespace).withName(secretName); + } + + private Secret buildSecret() { + return new SecretBuilder().withData(Map.of(SECRET_PASSWORD_FIELD, "Y9nk43yrQ_zzIPpfFU-I")).build(); + } + + private String getPassword(Resource<Secret> secret) { + return secret.get().getData().get(SECRET_PASSWORD_FIELD); + } + // } \ No newline at end of file diff --git a/src/main/java/de/ozgcloud/operator/keycloak/user/KeycloakUserService.java b/src/main/java/de/ozgcloud/operator/keycloak/user/KeycloakUserService.java index 1f33da6..a66d409 100644 --- a/src/main/java/de/ozgcloud/operator/keycloak/user/KeycloakUserService.java +++ b/src/main/java/de/ozgcloud/operator/keycloak/user/KeycloakUserService.java @@ -24,10 +24,15 @@ package de.ozgcloud.operator.keycloak.user; import java.util.Optional; +import java.util.logging.Level; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; +import org.springframework.util.StringUtils; +import lombok.extern.java.Log; + +@Log @Component class KeycloakUserService { @@ -38,6 +43,13 @@ class KeycloakUserService { private KeycloakUserMapper userMapper; public void createOrUpdateUser(OzgKeycloakUserSpec userSpec, String namespace) { + if (!StringUtils.hasLength(userSpec.getKeycloakUser().getPassword())) { + log.log(Level.INFO, "User has no password, create secret..."); + var password = remoteService.createSecret(userSpec, namespace); + log.log(Level.INFO, "set password: " + password + " to user..."); + userSpec.getKeycloakUser().setPassword(password); + } + log.log(Level.INFO, "proceed"); remoteService.getUserByName(userSpec.getKeycloakUser().getUsername(), namespace) .ifPresentOrElse(existingUser -> remoteService.updateUser(userMapper.update(existingUser, userSpec), namespace), () -> remoteService.createUser(userMapper.map(userSpec), namespace)); diff --git a/src/test/java/de/ozgcloud/operator/keycloak/user/KeycloakUserRemoteServiceTest.java b/src/test/java/de/ozgcloud/operator/keycloak/user/KeycloakUserRemoteServiceTest.java index 4f3c6c2..698c7d7 100644 --- a/src/test/java/de/ozgcloud/operator/keycloak/user/KeycloakUserRemoteServiceTest.java +++ b/src/test/java/de/ozgcloud/operator/keycloak/user/KeycloakUserRemoteServiceTest.java @@ -54,6 +54,7 @@ import org.mockito.Spy; import de.ozgcloud.operator.keycloak.KeycloakException; import de.ozgcloud.operator.keycloak.KeycloakGenericRemoteService; +import io.fabric8.kubernetes.client.KubernetesClient; class KeycloakUserRemoteServiceTest { @@ -91,6 +92,8 @@ class KeycloakUserRemoteServiceTest { private RoleMappingResource roleMappingResource; @Mock private UserRepresentation userRepresentation; + @Mock + private KubernetesClient kubernetesClient; @Nested class TestCreateUser { diff --git a/src/test/java/de/ozgcloud/operator/keycloak/user/KeycloakUserServiceTest.java b/src/test/java/de/ozgcloud/operator/keycloak/user/KeycloakUserServiceTest.java index f55c50d..3d3d0a6 100644 --- a/src/test/java/de/ozgcloud/operator/keycloak/user/KeycloakUserServiceTest.java +++ b/src/test/java/de/ozgcloud/operator/keycloak/user/KeycloakUserServiceTest.java @@ -28,6 +28,7 @@ import static org.mockito.Mockito.*; import java.util.Optional; +import org.apache.commons.lang3.StringUtils; import org.junit.jupiter.api.Nested; import org.junit.jupiter.api.Test; import org.keycloak.representations.idm.UserRepresentation; @@ -71,6 +72,18 @@ class KeycloakUserServiceTest { verify(userRemoteService).getUserByName(eq(userRepresentation.getUsername()), eq(TEST_NAMESPACE)); } + @Test + void shouldCreateSecretIfPasswordIsNotSet() { + when(userRemoteService.createSecret(any(), any())).thenReturn("TestPassword"); + + var testUser = OzgKeycloakUserSpecTestFactory.createBuilder() + .keycloakUser(KeycloakUserSpecUserTestFactory.createBuiler().password(StringUtils.EMPTY).build()).build(); + + userService.createOrUpdateUser(testUser, TEST_NAMESPACE); + + verify(userRemoteService).createSecret(testUser, TEST_NAMESPACE); + } + @Test void shouldCreateUserIfNotExists() { when(userRemoteService.getUserByName(OzgKeycloakUserSpecTestFactory.KEYCLOAK_USER.getUsername(), TEST_NAMESPACE)) diff --git a/src/test/java/de/ozgcloud/operator/keycloak/user/OzgKeycloakUserSpecTestFactory.java b/src/test/java/de/ozgcloud/operator/keycloak/user/OzgKeycloakUserSpecTestFactory.java index 1bf34b4..94ef24b 100644 --- a/src/test/java/de/ozgcloud/operator/keycloak/user/OzgKeycloakUserSpecTestFactory.java +++ b/src/test/java/de/ozgcloud/operator/keycloak/user/OzgKeycloakUserSpecTestFactory.java @@ -34,7 +34,7 @@ class OzgKeycloakUserSpecTestFactory { return createBuilder().build(); } - private static OzgKeycloakUserSpecBuilder createBuilder() { + public static OzgKeycloakUserSpecBuilder createBuilder() { return OzgKeycloakUserSpec.builder() .keycloakUser(KEYCLOAK_USER); } -- GitLab