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 33f5fc1872811de49114b03528820dc91d9bd829..50eba9211bacd3a0fd87e0529147f14e3c611403 100644 --- a/src/main/java/de/ozgcloud/operator/keycloak/client/KeycloakClientService.java +++ b/src/main/java/de/ozgcloud/operator/keycloak/client/KeycloakClientService.java @@ -68,7 +68,11 @@ class KeycloakClientService { } void setProtocolMapper(ClientRepresentation clientRepresentation) { - clientRepresentation.setProtocolMappers(List.of(mapperRepresentationBuilder.createOrganisationsEinheitIdMapper())); + clientRepresentation.setProtocolMappers(List.of( + mapperRepresentationBuilder.createOrganisationsEinheitIdMapper(), + mapperRepresentationBuilder.createOzgCloudUserIdMapper(), + mapperRepresentationBuilder.createOrganisationeEinheitIdLdapMapper(), + mapperRepresentationBuilder.createClientRolesMapper())); } void addOrUpdateClientRoles(OzgKeycloakClientSpec spec, String realm, String realClientId) { diff --git a/src/main/java/de/ozgcloud/operator/keycloak/client/ProtocolMapperRepresentationHelper.java b/src/main/java/de/ozgcloud/operator/keycloak/client/ProtocolMapperRepresentationHelper.java index 170da5a14bd1d00145fe5a1b386d68fc64bb0bdc..fd19aacfcc887d720e06676ef5765e143ce5f960 100644 --- a/src/main/java/de/ozgcloud/operator/keycloak/client/ProtocolMapperRepresentationHelper.java +++ b/src/main/java/de/ozgcloud/operator/keycloak/client/ProtocolMapperRepresentationHelper.java @@ -4,6 +4,7 @@ import java.util.HashMap; import java.util.Map; import java.util.logging.Level; +import org.apache.commons.lang3.StringUtils; import org.keycloak.representations.idm.ProtocolMapperRepresentation; import org.springframework.stereotype.Component; @@ -14,7 +15,9 @@ import lombok.extern.java.Log; class ProtocolMapperRepresentationHelper { static final String OPENID_CONNECT_PROTOCOL = "openid-connect"; - static final String ATTRIBUTE_PROTOCOL_MAPPER = "oidc-usermodel-attribute-mapper"; + + static final String USER_ATTRIBUTE_PROTOCOL_MAPPER = "oidc-usermodel-attribute-mapper"; + static final String USER_CLIENT_ROLE_PROTOCOL_MAPPER = "oidc-usermodel-client-role-mapper"; static final String CONFIG_ACCESS_TOKEN_CLAIM_KEY = "access.token.claim"; static final String CONFIG_AGGREGATE_ATTRS_KEY = "aggregate.attrs"; @@ -25,29 +28,102 @@ class ProtocolMapperRepresentationHelper { static final String CONFIG_USER_ATTRIBUTE_KEY = "user.attribute"; static final String CONFIG_USERINFO_TOKEN_CLAIM_KEY = "userinfo.token.claim"; + static final String CONFIG_USER_MODEL_CLIENT_ROLE_MAPPING_CLIENT_ID = "usermodel.clientRoleMapping.clientId"; + static final String CONFIG_USER_MODEL_CLIENT_ROLE_MAPPING_ROLE_PREFIX = "usermodel.clientRoleMapping.rolePrefix"; + static final String ORGANISATIONS_EINHEIT_ID_MAPPER_NAME = "organisationseinheitIdMapper"; + static final String OZGCLOUD_USER_ID_MAPPER_NAME = "ozgCloudUserId"; + static final String ORGANISATIONS_EINHEIT_ID_LDAP_MAPPER_NAME = "organisationseinheitIdLdapMapper"; + static final String CLIENT_ROLES_MAPPER_NAME = "client roles"; public ProtocolMapperRepresentation createOrganisationsEinheitIdMapper() { - log.log(Level.FINE, "Build organisationsEinheitId mapper..."); + log.log(Level.FINE, "Create createOrganisationsEinheitIdMapper..."); + return createUserAttributeMapper(ORGANISATIONS_EINHEIT_ID_MAPPER_NAME, buildOrganisationsEinheitMapperConfig()); + } + + Map<String, String> buildOrganisationsEinheitMapperConfig() { + var config = new HashMap<String, String>(); + config.put(CONFIG_ACCESS_TOKEN_CLAIM_KEY, "true"); + config.put(CONFIG_AGGREGATE_ATTRS_KEY, "true"); + config.put(CONFIG_CLAIM_NAME_KEY, "organisationseinheitId"); + config.put(CONFIG_ID_TOKEN_CLAIM_KEY, "true"); + config.put(CONFIG_JSON_TYPE_LABEL_KEY, "int"); + config.put(CONFIG_MULTIVALUED_KEY, "true"); + config.put(CONFIG_USER_ATTRIBUTE_KEY, "organisationseinheitId"); + config.put(CONFIG_USERINFO_TOKEN_CLAIM_KEY, "true"); + return config; + } + + public ProtocolMapperRepresentation createOzgCloudUserIdMapper() { + log.log(Level.FINE, "Create createOzgCloudUserIdMapper..."); + return createUserAttributeMapper(OZGCLOUD_USER_ID_MAPPER_NAME, buildOzgCloudUserIdMapperConfig()); + } + + Map<String, String> buildOzgCloudUserIdMapperConfig() { + var config = new HashMap<String, String>(); + config.put(CONFIG_ACCESS_TOKEN_CLAIM_KEY, "true"); + config.put(CONFIG_AGGREGATE_ATTRS_KEY, "false"); + config.put(CONFIG_CLAIM_NAME_KEY, "ozgCloudUserId"); + config.put(CONFIG_ID_TOKEN_CLAIM_KEY, "true"); + config.put(CONFIG_JSON_TYPE_LABEL_KEY, StringUtils.EMPTY); + config.put(CONFIG_MULTIVALUED_KEY, "false"); + config.put(CONFIG_USER_ATTRIBUTE_KEY, "ozgCloudUserId"); + config.put(CONFIG_USERINFO_TOKEN_CLAIM_KEY, "true"); + return config; + } + + public ProtocolMapperRepresentation createOrganisationeEinheitIdLdapMapper() { + log.log(Level.FINE, "Create createOrganisationeEinheitIdLdapMapper..."); + return createUserAttributeMapper(ORGANISATIONS_EINHEIT_ID_LDAP_MAPPER_NAME, buildOrganisationsEinheitIdLdapMapperConfig()); + } + + private ProtocolMapperRepresentation createUserAttributeMapper(String name, Map<String, String> config) { var mapper = new ProtocolMapperRepresentation(); - mapper.setName(ORGANISATIONS_EINHEIT_ID_MAPPER_NAME); + mapper.setName(name); mapper.setProtocol(OPENID_CONNECT_PROTOCOL); - mapper.setProtocolMapper(ATTRIBUTE_PROTOCOL_MAPPER); - mapper.setConfig(buildOrganisationsEinheitMapperConfig()); + mapper.setProtocolMapper(USER_ATTRIBUTE_PROTOCOL_MAPPER); + mapper.setConfig(config); return mapper; } - Map<String, String> buildOrganisationsEinheitMapperConfig() { + Map<String, String> buildOrganisationsEinheitIdLdapMapperConfig() { var config = new HashMap<String, String>(); config.put(CONFIG_ACCESS_TOKEN_CLAIM_KEY, "true"); - config.put(CONFIG_AGGREGATE_ATTRS_KEY, "true"); + config.put(CONFIG_AGGREGATE_ATTRS_KEY, "false"); config.put(CONFIG_CLAIM_NAME_KEY, "organisationseinheitId"); config.put(CONFIG_ID_TOKEN_CLAIM_KEY, "true"); config.put(CONFIG_JSON_TYPE_LABEL_KEY, "int"); config.put(CONFIG_MULTIVALUED_KEY, "true"); - config.put(CONFIG_USER_ATTRIBUTE_KEY, "organisationseinheitId"); + config.put(CONFIG_USER_ATTRIBUTE_KEY, "extensionAttribute1"); config.put(CONFIG_USERINFO_TOKEN_CLAIM_KEY, "true"); return config; } + + public ProtocolMapperRepresentation createClientRolesMapper() { + log.log(Level.FINE, "Create createClientRolesMapper..."); + return createUserClientRoleMapper(CLIENT_ROLES_MAPPER_NAME, buildClientRolesMapperConfig()); + } + + private ProtocolMapperRepresentation createUserClientRoleMapper(String name, Map<String, String> config) { + var mapper = new ProtocolMapperRepresentation(); + mapper.setName(name); + mapper.setProtocol(OPENID_CONNECT_PROTOCOL); + mapper.setProtocolMapper(USER_CLIENT_ROLE_PROTOCOL_MAPPER); + mapper.setConfig(config); + + return mapper; + } + + Map<String, String> buildClientRolesMapperConfig() { + var config = new HashMap<String, String>(); + config.put(CONFIG_ACCESS_TOKEN_CLAIM_KEY, "true"); + config.put(CONFIG_CLAIM_NAME_KEY, "resource_access.${client_id}.roles"); + config.put(CONFIG_ID_TOKEN_CLAIM_KEY, "false"); + config.put(CONFIG_JSON_TYPE_LABEL_KEY, StringUtils.EMPTY); + config.put(CONFIG_MULTIVALUED_KEY, "true"); + config.put(CONFIG_USER_MODEL_CLIENT_ROLE_MAPPING_CLIENT_ID, StringUtils.EMPTY); + config.put(CONFIG_USER_MODEL_CLIENT_ROLE_MAPPING_ROLE_PREFIX, StringUtils.EMPTY); + return config; + } } \ No newline at end of file diff --git a/src/test/java/de/ozgcloud/operator/keycloak/client/KeycloakClientServiceTest.java b/src/test/java/de/ozgcloud/operator/keycloak/client/KeycloakClientServiceTest.java index 299547392089d0e6823957391255e581fb159567..33c455f991e9b7ec5b382c61c85fd7806689b6d3 100644 --- a/src/test/java/de/ozgcloud/operator/keycloak/client/KeycloakClientServiceTest.java +++ b/src/test/java/de/ozgcloud/operator/keycloak/client/KeycloakClientServiceTest.java @@ -139,24 +139,92 @@ class KeycloakClientServiceTest { private final ClientRepresentation clientRepresentation = ClientRepresentationTestFactory.create(); private final ProtocolMapperRepresentation organisationsEinheitIdMapper = ProtocolMapperRepresentationTestFactory.create(); + private final ProtocolMapperRepresentation ozgCloudUserIdMapper = ProtocolMapperRepresentationTestFactory.create(); + private final ProtocolMapperRepresentation organisationeEinheitIdLdapMapper = ProtocolMapperRepresentationTestFactory.create(); + private final ProtocolMapperRepresentation clientRolesMapper = ProtocolMapperRepresentationTestFactory.create(); @BeforeEach void mockMapperHelper() { when(mapperHelper.createOrganisationsEinheitIdMapper()).thenReturn(organisationsEinheitIdMapper); + when(mapperHelper.createOzgCloudUserIdMapper()).thenReturn(ozgCloudUserIdMapper); + when(mapperHelper.createOrganisationeEinheitIdLdapMapper()).thenReturn(organisationeEinheitIdLdapMapper); + when(mapperHelper.createClientRolesMapper()).thenReturn(clientRolesMapper); } - @Test - void shouldCreateOrganisationsEinheitIdMapper() { - service.setProtocolMapper(clientRepresentation); + @DisplayName("organisationsEinheitId") + @Nested + class TestOrganisationsEinheitIdMapper { + + @Test + void shouldBeCreated() { + service.setProtocolMapper(clientRepresentation); + + verify(mapperHelper).createOrganisationsEinheitIdMapper(); + } - verify(mapperHelper).createOrganisationsEinheitIdMapper(); + @Test + void shouldBeSet() { + service.setProtocolMapper(clientRepresentation); + + assertThat(clientRepresentation.getProtocolMappers()).contains(organisationsEinheitIdMapper); + } } - @Test - void shouldSetOrganisationsEinheitIdMapper() { - service.setProtocolMapper(clientRepresentation); + @DisplayName("ozgCloudUserId") + @Nested + class TestOzgCloudUserIdMapper { + + @Test + void shouldBeCreated() { + service.setProtocolMapper(clientRepresentation); + + verify(mapperHelper).createOzgCloudUserIdMapper(); + } + + @Test + void shouldBeSet() { + service.setProtocolMapper(clientRepresentation); + + assertThat(clientRepresentation.getProtocolMappers()).contains(ozgCloudUserIdMapper); + } + } + + @DisplayName("organisationsEinheitIdLdap") + @Nested + class TestOrganisationsEinheitIdLdapMapper { + + @Test + void shouldBeCreated() { + service.setProtocolMapper(clientRepresentation); + + verify(mapperHelper).createOrganisationeEinheitIdLdapMapper(); + } + + @Test + void shouldBeSet() { + service.setProtocolMapper(clientRepresentation); + + assertThat(clientRepresentation.getProtocolMappers()).contains(organisationeEinheitIdLdapMapper); + } + } + + @DisplayName("client roles") + @Nested + class TestClientRolesMapper { + + @Test + void shouldBeCreated() { + service.setProtocolMapper(clientRepresentation); + + verify(mapperHelper).createClientRolesMapper(); + } + + @Test + void shouldBeSet() { + service.setProtocolMapper(clientRepresentation); - assertThat(clientRepresentation.getProtocolMappers()).contains(organisationsEinheitIdMapper); + assertThat(clientRepresentation.getProtocolMappers()).contains(clientRolesMapper); + } } } diff --git a/src/test/java/de/ozgcloud/operator/keycloak/client/ProtocolMapperRepresentationHelperTest.java b/src/test/java/de/ozgcloud/operator/keycloak/client/ProtocolMapperRepresentationHelperTest.java index a60e6809a30e238c9c8934bca51dfdd94ccff610..f2981c96fb544c39756c852f8371dfec53bd7fb9 100644 --- a/src/test/java/de/ozgcloud/operator/keycloak/client/ProtocolMapperRepresentationHelperTest.java +++ b/src/test/java/de/ozgcloud/operator/keycloak/client/ProtocolMapperRepresentationHelperTest.java @@ -5,6 +5,7 @@ import static org.mockito.Mockito.*; import java.util.Map; +import org.apache.commons.lang3.StringUtils; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Nested; import org.junit.jupiter.api.Test; @@ -38,7 +39,7 @@ class ProtocolMapperRepresentationHelperTest { void shouldSetProtocolMapper() { var mapper = create(); - assertThat(mapper.getProtocolMapper()).isEqualTo(ProtocolMapperRepresentationHelper.ATTRIBUTE_PROTOCOL_MAPPER); + assertThat(mapper.getProtocolMapper()).isEqualTo(ProtocolMapperRepresentationHelper.USER_ATTRIBUTE_PROTOCOL_MAPPER); } @Test @@ -117,4 +118,305 @@ class ProtocolMapperRepresentationHelperTest { return helper.createOrganisationsEinheitIdMapper(); } } + + @DisplayName("Create ozgCloudUserId mapper") + @Nested + class TestCreateOzgCloudUserIdMapper { + + @Test + void shouldSetName() { + var mapper = create(); + + assertThat(mapper.getName()).isEqualTo(ProtocolMapperRepresentationHelper.OZGCLOUD_USER_ID_MAPPER_NAME); + } + + @Test + void shouldSetProtocol() { + var mapper = create(); + + assertThat(mapper.getProtocol()).isEqualTo(ProtocolMapperRepresentationHelper.OPENID_CONNECT_PROTOCOL); + } + + @Test + void shouldSetProtocolMapper() { + var mapper = create(); + + assertThat(mapper.getProtocolMapper()).isEqualTo(ProtocolMapperRepresentationHelper.USER_ATTRIBUTE_PROTOCOL_MAPPER); + } + + @Test + void shouldBuildConfig() { + create(); + + verify(helper).buildOzgCloudUserIdMapperConfig(); + } + + @DisplayName("build config") + @Nested + class TestBuildOrganisationsEinheitIdConfig { + + @Test + void shouldSetAccessTokenClaim() { + var config = buildConfig(); + + assertThat(config).containsEntry(ProtocolMapperRepresentationHelper.CONFIG_ACCESS_TOKEN_CLAIM_KEY, "true"); + } + + @Test + void shouldSetAggregateAttrs() { + var config = buildConfig(); + + assertThat(config).containsEntry(ProtocolMapperRepresentationHelper.CONFIG_AGGREGATE_ATTRS_KEY, "false"); + } + + @Test + void shouldSetClaimName() { + var config = buildConfig(); + + assertThat(config).containsEntry(ProtocolMapperRepresentationHelper.CONFIG_CLAIM_NAME_KEY, "ozgCloudUserId"); + } + + @Test + void shouldSetIdTokenClaim() { + var config = buildConfig(); + + assertThat(config).containsEntry(ProtocolMapperRepresentationHelper.CONFIG_ID_TOKEN_CLAIM_KEY, "true"); + } + + @Test + void shouldSetJsonTypeLabel() { + var config = buildConfig(); + + assertThat(config).containsEntry(ProtocolMapperRepresentationHelper.CONFIG_JSON_TYPE_LABEL_KEY, StringUtils.EMPTY); + } + + @Test + void shouldSetMultivalued() { + var config = buildConfig(); + + assertThat(config).containsEntry(ProtocolMapperRepresentationHelper.CONFIG_MULTIVALUED_KEY, "false"); + } + + @Test + void shouldSetUserAttribute() { + var config = buildConfig(); + + assertThat(config).containsEntry(ProtocolMapperRepresentationHelper.CONFIG_USER_ATTRIBUTE_KEY, "ozgCloudUserId"); + } + + @Test + void shouldSetUserInfoTokenClaim() { + var config = buildConfig(); + + assertThat(config).containsEntry(ProtocolMapperRepresentationHelper.CONFIG_USERINFO_TOKEN_CLAIM_KEY, "true"); + } + + private Map<String, String> buildConfig() { + return helper.buildOzgCloudUserIdMapperConfig(); + } + } + + private ProtocolMapperRepresentation create() { + return helper.createOzgCloudUserIdMapper(); + } + } + + @DisplayName("Create organisationsEinheitIdLdap mapper") + @Nested + class TestCreateOrganisationsEinheitIdLdapMapper { + + @Test + void shouldSetName() { + var mapper = create(); + + assertThat(mapper.getName()).isEqualTo(ProtocolMapperRepresentationHelper.ORGANISATIONS_EINHEIT_ID_LDAP_MAPPER_NAME); + } + + @Test + void shouldSetProtocol() { + var mapper = create(); + + assertThat(mapper.getProtocol()).isEqualTo(ProtocolMapperRepresentationHelper.OPENID_CONNECT_PROTOCOL); + } + + @Test + void shouldSetProtocolMapper() { + var mapper = create(); + + assertThat(mapper.getProtocolMapper()).isEqualTo(ProtocolMapperRepresentationHelper.USER_ATTRIBUTE_PROTOCOL_MAPPER); + } + + @Test + void shouldBuildConfig() { + create(); + + verify(helper).buildOrganisationsEinheitIdLdapMapperConfig(); + } + + @DisplayName("build config") + @Nested + class TestBuildOrganisationsEinheitIdConfig { + + @Test + void shouldSetAccessTokenClaim() { + var config = buildConfig(); + + assertThat(config).containsEntry(ProtocolMapperRepresentationHelper.CONFIG_ACCESS_TOKEN_CLAIM_KEY, "true"); + } + + @Test + void shouldSetAggregateAttrs() { + var config = buildConfig(); + + assertThat(config).containsEntry(ProtocolMapperRepresentationHelper.CONFIG_AGGREGATE_ATTRS_KEY, "false"); + } + + @Test + void shouldSetClaimName() { + var config = buildConfig(); + + assertThat(config).containsEntry(ProtocolMapperRepresentationHelper.CONFIG_CLAIM_NAME_KEY, "organisationseinheitId"); + } + + @Test + void shouldSetIdTokenClaim() { + var config = buildConfig(); + + assertThat(config).containsEntry(ProtocolMapperRepresentationHelper.CONFIG_ID_TOKEN_CLAIM_KEY, "true"); + } + + @Test + void shouldSetJsonTypeLabel() { + var config = buildConfig(); + + assertThat(config).containsEntry(ProtocolMapperRepresentationHelper.CONFIG_JSON_TYPE_LABEL_KEY, "int"); + } + + @Test + void shouldSetMultivalued() { + var config = buildConfig(); + + assertThat(config).containsEntry(ProtocolMapperRepresentationHelper.CONFIG_MULTIVALUED_KEY, "true"); + } + + @Test + void shouldSetUserAttribute() { + var config = buildConfig(); + + assertThat(config).containsEntry(ProtocolMapperRepresentationHelper.CONFIG_USER_ATTRIBUTE_KEY, "extensionAttribute1"); + } + + @Test + void shouldSetUserInfoTokenClaim() { + var config = buildConfig(); + + assertThat(config).containsEntry(ProtocolMapperRepresentationHelper.CONFIG_USERINFO_TOKEN_CLAIM_KEY, "true"); + } + + private Map<String, String> buildConfig() { + return helper.buildOrganisationsEinheitIdLdapMapperConfig(); + } + } + + private ProtocolMapperRepresentation create() { + return helper.createOrganisationeEinheitIdLdapMapper(); + } + } + + @DisplayName("Create clientRoles mapper") + @Nested + class TestCreateClientRolesMapper { + + @Test + void shouldSetName() { + var mapper = create(); + + assertThat(mapper.getName()).isEqualTo(ProtocolMapperRepresentationHelper.CLIENT_ROLES_MAPPER_NAME); + } + + @Test + void shouldSetProtocol() { + var mapper = create(); + + assertThat(mapper.getProtocol()).isEqualTo(ProtocolMapperRepresentationHelper.OPENID_CONNECT_PROTOCOL); + } + + @Test + void shouldSetProtocolMapper() { + var mapper = create(); + + assertThat(mapper.getProtocolMapper()).isEqualTo(ProtocolMapperRepresentationHelper.USER_CLIENT_ROLE_PROTOCOL_MAPPER); + } + + @Test + void shouldBuildConfig() { + create(); + + verify(helper).buildClientRolesMapperConfig(); + } + + @DisplayName("build config") + @Nested + class TestBuildOrganisationsEinheitIdConfig { + + @Test + void shouldSetAccessTokenClaim() { + var config = buildConfig(); + + assertThat(config).containsEntry(ProtocolMapperRepresentationHelper.CONFIG_ACCESS_TOKEN_CLAIM_KEY, "true"); + } + + @Test + void shouldSetClaimName() { + var config = buildConfig(); + + assertThat(config).containsEntry(ProtocolMapperRepresentationHelper.CONFIG_CLAIM_NAME_KEY, "resource_access.${client_id}.roles"); + } + + @Test + void shouldSetIdTokenClaim() { + var config = buildConfig(); + + assertThat(config).containsEntry(ProtocolMapperRepresentationHelper.CONFIG_ID_TOKEN_CLAIM_KEY, "false"); + } + + @Test + void shouldSetJsonTypeLabel() { + var config = buildConfig(); + + assertThat(config).containsEntry(ProtocolMapperRepresentationHelper.CONFIG_JSON_TYPE_LABEL_KEY, StringUtils.EMPTY); + } + + @Test + void shouldSetMultivalued() { + var config = buildConfig(); + + assertThat(config).containsEntry(ProtocolMapperRepresentationHelper.CONFIG_MULTIVALUED_KEY, "true"); + } + + @Test + void shouldSetUserModelClientRoleMappingClientId() { + var config = buildConfig(); + + assertThat(config).containsEntry(ProtocolMapperRepresentationHelper.CONFIG_USER_MODEL_CLIENT_ROLE_MAPPING_CLIENT_ID, + StringUtils.EMPTY); + } + + @Test + void shouldSetUserModelClientRoleMappingRolePrefix() { + var config = buildConfig(); + + assertThat(config).containsEntry(ProtocolMapperRepresentationHelper.CONFIG_USER_MODEL_CLIENT_ROLE_MAPPING_ROLE_PREFIX, + StringUtils.EMPTY); + } + + private Map<String, String> buildConfig() { + return helper.buildClientRolesMapperConfig(); + } + } + + private ProtocolMapperRepresentation create() { + return helper.createClientRolesMapper(); + } + } }