Skip to content

Commit be3f7d0

Browse files
authored
Merge pull request #201 from pagopa/feature/PN-13461
[PN-13461] restore AdE checkCf service
2 parents faa0c56 + 10c1f05 commit be3f7d0

File tree

16 files changed

+531
-56
lines changed

16 files changed

+531
-56
lines changed

docs/external/AdE/VerificaCodiceFiscale.yaml

Lines changed: 8 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -19,10 +19,6 @@ x-commons:
1919
$ref: '#/components/responses/503ServiceUnavailable'
2020
default:
2121
$ref: '#/components/responses/default'
22-
23-
security:
24-
- IBM-Client-Secret: []
25-
IBM-Client-Id: []
2622

2723
openapi: 3.0.0
2824
info:
@@ -249,18 +245,6 @@ components:
249245
format: uri
250246
type: string
251247
type: object
252-
securitySchemes:
253-
IBM-Client-Secret:
254-
type: apiKey
255-
description: ''
256-
name: X-IBM-Client-Secret
257-
in: header
258-
IBM-Client-Id:
259-
type: apiKey
260-
description: ''
261-
name: X-IBM-Client-Id
262-
in: header
263-
264248
headers:
265249
Retry-After:
266250
description: |-
@@ -329,3 +313,11 @@ components:
329313
$ref: '#/components/headers/Retry-After'
330314
default:
331315
description: Unexpected error
316+
securitySchemes:
317+
bearerAuth:
318+
type: http
319+
scheme: bearer
320+
bearerFormat: JWT
321+
description: Implementazione conforme ad RFC8725. Contiene il JWT recuperato da PDND interoperabilità applicando le Linee Guida sull'infrastruttura tecnologica della Piattaforma Digitale Nazionale Dati per l'interoperabilità dei sistemi informativi e delle basi di dati ai sensi dell'articolo 50-ter, comma 2 del CAD
322+
security:
323+
- bearerAuth: [ ]

pom.xml

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -401,6 +401,29 @@
401401
<apiPackage>it.pagopa.pn.national.registries.generated.openapi.msclient.ipa.v1.api</apiPackage>
402402
</configuration>
403403
</execution>
404+
<execution>
405+
<id>generate-ADE-client</id>
406+
<goals>
407+
<goal>generate</goal>
408+
</goals>
409+
<phase>process-resources</phase>
410+
<configuration>
411+
<inputSpec>${project.basedir}/docs/external/AdE/VerificaCodiceFiscale.yaml</inputSpec>
412+
<generatorName>java</generatorName>
413+
<library>webclient</library>
414+
<generateApiDocumentation>false</generateApiDocumentation>
415+
<generateApiTests>false</generateApiTests>
416+
<generateModelTests>false</generateModelTests>
417+
<generateSupportingFiles>true</generateSupportingFiles>
418+
<templateDirectory>${project.build.directory}/dependency-resources/scripts/openapi/templates/6.0.0/client</templateDirectory>
419+
<configOptions>
420+
<swaggerAnnotations>false</swaggerAnnotations>
421+
<openApiNullable>false</openApiNullable>
422+
</configOptions>
423+
<modelPackage>it.pagopa.pn.national.registries.generated.openapi.msclient.ade.v1.dto</modelPackage>
424+
<apiPackage>it.pagopa.pn.national.registries.generated.openapi.msclient.ade.v1.api</apiPackage>
425+
</configuration>
426+
</execution>
404427
</executions>
405428
</plugin>
406429
<plugin>
Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
package it.pagopa.pn.national.registries.client.agenziaentrate;
2+
3+
import it.pagopa.pn.commons.exceptions.PnInternalException;
4+
import it.pagopa.pn.commons.log.PnLogger;
5+
import it.pagopa.pn.national.registries.cache.AccessTokenCacheEntry;
6+
import it.pagopa.pn.national.registries.cache.AccessTokenExpiringMap;
7+
import it.pagopa.pn.national.registries.config.adecheckcf.CheckCfSecretConfig;
8+
import it.pagopa.pn.national.registries.exceptions.PnNationalRegistriesException;
9+
import it.pagopa.pn.national.registries.generated.openapi.msclient.ade.v1.api.VerificheApi;
10+
import it.pagopa.pn.national.registries.generated.openapi.msclient.ade.v1.dto.Richiesta;
11+
import it.pagopa.pn.national.registries.generated.openapi.msclient.ade.v1.dto.VerificaCodiceFiscale;
12+
import it.pagopa.pn.national.registries.model.PdndSecretValue;
13+
import it.pagopa.pn.national.registries.model.agenziaentrate.TaxIdResponseKO;
14+
import it.pagopa.pn.national.registries.service.PnNationalRegistriesSecretService;
15+
import org.springframework.http.HttpStatus;
16+
import org.springframework.stereotype.Component;
17+
import org.springframework.web.reactive.function.client.WebClientResponseException;
18+
import reactor.core.publisher.Mono;
19+
import reactor.util.retry.Retry;
20+
21+
import java.nio.charset.Charset;
22+
23+
import static it.pagopa.pn.national.registries.constant.ProcessStatus.PROCESS_SERVICE_AGENZIA_ENTRATE_CHECK_TAX_ID;
24+
import static it.pagopa.pn.national.registries.exceptions.PnNationalRegistriesExceptionCodes.*;
25+
26+
@Component
27+
@lombok.CustomLog
28+
public class CheckCfClient {
29+
30+
private final AccessTokenExpiringMap accessTokenExpiringMap;
31+
private final VerificheApi verificheApi;
32+
private final CheckCfSecretConfig checkCfSecretConfig;
33+
34+
35+
private final PnNationalRegistriesSecretService pnNationalRegistriesSecretService;
36+
37+
protected CheckCfClient(AccessTokenExpiringMap accessTokenExpiringMap,
38+
VerificheApi verificheApi,
39+
CheckCfSecretConfig checkCfSecretConfig,
40+
PnNationalRegistriesSecretService pnNationalRegistriesSecretService) {
41+
this.accessTokenExpiringMap = accessTokenExpiringMap;
42+
this.checkCfSecretConfig = checkCfSecretConfig;
43+
this.verificheApi = verificheApi;
44+
this.pnNationalRegistriesSecretService = pnNationalRegistriesSecretService;
45+
}
46+
47+
public Mono<VerificaCodiceFiscale> callEService(Richiesta richiesta) {
48+
PdndSecretValue pdndSecretValue = pnNationalRegistriesSecretService.getPdndSecretValue(checkCfSecretConfig.getPdndSecret());
49+
return accessTokenExpiringMap.getPDNDToken(pdndSecretValue.getJwtConfig().getPurposeId(), pdndSecretValue, false)
50+
.flatMap(tokenEntry -> callVerifica(richiesta, tokenEntry))
51+
.retryWhen(Retry.max(1).filter(this::shouldRetry)
52+
.onRetryExhaustedThrow((retryBackoffSpec, retrySignal) ->
53+
new PnInternalException(ERROR_MESSAGE_ADE_UNAUTHORIZED, ERROR_CODE_UNAUTHORIZED, retrySignal.failure()))
54+
);
55+
}
56+
57+
private Mono<VerificaCodiceFiscale> callVerifica(Richiesta request, AccessTokenCacheEntry tokenEntry) {
58+
log.logInvokingExternalDownstreamService(PnLogger.EXTERNAL_SERVICES.ADE, PROCESS_SERVICE_AGENZIA_ENTRATE_CHECK_TAX_ID);
59+
verificheApi.getApiClient().setBearerToken(tokenEntry.getTokenValue());
60+
return verificheApi.postVerificaCodiceFiscale(request)
61+
.doOnError(throwable -> {
62+
log.logInvokationResultDownstreamFailed(PnLogger.EXTERNAL_SERVICES.ADE, throwable.getMessage());
63+
if (!shouldRetry(throwable) && throwable instanceof WebClientResponseException e) {
64+
throw new PnNationalRegistriesException(e.getMessage(), e.getStatusCode().value(),
65+
e.getStatusText(), e.getHeaders(), e.getResponseBodyAsByteArray(),
66+
Charset.defaultCharset(), TaxIdResponseKO.class);
67+
}
68+
});
69+
}
70+
71+
protected boolean shouldRetry(Throwable throwable) {
72+
if (throwable instanceof WebClientResponseException exception && exception.getStatusCode() == HttpStatus.UNAUTHORIZED) {
73+
log.debug("Try Retry call to CheckCf");
74+
return true;
75+
}
76+
return false;
77+
}
78+
}
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
package it.pagopa.pn.national.registries.config.adecheckcf;
2+
3+
import io.netty.handler.ssl.SslContext;
4+
import io.netty.handler.ssl.SslContextBuilder;
5+
import it.pagopa.pn.commons.exceptions.PnInternalException;
6+
import it.pagopa.pn.commons.pnclients.CommonBaseClient;
7+
import it.pagopa.pn.national.registries.client.SecureWebClientUtils;
8+
import it.pagopa.pn.national.registries.config.CustomRetryConfig;
9+
import it.pagopa.pn.national.registries.generated.openapi.msclient.ade.v1.ApiClient;
10+
import it.pagopa.pn.national.registries.generated.openapi.msclient.ade.v1.api.VerificheApi;
11+
import it.pagopa.pn.national.registries.model.TrustData;
12+
import it.pagopa.pn.national.registries.service.PnNationalRegistriesSecretService;
13+
import lombok.RequiredArgsConstructor;
14+
import lombok.extern.slf4j.Slf4j;
15+
import org.springframework.beans.factory.annotation.Value;
16+
import org.springframework.context.annotation.Bean;
17+
import org.springframework.context.annotation.Configuration;
18+
import org.springframework.web.reactive.function.client.ExchangeFilterFunction;
19+
import reactor.netty.http.client.HttpClient;
20+
21+
import java.io.IOException;
22+
23+
import static it.pagopa.pn.national.registries.exceptions.PnNationalRegistriesExceptionCodes.ERROR_CODE_CHECK_CF;
24+
import static it.pagopa.pn.national.registries.exceptions.PnNationalRegistriesExceptionCodes.ERROR_MESSAGE_CHECK_CF;
25+
26+
@Configuration
27+
@Slf4j
28+
@RequiredArgsConstructor
29+
public class CheckCfClientConfig extends CommonBaseClient {
30+
31+
private final CustomRetryConfig customRetryConfig;
32+
private final PnNationalRegistriesSecretService pnNationalRegistriesSecretService;
33+
private final CheckCfSecretConfig checkCfSecretConfig;
34+
private final SecureWebClientUtils secureWebClientUtils;
35+
36+
@Bean
37+
VerificheApi verificheApi(@Value("${pn.national.registries.ade-check-cf.base-path}") String basePath) {
38+
var apiClient = new ApiClient(initWebClient(ApiClient.buildWebClientBuilder()));
39+
apiClient.setBasePath(basePath);
40+
return new VerificheApi(apiClient);
41+
}
42+
43+
@Override
44+
protected HttpClient buildHttpClient() {
45+
return super.buildHttpClient()
46+
.secure(t -> t.sslContext(buildSslContext()));
47+
}
48+
49+
protected SslContext buildSslContext() {
50+
try {
51+
TrustData trustData = pnNationalRegistriesSecretService.getTrustedCertFromSecret(checkCfSecretConfig.getTrustData());
52+
return secureWebClientUtils.getSslContext(SslContextBuilder.forClient(), trustData.getTrust());
53+
} catch (IOException e) {
54+
throw new PnInternalException(ERROR_MESSAGE_CHECK_CF, ERROR_CODE_CHECK_CF, e);
55+
}
56+
}
57+
58+
@Override
59+
protected ExchangeFilterFunction buildRetryExchangeFilterFunction() {
60+
return customRetryConfig.buildRetryExchangeFilterFunction();
61+
}
62+
}
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
package it.pagopa.pn.national.registries.config.adecheckcf;
2+
3+
import lombok.Getter;
4+
import lombok.extern.slf4j.Slf4j;
5+
import org.springframework.beans.factory.annotation.Value;
6+
import org.springframework.stereotype.Component;
7+
8+
@Component
9+
@Slf4j
10+
@Getter
11+
public class CheckCfSecretConfig{
12+
private final String pdndSecret;
13+
private final String trustData;
14+
15+
public CheckCfSecretConfig(@Value("${pn.national.registries.pdnd.ade-check-cf.secret}") String pdndSecret,
16+
@Value("${pn.national.registries.trust.ade-check-cf.secret}") String trustData) {
17+
this.pdndSecret = pdndSecret;
18+
this.trustData = trustData;
19+
}
20+
}

src/main/java/it/pagopa/pn/national/registries/converter/AgenziaEntrateConverter.java

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
package it.pagopa.pn.national.registries.converter;
22

3+
import it.pagopa.pn.national.registries.generated.openapi.msclient.ade.v1.dto.VerificaCodiceFiscale;
34
import it.pagopa.pn.national.registries.generated.openapi.server.v1.dto.ADELegalOKDto;
5+
import it.pagopa.pn.national.registries.generated.openapi.server.v1.dto.CheckTaxIdOKDto;
46
import it.pagopa.pn.national.registries.model.agenziaentrate.CheckValidityRappresentanteResp;
57
import it.pagopa.pn.national.registries.model.agenziaentrate.ResultCodeEnum;
68
import it.pagopa.pn.national.registries.model.agenziaentrate.ResultDetailEnum;
@@ -9,6 +11,10 @@
911
@Component
1012
public class AgenziaEntrateConverter {
1113

14+
public static final String CODICE_FISCALE_VALIDO_NON_UTILIZZABILE = "Codice fiscale valido, non più utilizzabile in quanto aggiornato in altro codice fiscale";
15+
public static final String CODICE_FISCALE_NON_VALIDO_AGGIORNATO_IN_ALTRO = "Codice fiscale non utilizzabile in quanto aggiornato in altro codice fiscale";
16+
public static final String CODICE_FISCALE_NON_VALIDO = "Codice fiscale non valido";
17+
1218
public ADELegalOKDto adELegalResponseToDto(CheckValidityRappresentanteResp checkValidityRappresentanteResp) {
1319
ADELegalOKDto adeLegalOKDto = new ADELegalOKDto();
1420
adeLegalOKDto.setResultCode(ResultCodeEnum.fromValue(checkValidityRappresentanteResp.codiceRitorno));
@@ -19,4 +25,23 @@ public ADELegalOKDto adELegalResponseToDto(CheckValidityRappresentanteResp check
1925
return adeLegalOKDto;
2026
}
2127

28+
public CheckTaxIdOKDto convertToCfStatusDto(VerificaCodiceFiscale taxIdVerification) {
29+
CheckTaxIdOKDto cfStatusDto = new CheckTaxIdOKDto();
30+
cfStatusDto.setIsValid(taxIdVerification.getValido());
31+
cfStatusDto.setTaxId(taxIdVerification.getCodiceFiscale());
32+
if (taxIdVerification.getMessaggio() != null) {
33+
cfStatusDto.setErrorCode(decodeError(taxIdVerification.getMessaggio()));
34+
}
35+
return cfStatusDto;
36+
}
37+
38+
public CheckTaxIdOKDto.ErrorCodeEnum decodeError(String message) {
39+
return switch (message) {
40+
case CODICE_FISCALE_VALIDO_NON_UTILIZZABILE -> CheckTaxIdOKDto.ErrorCodeEnum.ERR01;
41+
case CODICE_FISCALE_NON_VALIDO_AGGIORNATO_IN_ALTRO -> CheckTaxIdOKDto.ErrorCodeEnum.ERR02;
42+
case CODICE_FISCALE_NON_VALIDO -> CheckTaxIdOKDto.ErrorCodeEnum.ERR03;
43+
default -> null;
44+
};
45+
}
46+
2247
}

src/main/java/it/pagopa/pn/national/registries/model/agenziaentrate/Request.java

Lines changed: 0 additions & 12 deletions
This file was deleted.

src/main/java/it/pagopa/pn/national/registries/model/agenziaentrate/TaxIdVerification.java

Lines changed: 0 additions & 14 deletions
This file was deleted.

src/main/java/it/pagopa/pn/national/registries/rest/AgenziaEntrateController.java

Lines changed: 23 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@
33
import it.pagopa.pn.national.registries.generated.openapi.server.v1.api.AgenziaEntrateApi;
44
import it.pagopa.pn.national.registries.generated.openapi.server.v1.dto.ADELegalOKDto;
55
import it.pagopa.pn.national.registries.generated.openapi.server.v1.dto.ADELegalRequestBodyDto;
6+
import it.pagopa.pn.national.registries.generated.openapi.server.v1.dto.CheckTaxIdOKDto;
7+
import it.pagopa.pn.national.registries.generated.openapi.server.v1.dto.CheckTaxIdRequestBodyDto;
68
import it.pagopa.pn.national.registries.service.AgenziaEntrateService;
79
import org.springframework.http.ResponseEntity;
810
import org.springframework.web.bind.annotation.RestController;
@@ -25,19 +27,35 @@ public AgenziaEntrateController(AgenziaEntrateService agenziaEntrateService, Sch
2527

2628
}
2729

30+
/**
31+
* POST /national-registries-private/agenzia-entrate/tax-id : Questo servizio ritorna la validità e l’esistenza di un dato codice fiscale descritta da un campo di ritorno booleano nell’oggetto json di response
32+
* Questo servizio ritorna la validità e l’esistenza di un dato codice fiscale descritta da un campo di ritorno booleano nell’oggetto json di response
33+
*
34+
* @param checkTaxIdRequestBodyDto Effettua la ricerca di un codice fiscale (required)
35+
* @return OK (status code 200)
36+
* or Bad request (status code 400)
37+
* or Internal server error (status code 500)
38+
*/
39+
@Override
40+
public Mono<ResponseEntity<CheckTaxIdOKDto>> checkTaxId(Mono<CheckTaxIdRequestBodyDto> checkTaxIdRequestBodyDto, final ServerWebExchange exchange) {
41+
return checkTaxIdRequestBodyDto.flatMap(agenziaEntrateService::callEService)
42+
.map(t -> ResponseEntity.ok().body(t))
43+
.publishOn(scheduler);
44+
}
45+
2846
/**
2947
* POST /national-registries-private/agenzia-entrate/legal : Il servizio consente la verifica di corrispondenza fra il codice fiscale del rappresentante legale di un soggetto giuridico e il soggetto giuridico stesso.
3048
* Il servizio consente la verifica di corrispondenza fra il codice fiscale del rappresentante legale di un soggetto giuridico e il soggetto giuridico stesso.
3149
*
32-
* @param adELegalRequestBodyDto (required)
50+
* @param adELegalRequestBodyDto (required)
3351
* @return OK (status code 200)
34-
* or Unauthorized (status code 401)
35-
* or Internal server error (status code 500)
36-
* or Service Unavailable (status code 503)
52+
* or Unauthorized (status code 401)
53+
* or Internal server error (status code 500)
54+
* or Service Unavailable (status code 503)
3755
*/
3856

3957
@Override
40-
public Mono<ResponseEntity<ADELegalOKDto>> adeLegal(Mono<ADELegalRequestBodyDto> adELegalRequestBodyDto, final ServerWebExchange exchange) {
58+
public Mono<ResponseEntity<ADELegalOKDto>> adeLegal(Mono<ADELegalRequestBodyDto> adELegalRequestBodyDto, final ServerWebExchange exchange) {
4159
return adELegalRequestBodyDto.flatMap(agenziaEntrateService::checkTaxIdAndVatNumber)
4260
.map(t -> ResponseEntity.ok().body(t))
4361
.publishOn(scheduler);

0 commit comments

Comments
 (0)