diff --git a/pom.xml b/pom.xml index d06edc1736ab30242ce2091e75b4e9991875d518..cf1ce94e22a41b506eb04d0a1923321f5178f063 100644 --- a/pom.xml +++ b/pom.xml @@ -21,7 +21,7 @@ <publishImage>false</publishImage> <build.number>SET_BY_JENKINS</build.number> <spring-cloud-config-server.version>4.1.2</spring-cloud-config-server.version> - <testcontainers-keycloak.version>3.2.0</testcontainers-keycloak.version> + <testcontainers-keycloak.version>3.4.0</testcontainers-keycloak.version> <mongock.version>5.4.0</mongock.version> <lombok-mapstruct-binding.version>0.2.0</lombok-mapstruct-binding.version> <mapstruct-processor.version>${mapstruct.version}</mapstruct-processor.version> diff --git a/src/main/java/de/ozgcloud/admin/keycloak/GroupMapper.java b/src/main/java/de/ozgcloud/admin/keycloak/GroupMapper.java index 3f2862be6c5cc756253d5e20c43d887aa24a001a..a36e5cdb894fc90dd6c3f398d6d1df300e61bbe5 100644 --- a/src/main/java/de/ozgcloud/admin/keycloak/GroupMapper.java +++ b/src/main/java/de/ozgcloud/admin/keycloak/GroupMapper.java @@ -1,9 +1,11 @@ package de.ozgcloud.admin.keycloak; import java.util.List; +import java.util.Map; import org.keycloak.representations.idm.GroupRepresentation; import org.mapstruct.Mapper; +import org.mapstruct.Mapping; import org.mapstruct.NullValueCheckStrategy; @Mapper(nullValueCheckStrategy = NullValueCheckStrategy.ALWAYS) @@ -11,6 +13,10 @@ interface GroupMapper { List<Group> fromGroupRepresentations(List<GroupRepresentation> groupRepresentations); - + @Mapping(target = "organisationsEinheitId", source = "attributes") Group fromGroupRepresentation(GroupRepresentation groupRepresentation); + + default String getOrganisationsEinheitId(Map<String, List<String>> attributes) { + return "dummy"; + } } diff --git a/src/main/java/de/ozgcloud/admin/keycloak/KeycloakConfiguration.java b/src/main/java/de/ozgcloud/admin/keycloak/KeycloakConfiguration.java index 3406a5a7799d702c610ff42c6a488794c8c172b2..06929b833bebe100f6839f3cf308227dd103c638 100644 --- a/src/main/java/de/ozgcloud/admin/keycloak/KeycloakConfiguration.java +++ b/src/main/java/de/ozgcloud/admin/keycloak/KeycloakConfiguration.java @@ -35,8 +35,6 @@ import lombok.RequiredArgsConstructor; @RequiredArgsConstructor public class KeycloakConfiguration { - private static final String CLIENT = "admin-cli"; - private final KeycloakApiProperties keycloakApiProperties; @Bean @@ -53,7 +51,7 @@ public class KeycloakConfiguration { return KeycloakBuilder.builder() .serverUrl(keycloakApiProperties.getUrl()) .realm(keycloakApiProperties.getRealm()) - .clientId(CLIENT) + .clientId(keycloakApiProperties.getClient()) .username(keycloakApiProperties.getUser()) .password(keycloakApiProperties.getPassword()) .build(); diff --git a/src/main/java/de/ozgcloud/admin/keycloak/KeycloakRemoteService.java b/src/main/java/de/ozgcloud/admin/keycloak/KeycloakRemoteService.java index c1e7db460923dd22c03aabc35d6cfa578261b32f..bca5221953c84c5d9a203722f7d314fb480f9057 100644 --- a/src/main/java/de/ozgcloud/admin/keycloak/KeycloakRemoteService.java +++ b/src/main/java/de/ozgcloud/admin/keycloak/KeycloakRemoteService.java @@ -1,8 +1,10 @@ package de.ozgcloud.admin.keycloak; +import java.util.List; import java.util.stream.Stream; import org.keycloak.admin.client.resource.RealmResource; +import org.keycloak.representations.idm.GroupRepresentation; import org.springframework.stereotype.Service; import lombok.RequiredArgsConstructor; @@ -17,4 +19,13 @@ public class KeycloakRemoteService { // realmResource.groups().groups(); return Stream.empty(); } + + // TODO: only for research + public List<GroupRepresentation> getGroupRepresentations() { + return realmResource.groups().groups(); + } + + public GroupRepresentation getGroupRepresentation(String id) { + return realmResource.groups().group(id).toRepresentation(); + } } diff --git a/src/main/resources/application-remotekc.yaml b/src/main/resources/application-remotekc.yaml index da5346a44342a8e6e74c9059746416003e7a2eeb..f31f6ab8e2a730b8fa28f55a9f45fc3ab22c9aae 100644 --- a/src/main/resources/application-remotekc.yaml +++ b/src/main/resources/application-remotekc.yaml @@ -5,4 +5,4 @@ ozgcloud: resource: admin keycloak: api: - url: ${auth-server-url} \ No newline at end of file + url: ${ozgcloud.oauth2.auth-server-url} \ No newline at end of file diff --git a/src/main/resources/application.yaml b/src/main/resources/application.yaml index 527ecc910f77c85c3f35149f595c4f8375a4aed9..53c18301fcdaa44a200e94c0b22c95a178713b31 100644 --- a/src/main/resources/application.yaml +++ b/src/main/resources/application.yaml @@ -78,7 +78,7 @@ ozgcloud: api: ldap-id-key: LDAP_ID organisations-einheit-id-key: organisationseinheitId - user: userManagerApiUser - password: userManagerApiUser + user: administrationApiUser + password: administrationApiUser realm: by-kiel-dev - client: alfa \ No newline at end of file + client: admin-cli \ No newline at end of file diff --git a/src/test/java/de/ozgcloud/admin/common/KeycloakInitializer.java b/src/test/java/de/ozgcloud/admin/common/KeycloakInitializer.java new file mode 100644 index 0000000000000000000000000000000000000000..3cf919b51996d6d932b5fc51c0ba4079cbb9d563 --- /dev/null +++ b/src/test/java/de/ozgcloud/admin/common/KeycloakInitializer.java @@ -0,0 +1,47 @@ +package de.ozgcloud.admin.common; + +import java.time.Duration; + +import org.springframework.boot.test.util.TestPropertyValues; +import org.springframework.context.ApplicationContextInitializer; +import org.springframework.context.ConfigurableApplicationContext; +import org.testcontainers.containers.wait.strategy.Wait; + +import dasniko.testcontainers.keycloak.KeycloakContainer; +import lombok.extern.log4j.Log4j2; + +@Log4j2 +public class KeycloakInitializer implements ApplicationContextInitializer<ConfigurableApplicationContext> { + + private static final String AUTH_SERVER_URL = "ozgcloud.oauth2.auth-server-url"; + + private static KeycloakContainer keycloakContainer; + + @Override + public void initialize(ConfigurableApplicationContext applicationContext) { + initContainer(); + setProperties(applicationContext); + } + + @SuppressWarnings("resource") + private void initContainer() { + if (keycloakContainer == null) { + log.info("Creating Keycloak-container..."); + keycloakContainer = new KeycloakContainer().withRealmImportFile("keycloak/realm-export.json").withVerboseOutput(); + } + if (!keycloakContainer.isRunning()) { + log.info("Starting Keycloak-container..."); + keycloakContainer.setWaitStrategy( + Wait.forLogMessage(".*message\":\"started.*", 1).withStartupTimeout(Duration.ofMinutes(3))); + keycloakContainer.start(); + log.info("Keycloak-container started"); + } + } + + private void setProperties(ConfigurableApplicationContext applicationContext) { + log.info("Keycloak URL: {}", keycloakContainer.getAuthServerUrl()); + + TestPropertyValues.of(AUTH_SERVER_URL + "=" + keycloakContainer.getAuthServerUrl()).applyTo(applicationContext); + + } +} diff --git a/src/test/java/de/ozgcloud/admin/keycloak/KeycloakRemoteServiceITCase.java b/src/test/java/de/ozgcloud/admin/keycloak/KeycloakRemoteServiceITCase.java new file mode 100644 index 0000000000000000000000000000000000000000..3fb7597d6f3e2f13ce87710e91d2b45ea40bb349 --- /dev/null +++ b/src/test/java/de/ozgcloud/admin/keycloak/KeycloakRemoteServiceITCase.java @@ -0,0 +1,37 @@ +package de.ozgcloud.admin.keycloak; + +import static org.assertj.core.api.Assertions.*; + +import org.junit.jupiter.api.Nested; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.test.context.ContextConfiguration; + +import de.ozgcloud.admin.common.KeycloakInitializer; +import de.ozgcloud.common.test.ITCase; + +@ITCase +@ContextConfiguration(initializers = KeycloakInitializer.class) +class KeycloakRemoteServiceITCase { + + @Autowired + private KeycloakRemoteService service; + + @Nested + class TestGetGroupRepresentations { + + @Test + void shouldReturnGroupRepresentations() { + var result = service.getGroupRepresentations(); + + assertThat(result).hasSize(6); + } + + @Test + void shouldReturnAttributes() { + var result = service.getGroupRepresentation("94f0562a-cb66-41a5-96c9-a984f0bee3ec"); + + assertThat(result.getAttributes().get("organisationseinheitId").getFirst()).isEqualTo("248240886"); + } + } +} diff --git a/src/test/resources/application-itcase.yaml b/src/test/resources/application-itcase.yaml index 5ef65dbc4d2c1a977a1f0232598477f4778df149..e1d232df76a4f7f98b4e114fd591afb40f84d513 100644 --- a/src/test/resources/application-itcase.yaml +++ b/src/test/resources/application-itcase.yaml @@ -8,4 +8,4 @@ ozgcloud: resource: admin keycloak: api: - url: ${auth-server-url} + url: ${ozgcloud.oauth2.auth-server-url} diff --git a/src/test/resources/keycloak/realm-export.json b/src/test/resources/keycloak/realm-export.json index 1a35e536dee166f56fe2a5b52dd5d6cb3452e21c..63f0d9bc8a233edde4e593c2269adbd2977557b1 100755 --- a/src/test/resources/keycloak/realm-export.json +++ b/src/test/resources/keycloak/realm-export.json @@ -44,6 +44,86 @@ "quickLoginCheckMilliSeconds": 1000, "maxDeltaTimeSeconds": 43200, "failureFactor": 30, + "groups": [ + { + "id": "94f0562a-cb66-41a5-96c9-a984f0bee3ec", + "name": "Bauamt", + "path": "/Bauamt", + "subGroups": [], + "attributes": { + "organisationseinheitId": [ + "248240886" + ] + }, + "realmRoles": [], + "clientRoles": {} + }, + { + "id": "bfd284be-9d30-4e9a-82d2-daf9ac6593b6", + "name": "Denkmalpflege", + "path": "/Denkmalpflege", + "subGroups": [], + "attributes": { + "organisationseinheitId": [ + "9093371" + ] + }, + "realmRoles": [], + "clientRoles": {} + }, + { + "id": "e80b596b-7559-4437-8349-4732ac567d15", + "name": "Fundstelle", + "path": "/Fundstelle", + "subGroups": [], + "attributes": { + "organisationseinheitId": [ + "10363455" + ] + }, + "realmRoles": [], + "clientRoles": {} + }, + { + "id": "ffad390f-00c0-4459-9512-eb1f4be3631e", + "name": "Landesamt für Denkmalpflege", + "path": "/Landesamt für Denkmalpflege", + "subGroups": [], + "attributes": { + "organisationseinheitId": [ + "9093371" + ] + }, + "realmRoles": [], + "clientRoles": {} + }, + { + "id": "155b4752-bbc3-4c6a-afa7-7769f1b2ea8a", + "name": "Ordnungsamt", + "path": "/Ordnungsamt", + "subGroups": [], + "attributes": { + "organisationseinheitId": [ + "9030229" + ] + }, + "realmRoles": [], + "clientRoles": {} + }, + { + "id": "53c11c42-9f8e-4cbc-b6da-1c1ff2d46187", + "name": "Wirtschaftsförderung", + "path": "/Wirtschaftsförderung", + "subGroups": [], + "attributes": { + "organisationseinheitId": [ + "9797773" + ] + }, + "realmRoles": [], + "clientRoles": {} + } + ], "defaultRole": { "id": "dd27b699-836d-4ed8-9111-ee34acbaf5ce", "name": "default-roles-by-kiel-dev", @@ -2037,16 +2117,20 @@ }, "users": [ { - "username": "admin-test", + "id": "b46def26-a599-4940-a32f-e070c478750d", + "username": "administrationApiUser", "firstName": "Vorname", "lastName": "Nachname", "enabled": true, "credentials": [ { "type": "password", - "value": "Password" + "value": "administrationApiUser" } - ] + ], + "clientRoles" : { + "realm-management" : [ "view-users" ] + } } ] } \ No newline at end of file