Skip to content

Commit

Permalink
P4ADEV-1274 added parameters validation
Browse files Browse the repository at this point in the history
  • Loading branch information
macacia committed Oct 17, 2024
1 parent 71dfc12 commit 9c9de8c
Show file tree
Hide file tree
Showing 12 changed files with 259 additions and 13 deletions.
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
package it.gov.pagopa.payhub.auth.service;

import it.gov.pagopa.payhub.auth.exception.custom.InvalidGrantTypeException;
import it.gov.pagopa.payhub.auth.service.a2a.ClientCredentialService;
import it.gov.pagopa.payhub.auth.service.a2a.ValidateClientCredentialsService;
import it.gov.pagopa.payhub.auth.service.exchange.ExchangeTokenService;
import it.gov.pagopa.payhub.auth.service.exchange.ValidateExternalTokenService;
import it.gov.pagopa.payhub.auth.service.logout.LogoutService;
import it.gov.pagopa.payhub.auth.service.user.UserService;
import it.gov.pagopa.payhub.model.generated.AccessToken;
Expand All @@ -11,19 +15,25 @@
@Slf4j
@Service
public class AuthnServiceImpl implements AuthnService {
private final ClientCredentialService clientCredentialService;
private final ExchangeTokenService exchangeTokenService;
private final UserService userService;
private final LogoutService logoutService;

public AuthnServiceImpl(ExchangeTokenService exchangeTokenService, UserService userService, LogoutService logoutService) {
this.exchangeTokenService = exchangeTokenService;
this.userService = userService;
this.logoutService = logoutService;
public AuthnServiceImpl(ClientCredentialService clientCredentialService, ExchangeTokenService exchangeTokenService, UserService userService, LogoutService logoutService) {
this.clientCredentialService = clientCredentialService;
this.exchangeTokenService = exchangeTokenService;
this.userService = userService;
this.logoutService = logoutService;
}

@Override
public AccessToken postToken(String clientId, String grantType, String scope, String subjectToken, String subjectIssuer, String subjectTokenType, String clientSecret) {
return exchangeTokenService.postToken(clientId, grantType, subjectToken, subjectIssuer, subjectTokenType, scope);
return switch (grantType) {
case ValidateExternalTokenService.ALLOWED_GRANT_TYPE -> exchangeTokenService.postToken(clientId, grantType, subjectToken, subjectIssuer, subjectTokenType, scope);
case ValidateClientCredentialsService.ALLOWED_GRANT_TYPE -> clientCredentialService.postToken(clientId, grantType, scope, clientSecret);
default -> throw new InvalidGrantTypeException("Invalid grantType " + grantType);
};
}

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

import it.gov.pagopa.payhub.model.generated.AccessToken;

public interface ClientCredentialService {
AccessToken postToken(String clientId, String grantType, String scope, String clientSecret);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package it.gov.pagopa.payhub.auth.service.a2a;

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

@Service
@Slf4j
public class ClientCredentialServiceImpl implements ClientCredentialService {

private final ValidateClientCredentialsService validateClientCredentialsService;

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

@Override
public AccessToken postToken(String clientId, String grantType, String scope, String clientSecret) {
validateClientCredentialsService.validate(clientId, grantType, scope, clientSecret);
//TODO return real AccessToken implementation
return new AccessToken("token", "bearer", 7);
}
}
Original file line number Diff line number Diff line change
@@ -1,13 +1,16 @@
package it.gov.pagopa.payhub.auth.service.a2a;

import it.gov.pagopa.payhub.auth.model.Client;
import it.gov.pagopa.payhub.model.generated.ClientDTO;
import it.gov.pagopa.payhub.model.generated.ClientNoSecretDTO;

import java.util.List;
import java.util.Optional;

public interface ClientService {

ClientDTO registerClient(String clientName, String organizationIpaCode);
String getClientSecret(String organizationIpaCode, String clientId);
List<ClientNoSecretDTO> getClients(String organizationIpaCode);
Optional<Client> getClientByClientId(String clientId);
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
import org.springframework.stereotype.Service;

import java.util.List;
import java.util.Optional;

@Service
@Slf4j
Expand All @@ -27,7 +28,6 @@ public ClientServiceImpl(ClientRegistrationService clientRegistrationService, Cl

@Override
public ClientDTO registerClient(String clientName, String organizationIpaCode) {

Client client = clientRegistrationService.registerClient(clientName, organizationIpaCode);
return clientMapper.mapToDTO(client);
}
Expand All @@ -44,4 +44,9 @@ public List<ClientNoSecretDTO> getClients(String organizationIpaCode) {
return clientRetrieverService.getClients(organizationIpaCode);
}

public Optional<Client> getClientByClientId(String clientId) {
log.info("Retrieving client for {}", clientId);
return clientRetrieverService.getClientByClientId(clientId);
}

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

import it.gov.pagopa.payhub.auth.exception.custom.InvalidExchangeClientException;
import it.gov.pagopa.payhub.auth.exception.custom.InvalidExchangeRequestException;
import it.gov.pagopa.payhub.auth.exception.custom.InvalidGrantTypeException;
import it.gov.pagopa.payhub.auth.model.Client;
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 grantType, String scope, String clientSecret) {
validateClient(clientId);
validateProtocolConfiguration(grantType, scope);
validateClientSecret(clientSecret);
log.info("authorization granted");
}

//TODO Client will be used to verify clientSecret and assign roles with organizationIpaCode
private Client validateClient(String clientId) {
return clientService.getClientByClientId(clientId)
.orElseThrow(() -> new InvalidExchangeClientException("Invalid clientId:"+ clientId));
}

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

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

}
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
import org.springframework.stereotype.Service;

import java.util.List;
import java.util.Optional;

@Service
@Slf4j
Expand Down Expand Up @@ -41,4 +42,6 @@ public List<ClientNoSecretDTO> getClients(String organizationIpaCode) {
.toList();
}

public Optional<Client> getClientByClientId(String clientId) { return clientRepository.findById(clientId); }

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

import it.gov.pagopa.payhub.auth.exception.custom.InvalidGrantTypeException;
import it.gov.pagopa.payhub.auth.service.a2a.ClientCredentialService;
import it.gov.pagopa.payhub.auth.service.a2a.ValidateClientCredentialsService;
import it.gov.pagopa.payhub.auth.service.exchange.ExchangeTokenService;
import it.gov.pagopa.payhub.auth.service.exchange.ValidateExternalTokenService;
import it.gov.pagopa.payhub.auth.service.logout.LogoutService;
import it.gov.pagopa.payhub.auth.service.user.UserService;
import it.gov.pagopa.payhub.model.generated.AccessToken;
Expand All @@ -14,9 +18,13 @@
import org.mockito.Mockito;
import org.mockito.junit.jupiter.MockitoExtension;

import static org.junit.jupiter.api.Assertions.assertThrows;

@ExtendWith(MockitoExtension.class)
class AuthnServiceTest {

@Mock
private ClientCredentialService clientCredentialService;
@Mock
private ExchangeTokenService exchangeTokenServiceMock;
@Mock
Expand All @@ -28,29 +36,30 @@ class AuthnServiceTest {

@BeforeEach
void init(){
service = new AuthnServiceImpl(exchangeTokenServiceMock, userServiceMock, logoutServiceMock);
service = new AuthnServiceImpl(clientCredentialService, exchangeTokenServiceMock, userServiceMock, logoutServiceMock);
}

@AfterEach
void verifyNotMoreInteractions(){
Mockito.verifyNoMoreInteractions(
exchangeTokenServiceMock,
userServiceMock,
logoutServiceMock
clientCredentialService,
exchangeTokenServiceMock,
userServiceMock,
logoutServiceMock
);
}

@Test
void whenPostTokenThenCallExchangeService(){
// Given
String clientId="CLIENT_ID";
String grantType="GRANT_TYPE";
String subjectToken="SUBJECT_TOKEN";
String subjectIssuer="SUBJECT_ISSUER";
String subjectTokenType="SUBJECT_TOKEN_TYPE";
String scope="SCOPE";
String clientSecret = "CLIENT_SECRET";

String grantType= ValidateExternalTokenService.ALLOWED_GRANT_TYPE;
AccessToken expectedResult = new AccessToken();
Mockito.when(exchangeTokenServiceMock.postToken(clientId, grantType, subjectToken, subjectIssuer, subjectTokenType, scope))
.thenReturn(expectedResult);
Expand All @@ -62,6 +71,43 @@ void whenPostTokenThenCallExchangeService(){
Assertions.assertSame(expectedResult, result);
}

@Test
void whenPostTokenThenCallClientCredentialService(){
// Given
String clientId="CLIENT_ID";
String subjectToken="SUBJECT_TOKEN";
String subjectIssuer="SUBJECT_ISSUER";
String subjectTokenType="SUBJECT_TOKEN_TYPE";
String scope="SCOPE";
String clientSecret = "CLIENT_SECRET";

String grantType= ValidateClientCredentialsService.ALLOWED_GRANT_TYPE;
AccessToken expectedResult = new AccessToken();
Mockito.when(clientCredentialService.postToken(clientId, grantType, scope, clientSecret)).thenReturn(expectedResult);

// When
AccessToken result = service.postToken(clientId, grantType, scope, subjectToken, subjectIssuer, subjectTokenType, clientSecret);

// Then
Assertions.assertSame(expectedResult, result);
}

@Test
void whenPostTokenWhenCallClientCredentialServiceThenInvalidGrantTypeException(){
// Given
String clientId="CLIENT_ID";
String subjectToken="SUBJECT_TOKEN";
String subjectIssuer="SUBJECT_ISSUER";
String subjectTokenType="SUBJECT_TOKEN_TYPE";
String scope="SCOPE";
String clientSecret = "CLIENT_SECRET";

String grantType="UNEXPECTED_GRANT_TYPE";
// When, Then
assertThrows(InvalidGrantTypeException.class, () ->
service.postToken(clientId, grantType, scope, subjectToken, subjectIssuer, subjectTokenType, clientSecret));
}

@Test
void whenGetUserInfoThenCallUserService(){
// Given
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
import org.mockito.junit.jupiter.MockitoExtension;

import java.util.List;
import java.util.Optional;
import java.util.UUID;

@ExtendWith(MockitoExtension.class)
Expand Down Expand Up @@ -103,4 +104,17 @@ void givenOrganizationIpaCodeWhenGetClientsThenGetClientNoSecretDTOList() {
Assertions.assertEquals(List.of(dto1, dto2), result);
}

@Test
void givenClientIdWhenGetClientByClientIdThenInvokeClientService() {
// Given
String clientId = "clientId";
Client expectedClient = new Client();

Mockito.when(clientRetrieverServiceMock.getClientByClientId(clientId)).thenReturn(Optional.of(expectedClient));
//When
Optional<Client> result = service.getClientByClientId(clientId);
// Then
Assertions.assertEquals(Optional.of(expectedClient), result);
}

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

import it.gov.pagopa.payhub.auth.exception.custom.InvalidExchangeClientException;
import it.gov.pagopa.payhub.auth.exception.custom.InvalidExchangeRequestException;
import it.gov.pagopa.payhub.auth.exception.custom.InvalidGrantTypeException;
import it.gov.pagopa.payhub.auth.model.Client;
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 java.util.Optional;

import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
import static org.junit.jupiter.api.Assertions.assertThrows;

@ExtendWith(MockitoExtension.class)
public class ValidateClientCredentialsServiceTest {
@Mock
private ClientService clientServiceMock;
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(clientServiceMock);
}

@Test
void givenValidRequestThenOk() {
Mockito.doReturn(Optional.of(new Client())).when(clientServiceMock).getClientByClientId(ALLOWED_CLIENT_ID);
assertDoesNotThrow(() ->
service.validate(ALLOWED_CLIENT_ID, ValidateClientCredentialsService.ALLOWED_GRANT_TYPE, ValidateClientCredentialsService.ALLOWED_SCOPE, ALLOWED_CLIENT_SECRET));
}

@Test
void givenInvalidExchangeClientException() {
assertThrows(InvalidExchangeClientException.class, () ->
service.validate("UNEXPECTED_CLIENT_ID", ValidateClientCredentialsService.ALLOWED_GRANT_TYPE, ValidateClientCredentialsService.ALLOWED_SCOPE, ALLOWED_CLIENT_SECRET));
}

@Test
void givenInvalidGrantTypeException() {
Mockito.doReturn(Optional.of(new Client())).when(clientServiceMock).getClientByClientId(ALLOWED_CLIENT_ID);
assertThrows(InvalidGrantTypeException.class, () ->
service.validate(ALLOWED_CLIENT_ID, "UNEXPECTED_GRANT_TYPE", ValidateClientCredentialsService.ALLOWED_SCOPE, ALLOWED_CLIENT_SECRET));
}

@Test
void givenInvalidScopeThenInvalidExchangeRequestException() {
Mockito.doReturn(Optional.of(new Client())).when(clientServiceMock).getClientByClientId(ALLOWED_CLIENT_ID);
assertThrows(InvalidExchangeRequestException.class, () ->
service.validate(ALLOWED_CLIENT_ID, ValidateClientCredentialsService.ALLOWED_GRANT_TYPE, "UNEXPECTED_SCOPE", ALLOWED_CLIENT_SECRET));
}

@Test
void givenNullClientSecretThenInvalidExchangeRequestException() {
Mockito.doReturn(Optional.of(new Client())).when(clientServiceMock).getClientByClientId(ALLOWED_CLIENT_ID);
assertThrows(InvalidExchangeRequestException.class, () ->
service.validate(ALLOWED_CLIENT_ID, ValidateClientCredentialsService.ALLOWED_GRANT_TYPE, ValidateClientCredentialsService.ALLOWED_SCOPE, null));
}

}
Loading

0 comments on commit 9c9de8c

Please sign in to comment.