Skip to content

Commit

Permalink
fixes
Browse files Browse the repository at this point in the history
  • Loading branch information
ElisKina-dev committed Jan 9, 2025
1 parent fd7ebcd commit d525e3a
Show file tree
Hide file tree
Showing 9 changed files with 407 additions and 152 deletions.
2 changes: 2 additions & 0 deletions helm/values.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
Original file line number Diff line number Diff line change
@@ -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;
Expand All @@ -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<IamUserInfoDTO, UserInfo> {

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
Expand Down Expand Up @@ -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<Operator> 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())
Expand All @@ -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;
}

}
Original file line number Diff line number Diff line change
@@ -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;
Expand All @@ -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;
Expand All @@ -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;
Expand Down Expand Up @@ -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;
}

Expand Down
5 changes: 5 additions & 0 deletions src/main/resources/application.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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:}"

Expand Down
Original file line number Diff line number Diff line change
@@ -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 <T> void assertAuthenticationShouldBeSetInThreadSafeMode(Function<String, T> apiInvoke, Class<T> apiReturnedType, Runnable apiUnloader) throws InterruptedException {
// Configuring useCases in a single thread
List<Pair<String, T>> 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.<ParameterizedTypeReference<?>>any());
}

}
Original file line number Diff line number Diff line change
@@ -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);
}

}
Loading

0 comments on commit d525e3a

Please sign in to comment.