From 0c5bd7896cb1fab62c22fb4151816bac4c16717d Mon Sep 17 00:00:00 2001 From: ElisKina-dev Date: Thu, 19 Dec 2024 17:57:24 +0100 Subject: [PATCH 01/15] recupero brokerId e brokerFiscalCode --- Dockerfile | 8 +++- build.gradle.kts | 35 +++++++++++++- .../auth/connector/OrganizationClient.java | 12 +++++ .../connector/OrganizationClientImpl.java | 48 +++++++++++++++++++ .../auth/service/user/UserServiceImpl.java | 39 ++++++++++++++- src/main/resources/application.yml | 2 + 6 files changed, 139 insertions(+), 5 deletions(-) create mode 100644 src/main/java/it/gov/pagopa/payhub/auth/connector/OrganizationClient.java create mode 100644 src/main/java/it/gov/pagopa/payhub/auth/connector/OrganizationClientImpl.java diff --git a/Dockerfile b/Dockerfile index cee3b16..e5ef892 100644 --- a/Dockerfile +++ b/Dockerfile @@ -37,7 +37,8 @@ RUN apk add --no-cache \ wget \ unzip \ bash \ - shadow + shadow \ + git # Create Gradle user RUN groupadd --system --gid 1000 ${APP_GROUP} && \ @@ -93,6 +94,7 @@ WORKDIR /build COPY --chown=${APP_USER}:${APP_GROUP} build.gradle.kts settings.gradle.kts ./ COPY --chown=${APP_USER}:${APP_GROUP} gradle.lockfile ./ COPY --chown=${APP_USER}:${APP_GROUP} openapi openapi/ +COPY .git .git # Generate OpenAPI stubs and download dependencies RUN mkdir -p src/main/java && \ @@ -101,7 +103,9 @@ RUN mkdir -p src/main/java && \ USER ${APP_USER} -RUN gradle openApiGenerate dependencies --no-daemon +RUN gradle openApiGenerateP4PAAUTH dependencies --no-daemon + +RUN gradle openApiGenerateOrganization dependencies --no-daemon # # 🏗️ Build Stage diff --git a/build.gradle.kts b/build.gradle.kts index 55c6a09..84e2c56 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -6,6 +6,7 @@ plugins { id("org.sonarqube") version "6.0.1.5171" id("com.github.ben-manes.versions") version "0.51.0" id("org.openapi.generator") version "7.10.0" + id("org.ajoberstar.grgit") version "5.3.0" } group = "it.gov.pagopa.payhub" @@ -112,7 +113,7 @@ configurations { } tasks.compileJava { - dependsOn("openApiGenerate") + dependsOn("openApiGenerateP4PAAUTH","openApiGenerateOrganization") } configure { @@ -125,7 +126,10 @@ springBoot { mainClass.value("it.gov.pagopa.payhub.auth.PayhubAuthApplication") } -openApiGenerate { +tasks.register("openApiGenerateP4PAAUTH") { + group = "openapi" + description = "description" + generatorName.set("spring") inputSpec.set("$rootDir/openapi/p4pa-auth.openapi.yaml") outputDir.set("$projectDir/build/generated") @@ -141,4 +145,31 @@ openApiGenerate { "generatedConstructorWithRequiredArgs" to "true", "additionalModelTypeAnnotations" to "@lombok.Data @lombok.Builder @lombok.AllArgsConstructor" )) +} + +var targetEnv = when (grgit.branch.current().name) { + "uat" -> "uat" + "main" -> "main" + else -> "develop" +} + +tasks.register("openApiGenerateOrganization") { + group = "openapi" + description = "description" + + generatorName.set("java") + remoteInputSpec.set("https://raw.githubusercontent.com/pagopa/p4pa-organization/refs/heads/$targetEnv/openapi/generated.openapi.json") + outputDir.set("$projectDir/build/generated") + apiPackage.set("it.gov.pagopa.pu.p4pa-organization.controller.generated") + modelPackage.set("it.gov.pagopa.pu.p4pa-organization.dto.generated") + configOptions.set(mapOf( + "swaggerAnnotations" to "false", + "openApiNullable" to "false", + "dateLibrary" to "java17", + "useSpringBoot3" to "true", + "useJakartaEe" to "true", + "serializationLibrary" to "jackson", + "generateSupportingFiles" to "true" + )) + library.set("resttemplate") } \ No newline at end of file diff --git a/src/main/java/it/gov/pagopa/payhub/auth/connector/OrganizationClient.java b/src/main/java/it/gov/pagopa/payhub/auth/connector/OrganizationClient.java new file mode 100644 index 0000000..9abce53 --- /dev/null +++ b/src/main/java/it/gov/pagopa/payhub/auth/connector/OrganizationClient.java @@ -0,0 +1,12 @@ +package it.gov.pagopa.payhub.auth.connector; + +import it.gov.pagopa.pu.p4pa_organization.dto.generated.EntityModelBroker; +import it.gov.pagopa.pu.p4pa_organization.dto.generated.EntityModelOrganization; + +public interface OrganizationClient { + + EntityModelBroker getBrokerById(Long id, String accessToken); + + EntityModelOrganization getOrganizationByIpaCode(String ipaCode, String accessToken); + +} diff --git a/src/main/java/it/gov/pagopa/payhub/auth/connector/OrganizationClientImpl.java b/src/main/java/it/gov/pagopa/payhub/auth/connector/OrganizationClientImpl.java new file mode 100644 index 0000000..c5335e0 --- /dev/null +++ b/src/main/java/it/gov/pagopa/payhub/auth/connector/OrganizationClientImpl.java @@ -0,0 +1,48 @@ +package it.gov.pagopa.payhub.auth.connector; + +import it.gov.pagopa.pu.p4pa_organization.controller.ApiClient; +import it.gov.pagopa.pu.p4pa_organization.controller.generated.BrokerEntityControllerApi; +import it.gov.pagopa.pu.p4pa_organization.controller.generated.OrganizationSearchControllerApi; +import it.gov.pagopa.pu.p4pa_organization.dto.generated.EntityModelBroker; +import it.gov.pagopa.pu.p4pa_organization.dto.generated.EntityModelOrganization; +import lombok.extern.log4j.Log4j2; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.boot.web.client.RestTemplateBuilder; +import org.springframework.stereotype.Service; +import org.springframework.web.client.RestTemplate; + +@Service +@Log4j2 +public class OrganizationClientImpl implements OrganizationClient { + + private final BrokerEntityControllerApi brokerEntityControllerApi; + private final OrganizationSearchControllerApi organizationSearchControllerApi; + + public OrganizationClientImpl(RestTemplateBuilder restTemplateBuilder, @Value("${app.organization.base-url}") String baseUrl) { + RestTemplate restTemplate = restTemplateBuilder.build(); + ApiClient apiClient = new ApiClient(restTemplate); + apiClient.setBasePath(baseUrl); + brokerEntityControllerApi = new BrokerEntityControllerApi(apiClient); + organizationSearchControllerApi = new OrganizationSearchControllerApi(apiClient); + } + + + public EntityModelBroker getBrokerById(Long id, String accessToken) { + try { + return brokerEntityControllerApi.getItemResourceBrokerGet(String.valueOf(id)); + } catch (Exception e) { + log.error(e.getCause()); + return null; + } + } + + public EntityModelOrganization getOrganizationByIpaCode(String ipaCode, String accessToken) { + try { + return organizationSearchControllerApi.executeSearchOrganizationGet(ipaCode); + } catch (Exception e) { + log.error(e.getCause()); + return null; + } + } + +} diff --git a/src/main/java/it/gov/pagopa/payhub/auth/service/user/UserServiceImpl.java b/src/main/java/it/gov/pagopa/payhub/auth/service/user/UserServiceImpl.java index 965f271..d165193 100644 --- a/src/main/java/it/gov/pagopa/payhub/auth/service/user/UserServiceImpl.java +++ b/src/main/java/it/gov/pagopa/payhub/auth/service/user/UserServiceImpl.java @@ -1,5 +1,6 @@ package it.gov.pagopa.payhub.auth.service.user; +import it.gov.pagopa.payhub.auth.connector.OrganizationClientImpl; import it.gov.pagopa.payhub.auth.dto.IamUserInfoDTO; import it.gov.pagopa.payhub.auth.exception.custom.InvalidAccessTokenException; import it.gov.pagopa.payhub.auth.model.Operator; @@ -10,7 +11,10 @@ import it.gov.pagopa.payhub.auth.service.user.retrieve.OrganizationOperatorRetrieverService; import it.gov.pagopa.payhub.model.generated.OperatorDTO; import it.gov.pagopa.payhub.model.generated.UserInfo; +import it.gov.pagopa.pu.p4pa_organization.dto.generated.EntityModelBroker; +import it.gov.pagopa.pu.p4pa_organization.dto.generated.EntityModelOrganization; import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Value; import org.springframework.data.domain.Page; import org.springframework.data.domain.Pageable; import org.springframework.stereotype.Service; @@ -21,11 +25,15 @@ @Slf4j public class UserServiceImpl implements UserService { + private OrganizationClientImpl organizationClient; private final TokenStoreService tokenStoreService; private final UserRegistrationService userRegistrationService; private final OperatorRegistrationService operatorRegistrationService; private final IamUserInfoDTO2UserInfoMapper userInfoMapper; private final OrganizationOperatorRetrieverService organizationOperatorRetrieverService; + @Value("${app.enable-access-organization-mode}") + private boolean organizationAccessMode; + public UserServiceImpl(TokenStoreService tokenStoreService, UserRegistrationService userRegistrationService, OperatorRegistrationService operatorRegistrationService, IamUserInfoDTO2UserInfoMapper userInfoMapper, OrganizationOperatorRetrieverService organizationOperatorRetrieverService) { this.tokenStoreService = tokenStoreService; @@ -51,9 +59,37 @@ public UserInfo getUserInfo(String accessToken) { IamUserInfoDTO userInfo = tokenStoreService.load(accessToken); if (userInfo == null) { throw new InvalidAccessTokenException("AccessToken not found"); + } + + EntityModelBroker brokerInfo = null; + + if (Boolean.TRUE.equals(organizationAccessMode) && userInfo.getOrganizationAccess() != null) { + log.debug("SelfCare mode enabled. Using organizationAccess: {}", userInfo.getOrganizationAccess()); + + String organizationIpaCode = userInfo.getOrganizationAccess().getOrganizationIpaCode(); + if (organizationIpaCode != null) { + EntityModelOrganization organization = organizationClient.getOrganizationByIpaCode(organizationIpaCode, accessToken); + + if (organization != null && organization.getBrokerId() != null) { + log.info("Organization found. Fetching broker details for brokerId: {}", organization.getBrokerId()); + brokerInfo = organizationClient.getBrokerById(organization.getBrokerId(), accessToken); + } else { + log.warn("No valid organization or brokerId found for IPA Code: {}", organizationIpaCode); + } + } } else { - return userInfoMapper.apply(userInfo); + log.debug("SelfCare mode disabled or organizationAccess not provided. Cannot fetch organization."); + } + + UserInfo result = userInfoMapper.apply(userInfo); + if (brokerInfo != null) { + result.setBrokerId(brokerInfo.getBrokerId()); + result.setBrokerFiscalCode(brokerInfo.getBrokerFiscalCode()); } + + log.debug("User info retrieved successfully with brokerId: {}", + brokerInfo != null ? brokerInfo.getBrokerId() : "N/A"); + return result; } @Override @@ -61,4 +97,5 @@ public Page retrieveOrganizationOperators(String organizationIpaCod log.info("Retrieving organization {} operators", organizationIpaCode); return organizationOperatorRetrieverService.retrieveOrganizationOperators(organizationIpaCode, pageable); } + } diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml index 35a1346..8718a2a 100644 --- a/src/main/resources/application.yml +++ b/src/main/resources/application.yml @@ -63,6 +63,8 @@ app: # Thus it will register te relation between the operator and the relation with the provided roles. # If disabled, the admin should register the associations using the provided API (otherwise they will be disabled) enable-access-organization-mode: "\${ACCESS_ORGANIZATION_MODE_ENABLED:true}" + organization: + base-url: "\${ORGANIZATION_BASE_URL:}" data-chiper: p4pa-auth-hash-key: "\${DATA_CIPHER_P4PA_AUTH_HASH_KEY:PEPPER}" From 4d144bab6c57ab2c24eda17dfbeff1c29f227bce Mon Sep 17 00:00:00 2001 From: ElisKina-dev Date: Wed, 8 Jan 2025 14:46:21 +0100 Subject: [PATCH 02/15] recupero brokerId e brokerFiscalCode --- openapi/p4pa-auth.openapi.yaml | 10 ++++ .../auth/connector/OrganizationClient.java | 12 ---- .../connector/OrganizationClientImpl.java | 48 --------------- .../client/OrganizationSearchClient.java | 48 +++++++++++++++ .../config/OrganizationApisHolder.java | 60 +++++++++++++++++++ .../auth/service/user/UserServiceImpl.java | 13 ++-- 6 files changed, 125 insertions(+), 66 deletions(-) delete mode 100644 src/main/java/it/gov/pagopa/payhub/auth/connector/OrganizationClient.java delete mode 100644 src/main/java/it/gov/pagopa/payhub/auth/connector/OrganizationClientImpl.java create mode 100644 src/main/java/it/gov/pagopa/payhub/auth/connector/client/OrganizationSearchClient.java create mode 100644 src/main/java/it/gov/pagopa/payhub/auth/connector/config/OrganizationApisHolder.java diff --git a/openapi/p4pa-auth.openapi.yaml b/openapi/p4pa-auth.openapi.yaml index ff80457..1d63313 100644 --- a/openapi/p4pa-auth.openapi.yaml +++ b/openapi/p4pa-auth.openapi.yaml @@ -551,6 +551,9 @@ components: - email - issuer - organizations + - brokerId + - brokerFiscalCode + - canManageUsers properties: userId: type: string @@ -572,6 +575,13 @@ components: type: array items: $ref: '#/components/schemas/UserOrganizationRoles' + brokerId: + type: integer + format: int64 + brokerFiscalCode: + type: string + canManageUsers: + type: boolean UserOrganizationRoles: type: object required: diff --git a/src/main/java/it/gov/pagopa/payhub/auth/connector/OrganizationClient.java b/src/main/java/it/gov/pagopa/payhub/auth/connector/OrganizationClient.java deleted file mode 100644 index 9abce53..0000000 --- a/src/main/java/it/gov/pagopa/payhub/auth/connector/OrganizationClient.java +++ /dev/null @@ -1,12 +0,0 @@ -package it.gov.pagopa.payhub.auth.connector; - -import it.gov.pagopa.pu.p4pa_organization.dto.generated.EntityModelBroker; -import it.gov.pagopa.pu.p4pa_organization.dto.generated.EntityModelOrganization; - -public interface OrganizationClient { - - EntityModelBroker getBrokerById(Long id, String accessToken); - - EntityModelOrganization getOrganizationByIpaCode(String ipaCode, String accessToken); - -} diff --git a/src/main/java/it/gov/pagopa/payhub/auth/connector/OrganizationClientImpl.java b/src/main/java/it/gov/pagopa/payhub/auth/connector/OrganizationClientImpl.java deleted file mode 100644 index c5335e0..0000000 --- a/src/main/java/it/gov/pagopa/payhub/auth/connector/OrganizationClientImpl.java +++ /dev/null @@ -1,48 +0,0 @@ -package it.gov.pagopa.payhub.auth.connector; - -import it.gov.pagopa.pu.p4pa_organization.controller.ApiClient; -import it.gov.pagopa.pu.p4pa_organization.controller.generated.BrokerEntityControllerApi; -import it.gov.pagopa.pu.p4pa_organization.controller.generated.OrganizationSearchControllerApi; -import it.gov.pagopa.pu.p4pa_organization.dto.generated.EntityModelBroker; -import it.gov.pagopa.pu.p4pa_organization.dto.generated.EntityModelOrganization; -import lombok.extern.log4j.Log4j2; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.boot.web.client.RestTemplateBuilder; -import org.springframework.stereotype.Service; -import org.springframework.web.client.RestTemplate; - -@Service -@Log4j2 -public class OrganizationClientImpl implements OrganizationClient { - - private final BrokerEntityControllerApi brokerEntityControllerApi; - private final OrganizationSearchControllerApi organizationSearchControllerApi; - - public OrganizationClientImpl(RestTemplateBuilder restTemplateBuilder, @Value("${app.organization.base-url}") String baseUrl) { - RestTemplate restTemplate = restTemplateBuilder.build(); - ApiClient apiClient = new ApiClient(restTemplate); - apiClient.setBasePath(baseUrl); - brokerEntityControllerApi = new BrokerEntityControllerApi(apiClient); - organizationSearchControllerApi = new OrganizationSearchControllerApi(apiClient); - } - - - public EntityModelBroker getBrokerById(Long id, String accessToken) { - try { - return brokerEntityControllerApi.getItemResourceBrokerGet(String.valueOf(id)); - } catch (Exception e) { - log.error(e.getCause()); - return null; - } - } - - public EntityModelOrganization getOrganizationByIpaCode(String ipaCode, String accessToken) { - try { - return organizationSearchControllerApi.executeSearchOrganizationGet(ipaCode); - } catch (Exception e) { - log.error(e.getCause()); - return null; - } - } - -} diff --git a/src/main/java/it/gov/pagopa/payhub/auth/connector/client/OrganizationSearchClient.java b/src/main/java/it/gov/pagopa/payhub/auth/connector/client/OrganizationSearchClient.java new file mode 100644 index 0000000..adf48ef --- /dev/null +++ b/src/main/java/it/gov/pagopa/payhub/auth/connector/client/OrganizationSearchClient.java @@ -0,0 +1,48 @@ +package it.gov.pagopa.payhub.auth.connector.client; + +import it.gov.pagopa.payhub.auth.connector.config.OrganizationApisHolder; +import it.gov.pagopa.pu.p4pa_organization.dto.generated.EntityModelBroker; +import it.gov.pagopa.pu.p4pa_organization.dto.generated.EntityModelOrganization; +import lombok.extern.slf4j.Slf4j; +import org.springframework.http.HttpStatus; +import org.springframework.stereotype.Service; +import org.springframework.web.client.HttpClientErrorException; + +@Service +@Slf4j +public class OrganizationSearchClient { + + private final OrganizationApisHolder organizationApisHolder; + + public OrganizationSearchClient(OrganizationApisHolder organizationApisHolder) { + this.organizationApisHolder = organizationApisHolder; + } + + + public EntityModelBroker getBrokerById(Long id, String accessToken) { + try { + return organizationApisHolder.getBrokerEntityControllerApi(accessToken).getItemResourceBrokerGet(String.valueOf(id)); + } catch (Exception e) { + log.error(String.valueOf(e.getCause())); + return null; + } + } + + public EntityModelOrganization getOrganizationByIpaCode(String ipaCode, String accessToken) { + try { + return organizationApisHolder.getOrganizationSearchControllerApi(accessToken) + .executeSearchOrganizationGet(ipaCode); + } catch (HttpClientErrorException e) { + if (e.getStatusCode() == HttpStatus.NOT_FOUND) { + log.warn("Organization with IPA code {} not found", ipaCode); + return null; + } + log.error("Error retrieving organization by IPA code: {}", ipaCode, e); + throw e; + } catch (Exception e) { + log.error("Unexpected error while retrieving organization by IPA code: {}", ipaCode, e); + throw e; + } + } + +} diff --git a/src/main/java/it/gov/pagopa/payhub/auth/connector/config/OrganizationApisHolder.java b/src/main/java/it/gov/pagopa/payhub/auth/connector/config/OrganizationApisHolder.java new file mode 100644 index 0000000..6388f4d --- /dev/null +++ b/src/main/java/it/gov/pagopa/payhub/auth/connector/config/OrganizationApisHolder.java @@ -0,0 +1,60 @@ +package it.gov.pagopa.payhub.auth.connector.config; + +import it.gov.pagopa.pu.p4pa_organization.controller.ApiClient; +import it.gov.pagopa.pu.p4pa_organization.controller.BaseApi; +import it.gov.pagopa.pu.p4pa_organization.controller.generated.BrokerEntityControllerApi; +import it.gov.pagopa.pu.p4pa_organization.controller.generated.OrganizationSearchControllerApi; +import jakarta.annotation.PreDestroy; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.boot.web.client.RestTemplateBuilder; +import org.springframework.context.annotation.Lazy; +import org.springframework.stereotype.Service; +import org.springframework.web.client.RestTemplate; + +@Lazy +@Service +public class OrganizationApisHolder { + + private final BrokerEntityControllerApi brokerEntityControllerApi; + private final OrganizationSearchControllerApi organizationSearchControllerApi; + + private final ThreadLocal bearerTokenHolder = new ThreadLocal<>(); + + public OrganizationApisHolder( + @Value("${rest.organization.base-url}") String baseUrl, + + RestTemplateBuilder restTemplateBuilder) { + RestTemplate restTemplate = restTemplateBuilder.build(); + ApiClient apiClient = new ApiClient(restTemplate); + apiClient.setBasePath(baseUrl); + apiClient.setBearerToken(bearerTokenHolder::get); + + this.organizationSearchControllerApi = new OrganizationSearchControllerApi(apiClient); + this.brokerEntityControllerApi = new BrokerEntityControllerApi(apiClient); + } + + @PreDestroy + public void unload() { + bearerTokenHolder.remove(); + } + + /** + * It will return a {@link OrganizationSearchControllerApi} instrumented with the provided accessToken. Use null if auth is not required + */ + public OrganizationSearchControllerApi getOrganizationSearchControllerApi(String accessToken) { + return getApi(accessToken, organizationSearchControllerApi); + } + + /** + * It will return a {@link BrokerEntityControllerApi} instrumented with the provided accessToken. Use null if auth is not required + */ + public BrokerEntityControllerApi getBrokerEntityControllerApi(String accessToken) { + return getApi(accessToken, brokerEntityControllerApi); + } + + private T getApi(String accessToken, T api) { + bearerTokenHolder.set(accessToken); + return api; + } + +} diff --git a/src/main/java/it/gov/pagopa/payhub/auth/service/user/UserServiceImpl.java b/src/main/java/it/gov/pagopa/payhub/auth/service/user/UserServiceImpl.java index d165193..25e4407 100644 --- a/src/main/java/it/gov/pagopa/payhub/auth/service/user/UserServiceImpl.java +++ b/src/main/java/it/gov/pagopa/payhub/auth/service/user/UserServiceImpl.java @@ -1,6 +1,6 @@ package it.gov.pagopa.payhub.auth.service.user; -import it.gov.pagopa.payhub.auth.connector.OrganizationClientImpl; +import it.gov.pagopa.payhub.auth.connector.client.OrganizationSearchClient; import it.gov.pagopa.payhub.auth.dto.IamUserInfoDTO; import it.gov.pagopa.payhub.auth.exception.custom.InvalidAccessTokenException; import it.gov.pagopa.payhub.auth.model.Operator; @@ -9,8 +9,8 @@ import it.gov.pagopa.payhub.auth.service.user.registration.OperatorRegistrationService; import it.gov.pagopa.payhub.auth.service.user.registration.UserRegistrationService; import it.gov.pagopa.payhub.auth.service.user.retrieve.OrganizationOperatorRetrieverService; -import it.gov.pagopa.payhub.model.generated.OperatorDTO; -import it.gov.pagopa.payhub.model.generated.UserInfo; +import it.gov.pagopa.payhub.dto.generated.OperatorDTO; +import it.gov.pagopa.payhub.dto.generated.UserInfo; import it.gov.pagopa.pu.p4pa_organization.dto.generated.EntityModelBroker; import it.gov.pagopa.pu.p4pa_organization.dto.generated.EntityModelOrganization; import lombok.extern.slf4j.Slf4j; @@ -25,7 +25,7 @@ @Slf4j public class UserServiceImpl implements UserService { - private OrganizationClientImpl organizationClient; + private OrganizationSearchClient organizationSearchClient; private final TokenStoreService tokenStoreService; private final UserRegistrationService userRegistrationService; private final OperatorRegistrationService operatorRegistrationService; @@ -68,11 +68,11 @@ public UserInfo getUserInfo(String accessToken) { String organizationIpaCode = userInfo.getOrganizationAccess().getOrganizationIpaCode(); if (organizationIpaCode != null) { - EntityModelOrganization organization = organizationClient.getOrganizationByIpaCode(organizationIpaCode, accessToken); + EntityModelOrganization organization = organizationSearchClient.getOrganizationByIpaCode(organizationIpaCode, accessToken); if (organization != null && organization.getBrokerId() != null) { log.info("Organization found. Fetching broker details for brokerId: {}", organization.getBrokerId()); - brokerInfo = organizationClient.getBrokerById(organization.getBrokerId(), accessToken); + brokerInfo = organizationSearchClient.getBrokerById(organization.getBrokerId(), accessToken); } else { log.warn("No valid organization or brokerId found for IPA Code: {}", organizationIpaCode); } @@ -82,6 +82,7 @@ public UserInfo getUserInfo(String accessToken) { } UserInfo result = userInfoMapper.apply(userInfo); + result.setCanManageUsers(!organizationAccessMode); if (brokerInfo != null) { result.setBrokerId(brokerInfo.getBrokerId()); result.setBrokerFiscalCode(brokerInfo.getBrokerFiscalCode()); From e3eee972e449e0f5e538cfc13d97566fc50ed8f5 Mon Sep 17 00:00:00 2001 From: ElisKina-dev Date: Wed, 8 Jan 2025 15:07:00 +0100 Subject: [PATCH 03/15] test postman --- postman/p4pa-auth-E2E.postman_collection.json | 22 +++++++++++++++---- ...ssModeOrganization.postman_collection.json | 19 ++++++++++++++-- 2 files changed, 35 insertions(+), 6 deletions(-) diff --git a/postman/p4pa-auth-E2E.postman_collection.json b/postman/p4pa-auth-E2E.postman_collection.json index 6d4981b..66d7002 100644 --- a/postman/p4pa-auth-E2E.postman_collection.json +++ b/postman/p4pa-auth-E2E.postman_collection.json @@ -1,10 +1,10 @@ { "info": { - "_postman_id": "5b798cd0-2e20-45a4-88bb-08a0b26c6158", + "_postman_id": "cc929f09-50c0-4887-bf81-b41f8c297554", "name": "p4pa-auth-E2E", "schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json", - "_exporter_id": "15747968", - "_collection_link": "https://warped-astronaut-141685.postman.co/workspace/P4PA~9a8b7dd5-97b6-4dd0-b3f5-95f25fd0b455/collection/15747968-5b798cd0-2e20-45a4-88bb-08a0b26c6158?action=share&source=collection_link&creator=15747968" + "_exporter_id": "29647564", + "_collection_link": "https://galactic-eclipse-948669.postman.co/workspace/New-Team-Workspace~be56c5f1-de0c-4252-95d0-ee80f35e2474/collection/29647564-cc929f09-50c0-4887-bf81-b41f8c297554?action=share&source=collection_link&creator=29647564" }, "item": [ { @@ -280,7 +280,21 @@ " pm.expect(jsonResponse).have.property(\"issuer\").to.eq(pm.environment.get(\"tokenExchange_issuer\"))\r", " pm.expect(jsonResponse).have.property(\"organizationAccess\").to.eq(\"IPA_TEST\")\r", "\r", - " pm.expect(jsonResponse.organizations).have.property(\"length\").to.gte(3)\r", + " if (jsonResponse.brokerId) {\r", + " pm.expect(jsonResponse).to.have.property(\"brokerId\").that.is.a(\"number\");\r", + " } else {\r", + " pm.expect(jsonResponse).to.not.have.property(\"brokerId\");\r", + " }\r", + "\r", + " if (jsonResponse.brokerFiscalCode) {\r", + " pm.expect(jsonResponse).to.have.property(\"brokerFiscalCode\").that.is.a(\"string\");\r", + " } else {\r", + " pm.expect(jsonResponse).to.not.have.property(\"brokerFiscalCode\");\r", + " }\r", + "\r", + " pm.expect(jsonResponse).to.have.property(\"canManageUsers\").that.is.a(\"boolean\");\r", + "\r", + " pm.expect(jsonResponse.organizations).to.have.property(\"length\").to.gte(3);\r", " \r", " pm.collectionVariables.set(\"mappedExternalUserId\",jsonResponse.mappedExternalUserId)\r", " pm.collectionVariables.set(\"organizationIpaCode\",jsonResponse.organizationAccess)\r", diff --git a/postman/p4pa-auth-NoAccessModeOrganization.postman_collection.json b/postman/p4pa-auth-NoAccessModeOrganization.postman_collection.json index d897f12..2400381 100644 --- a/postman/p4pa-auth-NoAccessModeOrganization.postman_collection.json +++ b/postman/p4pa-auth-NoAccessModeOrganization.postman_collection.json @@ -1,9 +1,10 @@ { "info": { - "_postman_id": "c1508e85-2efa-460b-8f3a-ff7ee32007a0", + "_postman_id": "4cce1599-b728-41d3-8dab-bfa5f589956c", "name": "p4pa-auth-NoAccessModeOrganization", "schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json", - "_exporter_id": "36568841" + "_exporter_id": "29647564", + "_collection_link": "https://galactic-eclipse-948669.postman.co/workspace/New-Team-Workspace~be56c5f1-de0c-4252-95d0-ee80f35e2474/collection/29647564-4cce1599-b728-41d3-8dab-bfa5f589956c?action=share&source=collection_link&creator=29647564" }, "item": [ { @@ -232,6 +233,20 @@ " pm.expect(jsonResponse).have.property(\"issuer\").to.eq(pm.environment.get(\"tokenExchange_issuer\"))\r", " pm.expect(jsonResponse).have.property(\"organizationAccess\").to.eq(\"IPA_TEST\")\r", "\r", + " if (jsonResponse.brokerId) {\r", + " pm.expect(jsonResponse).to.have.property(\"brokerId\").that.is.a(\"number\");\r", + " } else {\r", + " pm.expect(jsonResponse).to.not.have.property(\"brokerId\");\r", + " }\r", + "\r", + " if (jsonResponse.brokerFiscalCode) {\r", + " pm.expect(jsonResponse).to.have.property(\"brokerFiscalCode\").that.is.a(\"string\");\r", + " } else {\r", + " pm.expect(jsonResponse).to.not.have.property(\"brokerFiscalCode\");\r", + " }\r", + "\r", + " pm.expect(jsonResponse).to.have.property(\"canManageUsers\").that.is.a(\"boolean\");\r", + "\r", " pm.expect(jsonResponse.organizations).have.property(\"length\").to.gte(3)\r", " \r", " pm.collectionVariables.set(\"mappedExternalUserId\",jsonResponse.mappedExternalUserId)\r", From 734f614d8dff0bf91b2f20d8607341d1ff749b77 Mon Sep 17 00:00:00 2001 From: ElisKina-dev Date: Wed, 8 Jan 2025 16:05:52 +0100 Subject: [PATCH 04/15] fixes --- .../auth/connector/client/OrganizationSearchClient.java | 8 ++++---- .../pagopa/payhub/auth/service/user/UserServiceImpl.java | 8 ++++---- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/main/java/it/gov/pagopa/payhub/auth/connector/client/OrganizationSearchClient.java b/src/main/java/it/gov/pagopa/payhub/auth/connector/client/OrganizationSearchClient.java index adf48ef..a8f8076 100644 --- a/src/main/java/it/gov/pagopa/payhub/auth/connector/client/OrganizationSearchClient.java +++ b/src/main/java/it/gov/pagopa/payhub/auth/connector/client/OrganizationSearchClient.java @@ -1,8 +1,8 @@ package it.gov.pagopa.payhub.auth.connector.client; import it.gov.pagopa.payhub.auth.connector.config.OrganizationApisHolder; -import it.gov.pagopa.pu.p4pa_organization.dto.generated.EntityModelBroker; -import it.gov.pagopa.pu.p4pa_organization.dto.generated.EntityModelOrganization; +import it.gov.pagopa.pu.p4pa_organization.dto.generated.Broker; +import it.gov.pagopa.pu.p4pa_organization.dto.generated.Organization; import lombok.extern.slf4j.Slf4j; import org.springframework.http.HttpStatus; import org.springframework.stereotype.Service; @@ -19,7 +19,7 @@ public OrganizationSearchClient(OrganizationApisHolder organizationApisHolder) { } - public EntityModelBroker getBrokerById(Long id, String accessToken) { + public Broker getBrokerById(Long id, String accessToken) { try { return organizationApisHolder.getBrokerEntityControllerApi(accessToken).getItemResourceBrokerGet(String.valueOf(id)); } catch (Exception e) { @@ -28,7 +28,7 @@ public EntityModelBroker getBrokerById(Long id, String accessToken) { } } - public EntityModelOrganization getOrganizationByIpaCode(String ipaCode, String accessToken) { + public Organization getOrganizationByIpaCode(String ipaCode, String accessToken) { try { return organizationApisHolder.getOrganizationSearchControllerApi(accessToken) .executeSearchOrganizationGet(ipaCode); diff --git a/src/main/java/it/gov/pagopa/payhub/auth/service/user/UserServiceImpl.java b/src/main/java/it/gov/pagopa/payhub/auth/service/user/UserServiceImpl.java index 25e4407..657ce7c 100644 --- a/src/main/java/it/gov/pagopa/payhub/auth/service/user/UserServiceImpl.java +++ b/src/main/java/it/gov/pagopa/payhub/auth/service/user/UserServiceImpl.java @@ -11,8 +11,8 @@ import it.gov.pagopa.payhub.auth.service.user.retrieve.OrganizationOperatorRetrieverService; import it.gov.pagopa.payhub.dto.generated.OperatorDTO; import it.gov.pagopa.payhub.dto.generated.UserInfo; -import it.gov.pagopa.pu.p4pa_organization.dto.generated.EntityModelBroker; -import it.gov.pagopa.pu.p4pa_organization.dto.generated.EntityModelOrganization; +import it.gov.pagopa.pu.p4pa_organization.dto.generated.Broker; +import it.gov.pagopa.pu.p4pa_organization.dto.generated.Organization; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Value; import org.springframework.data.domain.Page; @@ -61,14 +61,14 @@ public UserInfo getUserInfo(String accessToken) { throw new InvalidAccessTokenException("AccessToken not found"); } - EntityModelBroker brokerInfo = null; + Broker brokerInfo = null; if (Boolean.TRUE.equals(organizationAccessMode) && userInfo.getOrganizationAccess() != null) { log.debug("SelfCare mode enabled. Using organizationAccess: {}", userInfo.getOrganizationAccess()); String organizationIpaCode = userInfo.getOrganizationAccess().getOrganizationIpaCode(); if (organizationIpaCode != null) { - EntityModelOrganization organization = organizationSearchClient.getOrganizationByIpaCode(organizationIpaCode, accessToken); + Organization organization = organizationSearchClient.getOrganizationByIpaCode(organizationIpaCode, accessToken); if (organization != null && organization.getBrokerId() != null) { log.info("Organization found. Fetching broker details for brokerId: {}", organization.getBrokerId()); From fd7ebcdb6a8d5de1a9e934722d6241ed9a1a445d Mon Sep 17 00:00:00 2001 From: ElisKina-dev Date: Wed, 8 Jan 2025 17:14:26 +0100 Subject: [PATCH 05/15] fixes --- postman/p4pa-auth-E2E.postman_collection.json | 15 ++------------- ...AccessModeOrganization.postman_collection.json | 15 ++------------- 2 files changed, 4 insertions(+), 26 deletions(-) diff --git a/postman/p4pa-auth-E2E.postman_collection.json b/postman/p4pa-auth-E2E.postman_collection.json index 66d7002..9a934f8 100644 --- a/postman/p4pa-auth-E2E.postman_collection.json +++ b/postman/p4pa-auth-E2E.postman_collection.json @@ -279,19 +279,8 @@ " pm.expect(jsonResponse).have.property(\"fiscalCode\").to.eq(\"DMEMPY15L21L736U\")\r", " pm.expect(jsonResponse).have.property(\"issuer\").to.eq(pm.environment.get(\"tokenExchange_issuer\"))\r", " pm.expect(jsonResponse).have.property(\"organizationAccess\").to.eq(\"IPA_TEST\")\r", - "\r", - " if (jsonResponse.brokerId) {\r", - " pm.expect(jsonResponse).to.have.property(\"brokerId\").that.is.a(\"number\");\r", - " } else {\r", - " pm.expect(jsonResponse).to.not.have.property(\"brokerId\");\r", - " }\r", - "\r", - " if (jsonResponse.brokerFiscalCode) {\r", - " pm.expect(jsonResponse).to.have.property(\"brokerFiscalCode\").that.is.a(\"string\");\r", - " } else {\r", - " pm.expect(jsonResponse).to.not.have.property(\"brokerFiscalCode\");\r", - " }\r", - "\r", + " pm.expect(jsonResponse).to.have.property(\"brokerId\").that.is.a(\"number\");\r", + " pm.expect(jsonResponse).to.have.property(\"brokerFiscalCode\").that.is.a(\"string\");\r", " pm.expect(jsonResponse).to.have.property(\"canManageUsers\").that.is.a(\"boolean\");\r", "\r", " pm.expect(jsonResponse.organizations).to.have.property(\"length\").to.gte(3);\r", diff --git a/postman/p4pa-auth-NoAccessModeOrganization.postman_collection.json b/postman/p4pa-auth-NoAccessModeOrganization.postman_collection.json index 2400381..bc21fd2 100644 --- a/postman/p4pa-auth-NoAccessModeOrganization.postman_collection.json +++ b/postman/p4pa-auth-NoAccessModeOrganization.postman_collection.json @@ -232,19 +232,8 @@ " pm.expect(jsonResponse).have.property(\"fiscalCode\").to.eq(\"DMEMPY15L21L736U\")\r", " pm.expect(jsonResponse).have.property(\"issuer\").to.eq(pm.environment.get(\"tokenExchange_issuer\"))\r", " pm.expect(jsonResponse).have.property(\"organizationAccess\").to.eq(\"IPA_TEST\")\r", - "\r", - " if (jsonResponse.brokerId) {\r", - " pm.expect(jsonResponse).to.have.property(\"brokerId\").that.is.a(\"number\");\r", - " } else {\r", - " pm.expect(jsonResponse).to.not.have.property(\"brokerId\");\r", - " }\r", - "\r", - " if (jsonResponse.brokerFiscalCode) {\r", - " pm.expect(jsonResponse).to.have.property(\"brokerFiscalCode\").that.is.a(\"string\");\r", - " } else {\r", - " pm.expect(jsonResponse).to.not.have.property(\"brokerFiscalCode\");\r", - " }\r", - "\r", + " pm.expect(jsonResponse).to.have.property(\"brokerId\").that.is.a(\"number\");\r", + " pm.expect(jsonResponse).to.have.property(\"brokerFiscalCode\").that.is.a(\"string\");\r", " pm.expect(jsonResponse).to.have.property(\"canManageUsers\").that.is.a(\"boolean\");\r", "\r", " pm.expect(jsonResponse.organizations).have.property(\"length\").to.gte(3)\r", From d525e3a3cdcdb071feb10db164b49d2f641b74ce Mon Sep 17 00:00:00 2001 From: ElisKina-dev Date: Thu, 9 Jan 2025 14:36:51 +0100 Subject: [PATCH 06/15] fixes --- helm/values.yaml | 2 + .../client/OrganizationSearchClient.java | 14 +- .../user/IamUserInfoDTO2UserInfoMapper.java | 28 +- .../auth/service/user/UserServiceImpl.java | 31 +-- src/main/resources/application.yml | 5 + .../auth/connector/BaseApiHolderTest.java | 70 +++++ .../client/OrganizationSearchClientTest.java | 102 ++++++++ .../config/OrganizationApiHolderTest.java | 61 +++++ .../IamUserInfoDTO2UserInfoMapperTest.java | 246 +++++++++--------- 9 files changed, 407 insertions(+), 152 deletions(-) create mode 100644 src/test/java/it/gov/pagopa/payhub/auth/connector/BaseApiHolderTest.java create mode 100644 src/test/java/it/gov/pagopa/payhub/auth/connector/client/OrganizationSearchClientTest.java create mode 100644 src/test/java/it/gov/pagopa/payhub/auth/connector/config/OrganizationApiHolderTest.java diff --git a/helm/values.yaml b/helm/values.yaml index 4ec0d56..0aeea49 100644 --- a/helm/values.yaml +++ b/helm/values.yaml @@ -68,6 +68,8 @@ microservice-chart: JWT_TOKEN_EXPIRATION_SECONDS: "14400" # 4 HOURS ACCESS_ORGANIZATION_MODE_ENABLED: "true" + ORGANIZATION_BASE_URL: "http://p4pa-organization-microservice-chart:8080" + envSecret: APPLICATIONINSIGHTS_CONNECTION_STRING: appinsights-connection-string diff --git a/src/main/java/it/gov/pagopa/payhub/auth/connector/client/OrganizationSearchClient.java b/src/main/java/it/gov/pagopa/payhub/auth/connector/client/OrganizationSearchClient.java index a8f8076..5c478bd 100644 --- a/src/main/java/it/gov/pagopa/payhub/auth/connector/client/OrganizationSearchClient.java +++ b/src/main/java/it/gov/pagopa/payhub/auth/connector/client/OrganizationSearchClient.java @@ -21,17 +21,23 @@ public OrganizationSearchClient(OrganizationApisHolder organizationApisHolder) { public Broker getBrokerById(Long id, String accessToken) { try { - return organizationApisHolder.getBrokerEntityControllerApi(accessToken).getItemResourceBrokerGet(String.valueOf(id)); + return organizationApisHolder.getBrokerEntityControllerApi(accessToken).crudGetBroker(String.valueOf(id)); + } catch (HttpClientErrorException e) { + if (e.getStatusCode() == HttpStatus.NOT_FOUND) { + log.info("Broker with ID {} not found.", id); + return null; + } + throw e; } catch (Exception e) { - log.error(String.valueOf(e.getCause())); - return null; + log.error("An unexpected error occurred: {}", e.getMessage(), e); + throw e; } } public Organization getOrganizationByIpaCode(String ipaCode, String accessToken) { try { return organizationApisHolder.getOrganizationSearchControllerApi(accessToken) - .executeSearchOrganizationGet(ipaCode); + .crudOrganizationsFindByIpaCode(ipaCode); } catch (HttpClientErrorException e) { if (e.getStatusCode() == HttpStatus.NOT_FOUND) { log.warn("Organization with IPA code {} not found", ipaCode); diff --git a/src/main/java/it/gov/pagopa/payhub/auth/service/user/IamUserInfoDTO2UserInfoMapper.java b/src/main/java/it/gov/pagopa/payhub/auth/service/user/IamUserInfoDTO2UserInfoMapper.java index 0815d00..e366e6f 100644 --- a/src/main/java/it/gov/pagopa/payhub/auth/service/user/IamUserInfoDTO2UserInfoMapper.java +++ b/src/main/java/it/gov/pagopa/payhub/auth/service/user/IamUserInfoDTO2UserInfoMapper.java @@ -1,6 +1,8 @@ package it.gov.pagopa.payhub.auth.service.user; +import it.gov.pagopa.payhub.auth.connector.client.OrganizationSearchClient; import it.gov.pagopa.payhub.auth.dto.IamUserInfoDTO; +import it.gov.pagopa.payhub.auth.dto.IamUserOrganizationRolesDTO; import it.gov.pagopa.payhub.auth.exception.custom.UserNotFoundException; import it.gov.pagopa.payhub.auth.model.Operator; import it.gov.pagopa.payhub.auth.model.User; @@ -9,24 +11,28 @@ import it.gov.pagopa.payhub.auth.utils.Constants; import it.gov.pagopa.payhub.dto.generated.UserInfo; import it.gov.pagopa.payhub.dto.generated.UserOrganizationRoles; +import it.gov.pagopa.pu.p4pa_organization.dto.generated.Broker; +import it.gov.pagopa.pu.p4pa_organization.dto.generated.Organization; import org.springframework.stereotype.Service; import java.util.ArrayList; import java.util.Collections; import java.util.List; +import java.util.Optional; import java.util.function.Function; @Service public class IamUserInfoDTO2UserInfoMapper implements Function { public static final String WS_USER_SUFFIX = "-WS_USER"; - private final UsersRepository usersRepository; private final OperatorsRepository operatorsRepository; + private final OrganizationSearchClient organizationSearchClient; - public IamUserInfoDTO2UserInfoMapper(UsersRepository usersRepository, OperatorsRepository operatorsRepository) { + public IamUserInfoDTO2UserInfoMapper(UsersRepository usersRepository, OperatorsRepository operatorsRepository, OrganizationSearchClient organizationSearchClient) { this.usersRepository = usersRepository; this.operatorsRepository = operatorsRepository; + this.organizationSearchClient = organizationSearchClient; } @Override @@ -60,6 +66,19 @@ public static String buildSystemMappedExternalUserId(String organizationIpaCode) private UserInfo userInfoMapper(IamUserInfoDTO iamUserInfoDTO) { User user = usersRepository.findById(iamUserInfoDTO.getInnerUserId()).orElseThrow(() -> new UserNotFoundException("Cannot found user having inner id:" + iamUserInfoDTO.getInnerUserId())); List userRoles = operatorsRepository.findAllByUserId(iamUserInfoDTO.getInnerUserId()); + + String orgIpaCode = Optional.ofNullable(iamUserInfoDTO.getOrganizationAccess()) + .map(IamUserOrganizationRolesDTO::getOrganizationIpaCode) + .orElseGet(() -> !userRoles.isEmpty() ? userRoles.get(0).getOrganizationIpaCode() : null); + + Broker brokerInfo = null; + if (orgIpaCode != null) { + Organization organization = organizationSearchClient.getOrganizationByIpaCode(orgIpaCode, String.valueOf(iamUserInfoDTO.getOrganizationAccess())); + if (organization != null && organization.getBrokerId() != null) { + brokerInfo = organizationSearchClient.getBrokerById(organization.getBrokerId(), String.valueOf(iamUserInfoDTO.getOrganizationAccess())); + } + } + UserInfo userInfo = UserInfo.builder() .userId(user.getUserId()) .mappedExternalUserId(user.getMappedExternalUserId()) @@ -80,6 +99,11 @@ private UserInfo userInfoMapper(IamUserInfoDTO iamUserInfoDTO) { if(iamUserInfoDTO.getOrganizationAccess() != null){ userInfo.setOrganizationAccess(iamUserInfoDTO.getOrganizationAccess().getOrganizationIpaCode()); } + if (brokerInfo != null) { + userInfo.setBrokerId(brokerInfo.getBrokerId()); + userInfo.setBrokerFiscalCode(brokerInfo.getBrokerFiscalCode()); + } return userInfo; } + } diff --git a/src/main/java/it/gov/pagopa/payhub/auth/service/user/UserServiceImpl.java b/src/main/java/it/gov/pagopa/payhub/auth/service/user/UserServiceImpl.java index 657ce7c..e837c95 100644 --- a/src/main/java/it/gov/pagopa/payhub/auth/service/user/UserServiceImpl.java +++ b/src/main/java/it/gov/pagopa/payhub/auth/service/user/UserServiceImpl.java @@ -1,6 +1,5 @@ package it.gov.pagopa.payhub.auth.service.user; -import it.gov.pagopa.payhub.auth.connector.client.OrganizationSearchClient; import it.gov.pagopa.payhub.auth.dto.IamUserInfoDTO; import it.gov.pagopa.payhub.auth.exception.custom.InvalidAccessTokenException; import it.gov.pagopa.payhub.auth.model.Operator; @@ -11,8 +10,6 @@ import it.gov.pagopa.payhub.auth.service.user.retrieve.OrganizationOperatorRetrieverService; import it.gov.pagopa.payhub.dto.generated.OperatorDTO; import it.gov.pagopa.payhub.dto.generated.UserInfo; -import it.gov.pagopa.pu.p4pa_organization.dto.generated.Broker; -import it.gov.pagopa.pu.p4pa_organization.dto.generated.Organization; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Value; import org.springframework.data.domain.Page; @@ -25,7 +22,6 @@ @Slf4j public class UserServiceImpl implements UserService { - private OrganizationSearchClient organizationSearchClient; private final TokenStoreService tokenStoreService; private final UserRegistrationService userRegistrationService; private final OperatorRegistrationService operatorRegistrationService; @@ -61,35 +57,12 @@ public UserInfo getUserInfo(String accessToken) { throw new InvalidAccessTokenException("AccessToken not found"); } - Broker brokerInfo = null; - - if (Boolean.TRUE.equals(organizationAccessMode) && userInfo.getOrganizationAccess() != null) { - log.debug("SelfCare mode enabled. Using organizationAccess: {}", userInfo.getOrganizationAccess()); - - String organizationIpaCode = userInfo.getOrganizationAccess().getOrganizationIpaCode(); - if (organizationIpaCode != null) { - Organization organization = organizationSearchClient.getOrganizationByIpaCode(organizationIpaCode, accessToken); - - if (organization != null && organization.getBrokerId() != null) { - log.info("Organization found. Fetching broker details for brokerId: {}", organization.getBrokerId()); - brokerInfo = organizationSearchClient.getBrokerById(organization.getBrokerId(), accessToken); - } else { - log.warn("No valid organization or brokerId found for IPA Code: {}", organizationIpaCode); - } - } - } else { - log.debug("SelfCare mode disabled or organizationAccess not provided. Cannot fetch organization."); - } - UserInfo result = userInfoMapper.apply(userInfo); + result.setCanManageUsers(!organizationAccessMode); - if (brokerInfo != null) { - result.setBrokerId(brokerInfo.getBrokerId()); - result.setBrokerFiscalCode(brokerInfo.getBrokerFiscalCode()); - } log.debug("User info retrieved successfully with brokerId: {}", - brokerInfo != null ? brokerInfo.getBrokerId() : "N/A"); + result.getBrokerId() != null ? result.getBrokerId() : "N/A"); return result; } diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml index 33e8de7..ea338bf 100644 --- a/src/main/resources/application.yml +++ b/src/main/resources/application.yml @@ -66,6 +66,11 @@ app: # Thus it will register te relation between the operator and the relation with the provided roles. # If disabled, the admin should register the associations using the provided API (otherwise they will be disabled) enable-access-organization-mode: "\${ACCESS_ORGANIZATION_MODE_ENABLED:true}" + +rest: + default-timeout: + connect-millis: "\${DEFAULT_REST_CONNECT_TIMEOUT_MILLIS:120000}" + read-millis: "\${DEFAULT_REST_READ_TIMEOUT_MILLIS:120000}" organization: base-url: "\${ORGANIZATION_BASE_URL:}" diff --git a/src/test/java/it/gov/pagopa/payhub/auth/connector/BaseApiHolderTest.java b/src/test/java/it/gov/pagopa/payhub/auth/connector/BaseApiHolderTest.java new file mode 100644 index 0000000..174a581 --- /dev/null +++ b/src/test/java/it/gov/pagopa/payhub/auth/connector/BaseApiHolderTest.java @@ -0,0 +1,70 @@ +package it.gov.pagopa.payhub.auth.connector; + +import org.apache.commons.lang3.tuple.Pair; +import org.junit.jupiter.api.Assertions; +import org.mockito.Mock; +import org.mockito.Mockito; +import org.springframework.core.ParameterizedTypeReference; +import org.springframework.http.HttpHeaders; +import org.springframework.http.ResponseEntity; +import org.springframework.web.client.RestTemplate; + +import java.util.Collections; +import java.util.List; +import java.util.concurrent.Callable; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.function.Function; +import java.util.stream.IntStream; + +public abstract class BaseApiHolderTest { + + @Mock + protected RestTemplate restTemplateMock; + + protected void assertAuthenticationShouldBeSetInThreadSafeMode(Function apiInvoke, Class apiReturnedType, Runnable apiUnloader) throws InterruptedException { + // Configuring useCases in a single thread + List> useCases = IntStream.rangeClosed(0, 100) + .mapToObj(i -> { + try { + String accessToken = "accessToken" + i; + T expectedResult = apiReturnedType.getConstructor().newInstance(); + + Mockito.doReturn(ResponseEntity.ok(expectedResult)) + .when(restTemplateMock) + .exchange( + Mockito.argThat(req -> + req.getHeaders().getOrDefault(HttpHeaders.AUTHORIZATION, Collections.emptyList()).getFirst() + .equals("Bearer " + accessToken)), + Mockito.eq(apiReturnedType)); + return Pair.of(accessToken, expectedResult); + } catch (Exception e) { + throw new IllegalStateException(e); + } + }) + .toList(); + + try (ExecutorService executorService = Executors.newFixedThreadPool(10)) { + executorService.invokeAll(useCases.stream() + .map(p -> (Callable) () -> { + // Given + String accessToken = p.getKey(); + T expectedResult = p.getValue(); + + // When + T result = apiInvoke.apply(accessToken); + + // Then + Assertions.assertSame(expectedResult, result); + return true; + }) + .toList()); + } + + apiUnloader.run(); + + Mockito.verify(restTemplateMock, Mockito.times(useCases.size())) + .exchange(Mockito.any(), Mockito.>any()); + } + +} diff --git a/src/test/java/it/gov/pagopa/payhub/auth/connector/client/OrganizationSearchClientTest.java b/src/test/java/it/gov/pagopa/payhub/auth/connector/client/OrganizationSearchClientTest.java new file mode 100644 index 0000000..3e67048 --- /dev/null +++ b/src/test/java/it/gov/pagopa/payhub/auth/connector/client/OrganizationSearchClientTest.java @@ -0,0 +1,102 @@ +package it.gov.pagopa.payhub.auth.connector.client; + +import it.gov.pagopa.payhub.auth.connector.client.OrganizationSearchClient; +import it.gov.pagopa.payhub.auth.connector.config.OrganizationApisHolder; +import it.gov.pagopa.pu.p4pa_organization.controller.generated.OrganizationSearchControllerApi; +import it.gov.pagopa.pu.p4pa_organization.dto.generated.Organization; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.Mock; +import org.mockito.Mockito; +import org.mockito.junit.jupiter.MockitoExtension; +import org.springframework.http.HttpStatus; +import org.springframework.web.client.HttpClientErrorException; + +@ExtendWith(MockitoExtension.class) +class OrganizationSearchClientTest { + @Mock + private OrganizationApisHolder organizationApisHolder; + @Mock + private OrganizationSearchControllerApi organizationSearchControllerApiMock; + + private OrganizationSearchClient organizationSearchClient; + + @BeforeEach + void setUp() { + organizationSearchClient = new OrganizationSearchClient(organizationApisHolder); + } + + @AfterEach + void verifyNoMoreInteractions() { + Mockito.verifyNoMoreInteractions( + organizationApisHolder + ); + } + + @Test + void whenGetOrganizationByIpaCodeThenInvokeWithAccessToken() { + String orgIpaCode = "ORGIPACODE"; + String accessToken = "ACCESSTOKEN"; + Organization expectedResult = new Organization(); + + Mockito.when(organizationApisHolder.getOrganizationSearchControllerApi(accessToken)) + .thenReturn(organizationSearchControllerApiMock); + Mockito.when(organizationSearchControllerApiMock.crudOrganizationsFindByIpaCode(orgIpaCode)) + .thenReturn(expectedResult); + + Organization result = organizationSearchClient.getOrganizationByIpaCode(orgIpaCode, accessToken); + + Assertions.assertSame(expectedResult, result); + } + + @Test + void givenNoExistentIpaCodeWhenGetOrganizationByIpaCodeThenNull() { + String orgIpaCode = "ORGIPACODE"; + String accessToken = "ACCESSTOKEN"; + + Mockito.when(organizationApisHolder.getOrganizationSearchControllerApi(accessToken)) + .thenReturn(organizationSearchControllerApiMock); + Mockito.when(organizationSearchControllerApiMock.crudOrganizationsFindByIpaCode(orgIpaCode)) + .thenThrow(new HttpClientErrorException(HttpStatus.NOT_FOUND)); + + Organization result = organizationSearchClient.getOrganizationByIpaCode(orgIpaCode, accessToken); + + Assertions.assertNull(result); + } + + @Test + void givenGenericHttpExceptionWhenGetOrganizationByIpaCodeThenThrowIt() { + String orgIpaCode = "ORGIPACODE"; + String accessToken = "ACCESSTOKEN"; + HttpClientErrorException expectedException = new HttpClientErrorException(HttpStatus.INTERNAL_SERVER_ERROR); + + Mockito.when(organizationApisHolder.getOrganizationSearchControllerApi(accessToken)) + .thenReturn(organizationSearchControllerApiMock); + Mockito.when(organizationSearchControllerApiMock.crudOrganizationsFindByIpaCode(orgIpaCode)) + .thenThrow(expectedException); + + HttpClientErrorException result = Assertions.assertThrows(expectedException.getClass(), () -> organizationSearchClient.getOrganizationByIpaCode(orgIpaCode, accessToken)); + + Assertions.assertSame(expectedException, result); + } + + @Test + void givenGenericExceptionWhenGetOrganizationByIpaCodeThenThrowIt() { + String orgIpaCode = "ORGIPACODE"; + String accessToken = "ACCESSTOKEN"; + RuntimeException expectedException = new RuntimeException(); + + Mockito.when(organizationApisHolder.getOrganizationSearchControllerApi(accessToken)) + .thenReturn(organizationSearchControllerApiMock); + Mockito.when(organizationSearchControllerApiMock.crudOrganizationsFindByIpaCode(orgIpaCode)) + .thenThrow(expectedException); + + RuntimeException result = Assertions.assertThrows(expectedException.getClass(), () -> organizationSearchClient.getOrganizationByIpaCode(orgIpaCode, accessToken)); + + Assertions.assertSame(expectedException, result); + } + +} diff --git a/src/test/java/it/gov/pagopa/payhub/auth/connector/config/OrganizationApiHolderTest.java b/src/test/java/it/gov/pagopa/payhub/auth/connector/config/OrganizationApiHolderTest.java new file mode 100644 index 0000000..eb4e152 --- /dev/null +++ b/src/test/java/it/gov/pagopa/payhub/auth/connector/config/OrganizationApiHolderTest.java @@ -0,0 +1,61 @@ +package it.gov.pagopa.payhub.auth.connector.config; + +import it.gov.pagopa.payhub.auth.connector.BaseApiHolderTest; +import it.gov.pagopa.payhub.auth.connector.config.OrganizationApisHolder; +import it.gov.pagopa.pu.p4pa_organization.controller.ApiClient; +import it.gov.pagopa.pu.p4pa_organization.dto.generated.Broker; +import it.gov.pagopa.pu.p4pa_organization.dto.generated.Organization; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.Mock; +import org.mockito.Mockito; +import org.mockito.junit.jupiter.MockitoExtension; +import org.springframework.boot.web.client.RestTemplateBuilder; +import org.springframework.web.util.DefaultUriBuilderFactory; + +@ExtendWith(MockitoExtension.class) +class OrganizationApiHolderTest extends BaseApiHolderTest { + @Mock + private RestTemplateBuilder restTemplateBuilderMock; + + private OrganizationApisHolder organizationApisHolder; + + @BeforeEach + void setUp() { + Mockito.when(restTemplateBuilderMock.build()).thenReturn(restTemplateMock); + Mockito.when(restTemplateMock.getUriTemplateHandler()).thenReturn(new DefaultUriBuilderFactory()); + ApiClient apiClient = new ApiClient(restTemplateMock); + String baseUrl = "http://example.com"; + apiClient.setBasePath(baseUrl); + organizationApisHolder = new OrganizationApisHolder(baseUrl, restTemplateBuilderMock); + } + + @AfterEach + void verifyNoMoreInteractions() { + Mockito.verifyNoMoreInteractions( + restTemplateBuilderMock, + restTemplateMock + ); + } + + @Test + void whenGetOrganizationSearchControllerApiThenAuthenticationShouldBeSetInThreadSafeMode() throws InterruptedException { + assertAuthenticationShouldBeSetInThreadSafeMode( + accessToken -> organizationApisHolder.getOrganizationSearchControllerApi(accessToken) + .crudOrganizationsFindByIpaCode("IPACODE"), + Organization.class, + organizationApisHolder::unload); + } + + @Test + void whenGetAuthnApiThenAuthenticationShouldBeSetInThreadSafeMode() throws InterruptedException { + assertAuthenticationShouldBeSetInThreadSafeMode( + accessToken -> organizationApisHolder.getBrokerEntityControllerApi(accessToken) + .crudGetBroker("BROKERID"), + Broker.class, + organizationApisHolder::unload); + } + +} \ No newline at end of file diff --git a/src/test/java/it/gov/pagopa/payhub/auth/service/user/IamUserInfoDTO2UserInfoMapperTest.java b/src/test/java/it/gov/pagopa/payhub/auth/service/user/IamUserInfoDTO2UserInfoMapperTest.java index a7c17b2..77574ef 100644 --- a/src/test/java/it/gov/pagopa/payhub/auth/service/user/IamUserInfoDTO2UserInfoMapperTest.java +++ b/src/test/java/it/gov/pagopa/payhub/auth/service/user/IamUserInfoDTO2UserInfoMapperTest.java @@ -1,5 +1,6 @@ package it.gov.pagopa.payhub.auth.service.user; +import it.gov.pagopa.payhub.auth.connector.client.OrganizationSearchClient; import it.gov.pagopa.payhub.auth.dto.IamUserInfoDTO; import it.gov.pagopa.payhub.auth.dto.IamUserOrganizationRolesDTO; import it.gov.pagopa.payhub.auth.exception.custom.UserNotFoundException; @@ -10,16 +11,21 @@ import it.gov.pagopa.payhub.auth.utils.Constants; import it.gov.pagopa.payhub.dto.generated.UserInfo; import it.gov.pagopa.payhub.dto.generated.UserOrganizationRoles; +import it.gov.pagopa.pu.p4pa_organization.dto.generated.Organization; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.InjectMocks; import org.mockito.Mock; import org.mockito.Mockito; import org.mockito.junit.jupiter.MockitoExtension; -import java.util.*; +import java.util.Collections; +import java.util.List; +import java.util.Optional; +import java.util.Set; @ExtendWith(MockitoExtension.class) class IamUserInfoDTO2UserInfoMapperTest { @@ -29,12 +35,16 @@ class IamUserInfoDTO2UserInfoMapperTest { @Mock private OperatorsRepository operatorsRepositoryMock; + @Mock + private OrganizationSearchClient organizationSearchClientMock; + + @InjectMocks private IamUserInfoDTO2UserInfoMapper mapper; @BeforeEach void init() { - mapper = new IamUserInfoDTO2UserInfoMapper(usersRepositoryMock, operatorsRepositoryMock); + mapper = new IamUserInfoDTO2UserInfoMapper(usersRepositoryMock, operatorsRepositoryMock, organizationSearchClientMock); } @AfterEach @@ -43,12 +53,12 @@ void verifyNotMoreInteractions() { } @Test - void givenNotUserWhenApplyThenUserNotFoundException(){ + void givenNotUserWhenApplyThenUserNotFoundException() { // Given IamUserInfoDTO iamUserInfo = IamUserInfoDTO.builder() - .userId("EXTERNALUSERID") - .innerUserId("INNERUSERID") - .build(); + .userId("EXTERNALUSERID") + .innerUserId("INNERUSERID") + .build(); Mockito.when(usersRepositoryMock.findById(iamUserInfo.getInnerUserId())).thenReturn(Optional.empty()); @@ -57,51 +67,53 @@ void givenNotUserWhenApplyThenUserNotFoundException(){ } @Test - void givenCompleteDataWhenApplyThenOk(){ + void givenCompleteDataWhenApplyThenOk() { // Given IamUserInfoDTO iamUserInfo = IamUserInfoDTO.builder() - .userId("EXTERNALUSERID") - .innerUserId("INNERUSERID") - .fiscalCode("FISCALCODE") - .familyName("FAMILYNAME") - .name("NAME") - .issuer("ISSUER") - .organizationAccess(IamUserOrganizationRolesDTO.builder() - .organizationIpaCode("ORG") - .email("EMAIL") - .build()) - .build(); + .userId("EXTERNALUSERID") + .innerUserId("INNERUSERID") + .fiscalCode("FISCALCODE") + .familyName("FAMILYNAME") + .name("NAME") + .issuer("ISSUER") + .organizationAccess(IamUserOrganizationRolesDTO.builder() + .organizationIpaCode("ORG") + .email("EMAIL") + .build()) + .build(); User user = User.builder() - .userId(iamUserInfo.getInnerUserId()) - .mappedExternalUserId("MAPPEDEXTERNALUSERID") - .build(); + .userId(iamUserInfo.getInnerUserId()) + .mappedExternalUserId("MAPPEDEXTERNALUSERID") + .build(); List organizationRoles = List.of(Operator.builder() - .operatorId("OPERATORID") - .organizationIpaCode("ORG") - .roles(Set.of("ROLE")) - .email("EMAIL") - .build()); + .operatorId("OPERATORID") + .organizationIpaCode("ORG") + .roles(Set.of("ROLE")) + .email("EMAIL") + .build()); UserInfo expected = UserInfo.builder() - .userId("INNERUSERID") - .mappedExternalUserId("MAPPEDEXTERNALUSERID") - .fiscalCode("FISCALCODE") - .familyName("FAMILYNAME") - .name("NAME") - .issuer("ISSUER") - .organizationAccess("ORG") - .organizations(List.of(UserOrganizationRoles.builder() - .operatorId("OPERATORID") - .organizationIpaCode("ORG") - .roles(List.of("ROLE")) - .email("EMAIL") - .build())) - .build(); + .userId("INNERUSERID") + .mappedExternalUserId("MAPPEDEXTERNALUSERID") + .fiscalCode("FISCALCODE") + .familyName("FAMILYNAME") + .name("NAME") + .issuer("ISSUER") + .organizationAccess("ORG") + .organizations(List.of(UserOrganizationRoles.builder() + .operatorId("OPERATORID") + .organizationIpaCode("ORG") + .roles(List.of("ROLE")) + .email("EMAIL") + .build())) + .build(); Mockito.when(usersRepositoryMock.findById(iamUserInfo.getInnerUserId())).thenReturn(Optional.of(user)); Mockito.when(operatorsRepositoryMock.findAllByUserId(user.getUserId())).thenReturn(organizationRoles); + Mockito.when(organizationSearchClientMock.getOrganizationByIpaCode(Mockito.eq("ORG"), Mockito.anyString())) + .thenReturn(new Organization()); // When UserInfo result = mapper.apply(iamUserInfo); @@ -111,36 +123,36 @@ void givenCompleteDataWhenApplyThenOk(){ } @Test - void givenNotOperatorsWhenApplyThenOk(){ + void givenNotOperatorsWhenApplyThenOk() { // Given IamUserInfoDTO iamUserInfo = IamUserInfoDTO.builder() - .userId("EXTERNALUSERID") - .innerUserId("INNERUSERID") - .fiscalCode("FISCALCODE") - .familyName("FAMILYNAME") - .name("NAME") - .issuer("ISSUER") - .organizationAccess(IamUserOrganizationRolesDTO.builder() - .organizationIpaCode("ORG") - .email("EMAIL") - .build()) - .build(); + .userId("EXTERNALUSERID") + .innerUserId("INNERUSERID") + .fiscalCode("FISCALCODE") + .familyName("FAMILYNAME") + .name("NAME") + .issuer("ISSUER") + .organizationAccess(IamUserOrganizationRolesDTO.builder() + .organizationIpaCode("ORG") + .email("EMAIL") + .build()) + .build(); User user = User.builder() - .userId(iamUserInfo.getInnerUserId()) - .mappedExternalUserId("MAPPEDEXTERNALUSERID") - .build(); + .userId(iamUserInfo.getInnerUserId()) + .mappedExternalUserId("MAPPEDEXTERNALUSERID") + .build(); UserInfo expected = UserInfo.builder() - .userId("INNERUSERID") - .mappedExternalUserId("MAPPEDEXTERNALUSERID") - .fiscalCode("FISCALCODE") - .familyName("FAMILYNAME") - .name("NAME") - .issuer("ISSUER") - .organizationAccess("ORG") - .organizations(Collections.emptyList()) - .build(); + .userId("INNERUSERID") + .mappedExternalUserId("MAPPEDEXTERNALUSERID") + .fiscalCode("FISCALCODE") + .familyName("FAMILYNAME") + .name("NAME") + .issuer("ISSUER") + .organizationAccess("ORG") + .organizations(Collections.emptyList()) + .build(); Mockito.when(usersRepositoryMock.findById(iamUserInfo.getInnerUserId())).thenReturn(Optional.of(user)); Mockito.when(operatorsRepositoryMock.findAllByUserId(user.getUserId())).thenReturn(Collections.emptyList()); @@ -153,43 +165,43 @@ void givenNotOperatorsWhenApplyThenOk(){ } @Test - void givenNoOrganizationAccessWhenApplyThenOk(){ + void givenNoOrganizationAccessWhenApplyThenOk() { // Given IamUserInfoDTO iamUserInfo = IamUserInfoDTO.builder() - .userId("EXTERNALUSERID") - .innerUserId("INNERUSERID") - .fiscalCode("FISCALCODE") - .familyName("FAMILYNAME") - .name("NAME") - .issuer("ISSUER") - .build(); + .userId("EXTERNALUSERID") + .innerUserId("INNERUSERID") + .fiscalCode("FISCALCODE") + .familyName("FAMILYNAME") + .name("NAME") + .issuer("ISSUER") + .build(); User user = User.builder() - .userId(iamUserInfo.getInnerUserId()) - .mappedExternalUserId("MAPPEDEXTERNALUSERID") - .build(); + .userId(iamUserInfo.getInnerUserId()) + .mappedExternalUserId("MAPPEDEXTERNALUSERID") + .build(); List organizationRoles = List.of(Operator.builder() - .operatorId("OPERATORID") - .organizationIpaCode("ORG") - .roles(Set.of("ROLE")) - .email("EMAIL") - .build()); + .operatorId("OPERATORID") + .organizationIpaCode("ORG") + .roles(Set.of("ROLE")) + .email("EMAIL") + .build()); UserInfo expected = UserInfo.builder() - .userId("INNERUSERID") - .mappedExternalUserId("MAPPEDEXTERNALUSERID") - .fiscalCode("FISCALCODE") - .familyName("FAMILYNAME") - .name("NAME") - .issuer("ISSUER") - .organizations(List.of(UserOrganizationRoles.builder() - .operatorId("OPERATORID") - .organizationIpaCode("ORG") - .roles(List.of("ROLE")) - .email("EMAIL") - .build())) - .build(); + .userId("INNERUSERID") + .mappedExternalUserId("MAPPEDEXTERNALUSERID") + .fiscalCode("FISCALCODE") + .familyName("FAMILYNAME") + .name("NAME") + .issuer("ISSUER") + .organizations(List.of(UserOrganizationRoles.builder() + .operatorId("OPERATORID") + .organizationIpaCode("ORG") + .roles(List.of("ROLE")) + .email("EMAIL") + .build())) + .build(); Mockito.when(usersRepositoryMock.findById(iamUserInfo.getInnerUserId())).thenReturn(Optional.of(user)); Mockito.when(operatorsRepositoryMock.findAllByUserId(user.getUserId())).thenReturn(organizationRoles); @@ -202,34 +214,34 @@ void givenNoOrganizationAccessWhenApplyThenOk(){ } @Test - void givenSystemUserWhenApplyThenOk(){ + void givenSystemUserWhenApplyThenOk() { // Given IamUserInfoDTO iamUserInfo = IamUserInfoDTO.builder() - .systemUser(Boolean.TRUE) - .userId("EXTERNALUSERID") - .innerUserId("INNERUSERID") - .fiscalCode("FISCALCODE") - .familyName("FAMILYNAME") - .name("NAME") - .issuer("IPA_CODE") - .organizationAccess(IamUserOrganizationRolesDTO.builder() - .organizationIpaCode("IPA_CODE") - .roles(Collections.singletonList(Constants.ROLE_ADMIN)) - .build()) - .build(); + .systemUser(Boolean.TRUE) + .userId("EXTERNALUSERID") + .innerUserId("INNERUSERID") + .fiscalCode("FISCALCODE") + .familyName("FAMILYNAME") + .name("NAME") + .issuer("IPA_CODE") + .organizationAccess(IamUserOrganizationRolesDTO.builder() + .organizationIpaCode("IPA_CODE") + .roles(Collections.singletonList(Constants.ROLE_ADMIN)) + .build()) + .build(); UserInfo expected = UserInfo.builder() - .userId("EXTERNALUSERID") - .mappedExternalUserId("IPA_CODE-WS_USER") - .fiscalCode("FISCALCODE") - .familyName("FAMILYNAME") - .name("NAME") - .issuer("IPA_CODE") - .organizations(Collections.singletonList(UserOrganizationRoles.builder() - .organizationIpaCode("IPA_CODE") - .roles(List.of(Constants.ROLE_ADMIN)) - .build())) - .build(); + .userId("EXTERNALUSERID") + .mappedExternalUserId("IPA_CODE-WS_USER") + .fiscalCode("FISCALCODE") + .familyName("FAMILYNAME") + .name("NAME") + .issuer("IPA_CODE") + .organizations(Collections.singletonList(UserOrganizationRoles.builder() + .organizationIpaCode("IPA_CODE") + .roles(List.of(Constants.ROLE_ADMIN)) + .build())) + .build(); // When UserInfo result = mapper.apply(iamUserInfo); From 93af227b1a7fb31fe83d939f426f9f609be23b40 Mon Sep 17 00:00:00 2001 From: ElisKina-dev Date: Thu, 9 Jan 2025 16:37:01 +0100 Subject: [PATCH 07/15] fixes --- .../user/IamUserInfoDTO2UserInfoMapper.java | 174 ++++++++++-------- .../auth/service/user/UserServiceImpl.java | 7 +- .../client/OrganizationSearchClientTest.java | 1 - .../config/OrganizationApiHolderTest.java | 1 - .../IamUserInfoDTO2UserInfoMapperTest.java | 19 +- 5 files changed, 108 insertions(+), 94 deletions(-) diff --git a/src/main/java/it/gov/pagopa/payhub/auth/service/user/IamUserInfoDTO2UserInfoMapper.java b/src/main/java/it/gov/pagopa/payhub/auth/service/user/IamUserInfoDTO2UserInfoMapper.java index e366e6f..a3fc651 100644 --- a/src/main/java/it/gov/pagopa/payhub/auth/service/user/IamUserInfoDTO2UserInfoMapper.java +++ b/src/main/java/it/gov/pagopa/payhub/auth/service/user/IamUserInfoDTO2UserInfoMapper.java @@ -13,6 +13,7 @@ import it.gov.pagopa.payhub.dto.generated.UserOrganizationRoles; import it.gov.pagopa.pu.p4pa_organization.dto.generated.Broker; import it.gov.pagopa.pu.p4pa_organization.dto.generated.Organization; +import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Service; import java.util.ArrayList; @@ -24,86 +25,97 @@ @Service public class IamUserInfoDTO2UserInfoMapper implements Function { - public static final String WS_USER_SUFFIX = "-WS_USER"; - private final UsersRepository usersRepository; - private final OperatorsRepository operatorsRepository; - private final OrganizationSearchClient organizationSearchClient; - - public IamUserInfoDTO2UserInfoMapper(UsersRepository usersRepository, OperatorsRepository operatorsRepository, OrganizationSearchClient organizationSearchClient) { - this.usersRepository = usersRepository; - this.operatorsRepository = operatorsRepository; - this.organizationSearchClient = organizationSearchClient; - } - - @Override - public UserInfo apply(IamUserInfoDTO iamUserInfoDTO) { - if (iamUserInfoDTO.isSystemUser()) { - return systemUserMapper(iamUserInfoDTO); - } - return userInfoMapper(iamUserInfoDTO); - } - - private UserInfo systemUserMapper(IamUserInfoDTO iamUserInfoDTO) { - String organizationIpaCode = iamUserInfoDTO.getOrganizationAccess().getOrganizationIpaCode(); - return UserInfo.builder() - .userId(iamUserInfoDTO.getUserId()) - .mappedExternalUserId(buildSystemMappedExternalUserId(organizationIpaCode)) - .fiscalCode(iamUserInfoDTO.getFiscalCode()) - .familyName(iamUserInfoDTO.getFamilyName()) - .name(iamUserInfoDTO.getName()) - .issuer(iamUserInfoDTO.getIssuer()) - .organizations(Collections.singletonList(UserOrganizationRoles.builder() - .organizationIpaCode(organizationIpaCode) - .roles(Collections.singletonList(Constants.ROLE_ADMIN)) - .build())) - .build(); - } - - public static String buildSystemMappedExternalUserId(String organizationIpaCode) { - return organizationIpaCode + WS_USER_SUFFIX; - } - - private UserInfo userInfoMapper(IamUserInfoDTO iamUserInfoDTO) { - User user = usersRepository.findById(iamUserInfoDTO.getInnerUserId()).orElseThrow(() -> new UserNotFoundException("Cannot found user having inner id:" + iamUserInfoDTO.getInnerUserId())); - List userRoles = operatorsRepository.findAllByUserId(iamUserInfoDTO.getInnerUserId()); - - String orgIpaCode = Optional.ofNullable(iamUserInfoDTO.getOrganizationAccess()) - .map(IamUserOrganizationRolesDTO::getOrganizationIpaCode) - .orElseGet(() -> !userRoles.isEmpty() ? userRoles.get(0).getOrganizationIpaCode() : null); - - Broker brokerInfo = null; - if (orgIpaCode != null) { - Organization organization = organizationSearchClient.getOrganizationByIpaCode(orgIpaCode, String.valueOf(iamUserInfoDTO.getOrganizationAccess())); - if (organization != null && organization.getBrokerId() != null) { - brokerInfo = organizationSearchClient.getBrokerById(organization.getBrokerId(), String.valueOf(iamUserInfoDTO.getOrganizationAccess())); - } - } - - UserInfo userInfo = UserInfo.builder() - .userId(user.getUserId()) - .mappedExternalUserId(user.getMappedExternalUserId()) - .fiscalCode(iamUserInfoDTO.getFiscalCode()) - .familyName(iamUserInfoDTO.getFamilyName()) - .name(iamUserInfoDTO.getName()) - .issuer(iamUserInfoDTO.getIssuer()) - .organizations(userRoles.stream() - .map(r -> UserOrganizationRoles.builder() - .operatorId(r.getOperatorId()) - .organizationIpaCode(r.getOrganizationIpaCode()) - .roles(new ArrayList<>(r.getRoles())) - .email(r.getEmail()) - .build()) - .toList()) - .build(); - - if(iamUserInfoDTO.getOrganizationAccess() != null){ - userInfo.setOrganizationAccess(iamUserInfoDTO.getOrganizationAccess().getOrganizationIpaCode()); - } - if (brokerInfo != null) { - userInfo.setBrokerId(brokerInfo.getBrokerId()); - userInfo.setBrokerFiscalCode(brokerInfo.getBrokerFiscalCode()); - } - return userInfo; - } + public static final String WS_USER_SUFFIX = "-WS_USER"; + private final UsersRepository usersRepository; + private final OperatorsRepository operatorsRepository; + private final OrganizationSearchClient organizationSearchClient; + @Value("${app.enable-access-organization-mode}") + private boolean organizationAccessMode; + + public IamUserInfoDTO2UserInfoMapper(UsersRepository usersRepository, OperatorsRepository operatorsRepository, OrganizationSearchClient organizationSearchClient) { + this.usersRepository = usersRepository; + this.operatorsRepository = operatorsRepository; + this.organizationSearchClient = organizationSearchClient; + } + + @Override + public UserInfo apply(IamUserInfoDTO iamUserInfoDTO) { + throw new UnsupportedOperationException("AccessToken is required for this operation."); + } + + public UserInfo apply(IamUserInfoDTO iamUserInfoDTO, String accessToken) { + if (iamUserInfoDTO.isSystemUser()) { + return systemUserMapper(iamUserInfoDTO); + } + return userInfoMapper(iamUserInfoDTO, accessToken); + } + + private UserInfo systemUserMapper(IamUserInfoDTO iamUserInfoDTO) { + String organizationIpaCode = iamUserInfoDTO.getOrganizationAccess().getOrganizationIpaCode(); + return UserInfo.builder() + .userId(iamUserInfoDTO.getUserId()) + .mappedExternalUserId(buildSystemMappedExternalUserId(organizationIpaCode)) + .fiscalCode(iamUserInfoDTO.getFiscalCode()) + .familyName(iamUserInfoDTO.getFamilyName()) + .name(iamUserInfoDTO.getName()) + .issuer(iamUserInfoDTO.getIssuer()) + .organizations(Collections.singletonList(UserOrganizationRoles.builder() + .organizationIpaCode(organizationIpaCode) + .roles(Collections.singletonList(Constants.ROLE_ADMIN)) + .build())) + .build(); + } + + public static String buildSystemMappedExternalUserId(String organizationIpaCode) { + return organizationIpaCode + WS_USER_SUFFIX; + } + + private UserInfo userInfoMapper(IamUserInfoDTO iamUserInfoDTO, String accessToken) { + User user = usersRepository.findById(iamUserInfoDTO.getInnerUserId()).orElseThrow(() -> new UserNotFoundException("Cannot found user having inner id:" + iamUserInfoDTO.getInnerUserId())); + List userRoles = operatorsRepository.findAllByUserId(iamUserInfoDTO.getInnerUserId()); + + Broker brokerInfo = getSessionBroker(iamUserInfoDTO, userRoles, accessToken); + + UserInfo userInfo = UserInfo.builder() + .userId(user.getUserId()) + .mappedExternalUserId(user.getMappedExternalUserId()) + .fiscalCode(iamUserInfoDTO.getFiscalCode()) + .familyName(iamUserInfoDTO.getFamilyName()) + .name(iamUserInfoDTO.getName()) + .issuer(iamUserInfoDTO.getIssuer()) + .organizations(userRoles.stream() + .map(r -> UserOrganizationRoles.builder() + .operatorId(r.getOperatorId()) + .organizationIpaCode(r.getOrganizationIpaCode()) + .roles(new ArrayList<>(r.getRoles())) + .email(r.getEmail()) + .build()) + .toList()) + .build(); + + if (iamUserInfoDTO.getOrganizationAccess() != null) { + userInfo.setOrganizationAccess(iamUserInfoDTO.getOrganizationAccess().getOrganizationIpaCode()); + } + if (brokerInfo != null) { + userInfo.setBrokerId(brokerInfo.getBrokerId()); + userInfo.setBrokerFiscalCode(brokerInfo.getBrokerFiscalCode()); + } + userInfo.setCanManageUsers(!organizationAccessMode); + return userInfo; + } + + private Broker getSessionBroker(IamUserInfoDTO iamUserInfoDTO, List userRoles, String accessToken) { + String orgIpaCode = Optional.ofNullable(iamUserInfoDTO.getOrganizationAccess()) + .map(IamUserOrganizationRolesDTO::getOrganizationIpaCode) + .orElseGet(() -> !userRoles.isEmpty() ? userRoles.get(0).getOrganizationIpaCode() : null); + + if (orgIpaCode != null) { + Organization organization = organizationSearchClient.getOrganizationByIpaCode(orgIpaCode, accessToken); + if (organization != null && organization.getBrokerId() != null) { + return organizationSearchClient.getBrokerById(organization.getBrokerId(), accessToken); + } + } + return null; + } } diff --git a/src/main/java/it/gov/pagopa/payhub/auth/service/user/UserServiceImpl.java b/src/main/java/it/gov/pagopa/payhub/auth/service/user/UserServiceImpl.java index e837c95..c96f758 100644 --- a/src/main/java/it/gov/pagopa/payhub/auth/service/user/UserServiceImpl.java +++ b/src/main/java/it/gov/pagopa/payhub/auth/service/user/UserServiceImpl.java @@ -11,7 +11,6 @@ import it.gov.pagopa.payhub.dto.generated.OperatorDTO; import it.gov.pagopa.payhub.dto.generated.UserInfo; import lombok.extern.slf4j.Slf4j; -import org.springframework.beans.factory.annotation.Value; import org.springframework.data.domain.Page; import org.springframework.data.domain.Pageable; import org.springframework.stereotype.Service; @@ -27,8 +26,6 @@ public class UserServiceImpl implements UserService { private final OperatorRegistrationService operatorRegistrationService; private final IamUserInfoDTO2UserInfoMapper userInfoMapper; private final OrganizationOperatorRetrieverService organizationOperatorRetrieverService; - @Value("${app.enable-access-organization-mode}") - private boolean organizationAccessMode; public UserServiceImpl(TokenStoreService tokenStoreService, UserRegistrationService userRegistrationService, OperatorRegistrationService operatorRegistrationService, IamUserInfoDTO2UserInfoMapper userInfoMapper, OrganizationOperatorRetrieverService organizationOperatorRetrieverService) { @@ -59,10 +56,8 @@ public UserInfo getUserInfo(String accessToken) { UserInfo result = userInfoMapper.apply(userInfo); - result.setCanManageUsers(!organizationAccessMode); + log.debug("User info retrieved successfully with brokerId: {}", result.getBrokerId()); - log.debug("User info retrieved successfully with brokerId: {}", - result.getBrokerId() != null ? result.getBrokerId() : "N/A"); return result; } diff --git a/src/test/java/it/gov/pagopa/payhub/auth/connector/client/OrganizationSearchClientTest.java b/src/test/java/it/gov/pagopa/payhub/auth/connector/client/OrganizationSearchClientTest.java index 3e67048..1c7609d 100644 --- a/src/test/java/it/gov/pagopa/payhub/auth/connector/client/OrganizationSearchClientTest.java +++ b/src/test/java/it/gov/pagopa/payhub/auth/connector/client/OrganizationSearchClientTest.java @@ -1,6 +1,5 @@ package it.gov.pagopa.payhub.auth.connector.client; -import it.gov.pagopa.payhub.auth.connector.client.OrganizationSearchClient; import it.gov.pagopa.payhub.auth.connector.config.OrganizationApisHolder; import it.gov.pagopa.pu.p4pa_organization.controller.generated.OrganizationSearchControllerApi; import it.gov.pagopa.pu.p4pa_organization.dto.generated.Organization; diff --git a/src/test/java/it/gov/pagopa/payhub/auth/connector/config/OrganizationApiHolderTest.java b/src/test/java/it/gov/pagopa/payhub/auth/connector/config/OrganizationApiHolderTest.java index eb4e152..f96fd0a 100644 --- a/src/test/java/it/gov/pagopa/payhub/auth/connector/config/OrganizationApiHolderTest.java +++ b/src/test/java/it/gov/pagopa/payhub/auth/connector/config/OrganizationApiHolderTest.java @@ -1,7 +1,6 @@ package it.gov.pagopa.payhub.auth.connector.config; import it.gov.pagopa.payhub.auth.connector.BaseApiHolderTest; -import it.gov.pagopa.payhub.auth.connector.config.OrganizationApisHolder; import it.gov.pagopa.pu.p4pa_organization.controller.ApiClient; import it.gov.pagopa.pu.p4pa_organization.dto.generated.Broker; import it.gov.pagopa.pu.p4pa_organization.dto.generated.Organization; diff --git a/src/test/java/it/gov/pagopa/payhub/auth/service/user/IamUserInfoDTO2UserInfoMapperTest.java b/src/test/java/it/gov/pagopa/payhub/auth/service/user/IamUserInfoDTO2UserInfoMapperTest.java index 77574ef..7655f20 100644 --- a/src/test/java/it/gov/pagopa/payhub/auth/service/user/IamUserInfoDTO2UserInfoMapperTest.java +++ b/src/test/java/it/gov/pagopa/payhub/auth/service/user/IamUserInfoDTO2UserInfoMapperTest.java @@ -41,6 +41,7 @@ class IamUserInfoDTO2UserInfoMapperTest { @InjectMocks private IamUserInfoDTO2UserInfoMapper mapper; + private final boolean organizationAccessMode = false; @BeforeEach void init() { @@ -54,6 +55,7 @@ void verifyNotMoreInteractions() { @Test void givenNotUserWhenApplyThenUserNotFoundException() { + String accessToken = "sampleAccessToken"; // Given IamUserInfoDTO iamUserInfo = IamUserInfoDTO.builder() .userId("EXTERNALUSERID") @@ -63,11 +65,12 @@ void givenNotUserWhenApplyThenUserNotFoundException() { Mockito.when(usersRepositoryMock.findById(iamUserInfo.getInnerUserId())).thenReturn(Optional.empty()); // When, Then - Assertions.assertThrows(UserNotFoundException.class, () -> mapper.apply(iamUserInfo)); + Assertions.assertThrows(UserNotFoundException.class, () -> mapper.apply(iamUserInfo, accessToken)); } @Test void givenCompleteDataWhenApplyThenOk() { + String accessToken = "sampleAccessToken"; // Given IamUserInfoDTO iamUserInfo = IamUserInfoDTO.builder() .userId("EXTERNALUSERID") @@ -108,6 +111,7 @@ void givenCompleteDataWhenApplyThenOk() { .roles(List.of("ROLE")) .email("EMAIL") .build())) + .canManageUsers(!organizationAccessMode) .build(); Mockito.when(usersRepositoryMock.findById(iamUserInfo.getInnerUserId())).thenReturn(Optional.of(user)); @@ -116,7 +120,7 @@ void givenCompleteDataWhenApplyThenOk() { .thenReturn(new Organization()); // When - UserInfo result = mapper.apply(iamUserInfo); + UserInfo result = mapper.apply(iamUserInfo, accessToken); // Then Assertions.assertEquals(expected, result); @@ -124,6 +128,7 @@ void givenCompleteDataWhenApplyThenOk() { @Test void givenNotOperatorsWhenApplyThenOk() { + String accessToken = "sampleAccessToken"; // Given IamUserInfoDTO iamUserInfo = IamUserInfoDTO.builder() .userId("EXTERNALUSERID") @@ -152,13 +157,14 @@ void givenNotOperatorsWhenApplyThenOk() { .issuer("ISSUER") .organizationAccess("ORG") .organizations(Collections.emptyList()) + .canManageUsers(!organizationAccessMode) .build(); Mockito.when(usersRepositoryMock.findById(iamUserInfo.getInnerUserId())).thenReturn(Optional.of(user)); Mockito.when(operatorsRepositoryMock.findAllByUserId(user.getUserId())).thenReturn(Collections.emptyList()); // When - UserInfo result = mapper.apply(iamUserInfo); + UserInfo result = mapper.apply(iamUserInfo, accessToken); // Then Assertions.assertEquals(expected, result); @@ -166,6 +172,7 @@ void givenNotOperatorsWhenApplyThenOk() { @Test void givenNoOrganizationAccessWhenApplyThenOk() { + String accessToken = "sampleAccessToken"; // Given IamUserInfoDTO iamUserInfo = IamUserInfoDTO.builder() .userId("EXTERNALUSERID") @@ -201,13 +208,14 @@ void givenNoOrganizationAccessWhenApplyThenOk() { .roles(List.of("ROLE")) .email("EMAIL") .build())) + .canManageUsers(!organizationAccessMode) .build(); Mockito.when(usersRepositoryMock.findById(iamUserInfo.getInnerUserId())).thenReturn(Optional.of(user)); Mockito.when(operatorsRepositoryMock.findAllByUserId(user.getUserId())).thenReturn(organizationRoles); // When - UserInfo result = mapper.apply(iamUserInfo); + UserInfo result = mapper.apply(iamUserInfo, accessToken); // Then Assertions.assertEquals(expected, result); @@ -215,6 +223,7 @@ void givenNoOrganizationAccessWhenApplyThenOk() { @Test void givenSystemUserWhenApplyThenOk() { + String accessToken = "sampleAccessToken"; // Given IamUserInfoDTO iamUserInfo = IamUserInfoDTO.builder() .systemUser(Boolean.TRUE) @@ -244,7 +253,7 @@ void givenSystemUserWhenApplyThenOk() { .build(); // When - UserInfo result = mapper.apply(iamUserInfo); + UserInfo result = mapper.apply(iamUserInfo, accessToken); // Then Assertions.assertEquals(expected, result); From 071f8def95b43a6d98119dfed0119cd93def1d72 Mon Sep 17 00:00:00 2001 From: ElisKina-dev Date: Thu, 9 Jan 2025 18:03:13 +0100 Subject: [PATCH 08/15] fixes --- .../user/IamUserInfoDTO2UserInfoMapper.java | 15 ++++----------- .../payhub/auth/service/user/UserServiceImpl.java | 2 +- .../user/IamUserInfoDTO2UserInfoMapperTest.java | 4 +--- .../payhub/auth/service/user/UserServiceTest.java | 2 +- 4 files changed, 7 insertions(+), 16 deletions(-) diff --git a/src/main/java/it/gov/pagopa/payhub/auth/service/user/IamUserInfoDTO2UserInfoMapper.java b/src/main/java/it/gov/pagopa/payhub/auth/service/user/IamUserInfoDTO2UserInfoMapper.java index a3fc651..e9024d7 100644 --- a/src/main/java/it/gov/pagopa/payhub/auth/service/user/IamUserInfoDTO2UserInfoMapper.java +++ b/src/main/java/it/gov/pagopa/payhub/auth/service/user/IamUserInfoDTO2UserInfoMapper.java @@ -13,34 +13,27 @@ import it.gov.pagopa.payhub.dto.generated.UserOrganizationRoles; import it.gov.pagopa.pu.p4pa_organization.dto.generated.Broker; import it.gov.pagopa.pu.p4pa_organization.dto.generated.Organization; -import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Service; import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.Optional; -import java.util.function.Function; @Service -public class IamUserInfoDTO2UserInfoMapper implements Function { +public class IamUserInfoDTO2UserInfoMapper { public static final String WS_USER_SUFFIX = "-WS_USER"; private final UsersRepository usersRepository; private final OperatorsRepository operatorsRepository; private final OrganizationSearchClient organizationSearchClient; - @Value("${app.enable-access-organization-mode}") - private boolean organizationAccessMode; + private final boolean organizationAccessMode; - public IamUserInfoDTO2UserInfoMapper(UsersRepository usersRepository, OperatorsRepository operatorsRepository, OrganizationSearchClient organizationSearchClient) { + public IamUserInfoDTO2UserInfoMapper(UsersRepository usersRepository, OperatorsRepository operatorsRepository, OrganizationSearchClient organizationSearchClient, boolean organizationAccessMode) { this.usersRepository = usersRepository; this.operatorsRepository = operatorsRepository; this.organizationSearchClient = organizationSearchClient; - } - - @Override - public UserInfo apply(IamUserInfoDTO iamUserInfoDTO) { - throw new UnsupportedOperationException("AccessToken is required for this operation."); + this.organizationAccessMode = organizationAccessMode; } public UserInfo apply(IamUserInfoDTO iamUserInfoDTO, String accessToken) { diff --git a/src/main/java/it/gov/pagopa/payhub/auth/service/user/UserServiceImpl.java b/src/main/java/it/gov/pagopa/payhub/auth/service/user/UserServiceImpl.java index c96f758..5bb822a 100644 --- a/src/main/java/it/gov/pagopa/payhub/auth/service/user/UserServiceImpl.java +++ b/src/main/java/it/gov/pagopa/payhub/auth/service/user/UserServiceImpl.java @@ -54,7 +54,7 @@ public UserInfo getUserInfo(String accessToken) { throw new InvalidAccessTokenException("AccessToken not found"); } - UserInfo result = userInfoMapper.apply(userInfo); + UserInfo result = userInfoMapper.apply(userInfo, accessToken); log.debug("User info retrieved successfully with brokerId: {}", result.getBrokerId()); diff --git a/src/test/java/it/gov/pagopa/payhub/auth/service/user/IamUserInfoDTO2UserInfoMapperTest.java b/src/test/java/it/gov/pagopa/payhub/auth/service/user/IamUserInfoDTO2UserInfoMapperTest.java index 7655f20..a3204af 100644 --- a/src/test/java/it/gov/pagopa/payhub/auth/service/user/IamUserInfoDTO2UserInfoMapperTest.java +++ b/src/test/java/it/gov/pagopa/payhub/auth/service/user/IamUserInfoDTO2UserInfoMapperTest.java @@ -17,7 +17,6 @@ import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; -import org.mockito.InjectMocks; import org.mockito.Mock; import org.mockito.Mockito; import org.mockito.junit.jupiter.MockitoExtension; @@ -38,14 +37,13 @@ class IamUserInfoDTO2UserInfoMapperTest { @Mock private OrganizationSearchClient organizationSearchClientMock; - @InjectMocks private IamUserInfoDTO2UserInfoMapper mapper; private final boolean organizationAccessMode = false; @BeforeEach void init() { - mapper = new IamUserInfoDTO2UserInfoMapper(usersRepositoryMock, operatorsRepositoryMock, organizationSearchClientMock); + mapper = new IamUserInfoDTO2UserInfoMapper(usersRepositoryMock, operatorsRepositoryMock, organizationSearchClientMock, organizationAccessMode); } @AfterEach diff --git a/src/test/java/it/gov/pagopa/payhub/auth/service/user/UserServiceTest.java b/src/test/java/it/gov/pagopa/payhub/auth/service/user/UserServiceTest.java index 2542138..59e46a7 100644 --- a/src/test/java/it/gov/pagopa/payhub/auth/service/user/UserServiceTest.java +++ b/src/test/java/it/gov/pagopa/payhub/auth/service/user/UserServiceTest.java @@ -76,7 +76,7 @@ void givenAccessTokenWhenGetUserInfoThenOk() { IamUserInfoDTO iamUserInfo = new IamUserInfoDTO(); UserInfo expectedUserInfo = new UserInfo(); Mockito.when(tokenStoreServiceMock.load(accessToken)).thenReturn(iamUserInfo); - Mockito.when(userInfoMapperMock.apply(iamUserInfo)).thenReturn(expectedUserInfo); + Mockito.when(userInfoMapperMock.apply(iamUserInfo, accessToken)).thenReturn(expectedUserInfo); // When UserInfo result = service.getUserInfo(accessToken); From a960b7d3212374d3c7abeb284cfd442dbb0158da Mon Sep 17 00:00:00 2001 From: ElisKina-dev Date: Thu, 9 Jan 2025 18:13:59 +0100 Subject: [PATCH 09/15] fixes --- .../auth/service/user/IamUserInfoDTO2UserInfoMapper.java | 6 +++++- .../service/user/IamUserInfoDTO2UserInfoMapperTest.java | 2 +- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/src/main/java/it/gov/pagopa/payhub/auth/service/user/IamUserInfoDTO2UserInfoMapper.java b/src/main/java/it/gov/pagopa/payhub/auth/service/user/IamUserInfoDTO2UserInfoMapper.java index e9024d7..67f3d30 100644 --- a/src/main/java/it/gov/pagopa/payhub/auth/service/user/IamUserInfoDTO2UserInfoMapper.java +++ b/src/main/java/it/gov/pagopa/payhub/auth/service/user/IamUserInfoDTO2UserInfoMapper.java @@ -13,6 +13,7 @@ import it.gov.pagopa.payhub.dto.generated.UserOrganizationRoles; import it.gov.pagopa.pu.p4pa_organization.dto.generated.Broker; import it.gov.pagopa.pu.p4pa_organization.dto.generated.Organization; +import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Service; import java.util.ArrayList; @@ -29,7 +30,10 @@ public class IamUserInfoDTO2UserInfoMapper { private final OrganizationSearchClient organizationSearchClient; private final boolean organizationAccessMode; - public IamUserInfoDTO2UserInfoMapper(UsersRepository usersRepository, OperatorsRepository operatorsRepository, OrganizationSearchClient organizationSearchClient, boolean organizationAccessMode) { + public IamUserInfoDTO2UserInfoMapper(@Value("${app.enable-access-organization-mode}") boolean organizationAccessMode, + UsersRepository usersRepository, + OperatorsRepository operatorsRepository, + OrganizationSearchClient organizationSearchClient) { this.usersRepository = usersRepository; this.operatorsRepository = operatorsRepository; this.organizationSearchClient = organizationSearchClient; diff --git a/src/test/java/it/gov/pagopa/payhub/auth/service/user/IamUserInfoDTO2UserInfoMapperTest.java b/src/test/java/it/gov/pagopa/payhub/auth/service/user/IamUserInfoDTO2UserInfoMapperTest.java index a3204af..93ac0a4 100644 --- a/src/test/java/it/gov/pagopa/payhub/auth/service/user/IamUserInfoDTO2UserInfoMapperTest.java +++ b/src/test/java/it/gov/pagopa/payhub/auth/service/user/IamUserInfoDTO2UserInfoMapperTest.java @@ -43,7 +43,7 @@ class IamUserInfoDTO2UserInfoMapperTest { @BeforeEach void init() { - mapper = new IamUserInfoDTO2UserInfoMapper(usersRepositoryMock, operatorsRepositoryMock, organizationSearchClientMock, organizationAccessMode); + mapper = new IamUserInfoDTO2UserInfoMapper(organizationAccessMode, usersRepositoryMock, operatorsRepositoryMock, organizationSearchClientMock); } @AfterEach From 411f788edee3ddbf66de44d7b3ae36850f2e63f1 Mon Sep 17 00:00:00 2001 From: ElisKina-dev Date: Fri, 10 Jan 2025 11:09:56 +0100 Subject: [PATCH 10/15] fix --- openapi/p4pa-auth.openapi.yaml | 1 - 1 file changed, 1 deletion(-) diff --git a/openapi/p4pa-auth.openapi.yaml b/openapi/p4pa-auth.openapi.yaml index 1d63313..9ee600b 100644 --- a/openapi/p4pa-auth.openapi.yaml +++ b/openapi/p4pa-auth.openapi.yaml @@ -551,7 +551,6 @@ components: - email - issuer - organizations - - brokerId - brokerFiscalCode - canManageUsers properties: From ff3edbe735597ba2a3947f93ff06c2920bbe7ce6 Mon Sep 17 00:00:00 2001 From: ElisKina-dev Date: Fri, 10 Jan 2025 11:27:29 +0100 Subject: [PATCH 11/15] fix --- openapi/p4pa-auth.openapi.yaml | 1 - 1 file changed, 1 deletion(-) diff --git a/openapi/p4pa-auth.openapi.yaml b/openapi/p4pa-auth.openapi.yaml index 9ee600b..fd357ba 100644 --- a/openapi/p4pa-auth.openapi.yaml +++ b/openapi/p4pa-auth.openapi.yaml @@ -551,7 +551,6 @@ components: - email - issuer - organizations - - brokerFiscalCode - canManageUsers properties: userId: From 7672652faa5c5166e6ad88bddec5010c9d6fede6 Mon Sep 17 00:00:00 2001 From: ElisKina-dev Date: Fri, 10 Jan 2025 12:06:15 +0100 Subject: [PATCH 12/15] fix --- .../it/gov/pagopa/payhub/auth/dto/IamUserInfoDTO.java | 1 + .../auth/service/user/IamUserInfoDTO2UserInfoMapper.java | 2 ++ .../payhub/auth/mapper/ClientDTO2UserInfoMapperTest.java | 2 +- .../service/user/IamUserInfoDTO2UserInfoMapperTest.java | 8 ++++++++ 4 files changed, 12 insertions(+), 1 deletion(-) diff --git a/src/main/java/it/gov/pagopa/payhub/auth/dto/IamUserInfoDTO.java b/src/main/java/it/gov/pagopa/payhub/auth/dto/IamUserInfoDTO.java index 7f98798..77e8a5b 100644 --- a/src/main/java/it/gov/pagopa/payhub/auth/dto/IamUserInfoDTO.java +++ b/src/main/java/it/gov/pagopa/payhub/auth/dto/IamUserInfoDTO.java @@ -17,6 +17,7 @@ public class IamUserInfoDTO { private String name; private String issuer; private IamUserOrganizationRolesDTO organizationAccess; + private Long brokerId; // field calculated upon registration private String innerUserId; diff --git a/src/main/java/it/gov/pagopa/payhub/auth/service/user/IamUserInfoDTO2UserInfoMapper.java b/src/main/java/it/gov/pagopa/payhub/auth/service/user/IamUserInfoDTO2UserInfoMapper.java index 67f3d30..70ac75e 100644 --- a/src/main/java/it/gov/pagopa/payhub/auth/service/user/IamUserInfoDTO2UserInfoMapper.java +++ b/src/main/java/it/gov/pagopa/payhub/auth/service/user/IamUserInfoDTO2UserInfoMapper.java @@ -60,6 +60,7 @@ private UserInfo systemUserMapper(IamUserInfoDTO iamUserInfoDTO) { .organizationIpaCode(organizationIpaCode) .roles(Collections.singletonList(Constants.ROLE_ADMIN)) .build())) + .brokerId(iamUserInfoDTO.getBrokerId()) .build(); } @@ -88,6 +89,7 @@ private UserInfo userInfoMapper(IamUserInfoDTO iamUserInfoDTO, String accessToke .email(r.getEmail()) .build()) .toList()) + .brokerId(iamUserInfoDTO.getBrokerId()) .build(); if (iamUserInfoDTO.getOrganizationAccess() != null) { diff --git a/src/test/java/it/gov/pagopa/payhub/auth/mapper/ClientDTO2UserInfoMapperTest.java b/src/test/java/it/gov/pagopa/payhub/auth/mapper/ClientDTO2UserInfoMapperTest.java index 22cb6c2..14a57c3 100644 --- a/src/test/java/it/gov/pagopa/payhub/auth/mapper/ClientDTO2UserInfoMapperTest.java +++ b/src/test/java/it/gov/pagopa/payhub/auth/mapper/ClientDTO2UserInfoMapperTest.java @@ -46,6 +46,6 @@ void givenDTOWhenApplyTheOk() { IamUserInfoDTO result = mapper.apply(clientDTO); //Then Assertions.assertEquals(iamUserInfoDTO, result); - TestUtils.checkNotNullFields(result, "innerUserId"); + TestUtils.checkNotNullFields(result, "innerUserId", "brokerId"); } } diff --git a/src/test/java/it/gov/pagopa/payhub/auth/service/user/IamUserInfoDTO2UserInfoMapperTest.java b/src/test/java/it/gov/pagopa/payhub/auth/service/user/IamUserInfoDTO2UserInfoMapperTest.java index 93ac0a4..25c77df 100644 --- a/src/test/java/it/gov/pagopa/payhub/auth/service/user/IamUserInfoDTO2UserInfoMapperTest.java +++ b/src/test/java/it/gov/pagopa/payhub/auth/service/user/IamUserInfoDTO2UserInfoMapperTest.java @@ -81,6 +81,7 @@ void givenCompleteDataWhenApplyThenOk() { .organizationIpaCode("ORG") .email("EMAIL") .build()) + .brokerId(1L) .build(); User user = User.builder() @@ -109,6 +110,7 @@ void givenCompleteDataWhenApplyThenOk() { .roles(List.of("ROLE")) .email("EMAIL") .build())) + .brokerId(1L) .canManageUsers(!organizationAccessMode) .build(); @@ -139,6 +141,7 @@ void givenNotOperatorsWhenApplyThenOk() { .organizationIpaCode("ORG") .email("EMAIL") .build()) + .brokerId(1L) .build(); User user = User.builder() @@ -155,6 +158,7 @@ void givenNotOperatorsWhenApplyThenOk() { .issuer("ISSUER") .organizationAccess("ORG") .organizations(Collections.emptyList()) + .brokerId(1L) .canManageUsers(!organizationAccessMode) .build(); @@ -179,6 +183,7 @@ void givenNoOrganizationAccessWhenApplyThenOk() { .familyName("FAMILYNAME") .name("NAME") .issuer("ISSUER") + .brokerId(1L) .build(); User user = User.builder() @@ -206,6 +211,7 @@ void givenNoOrganizationAccessWhenApplyThenOk() { .roles(List.of("ROLE")) .email("EMAIL") .build())) + .brokerId(1L) .canManageUsers(!organizationAccessMode) .build(); @@ -235,6 +241,7 @@ void givenSystemUserWhenApplyThenOk() { .organizationIpaCode("IPA_CODE") .roles(Collections.singletonList(Constants.ROLE_ADMIN)) .build()) + .brokerId(1L) .build(); UserInfo expected = UserInfo.builder() @@ -248,6 +255,7 @@ void givenSystemUserWhenApplyThenOk() { .organizationIpaCode("IPA_CODE") .roles(List.of(Constants.ROLE_ADMIN)) .build())) + .brokerId(1L) .build(); // When From 656a7285028387423ec48f8941c6988e1de1cbed Mon Sep 17 00:00:00 2001 From: ElisKina-dev Date: Fri, 10 Jan 2025 14:32:27 +0100 Subject: [PATCH 13/15] fix --- .../payhub/auth/dto/IamUserInfoDTO.java | 1 - .../user/IamUserInfoDTO2UserInfoMapper.java | 41 +++++++--- .../mapper/ClientDTO2UserInfoMapperTest.java | 2 +- .../IamUserInfoDTO2UserInfoMapperTest.java | 80 ++++++++++++++----- 4 files changed, 90 insertions(+), 34 deletions(-) diff --git a/src/main/java/it/gov/pagopa/payhub/auth/dto/IamUserInfoDTO.java b/src/main/java/it/gov/pagopa/payhub/auth/dto/IamUserInfoDTO.java index 77e8a5b..7f98798 100644 --- a/src/main/java/it/gov/pagopa/payhub/auth/dto/IamUserInfoDTO.java +++ b/src/main/java/it/gov/pagopa/payhub/auth/dto/IamUserInfoDTO.java @@ -17,7 +17,6 @@ public class IamUserInfoDTO { private String name; private String issuer; private IamUserOrganizationRolesDTO organizationAccess; - private Long brokerId; // field calculated upon registration private String innerUserId; diff --git a/src/main/java/it/gov/pagopa/payhub/auth/service/user/IamUserInfoDTO2UserInfoMapper.java b/src/main/java/it/gov/pagopa/payhub/auth/service/user/IamUserInfoDTO2UserInfoMapper.java index 70ac75e..b9ebdba 100644 --- a/src/main/java/it/gov/pagopa/payhub/auth/service/user/IamUserInfoDTO2UserInfoMapper.java +++ b/src/main/java/it/gov/pagopa/payhub/auth/service/user/IamUserInfoDTO2UserInfoMapper.java @@ -3,11 +3,13 @@ import it.gov.pagopa.payhub.auth.connector.client.OrganizationSearchClient; import it.gov.pagopa.payhub.auth.dto.IamUserInfoDTO; import it.gov.pagopa.payhub.auth.dto.IamUserOrganizationRolesDTO; +import it.gov.pagopa.payhub.auth.exception.custom.InvalidAccessTokenException; import it.gov.pagopa.payhub.auth.exception.custom.UserNotFoundException; import it.gov.pagopa.payhub.auth.model.Operator; import it.gov.pagopa.payhub.auth.model.User; import it.gov.pagopa.payhub.auth.repository.OperatorsRepository; import it.gov.pagopa.payhub.auth.repository.UsersRepository; +import it.gov.pagopa.payhub.auth.service.TokenStoreService; import it.gov.pagopa.payhub.auth.utils.Constants; import it.gov.pagopa.payhub.dto.generated.UserInfo; import it.gov.pagopa.payhub.dto.generated.UserOrganizationRoles; @@ -29,27 +31,30 @@ public class IamUserInfoDTO2UserInfoMapper { private final OperatorsRepository operatorsRepository; private final OrganizationSearchClient organizationSearchClient; private final boolean organizationAccessMode; + private final TokenStoreService tokenStoreService; public IamUserInfoDTO2UserInfoMapper(@Value("${app.enable-access-organization-mode}") boolean organizationAccessMode, UsersRepository usersRepository, OperatorsRepository operatorsRepository, - OrganizationSearchClient organizationSearchClient) { + OrganizationSearchClient organizationSearchClient, + TokenStoreService tokenStoreService) { this.usersRepository = usersRepository; this.operatorsRepository = operatorsRepository; this.organizationSearchClient = organizationSearchClient; this.organizationAccessMode = organizationAccessMode; + this.tokenStoreService = tokenStoreService; } public UserInfo apply(IamUserInfoDTO iamUserInfoDTO, String accessToken) { if (iamUserInfoDTO.isSystemUser()) { - return systemUserMapper(iamUserInfoDTO); + return systemUserMapper(iamUserInfoDTO, accessToken); } return userInfoMapper(iamUserInfoDTO, accessToken); } - private UserInfo systemUserMapper(IamUserInfoDTO iamUserInfoDTO) { + private UserInfo systemUserMapper(IamUserInfoDTO iamUserInfoDTO, String accessToken) { String organizationIpaCode = iamUserInfoDTO.getOrganizationAccess().getOrganizationIpaCode(); - return UserInfo.builder() + UserInfo userInfo = UserInfo.builder() .userId(iamUserInfoDTO.getUserId()) .mappedExternalUserId(buildSystemMappedExternalUserId(organizationIpaCode)) .fiscalCode(iamUserInfoDTO.getFiscalCode()) @@ -60,8 +65,9 @@ private UserInfo systemUserMapper(IamUserInfoDTO iamUserInfoDTO) { .organizationIpaCode(organizationIpaCode) .roles(Collections.singletonList(Constants.ROLE_ADMIN)) .build())) - .brokerId(iamUserInfoDTO.getBrokerId()) .build(); + setBrokerInfo(userInfo, accessToken); + return userInfo; } public static String buildSystemMappedExternalUserId(String organizationIpaCode) { @@ -72,8 +78,6 @@ private UserInfo userInfoMapper(IamUserInfoDTO iamUserInfoDTO, String accessToke User user = usersRepository.findById(iamUserInfoDTO.getInnerUserId()).orElseThrow(() -> new UserNotFoundException("Cannot found user having inner id:" + iamUserInfoDTO.getInnerUserId())); List userRoles = operatorsRepository.findAllByUserId(iamUserInfoDTO.getInnerUserId()); - Broker brokerInfo = getSessionBroker(iamUserInfoDTO, userRoles, accessToken); - UserInfo userInfo = UserInfo.builder() .userId(user.getUserId()) .mappedExternalUserId(user.getMappedExternalUserId()) @@ -89,16 +93,12 @@ private UserInfo userInfoMapper(IamUserInfoDTO iamUserInfoDTO, String accessToke .email(r.getEmail()) .build()) .toList()) - .brokerId(iamUserInfoDTO.getBrokerId()) .build(); if (iamUserInfoDTO.getOrganizationAccess() != null) { userInfo.setOrganizationAccess(iamUserInfoDTO.getOrganizationAccess().getOrganizationIpaCode()); } - if (brokerInfo != null) { - userInfo.setBrokerId(brokerInfo.getBrokerId()); - userInfo.setBrokerFiscalCode(brokerInfo.getBrokerFiscalCode()); - } + setBrokerInfo(userInfo, accessToken); userInfo.setCanManageUsers(!organizationAccessMode); return userInfo; } @@ -117,4 +117,21 @@ private Broker getSessionBroker(IamUserInfoDTO iamUserInfoDTO, List us return null; } + private void setBrokerInfo(UserInfo userInfo, String accessToken) { + IamUserInfoDTO iamUserInfo = tokenStoreService.load(accessToken); + if (iamUserInfo == null) { + throw new InvalidAccessTokenException("AccessToken not found"); + } + + List userRoles = operatorsRepository.findAllByUserId(iamUserInfo.getInnerUserId()); + Broker brokerInfo = getSessionBroker(iamUserInfo, userRoles, accessToken); + + if (brokerInfo != null) { + userInfo.setBrokerId(brokerInfo.getBrokerId()); + userInfo.setBrokerFiscalCode(brokerInfo.getBrokerFiscalCode()); + } else { + throw new IllegalStateException("Broker information not found for the user."); + } + } + } diff --git a/src/test/java/it/gov/pagopa/payhub/auth/mapper/ClientDTO2UserInfoMapperTest.java b/src/test/java/it/gov/pagopa/payhub/auth/mapper/ClientDTO2UserInfoMapperTest.java index 14a57c3..22cb6c2 100644 --- a/src/test/java/it/gov/pagopa/payhub/auth/mapper/ClientDTO2UserInfoMapperTest.java +++ b/src/test/java/it/gov/pagopa/payhub/auth/mapper/ClientDTO2UserInfoMapperTest.java @@ -46,6 +46,6 @@ void givenDTOWhenApplyTheOk() { IamUserInfoDTO result = mapper.apply(clientDTO); //Then Assertions.assertEquals(iamUserInfoDTO, result); - TestUtils.checkNotNullFields(result, "innerUserId", "brokerId"); + TestUtils.checkNotNullFields(result, "innerUserId"); } } diff --git a/src/test/java/it/gov/pagopa/payhub/auth/service/user/IamUserInfoDTO2UserInfoMapperTest.java b/src/test/java/it/gov/pagopa/payhub/auth/service/user/IamUserInfoDTO2UserInfoMapperTest.java index 25c77df..3f2786d 100644 --- a/src/test/java/it/gov/pagopa/payhub/auth/service/user/IamUserInfoDTO2UserInfoMapperTest.java +++ b/src/test/java/it/gov/pagopa/payhub/auth/service/user/IamUserInfoDTO2UserInfoMapperTest.java @@ -8,9 +8,11 @@ import it.gov.pagopa.payhub.auth.model.User; import it.gov.pagopa.payhub.auth.repository.OperatorsRepository; import it.gov.pagopa.payhub.auth.repository.UsersRepository; +import it.gov.pagopa.payhub.auth.service.TokenStoreService; import it.gov.pagopa.payhub.auth.utils.Constants; import it.gov.pagopa.payhub.dto.generated.UserInfo; import it.gov.pagopa.payhub.dto.generated.UserOrganizationRoles; +import it.gov.pagopa.pu.p4pa_organization.dto.generated.Broker; import it.gov.pagopa.pu.p4pa_organization.dto.generated.Organization; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.Assertions; @@ -37,13 +39,16 @@ class IamUserInfoDTO2UserInfoMapperTest { @Mock private OrganizationSearchClient organizationSearchClientMock; + @Mock + private TokenStoreService tokenStoreService; + private IamUserInfoDTO2UserInfoMapper mapper; private final boolean organizationAccessMode = false; @BeforeEach void init() { - mapper = new IamUserInfoDTO2UserInfoMapper(organizationAccessMode, usersRepositoryMock, operatorsRepositoryMock, organizationSearchClientMock); + mapper = new IamUserInfoDTO2UserInfoMapper(organizationAccessMode, usersRepositoryMock, operatorsRepositoryMock, organizationSearchClientMock, tokenStoreService); } @AfterEach @@ -54,7 +59,7 @@ void verifyNotMoreInteractions() { @Test void givenNotUserWhenApplyThenUserNotFoundException() { String accessToken = "sampleAccessToken"; - // Given + IamUserInfoDTO iamUserInfo = IamUserInfoDTO.builder() .userId("EXTERNALUSERID") .innerUserId("INNERUSERID") @@ -62,14 +67,13 @@ void givenNotUserWhenApplyThenUserNotFoundException() { Mockito.when(usersRepositoryMock.findById(iamUserInfo.getInnerUserId())).thenReturn(Optional.empty()); - // When, Then Assertions.assertThrows(UserNotFoundException.class, () -> mapper.apply(iamUserInfo, accessToken)); } @Test void givenCompleteDataWhenApplyThenOk() { String accessToken = "sampleAccessToken"; - // Given + IamUserInfoDTO iamUserInfo = IamUserInfoDTO.builder() .userId("EXTERNALUSERID") .innerUserId("INNERUSERID") @@ -81,7 +85,6 @@ void givenCompleteDataWhenApplyThenOk() { .organizationIpaCode("ORG") .email("EMAIL") .build()) - .brokerId(1L) .build(); User user = User.builder() @@ -116,20 +119,28 @@ void givenCompleteDataWhenApplyThenOk() { Mockito.when(usersRepositoryMock.findById(iamUserInfo.getInnerUserId())).thenReturn(Optional.of(user)); Mockito.when(operatorsRepositoryMock.findAllByUserId(user.getUserId())).thenReturn(organizationRoles); + + Organization mockOrganization = new Organization(); + mockOrganization.setBrokerId(1L); Mockito.when(organizationSearchClientMock.getOrganizationByIpaCode(Mockito.eq("ORG"), Mockito.anyString())) - .thenReturn(new Organization()); + .thenReturn(mockOrganization); + + Broker mockBroker = new Broker(); + mockBroker.setBrokerId(1L); + Mockito.when(organizationSearchClientMock.getBrokerById(Mockito.anyLong(), Mockito.anyString())) + .thenReturn(mockBroker); + + Mockito.when(tokenStoreService.load("sampleAccessToken")).thenReturn(iamUserInfo); - // When UserInfo result = mapper.apply(iamUserInfo, accessToken); - // Then Assertions.assertEquals(expected, result); } @Test void givenNotOperatorsWhenApplyThenOk() { String accessToken = "sampleAccessToken"; - // Given + IamUserInfoDTO iamUserInfo = IamUserInfoDTO.builder() .userId("EXTERNALUSERID") .innerUserId("INNERUSERID") @@ -141,7 +152,6 @@ void givenNotOperatorsWhenApplyThenOk() { .organizationIpaCode("ORG") .email("EMAIL") .build()) - .brokerId(1L) .build(); User user = User.builder() @@ -165,17 +175,27 @@ void givenNotOperatorsWhenApplyThenOk() { Mockito.when(usersRepositoryMock.findById(iamUserInfo.getInnerUserId())).thenReturn(Optional.of(user)); Mockito.when(operatorsRepositoryMock.findAllByUserId(user.getUserId())).thenReturn(Collections.emptyList()); - // When + Organization mockOrganization = new Organization(); + mockOrganization.setBrokerId(1L); + Mockito.when(organizationSearchClientMock.getOrganizationByIpaCode(Mockito.eq("ORG"), Mockito.anyString())) + .thenReturn(mockOrganization); + + Broker mockBroker = new Broker(); + mockBroker.setBrokerId(1L); + Mockito.when(organizationSearchClientMock.getBrokerById(Mockito.anyLong(), Mockito.anyString())) + .thenReturn(mockBroker); + + Mockito.when(tokenStoreService.load("sampleAccessToken")).thenReturn(iamUserInfo); + UserInfo result = mapper.apply(iamUserInfo, accessToken); - // Then Assertions.assertEquals(expected, result); } @Test void givenNoOrganizationAccessWhenApplyThenOk() { String accessToken = "sampleAccessToken"; - // Given + IamUserInfoDTO iamUserInfo = IamUserInfoDTO.builder() .userId("EXTERNALUSERID") .innerUserId("INNERUSERID") @@ -183,7 +203,6 @@ void givenNoOrganizationAccessWhenApplyThenOk() { .familyName("FAMILYNAME") .name("NAME") .issuer("ISSUER") - .brokerId(1L) .build(); User user = User.builder() @@ -218,17 +237,27 @@ void givenNoOrganizationAccessWhenApplyThenOk() { Mockito.when(usersRepositoryMock.findById(iamUserInfo.getInnerUserId())).thenReturn(Optional.of(user)); Mockito.when(operatorsRepositoryMock.findAllByUserId(user.getUserId())).thenReturn(organizationRoles); - // When + Organization mockOrganization = new Organization(); + mockOrganization.setBrokerId(1L); + Mockito.when(organizationSearchClientMock.getOrganizationByIpaCode(Mockito.eq("ORG"), Mockito.anyString())) + .thenReturn(mockOrganization); + + Broker mockBroker = new Broker(); + mockBroker.setBrokerId(1L); + Mockito.when(organizationSearchClientMock.getBrokerById(Mockito.anyLong(), Mockito.anyString())) + .thenReturn(mockBroker); + + Mockito.when(tokenStoreService.load("sampleAccessToken")).thenReturn(iamUserInfo); + UserInfo result = mapper.apply(iamUserInfo, accessToken); - // Then Assertions.assertEquals(expected, result); } @Test void givenSystemUserWhenApplyThenOk() { String accessToken = "sampleAccessToken"; - // Given + IamUserInfoDTO iamUserInfo = IamUserInfoDTO.builder() .systemUser(Boolean.TRUE) .userId("EXTERNALUSERID") @@ -241,7 +270,6 @@ void givenSystemUserWhenApplyThenOk() { .organizationIpaCode("IPA_CODE") .roles(Collections.singletonList(Constants.ROLE_ADMIN)) .build()) - .brokerId(1L) .build(); UserInfo expected = UserInfo.builder() @@ -258,11 +286,23 @@ void givenSystemUserWhenApplyThenOk() { .brokerId(1L) .build(); - // When + Organization mockOrganization = new Organization(); + mockOrganization.setBrokerId(1L); + Mockito.when(organizationSearchClientMock.getOrganizationByIpaCode(Mockito.eq("IPA_CODE"), Mockito.anyString())) + .thenReturn(mockOrganization); + + Broker mockBroker = new Broker(); + mockBroker.setBrokerId(1L); + Mockito.when(organizationSearchClientMock.getBrokerById(Mockito.anyLong(), Mockito.anyString())) + .thenReturn(mockBroker); + + Mockito.when(tokenStoreService.load("sampleAccessToken")).thenReturn(iamUserInfo); + Mockito.when(operatorsRepositoryMock.findAllByUserId(Mockito.anyString())).thenReturn(Collections.emptyList()); + UserInfo result = mapper.apply(iamUserInfo, accessToken); - // Then Assertions.assertEquals(expected, result); } + } From 70cc8d2b2afef516b109e1fbbbc97455fd053dc7 Mon Sep 17 00:00:00 2001 From: ElisKina-dev Date: Fri, 10 Jan 2025 15:47:22 +0100 Subject: [PATCH 14/15] fix --- .../user/IamUserInfoDTO2UserInfoMapper.java | 31 ++++++++----------- .../IamUserInfoDTO2UserInfoMapperTest.java | 15 +-------- 2 files changed, 14 insertions(+), 32 deletions(-) diff --git a/src/main/java/it/gov/pagopa/payhub/auth/service/user/IamUserInfoDTO2UserInfoMapper.java b/src/main/java/it/gov/pagopa/payhub/auth/service/user/IamUserInfoDTO2UserInfoMapper.java index b9ebdba..632527e 100644 --- a/src/main/java/it/gov/pagopa/payhub/auth/service/user/IamUserInfoDTO2UserInfoMapper.java +++ b/src/main/java/it/gov/pagopa/payhub/auth/service/user/IamUserInfoDTO2UserInfoMapper.java @@ -3,13 +3,11 @@ import it.gov.pagopa.payhub.auth.connector.client.OrganizationSearchClient; import it.gov.pagopa.payhub.auth.dto.IamUserInfoDTO; import it.gov.pagopa.payhub.auth.dto.IamUserOrganizationRolesDTO; -import it.gov.pagopa.payhub.auth.exception.custom.InvalidAccessTokenException; import it.gov.pagopa.payhub.auth.exception.custom.UserNotFoundException; import it.gov.pagopa.payhub.auth.model.Operator; import it.gov.pagopa.payhub.auth.model.User; import it.gov.pagopa.payhub.auth.repository.OperatorsRepository; import it.gov.pagopa.payhub.auth.repository.UsersRepository; -import it.gov.pagopa.payhub.auth.service.TokenStoreService; import it.gov.pagopa.payhub.auth.utils.Constants; import it.gov.pagopa.payhub.dto.generated.UserInfo; import it.gov.pagopa.payhub.dto.generated.UserOrganizationRoles; @@ -18,10 +16,7 @@ import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Service; -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; -import java.util.Optional; +import java.util.*; @Service public class IamUserInfoDTO2UserInfoMapper { @@ -31,18 +26,15 @@ public class IamUserInfoDTO2UserInfoMapper { private final OperatorsRepository operatorsRepository; private final OrganizationSearchClient organizationSearchClient; private final boolean organizationAccessMode; - private final TokenStoreService tokenStoreService; public IamUserInfoDTO2UserInfoMapper(@Value("${app.enable-access-organization-mode}") boolean organizationAccessMode, UsersRepository usersRepository, OperatorsRepository operatorsRepository, - OrganizationSearchClient organizationSearchClient, - TokenStoreService tokenStoreService) { + OrganizationSearchClient organizationSearchClient) { this.usersRepository = usersRepository; this.operatorsRepository = operatorsRepository; this.organizationSearchClient = organizationSearchClient; this.organizationAccessMode = organizationAccessMode; - this.tokenStoreService = tokenStoreService; } public UserInfo apply(IamUserInfoDTO iamUserInfoDTO, String accessToken) { @@ -66,7 +58,7 @@ private UserInfo systemUserMapper(IamUserInfoDTO iamUserInfoDTO, String accessTo .roles(Collections.singletonList(Constants.ROLE_ADMIN)) .build())) .build(); - setBrokerInfo(userInfo, accessToken); + setBrokerInfo(userInfo, iamUserInfoDTO, accessToken); return userInfo; } @@ -98,7 +90,7 @@ private UserInfo userInfoMapper(IamUserInfoDTO iamUserInfoDTO, String accessToke if (iamUserInfoDTO.getOrganizationAccess() != null) { userInfo.setOrganizationAccess(iamUserInfoDTO.getOrganizationAccess().getOrganizationIpaCode()); } - setBrokerInfo(userInfo, accessToken); + setBrokerInfo(userInfo, iamUserInfoDTO, accessToken); userInfo.setCanManageUsers(!organizationAccessMode); return userInfo; } @@ -117,13 +109,16 @@ private Broker getSessionBroker(IamUserInfoDTO iamUserInfoDTO, List us return null; } - private void setBrokerInfo(UserInfo userInfo, String accessToken) { - IamUserInfoDTO iamUserInfo = tokenStoreService.load(accessToken); - if (iamUserInfo == null) { - throw new InvalidAccessTokenException("AccessToken not found"); - } + private void setBrokerInfo(UserInfo userInfo, IamUserInfoDTO iamUserInfo, String accessToken) { + List userRoles = userInfo.getOrganizations().stream() + .map(org -> Operator.builder() + .operatorId(org.getOperatorId()) + .organizationIpaCode(org.getOrganizationIpaCode()) + .roles(new HashSet<>(org.getRoles())) + .email(org.getEmail()) + .build()) + .toList(); - List userRoles = operatorsRepository.findAllByUserId(iamUserInfo.getInnerUserId()); Broker brokerInfo = getSessionBroker(iamUserInfo, userRoles, accessToken); if (brokerInfo != null) { diff --git a/src/test/java/it/gov/pagopa/payhub/auth/service/user/IamUserInfoDTO2UserInfoMapperTest.java b/src/test/java/it/gov/pagopa/payhub/auth/service/user/IamUserInfoDTO2UserInfoMapperTest.java index 3f2786d..ad8925b 100644 --- a/src/test/java/it/gov/pagopa/payhub/auth/service/user/IamUserInfoDTO2UserInfoMapperTest.java +++ b/src/test/java/it/gov/pagopa/payhub/auth/service/user/IamUserInfoDTO2UserInfoMapperTest.java @@ -8,7 +8,6 @@ import it.gov.pagopa.payhub.auth.model.User; import it.gov.pagopa.payhub.auth.repository.OperatorsRepository; import it.gov.pagopa.payhub.auth.repository.UsersRepository; -import it.gov.pagopa.payhub.auth.service.TokenStoreService; import it.gov.pagopa.payhub.auth.utils.Constants; import it.gov.pagopa.payhub.dto.generated.UserInfo; import it.gov.pagopa.payhub.dto.generated.UserOrganizationRoles; @@ -39,16 +38,13 @@ class IamUserInfoDTO2UserInfoMapperTest { @Mock private OrganizationSearchClient organizationSearchClientMock; - @Mock - private TokenStoreService tokenStoreService; - private IamUserInfoDTO2UserInfoMapper mapper; private final boolean organizationAccessMode = false; @BeforeEach void init() { - mapper = new IamUserInfoDTO2UserInfoMapper(organizationAccessMode, usersRepositoryMock, operatorsRepositoryMock, organizationSearchClientMock, tokenStoreService); + mapper = new IamUserInfoDTO2UserInfoMapper(organizationAccessMode, usersRepositoryMock, operatorsRepositoryMock, organizationSearchClientMock); } @AfterEach @@ -130,8 +126,6 @@ void givenCompleteDataWhenApplyThenOk() { Mockito.when(organizationSearchClientMock.getBrokerById(Mockito.anyLong(), Mockito.anyString())) .thenReturn(mockBroker); - Mockito.when(tokenStoreService.load("sampleAccessToken")).thenReturn(iamUserInfo); - UserInfo result = mapper.apply(iamUserInfo, accessToken); Assertions.assertEquals(expected, result); @@ -185,8 +179,6 @@ void givenNotOperatorsWhenApplyThenOk() { Mockito.when(organizationSearchClientMock.getBrokerById(Mockito.anyLong(), Mockito.anyString())) .thenReturn(mockBroker); - Mockito.when(tokenStoreService.load("sampleAccessToken")).thenReturn(iamUserInfo); - UserInfo result = mapper.apply(iamUserInfo, accessToken); Assertions.assertEquals(expected, result); @@ -247,8 +239,6 @@ void givenNoOrganizationAccessWhenApplyThenOk() { Mockito.when(organizationSearchClientMock.getBrokerById(Mockito.anyLong(), Mockito.anyString())) .thenReturn(mockBroker); - Mockito.when(tokenStoreService.load("sampleAccessToken")).thenReturn(iamUserInfo); - UserInfo result = mapper.apply(iamUserInfo, accessToken); Assertions.assertEquals(expected, result); @@ -296,9 +286,6 @@ void givenSystemUserWhenApplyThenOk() { Mockito.when(organizationSearchClientMock.getBrokerById(Mockito.anyLong(), Mockito.anyString())) .thenReturn(mockBroker); - Mockito.when(tokenStoreService.load("sampleAccessToken")).thenReturn(iamUserInfo); - Mockito.when(operatorsRepositoryMock.findAllByUserId(Mockito.anyString())).thenReturn(Collections.emptyList()); - UserInfo result = mapper.apply(iamUserInfo, accessToken); Assertions.assertEquals(expected, result); From b368268ae3b2a8e25173283f899428cc80958559 Mon Sep 17 00:00:00 2001 From: ElisKina-dev Date: Fri, 10 Jan 2025 16:36:15 +0100 Subject: [PATCH 15/15] fix --- .../user/IamUserInfoDTO2UserInfoMapper.java | 20 +++++++------------ 1 file changed, 7 insertions(+), 13 deletions(-) diff --git a/src/main/java/it/gov/pagopa/payhub/auth/service/user/IamUserInfoDTO2UserInfoMapper.java b/src/main/java/it/gov/pagopa/payhub/auth/service/user/IamUserInfoDTO2UserInfoMapper.java index 632527e..e0d69cf 100644 --- a/src/main/java/it/gov/pagopa/payhub/auth/service/user/IamUserInfoDTO2UserInfoMapper.java +++ b/src/main/java/it/gov/pagopa/payhub/auth/service/user/IamUserInfoDTO2UserInfoMapper.java @@ -16,7 +16,10 @@ import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Service; -import java.util.*; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Optional; @Service public class IamUserInfoDTO2UserInfoMapper { @@ -95,10 +98,10 @@ private UserInfo userInfoMapper(IamUserInfoDTO iamUserInfoDTO, String accessToke return userInfo; } - private Broker getSessionBroker(IamUserInfoDTO iamUserInfoDTO, List userRoles, String accessToken) { + private Broker getSessionBroker(IamUserInfoDTO iamUserInfoDTO, List userOrganizations, String accessToken) { String orgIpaCode = Optional.ofNullable(iamUserInfoDTO.getOrganizationAccess()) .map(IamUserOrganizationRolesDTO::getOrganizationIpaCode) - .orElseGet(() -> !userRoles.isEmpty() ? userRoles.get(0).getOrganizationIpaCode() : null); + .orElseGet(() -> userOrganizations.isEmpty() ? null : userOrganizations.get(0).getOrganizationIpaCode()); if (orgIpaCode != null) { Organization organization = organizationSearchClient.getOrganizationByIpaCode(orgIpaCode, accessToken); @@ -110,16 +113,7 @@ private Broker getSessionBroker(IamUserInfoDTO iamUserInfoDTO, List us } private void setBrokerInfo(UserInfo userInfo, IamUserInfoDTO iamUserInfo, String accessToken) { - List userRoles = userInfo.getOrganizations().stream() - .map(org -> Operator.builder() - .operatorId(org.getOperatorId()) - .organizationIpaCode(org.getOrganizationIpaCode()) - .roles(new HashSet<>(org.getRoles())) - .email(org.getEmail()) - .build()) - .toList(); - - Broker brokerInfo = getSessionBroker(iamUserInfo, userRoles, accessToken); + Broker brokerInfo = getSessionBroker(iamUserInfo, userInfo.getOrganizations(), accessToken); if (brokerInfo != null) { userInfo.setBrokerId(brokerInfo.getBrokerId());