Skip to content

Commit

Permalink
P4ADEV-1275 resolved change request
Browse files Browse the repository at this point in the history
  • Loading branch information
macacia committed Oct 18, 2024
1 parent eb2fae0 commit c9fdd9b
Show file tree
Hide file tree
Showing 11 changed files with 129 additions and 58 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ public ResponseEntity<AuthErrorDTO> handleInvalidGrantError(RuntimeException ex,
return handleAuthErrorException(ex, request, HttpStatus.UNAUTHORIZED, AuthErrorDTO.ErrorEnum.INVALID_GRANT);
}

@ExceptionHandler(InvalidExchangeClientException.class)
@ExceptionHandler({InvalidExchangeClientException.class, ClientUnauthorizedException.class})
public ResponseEntity<AuthErrorDTO> handleInvalidClientError(RuntimeException ex, HttpServletRequest request){
return handleAuthErrorException(ex, request, HttpStatus.UNAUTHORIZED, AuthErrorDTO.ErrorEnum.INVALID_CLIENT);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package it.gov.pagopa.payhub.auth.exception.custom;

public class ClientUnauthorizedException extends RuntimeException {
public ClientUnauthorizedException(String message){
super(message);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package it.gov.pagopa.payhub.auth.service.a2a;

import it.gov.pagopa.payhub.model.generated.ClientDTO;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

@Service
@Slf4j
public class AuthorizeClientCredentialsRequestService {
private final ClientService clientService;

public AuthorizeClientCredentialsRequestService(ClientService clientService) {
this.clientService = clientService;
}

public ClientDTO authorizeCredentials(String clientId, String clientSecret) {
return clientService.authorizeCredentials(clientId, clientSecret);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,15 +9,18 @@
public class ClientCredentialServiceImpl implements ClientCredentialService {

private final ValidateClientCredentialsService validateClientCredentialsService;
private final AuthorizeClientCredentialsRequestService authorizeClientCredentialsRequestService;

public ClientCredentialServiceImpl(ValidateClientCredentialsService validateClientCredentialsService) {
public ClientCredentialServiceImpl(ValidateClientCredentialsService validateClientCredentialsService, AuthorizeClientCredentialsRequestService authorizeClientCredentialsRequestService) {
this.validateClientCredentialsService = validateClientCredentialsService;
this.authorizeClientCredentialsRequestService = authorizeClientCredentialsRequestService;
}

@Override
public AccessToken postToken(String clientId, String scope, String clientSecret) {
log.info("Client {} requested authentication with client_credentials grant type and scope {}", clientId, scope);
validateClientCredentialsService.validate(clientId, scope, clientSecret);
validateClientCredentialsService.validate(scope, clientSecret);
authorizeClientCredentialsRequestService.authorizeCredentials(clientId, clientSecret);
return AccessToken.builder().accessToken("accessToken").build();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,5 +13,5 @@ public interface ClientService {
String getClientSecret(String organizationIpaCode, String clientId);
List<ClientNoSecretDTO> getClients(String organizationIpaCode);
Optional<Client> getClientByClientId(String clientId);
ClientDTO verifyCredentials(String clientId, String clientSecret);
ClientDTO authorizeCredentials(String clientId, String clientSecret);
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
package it.gov.pagopa.payhub.auth.service.a2a;

import it.gov.pagopa.payhub.auth.exception.custom.InvalidExchangeRequestException;
import it.gov.pagopa.payhub.auth.exception.custom.ClientUnauthorizedException;
import it.gov.pagopa.payhub.auth.mapper.ClientMapper;
import it.gov.pagopa.payhub.auth.model.Client;
import it.gov.pagopa.payhub.auth.service.a2a.registration.ClientRegistrationService;
Expand Down Expand Up @@ -50,11 +50,11 @@ public Optional<Client> getClientByClientId(String clientId) {
return clientRetrieverService.getClientByClientId(clientId);
}

public ClientDTO verifyCredentials(String clientId, String clientSecret) {
return this.getClientByClientId(clientId)
public ClientDTO authorizeCredentials(String clientId, String clientSecret) {
return getClientByClientId(clientId)
.map(clientMapper::mapToDTO)
.filter(dto -> dto.getClientSecret().equals(clientSecret))
.orElseThrow(() -> new InvalidExchangeRequestException("Invalid client-credentials"));
.orElseThrow(() -> new ClientUnauthorizedException("Unauthorized client for client-credentials"));
}

}
Original file line number Diff line number Diff line change
@@ -1,38 +1,31 @@
package it.gov.pagopa.payhub.auth.service.a2a;

import it.gov.pagopa.payhub.auth.exception.custom.InvalidExchangeRequestException;
import it.gov.pagopa.payhub.auth.exception.custom.ClientUnauthorizedException;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

@Service
@Slf4j
public class ValidateClientCredentialsService {
private final ClientService clientService;

public static final String ALLOWED_GRANT_TYPE = "client_credentials";
public static final String ALLOWED_SCOPE = "openid";

public ValidateClientCredentialsService(ClientService clientService) {
this.clientService = clientService;
}

public void validate(String clientId, String scope, String clientSecret) {
public void validate(String scope, String clientSecret) {
validateProtocolConfiguration(scope);
validateClientSecret(clientSecret);
clientService.verifyCredentials(clientId, clientSecret);
log.debug("authorization granted");
}

private void validateProtocolConfiguration(String scope) {
if (!ALLOWED_SCOPE.equals(scope)){
throw new InvalidExchangeRequestException("Invalid scope " + scope);
throw new ClientUnauthorizedException("Invalid scope " + scope);
}
}

private void validateClientSecret(String clientSecret) {
if (!StringUtils.hasText(clientSecret)) {
throw new InvalidExchangeRequestException("clientSecret is mandatory with client-credentials grant type");
throw new ClientUnauthorizedException("clientSecret is mandatory with client-credentials grant type");
}
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
package it.gov.pagopa.payhub.auth.service;

import it.gov.pagopa.payhub.auth.service.a2a.AuthorizeClientCredentialsRequestService;
import it.gov.pagopa.payhub.auth.service.a2a.ClientService;
import it.gov.pagopa.payhub.model.generated.ClientDTO;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.mockito.Mock;
import org.mockito.Mockito;

class AuthorizeClientCredentialsRequestServiceTest {

@Mock
private ClientService clientService;
private AuthorizeClientCredentialsRequestService service;

@BeforeEach
void init() {
service = new AuthorizeClientCredentialsRequestService(clientService);
}

@Test
void givenValidTokenWhenPostTokenThenSuccess(){
// Given
String clientId="CLIENT_ID";
String clientSecret="CLIENT_SECRET";
ClientDTO expectedClientDTO = new ClientDTO();

Mockito.doReturn(expectedClientDTO).when(clientService).authorizeCredentials(clientId, clientSecret);
//When
ClientDTO result = service.authorizeCredentials(clientId, clientSecret);
//Then
Assertions.assertEquals(expectedClientDTO, result);
}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package it.gov.pagopa.payhub.auth.service.a2a;

import it.gov.pagopa.payhub.model.generated.AccessToken;
import it.gov.pagopa.payhub.model.generated.ClientDTO;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
Expand All @@ -14,11 +15,14 @@ class ClientCredentialsServiceTest {

@Mock
private ValidateClientCredentialsService validateClientCredentialsServiceMock;
@Mock
private AuthorizeClientCredentialsRequestService authorizeClientCredentialsRequestService;

private ClientCredentialService service;

@BeforeEach
void init() {
service = new ClientCredentialServiceImpl(validateClientCredentialsServiceMock);
service = new ClientCredentialServiceImpl(validateClientCredentialsServiceMock, authorizeClientCredentialsRequestService);
}

@Test
Expand All @@ -28,7 +32,8 @@ void givenValidTokenWhenPostTokenThenSuccess(){
String scope="SCOPE";
String clientSecret="CLIENT_SECRET";

Mockito.doNothing().when(validateClientCredentialsServiceMock).validate(clientId, scope, clientSecret);
Mockito.doNothing().when(validateClientCredentialsServiceMock).validate(scope, clientSecret);
Mockito.doReturn(new ClientDTO()).when(authorizeClientCredentialsRequestService).authorizeCredentials(clientId, clientSecret);
AccessToken expectedAccessToken = AccessToken.builder().accessToken("accessToken").build();
//When
AccessToken result = service.postToken(clientId, scope, clientSecret);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package it.gov.pagopa.payhub.auth.service.a2a;

import it.gov.pagopa.payhub.auth.exception.custom.ClientUnauthorizedException;
import it.gov.pagopa.payhub.auth.mapper.ClientMapper;
import it.gov.pagopa.payhub.auth.model.Client;
import it.gov.pagopa.payhub.auth.service.a2a.registration.ClientRegistrationService;
Expand Down Expand Up @@ -118,7 +119,7 @@ void givenClientIdWhenGetClientByClientIdThenInvokeClientService() {
}

@Test
void givenCredentialsWhenGetClientByClientIdThenInvokeClientService() {
void givenRightCredentialsWhenVerifyCredentialsThenOk() {
// Given
String organizationIpaCode = "IPA_TEST_2";
String clientName = "SERVICE_001";
Expand All @@ -136,9 +137,42 @@ void givenCredentialsWhenGetClientByClientIdThenInvokeClientService() {
Mockito.when(clientRetrieverServiceMock.getClientByClientId(clientId)).thenReturn(Optional.of(mockClient));
Mockito.when(clientMapperMock.mapToDTO(mockClient)).thenReturn(expectedClientDTO);
// When
ClientDTO actualClientDTO = service.verifyCredentials(clientId, clientSecretMock);
ClientDTO actualClientDTO = service.authorizeCredentials(clientId, clientSecretMock);
// Then
Assertions.assertEquals(expectedClientDTO, actualClientDTO);
}

@Test
void givenUnexpectedClientIdCredentialsWhenVerifyCredentialsThenClientUnauthorizedException() {
// Given
String clientId = "UNEXPECTED_CLIENT_ID";
String clientSecretMock = UUID.randomUUID().toString();

Mockito.when(clientRetrieverServiceMock.getClientByClientId(clientId)).thenThrow(new ClientUnauthorizedException("error"));
// When, Then
Assertions.assertThrows(ClientUnauthorizedException.class, () -> service.authorizeCredentials(clientId, clientSecretMock));
}

@Test
void givenUnexpectedClientSecretCredentialsWhenVerifyCredentialsThenClientUnauthorizedException() {
// Given
String organizationIpaCode = "IPA_TEST_2";
String clientName = "SERVICE_001";
String clientId = organizationIpaCode + clientName;
String clientSecret = UUID.randomUUID().toString();

Client mockClient = new Client();
ClientDTO expectedClientDTO = ClientDTO.builder()
.clientId(clientId)
.clientName(clientName)
.organizationIpaCode(organizationIpaCode)
.clientSecret(UUID.randomUUID().toString())
.build();

Mockito.when(clientRetrieverServiceMock.getClientByClientId(clientId)).thenReturn(Optional.of(mockClient));
Mockito.when(clientMapperMock.mapToDTO(mockClient)).thenReturn(expectedClientDTO);

// When, Then
Assertions.assertThrows(ClientUnauthorizedException.class, () -> service.authorizeCredentials(clientId, clientSecret));
}
}
Original file line number Diff line number Diff line change
@@ -1,12 +1,9 @@
package it.gov.pagopa.payhub.auth.service.a2a;

import it.gov.pagopa.payhub.auth.exception.custom.InvalidExchangeRequestException;
import it.gov.pagopa.payhub.model.generated.ClientDTO;
import org.junit.jupiter.api.BeforeEach;
import it.gov.pagopa.payhub.auth.exception.custom.ClientUnauthorizedException;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.InjectMocks;
import org.mockito.junit.jupiter.MockitoExtension;

import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
Expand All @@ -15,51 +12,28 @@
@ExtendWith(MockitoExtension.class)
class ValidateClientCredentialsServiceTest {

@Mock
private ClientService clientService;

@InjectMocks
private ValidateClientCredentialsService service;

private static final String ALLOWED_CLIENT_ID = "CLIENTID";
private static final String ALLOWED_CLIENT_SECRET = "CLIENTSECRET";

@BeforeEach
void setup(){
service = new ValidateClientCredentialsService(clientService);
}

@Test
void givenValidRequestThenOk() {
Mockito.doReturn(new ClientDTO()).when(clientService).verifyCredentials(ALLOWED_CLIENT_ID, ALLOWED_CLIENT_SECRET);
assertDoesNotThrow(() ->
service.validate(ALLOWED_CLIENT_ID, ValidateClientCredentialsService.ALLOWED_SCOPE, ALLOWED_CLIENT_SECRET));
}

@Test
void givenInvalidClientIdThenInvalidExchangeRequestException() {
Mockito.doThrow(new InvalidExchangeRequestException("error"))
.when(clientService).verifyCredentials("UNEXPECTED_CLIENT_ID", ALLOWED_CLIENT_SECRET);
assertThrows(InvalidExchangeRequestException.class, () ->
service.validate("UNEXPECTED_CLIENT_ID", ValidateClientCredentialsService.ALLOWED_SCOPE, ALLOWED_CLIENT_SECRET));
service.validate(ValidateClientCredentialsService.ALLOWED_SCOPE, ALLOWED_CLIENT_SECRET));
}

@Test
void givenInvalidScopeThenInvalidExchangeRequestException() {
assertThrows(InvalidExchangeRequestException.class, () ->
service.validate(ALLOWED_CLIENT_ID, "UNEXPECTED_SCOPE", ALLOWED_CLIENT_SECRET));
assertThrows(ClientUnauthorizedException.class, () ->
service.validate( "UNEXPECTED_SCOPE", ALLOWED_CLIENT_SECRET));
}

@Test
void givenNullClientSecretThenInvalidExchangeRequestException() {
assertThrows(InvalidExchangeRequestException.class, () ->
service.validate(ALLOWED_CLIENT_ID, ValidateClientCredentialsService.ALLOWED_SCOPE, null));
}

@Test
void givenInvalidClientSecretThenInvalidExchangeRequestException() {
Mockito.doThrow(new InvalidExchangeRequestException("error"))
.when(clientService).verifyCredentials(ALLOWED_CLIENT_ID, "UNEXPECTED_CLIENT_SECRET");
assertThrows(InvalidExchangeRequestException.class, () ->
service.validate(ALLOWED_CLIENT_ID, ValidateClientCredentialsService.ALLOWED_SCOPE, "UNEXPECTED_CLIENT_SECRET"));
assertThrows(ClientUnauthorizedException.class, () ->
service.validate(ValidateClientCredentialsService.ALLOWED_SCOPE, null));
}

}

0 comments on commit c9fdd9b

Please sign in to comment.