diff --git a/build-native-local-docker-image.sh b/build-native-local-docker-image.sh index 7f1e202cbe5cb164e8216d35972bb4f735aa24e2..e65bf55cd272e2640ca330ead957529cb9e6572c 100755 --- a/build-native-local-docker-image.sh +++ b/build-native-local-docker-image.sh @@ -1,5 +1,8 @@ #!/usr/bin/env bash +export QUARKUS_CONTAINER_IMAGE_NAME=user-manager +export QUARKUS_CONTAINER_IMAGE_TAG=build-latest +export QUARKUS_NATIVE_CONTAINER_RUNTIME=docker cd user-manager-server ./mvnw clean install -D skipTests \ -Pnative \ diff --git a/user-manager-server/src/main/java/de/itvsh/kop/user/keycloak/KeycloakApiService.java b/user-manager-server/src/main/java/de/itvsh/kop/user/keycloak/KeycloakApiService.java index 1d0bb8ef1530e64cc59beed31409170859e68401..bf13b2244deff9f3f6402984f1c75c91b374034c 100644 --- a/user-manager-server/src/main/java/de/itvsh/kop/user/keycloak/KeycloakApiService.java +++ b/user-manager-server/src/main/java/de/itvsh/kop/user/keycloak/KeycloakApiService.java @@ -45,6 +45,7 @@ import de.itvsh.kop.common.logging.KopLogging; import de.itvsh.kop.user.RemoteUserIterator; import de.itvsh.kop.user.User; import de.itvsh.kop.user.UserResourceMapper; +import de.itvsh.kop.user.common.errorhandling.KeycloakUnavailableException; import lombok.extern.log4j.Log4j2; @ApplicationScoped @@ -86,17 +87,8 @@ class KeycloakApiService { <T> T handlingKeycloakException(Supplier<T> runnable) { try { return runnable.get(); - } catch (ClientErrorException e) { - // throw new KeycloakUnavailableException(properties.user(), properties.realm(), keycloakUrl, e); - LOG.error("client error with status {} and message {}: {} / ", e.getMessage(), e.getResponse().getStatus(), e.getResponse().getEntity() - , e); - throw e; - } catch (ProcessingException e) { - LOG.error("error processing request or response ", e.getMessage(), e); - throw e; - } catch (IllegalStateException e) { - LOG.error("illegal state ", e.getMessage(), e); - throw e; + } catch (ClientErrorException | ProcessingException | IllegalStateException e) { + throw new KeycloakUnavailableException(properties.user(), properties.realm(), keycloakUrl, e); } } @@ -110,7 +102,7 @@ class KeycloakApiService { } } - private void tryUpdateUserResource(UserResource userResource, UserRepresentation userRepresentation, String attributeName) { + void tryUpdateUserResource(UserResource userResource, UserRepresentation userRepresentation, String attributeName) { try { userResource.update(new OlderUserRepresentation(userRepresentation)); } catch (BadRequestException e) { diff --git a/user-manager-server/src/test/java/de/itvsh/kop/user/keycloak/KeycloakApiServiceTest.java b/user-manager-server/src/test/java/de/itvsh/kop/user/keycloak/KeycloakApiServiceTest.java index cf01856d14a3dbaf5ea7ba86eae54bd87692fd71..7a38923e5d4f779eb87ed9aedfd686e3dcd01f19 100644 --- a/user-manager-server/src/test/java/de/itvsh/kop/user/keycloak/KeycloakApiServiceTest.java +++ b/user-manager-server/src/test/java/de/itvsh/kop/user/keycloak/KeycloakApiServiceTest.java @@ -36,7 +36,6 @@ import jakarta.ws.rs.ClientErrorException; import jakarta.ws.rs.ProcessingException; import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Nested; import org.junit.jupiter.api.Test; @@ -44,6 +43,8 @@ import org.keycloak.admin.client.resource.RealmResource; import org.keycloak.admin.client.resource.UserResource; import org.keycloak.admin.client.resource.UsersResource; import org.keycloak.representations.idm.UserRepresentation; +import org.mockito.ArgumentCaptor; +import org.mockito.Captor; import org.mockito.InjectMocks; import org.mockito.Mock; import org.mockito.Spy; @@ -149,7 +150,6 @@ class KeycloakApiServiceTest { @DisplayName("handling keycloak exception") @Nested - @Disabled("temporary for testing in cluster") class TestHandlingKeycloakException { @Test @@ -180,7 +180,6 @@ class KeycloakApiServiceTest { @DisplayName("Set user attribute") @Nested - @Disabled("temporary for testing") class TestUpdateUserAttribute { private static final String KEYCLOAK_USER_ID = "1ae2-b123"; @@ -231,7 +230,7 @@ class KeycloakApiServiceTest { service.updateAttribute(KEYCLOAK_USER_ID, ATTRIBUTE_NAME_USER_ID, ATTRIBUTE_VALUE_USER_ID); verify(userRepresentation).singleAttribute(ATTRIBUTE_NAME_USER_ID, ATTRIBUTE_VALUE_USER_ID); - verify(userResource).update(userRepresentation); + verify(service).tryUpdateUserResource(userResource, userRepresentation, ATTRIBUTE_NAME_USER_ID); } @Test @@ -241,7 +240,7 @@ class KeycloakApiServiceTest { service.updateAttribute(KEYCLOAK_USER_ID, ATTRIBUTE_NAME_USER_ID, ATTRIBUTE_VALUE_USER_ID); verify(userRepresentation).singleAttribute(ATTRIBUTE_NAME_USER_ID, ATTRIBUTE_VALUE_USER_ID); - verify(userResource).update(userRepresentation); + verify(service).tryUpdateUserResource(userResource, userRepresentation, ATTRIBUTE_NAME_USER_ID); } @Test @@ -249,7 +248,7 @@ class KeycloakApiServiceTest { service.updateAttribute(KEYCLOAK_USER_ID, ATTRIBUTE_NAME_USER_ID, NEW_USER_ID); verify(userRepresentation).singleAttribute(ATTRIBUTE_NAME_USER_ID, NEW_USER_ID); - verify(userResource).update(userRepresentation); + verify(service).tryUpdateUserResource(userResource, userRepresentation, ATTRIBUTE_NAME_USER_ID); } @Test @@ -257,15 +256,98 @@ class KeycloakApiServiceTest { service.updateAttribute(KEYCLOAK_USER_ID, ATTRIBUTE_NAME_USER_ID, ATTRIBUTE_VALUE_USER_ID); verify(userRepresentation, never()).singleAttribute(ATTRIBUTE_NAME_USER_ID, ATTRIBUTE_VALUE_USER_ID); + verify(service, never()).tryUpdateUserResource(userResource, userRepresentation, ATTRIBUTE_NAME_USER_ID); } @Test void shouldCatchBadRequestException() { when(userRepresentation.firstAttribute(ATTRIBUTE_NAME_USER_ID)).thenReturn(NEW_USER_ID); - doThrow(new BadRequestException("error message")).when(userResource).update(userRepresentation); + doThrow(new BadRequestException("error message")).when(userResource).update(any(OlderUserRepresentation.class)); assertThatCode( () -> service.updateAttribute(KEYCLOAK_USER_ID, ATTRIBUTE_NAME_USER_ID, ATTRIBUTE_VALUE_USER_ID)).doesNotThrowAnyException(); } } + + @Nested + class TestTryUpdateUserResource { + + private static final String ATTRIBUTE_NAME_USER_ID = "userId"; + + @Captor + private ArgumentCaptor<UserRepresentation> userRepresentationArgumentCaptor; + + @Mock + private UserRepresentation userRepresentation; + + @Test + void shouldUpdateUserResource() { + service.tryUpdateUserResource(userResource, userRepresentation, ATTRIBUTE_NAME_USER_ID); + + verify(userResource).update(any(OlderUserRepresentation.class)); + } + + @Test + void shouldCreateOlderUserRepresentation() { + service.tryUpdateUserResource(userResource, userRepresentation, ATTRIBUTE_NAME_USER_ID); + + verify(userResource).update(userRepresentationArgumentCaptor.capture()); + assertThat(userRepresentationArgumentCaptor.getValue()) + .extracting( + UserRepresentation::getId, + UserRepresentation::getCreatedTimestamp, + UserRepresentation::getAttributes, + UserRepresentation::getEmail, + UserRepresentation::getFirstName, + UserRepresentation::getLastName, + UserRepresentation::isEmailVerified, + UserRepresentation::getAccess, + UserRepresentation::getClientConsents, + UserRepresentation::getClientRoles, + UserRepresentation::getCredentials, + UserRepresentation::getDisableableCredentialTypes, + UserRepresentation::getFederatedIdentities, + UserRepresentation::getFederationLink, + UserRepresentation::getGroups, + UserRepresentation::getNotBefore, + UserRepresentation::getOrigin, + UserRepresentation::getRealmRoles, + UserRepresentation::getRequiredActions, + UserRepresentation::getSelf, + UserRepresentation::getServiceAccountClientId, + UserRepresentation::getSocialLinks, + UserRepresentation::isEnabled, + UserRepresentation::getUserProfileMetadata, + UserRepresentation::isTotp + ) + .containsExactly( + userRepresentation.getId(), + userRepresentation.getCreatedTimestamp(), + userRepresentation.getAttributes(), + userRepresentation.getEmail(), + userRepresentation.getFirstName(), + userRepresentation.getLastName(), + userRepresentation.isEmailVerified(), + userRepresentation.getAccess(), + userRepresentation.getClientConsents(), + userRepresentation.getClientRoles(), + userRepresentation.getCredentials(), + userRepresentation.getDisableableCredentialTypes(), + userRepresentation.getFederatedIdentities(), + userRepresentation.getFederationLink(), + userRepresentation.getGroups(), + userRepresentation.getNotBefore(), + userRepresentation.getOrigin(), + userRepresentation.getRealmRoles(), + userRepresentation.getRequiredActions(), + userRepresentation.getSelf(), + userRepresentation.getServiceAccountClientId(), + userRepresentation.getSocialLinks(), + userRepresentation.isEnabled(), + userRepresentation.getUserProfileMetadata(), + userRepresentation.isTotp() + ); + } + + } } \ No newline at end of file