Skip to content

Commit

Permalink
618 autenticazione client tramite header http (#622)
Browse files Browse the repository at this point in the history
Issue #618
Autenticazione client tramite Header HTTP

Aggiunta possibilita' di configurare l'autenticazione HTTP Header per i connettori verso le API PagoPA e API Ente.
Modificato componente client per utilizzare la nuova tipologia di autenticazione.
Aggiunti test di configurazione e utilizzo della nuova tipologia.
Allineato Cruscotto.
  • Loading branch information
pintorig committed Sep 22, 2023
1 parent 9a76e9c commit 9d11c75
Show file tree
Hide file tree
Showing 22 changed files with 613 additions and 93 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,8 @@ Examples:
| servizioIntegrazione | { versioneApi: 'REST v1', url: 'http://prova.it', auth: { tipo: 'Server', ksLocation: '/tmp/keystore.jks', ksPassword: 'kspwd', tsLocation: '/tmp/truststore.jks', tsPassword: 'tspwd', tsType: 'XXX', sslType: 'TLSv1.2' } } | 'tsType' |
| servizioIntegrazione | { versioneApi: 'REST v1', url: 'http://prova.it', auth: { tipo: 'Server', ksLocation: '/tmp/keystore.jks', ksPassword: 'kspwd', tsLocation: '/tmp/truststore.jks', tsPassword: 'tspwd', tsType: 'JKS', sslType: null } } | 'sslType' |
| servizioIntegrazione | { versioneApi: 'REST v1', url: 'http://prova.it', auth: { tipo: 'Server', ksLocation: '/tmp/keystore.jks', ksPassword: 'kspwd', tsLocation: '/tmp/truststore.jks', tsPassword: 'tspwd', tsType: 'JKS', sslType: 'XXX' } } | 'sslType' |
| servizioIntegrazione | { versioneApi: 'REST v1', url: 'http://prova.it', auth: { headerName: null, headerValue: 'govpay' } } | 'headerName' |
| servizioIntegrazione | { versioneApi: 'REST v1', url: 'http://prova.it', auth: { headerName: 'X-GOVPAY-AUTH', headerValue: null } } | 'headerValue' |
| abilitato | null | 'abilitato' |
| abilitato | 'sss' | 'abilitato' |
| apiPagamenti | null | 'apiPagamenti' |
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,8 @@ Examples:
| servizioIntegrazione | { versioneApi: 'REST v2', url: 'http://prova.it', auth: { username: 'usr', password: 'pwd' } } |
| servizioIntegrazione | { versioneApi: 'REST v2', url: 'http://prova.it', auth: { tipo: 'Client', ksLocation: '/tmp/keystore.jks', ksPassword: 'kspwd', tsLocation: '/tmp/truststore.jks', tsPassword: 'tspwd', tsType: 'JKS', sslType: 'TLSv1.2' , ksType: 'JKS', ksPKeyPasswd: 'ksPKeyPasswd' } } |
| servizioIntegrazione | { versioneApi: 'REST v2', url: 'http://prova.it', auth: { tipo: 'Server', tsLocation: '/tmp/truststore.jks', tsPassword: 'tspwd', tsType: 'JKS', sslType: 'TLSv1.2' } } |
| servizioIntegrazione | { versioneApi: 'REST v1', url: 'http://prova.it', auth: { headerName: 'X-GOVPAY-AUTH', headerValue: 'govpay' } } |
| servizioIntegrazione | { versioneApi: 'REST v2', url: 'http://prova.it', auth: { headerName: 'X-GOVPAY-AUTH', headerValue: 'govpay' } } |
| abilitato | false |
| abilitato | true |
| apiPagamenti | false |
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ Background:
* def intermediarioBasicAuth = read('classpath:test/api/backoffice/v1/intermediari/put/msg/intermediarioBasicAuth.json')
* def intermediarioClientAuth = read('classpath:test/api/backoffice/v1/intermediari/put/msg/intermediarioClientAuth.json')
* def intermediarioServerAuth = read('classpath:test/api/backoffice/v1/intermediari/put/msg/intermediarioServerAuth.json')
* def intermediarioHeaderAuth = read('classpath:test/api/backoffice/v1/intermediari/put/msg/intermediarioHeaderAuth.json')
* def loremIpsum = 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Phasellus non neque vestibulum, porta eros quis, fringilla enim. Nam sit amet justo sagittis, pretium urna et, convallis nisl. Proin fringilla consequat ex quis pharetra. Nam laoreet dignissim leo. Ut pulvinar odio et egestas placerat. Quisque tincidunt egestas orci, feugiat lobortis nisi tempor id. Donec aliquet sed massa at congue. Sed dictum, elit id molestie ornare, nibh augue facilisis ex, in molestie metus enim finibus arcu. Donec non elit dictum, dignissim dui sed, facilisis enim. Suspendisse nec cursus nisi. Ut turpis justo, fermentum vitae odio et, hendrerit sodales tortor. Aliquam varius facilisis nulla vitae hendrerit. In cursus et lacus vel consectetur.'

Scenario Outline: <field> non valida
Expand Down Expand Up @@ -117,3 +118,28 @@ Examples:
| subscriptionKey | intermediarioServerAuth.servizioPagoPa.subscriptionKey | '' | 'subscriptionKey' |
| subscriptionKey | intermediarioServerAuth.servizioPagoPa.subscriptionKey | loremIpsum | 'subscriptionKey' |


Scenario Outline: <field> non valida

* set <fieldRequest> = <fieldValue>

Given url backofficeBaseurl
And path 'intermediari', idIntermediario
And headers basicAutenticationHeader
And request intermediarioHeaderAuth
When method put
Then status 400

* match response == { categoria: 'RICHIESTA', codice: 'SINTASSI', descrizione: 'Richiesta non valida', dettaglio: '#notnull' }
* match response.dettaglio contains <fieldResponse>

Examples:
| field | fieldRequest | fieldValue | fieldResponse |
| headerName | intermediarioHeaderAuth.servizioPagoPa.auth.headerName | null | 'headerName' |
| headerValue | intermediarioHeaderAuth.servizioPagoPa.auth.headerValue | null | 'headerValue' |
| subscriptionKey | intermediarioHeaderAuth.servizioPagoPa.subscriptionKey | '' | 'subscriptionKey' |
| subscriptionKey | intermediarioHeaderAuth.servizioPagoPa.subscriptionKey | loremIpsum | 'subscriptionKey' |
| denominazione | intermediarioHeaderAuth.denominazione | null | 'denominazione' |



Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ Background:
* def intermediarioBasicAuth = read('classpath:test/api/backoffice/v1/intermediari/put/msg/intermediarioBasicAuth.json')
* def intermediarioServerAuth = read('classpath:test/api/backoffice/v1/intermediari/put/msg/intermediarioServerAuth.json')
* def intermediarioClientAuth = read('classpath:test/api/backoffice/v1/intermediari/put/msg/intermediarioClientAuth.json')
* def intermediarioHeaderAuth = read('classpath:test/api/backoffice/v1/intermediari/put/msg/intermediarioHeaderAuth.json')

Scenario: Configurazione intermediario senza autenticazione verso pagoPA

Expand Down Expand Up @@ -110,3 +111,23 @@ When method get
Then status 200
And match response == intermediario

Scenario: Configurazione intermediario con autenticazione header verso pagoPA

Given url backofficeBaseurl
And path 'intermediari', idIntermediario
And headers basicAutenticationHeader
And request intermediarioHeaderAuth
When method put
Then assert responseStatus == 200 || responseStatus == 201

* set intermediarioHeaderAuth.idIntermediario = idIntermediario
* set intermediarioHeaderAuth.stazioni = '#ignore'

Given url backofficeBaseurl
And path 'intermediari', idIntermediario
And headers basicAutenticationHeader
When method get
Then status 200
And match response == intermediarioHeaderAuth


Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
{
"denominazione": "Soggetto Intermediario",
"principalPagoPa": '#(ndpsym_user)',
"servizioPagoPa": {
"urlRPT": '#(ndpsym_url + "/pagopa/PagamentiTelematiciRPTservice")',
"auth": {
"headerName": "X-GOVPAY-AUTH",
"headerValue": "govpay"
}
},
"abilitato": true
}
Original file line number Diff line number Diff line change
Expand Up @@ -322,6 +322,137 @@ And match response.risultati[1] ==
"""
And match response.risultati[1].parametriRichiesta.url == ente_api_url + "/v1/avvisi/"+ idDominio + "/" + numeroAvviso

@test-auth
Scenario: Verifica tutti gli eventi di un Pagamento eseguito di un dovuto precaricato non scaduto verso API Ente con autenticazione header

* def headerPrincipal = 'govpay'
* def applicazione = read('classpath:configurazione/v1/msg/applicazione.json')
* set applicazione.servizioIntegrazione.versioneApi = 'REST v2'
* set applicazione.servizioIntegrazione.url = ente_api_url + '/v1'
* set applicazione.servizioIntegrazione.auth.headerName = 'X-GOVPAY-AUTH'
* set applicazione.servizioIntegrazione.auth.headerValue = headerPrincipal


# "url": '#(ente_api_url + "/v1")',

Given url backofficeBaseurl
And path 'applicazioni', idA2A
And headers gpAdminBasicAutenticationHeader
And request applicazione
When method put
Then assert responseStatus == 200 || responseStatus == 201

* call read('classpath:configurazione/v1/operazioni-resetCache.feature')

* def idPendenza = getCurrentTimeMillis()
* def pendenzaPut = read('classpath:test/api/pendenza/v3/pendenze/put/msg/pendenza-put_monovoce_riferimento.json')

Given url backofficeBaseurl
And path '/pendenze', idA2A, idPendenza
And headers idA2ABasicAutenticationHeader
And request pendenzaPut
When method put
Then status 201

* def numeroAvviso = response.numeroAvviso
* def iuv = getIuvFromNumeroAvviso(numeroAvviso)

* def importo = pendenzaPut.importo

* def esitoAttivaRPT = read('classpath:test/workflow/modello3/v1/msg/attiva-response-ok.json')
* def esitoVerificaRPT = read('classpath:test/workflow/modello3/v1/msg/verifica-response-ok.json')

# Verifico il pagamento

* call read('classpath:utils/psp-verifica-rpt.feature')
* match response.esitoVerificaRPT == esitoVerificaRPT
* def ccp = response.ccp

# Attivo il pagamento

* def tipoRicevuta = "R01"
* call read('classpath:utils/psp-attiva-rpt.feature')
* match response.dati == esitoAttivaRPT

# Verifico la notifica di terminazione

* call read('classpath:utils/pa-notifica-terminazione.feature')
* match response == read('classpath:test/api/ente/v2/ricevute/put/msg/transazione-get-singolo_eseguito_ente.json')

# Verifico lo stato della pendenza

* call read('classpath:utils/api/v1/backoffice/pendenza-get-dettaglio.feature')
* match response.stato == 'ESEGUITA'
* match response.dataPagamento == '#regex \\d\\d\\d\\d-\\d\\d-\\d\\d'
* match response.voci[0].stato == 'Eseguito'
* match response.rpp == '#[1]'
* match response.rpp[0].stato == 'RT_ACCETTATA_PA'
* match response.rpp[0].rt == '#notnull'

* def backofficeBaseurl = getGovPayApiBaseUrl({api: 'backoffice', versione: 'v1', autenticazione: 'basic'})

* call sleep(200)

Given url backofficeBaseurl
And path '/eventi'
And param idDominio = idDominio
And param iuv = iuv
And param componente = 'API_ENTE'
# And param tipoEvento = 'nodoInviaRPT'
And param messaggi = true
And headers gpAdminBasicAutenticationHeader
When method get
Then status 200
And match response ==
"""
{
numRisultati: 1,
numPagine: '#number',
risultatiPerPagina: 25,
pagina: 1,
prossimiRisultati: '#ignore',
risultati: '#[1]'
}
"""

# Notifica Ricevuta

And match response.risultati[0] ==
"""
{
"id": "#notnull",
"idDominio":"#(idDominio)",
"iuv":"#(iuv)",
"ccp":"#(''+ccp)",
"idA2A": "#(idA2A)",
"idPendenza": "#(''+idPendenza)",
"idPagamento": "#notnull",
"componente": "API_ENTE",
"categoriaEvento": "INTERFACCIA",
"ruolo": "CLIENT",
"tipoEvento": "notificaRicevuta",
"sottotipoEvento": "##null",
"esito": "OK",
"sottotipoEsito": "200",
"dettaglioEsito": "##string",
"dataEvento": "#notnull",
"durataEvento": "#notnull",
"clusterId" : "#notnull",
"transactionId" : "#notnull",
"parametriRichiesta": {
"dataOraRichiesta":"#regex \\d\\d\\d\\d-\\d\\d-\\d\\dT\\d\\d:\\d\\d:\\d\\d\\.\\d\\d\\d",
"url": "#notnull",
"method": "PUT",
"headers": "#array",
"payload": "#ignore",
"principal": "#(headerPrincipal)"
},
"parametriRisposta": {
"dataOraRisposta":"#regex \\d\\d\\d\\d-\\d\\d-\\d\\dT\\d\\d:\\d\\d:\\d\\d\\.\\d\\d\\d",
"status": 200,
"headers": "#array",
"payload": "#ignore"
}
}
"""
And match response.risultati[0].parametriRichiesta.url == ente_api_url + "/v1/ricevute/"+ idDominio + "/" + iuv +"/"+ ccp
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ public class OperazioniDAO extends BaseDAO{
public final static String ELABORAZIONE_RICONCILIAZIONI = "elaborazioneRiconciliazioni";
public final static String CHIUSURA_RPT_SCADUTE = "chiusuraRptScadute";

public LeggiOperazioneDTOResponse eseguiOperazione(LeggiOperazioneDTO leggiOperazioneDTO) throws ServiceException, OperazioneNonTrovataException, NotAuthorizedException, NotAuthenticatedException{
public LeggiOperazioneDTOResponse eseguiOperazione(LeggiOperazioneDTO leggiOperazioneDTO) throws OperazioneNonTrovataException{
LeggiOperazioneDTOResponse response = new LeggiOperazioneDTOResponse();

try {
Expand All @@ -57,10 +57,8 @@ public LeggiOperazioneDTOResponse eseguiOperazione(LeggiOperazioneDTO leggiOpera
esitoOperazione = it.govpay.core.business.Operazioni.spedizionePromemoria(ctx);
} else if(leggiOperazioneDTO.getIdOperazione().equals(GESTIONE_PROMEMORIA)){
esitoOperazione = it.govpay.core.business.Operazioni.gestionePromemoria(ctx);
} else if(leggiOperazioneDTO.getIdOperazione().equals(GENERAZIONE_AVVISI_PAGAMENTO)){
it.govpay.core.business.Operazioni.setEseguiGenerazioneAvvisi();
esitoOperazione = "Generazione Avvisi Pagamento schedulata";
} else if(leggiOperazioneDTO.getIdOperazione().equals(ATTIVAZIONE_GENERAZIONE_AVVISI_PAGAMENTO)){
} else if(leggiOperazioneDTO.getIdOperazione().equals(GENERAZIONE_AVVISI_PAGAMENTO) ||
leggiOperazioneDTO.getIdOperazione().equals(ATTIVAZIONE_GENERAZIONE_AVVISI_PAGAMENTO)){
it.govpay.core.business.Operazioni.setEseguiGenerazioneAvvisi();
esitoOperazione = "Generazione Avvisi Pagamento schedulata";
} else if(leggiOperazioneDTO.getIdOperazione().equals(ELABORAZIONE_TRACCIATI_PENDENZE)){
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -127,12 +127,17 @@ public abstract class BasicClientCORE {
private static Logger log = LoggerWrapperFactory.getLogger(BasicClientCORE.class);

protected boolean debug = true;
// protected static Map<String, SSLContext> sslContexts = new HashMap<>();
protected URL url = null;
// protected SSLContext sslContext;
protected boolean ishttpBasicEnabled=false, isSslEnabled=false, isSubscriptionKeyEnabled=false;
protected String httpBasicUser, httpBasicPassword;
protected String subscriptionKeyHeaderName, subscriptionKeyHeaderValue;
protected boolean ishttpBasicEnabled=false;
protected boolean isSslEnabled=false;
protected boolean isSubscriptionKeyEnabled=false;
protected boolean ishttpHeaderEnabled=false;
protected String httpBasicUser;
protected String httpBasicPassword;
protected String subscriptionKeyHeaderName;
protected String subscriptionKeyHeaderValue;
protected String httpHeaderName;
protected String httpHeaderValue;
protected String errMsg;
protected String destinatario;
protected String mittente;
Expand Down Expand Up @@ -315,6 +320,14 @@ private BasicClientCORE(String bundleKey, Connettore connettore) throws ClientEx
this.getEventoCtx().setPrincipal(this.httpBasicUser);
}

if(connettore.getTipoAutenticazione().equals(EnumAuthType.HTTP_HEADER)) {
this.ishttpHeaderEnabled = true;
this.httpHeaderName = connettore.getHttpHeaderName();
this.httpHeaderValue = connettore.getHttpHeaderValue();

this.getEventoCtx().setPrincipal(this.httpHeaderValue);
}

if(connettore.getSubscriptionKeyValue() != null) {
// se non ho impostato nessuna autenticazione salvo SubscriptionKey come metodo di autenticazione per l'evento.
if(connettore.getTipoAutenticazione().equals(EnumAuthType.NONE)) {
Expand Down Expand Up @@ -619,6 +632,17 @@ private byte[] send(boolean soap, String azione, byte[] body, boolean isAzioneIn
log.debug("Impostato Header Authorization [Basic "+encoding+"]");
}

// Authentication HTTP Header
if(this.ishttpHeaderEnabled) {
if(this.debug)
log.debug("Impostazione autenticazione...");

this.dumpRequest.getHeaders().put(this.httpHeaderName, this.httpHeaderValue);
this.httpRequest.addHeader(this.httpHeaderName, this.httpHeaderValue);
if(this.debug)
log.debug("Impostato Autenticazione tramite Header HTTP [{}:{}]", this.httpHeaderName, this.httpHeaderValue);
}

// Authentication Subscription Key
if(this.isSubscriptionKeyEnabled) {
if(this.debug)
Expand Down
20 changes: 19 additions & 1 deletion jars/orm-beans/src/main/java/it/govpay/model/Connettore.java
Original file line number Diff line number Diff line change
Expand Up @@ -39,9 +39,11 @@ public class Connettore extends Versionabile {
public static final String P_AZIONEINURL_NAME = "AZIONEINURL";
public static final String P_VERSIONE = "VERSIONE";
public static final String P_SUBSCRIPTION_KEY_VALUE = "SUBSCRIPTION_KEY_VALUE";
public static final String P_HTTP_HEADER_AUTH_HEADER_NAME_NAME = "HTTP_HEADER_AUTH_HEADER_NAME";
public static final String P_HTTP_HEADER_AUTH_HEADER_VALUE_NAME = "HTTP_HEADER_AUTH_HEADER_VALUE";

public enum EnumAuthType {
SSL, HTTPBasic, NONE
SSL, HTTPBasic, HTTP_HEADER, NONE
}

public enum EnumSslType {
Expand Down Expand Up @@ -69,6 +71,8 @@ public enum Tipo {
private String urlServiziAvvisatura;
private boolean azioneInUrl;
private String subscriptionKeyValue;
private String httpHeaderName;
private String httpHeaderValue;

public Connettore() {
}
Expand All @@ -91,6 +95,8 @@ public Connettore(Connettore src) {
this.tipoSsl = src.tipoSsl;
this.url = src.url;
this.urlServiziAvvisatura = src.urlServiziAvvisatura;
this.httpHeaderName = src.httpHeaderName;
this.httpHeaderValue = src.httpHeaderValue;
}

public String getIdConnettore() {
Expand Down Expand Up @@ -198,4 +204,16 @@ public String getSubscriptionKeyValue() {
public void setSubscriptionKeyValue(String subscriptionKeyValue) {
this.subscriptionKeyValue = subscriptionKeyValue;
}
public String getHttpHeaderName() {
return httpHeaderName;
}
public void setHttpHeaderName(String httpHeaderName) {
this.httpHeaderName = httpHeaderName;
}
public String getHttpHeaderValue() {
return httpHeaderValue;
}
public void setHttpHeaderValue(String httpHeaderValue) {
this.httpHeaderValue = httpHeaderValue;
}
}

0 comments on commit 9d11c75

Please sign in to comment.