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 43578031cef4a239b75c2968d7f1fc9112fca2d2..a0591951b94840f8c50a09adaa46b3909b6d9fa6 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 4e1d2f02fbfb611f550e9682ef5b0dedd7224d66..4430bc21802083a0f3684bda1c6f488a52ae7111 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 1f33da68e3371d2b7d6265572796ff2bdad4fa96..a66d409f402a6b68a8a085fc0aac971671c4c843 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 4f3c6c2fd5a6afe15abcb331d5bf6a2124201cf1..698c7d742c543a16415820d6f1c7068a40e14a0a 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 f55c50d6c2a6213d0658037b278fc0b049f130d4..3d3d0a6167d2054c42b6125843ddfdcd68c3529e 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 1bf34b4f8583cf867b3769277c896e2772a13081..94ef24b485a12c627d0e9fb056e499a38d6f633b 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); }