ConnettoreSignalHubPseudonymization.java

  1. /*
  2.  * GovWay - A customizable API Gateway
  3.  * https://govway.org
  4.  *
  5.  * Copyright (c) 2005-2025 Link.it srl (https://link.it).
  6.  *
  7.  * This program is free software: you can redistribute it and/or modify
  8.  * it under the terms of the GNU General Public License version 3, as published by
  9.  * the Free Software Foundation.
  10.  *
  11.  * This program is distributed in the hope that it will be useful,
  12.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14.  * GNU General Public License for more details.
  15.  *
  16.  * You should have received a copy of the GNU General Public License
  17.  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
  18.  *
  19.  */

  20. package org.openspcoop2.protocol.modipa.connettori;

  21. import java.io.ByteArrayInputStream;
  22. import java.util.ArrayList;
  23. import java.util.HashMap;
  24. import java.util.Iterator;
  25. import java.util.List;
  26. import java.util.Map;

  27. import org.openspcoop2.core.config.ResponseCachingConfigurazione;
  28. import org.openspcoop2.core.config.driver.DriverConfigurazioneException;
  29. import org.openspcoop2.core.config.driver.db.DriverConfigurazioneDB;
  30. import org.openspcoop2.core.constants.CostantiConnettori;
  31. import org.openspcoop2.core.id.IDServizio;
  32. import org.openspcoop2.core.registry.ProtocolProperty;
  33. import org.openspcoop2.core.transazioni.constants.TipoMessaggio;
  34. import org.openspcoop2.message.OpenSPCoop2MessageFactory;
  35. import org.openspcoop2.message.OpenSPCoop2MessageParseResult;
  36. import org.openspcoop2.message.OpenSPCoop2SoapMessage;
  37. import org.openspcoop2.message.constants.Costanti;
  38. import org.openspcoop2.message.constants.MessageRole;
  39. import org.openspcoop2.message.constants.MessageType;
  40. import org.openspcoop2.message.soap.TunnelSoapUtils;
  41. import org.openspcoop2.pdd.config.ConfigurazionePdDReader;
  42. import org.openspcoop2.pdd.config.DigestServiceParams;
  43. import org.openspcoop2.pdd.config.DigestServiceParamsDriver;
  44. import org.openspcoop2.pdd.core.PdDContext;
  45. import org.openspcoop2.pdd.core.Utilities;
  46. import org.openspcoop2.pdd.core.connettori.ConnettoreBaseWithResponse;
  47. import org.openspcoop2.pdd.core.connettori.ConnettoreException;
  48. import org.openspcoop2.pdd.core.connettori.ConnettoreLogger;
  49. import org.openspcoop2.pdd.core.connettori.ConnettoreMsg;
  50. import org.openspcoop2.protocol.modipa.constants.ModICostanti;
  51. import org.openspcoop2.protocol.modipa.utils.SignalHubUtils;
  52. import org.openspcoop2.protocol.sdk.ProtocolException;
  53. import org.openspcoop2.protocol.sdk.state.RequestInfo;
  54. import org.openspcoop2.utils.UtilsException;
  55. import org.openspcoop2.utils.date.DateManager;
  56. import org.openspcoop2.utils.io.DumpByteArrayOutputStream;
  57. import org.openspcoop2.utils.json.JSONUtils;
  58. import org.openspcoop2.utils.rest.problem.JsonSerializer;
  59. import org.openspcoop2.utils.rest.problem.ProblemRFC7807;
  60. import org.openspcoop2.utils.transport.TransportResponseContext;
  61. import org.openspcoop2.utils.transport.TransportUtils;
  62. import org.openspcoop2.utils.transport.http.HttpConstants;
  63. import org.openspcoop2.utils.transport.http.HttpUtilities;

  64. import com.fasterxml.jackson.databind.node.ObjectNode;


  65. /**
  66.  *
  67.  * @author Tommaso Burlon (tommaso.burlon@link.it)
  68.  * @author $Author$
  69.  * @version $Rev$, $Date$
  70.  */

  71. public class ConnettoreSignalHubPseudonymization extends ConnettoreBaseWithResponse {
  72.    
  73.     @Override
  74.     public String getProtocollo() {
  75.         return "http";
  76.     }
  77.    
  78.     public static final String LOCATION = "govway://signalHubPseudonymization";
  79.    
  80.     private DumpByteArrayOutputStream requestBout = null;

  81.    
  82.     private DigestServiceParams initCryptoInfo(DigestServiceParamsDriver driver, PdDContext context) throws UtilsException, DriverConfigurazioneException, ProtocolException {
  83.         RequestInfo reqInfo = (RequestInfo) context.getObject(org.openspcoop2.core.constants.Costanti.REQUEST_INFO);
  84.         IDServizio idServizio = reqInfo.getIdServizio();
  85.         DigestServiceParams param = null;
  86.        
  87.         List<ProtocolProperty> protocolProperty = SignalHubUtils.obtainSignalHubProtocolProperty(context);
  88.        
  89.         // provo ad inizializzare il db
  90.         driver.acquireLock(reqInfo.getIdTransazione());
  91.         try {
  92.            
  93.             // se le informazioni crittografiche esistono gia le ritorno altrimenti le genero
  94.             param = driver.getLastEntry(idServizio);
  95.             if (param != null)
  96.                 return param;
  97.            
  98.             param = SignalHubUtils.generateDigestServiceParams(idServizio, protocolProperty, null);
  99.             driver.addNewEntry(param);
  100.         } finally {
  101.             driver.releaseLock();
  102.         }
  103.        
  104.         return param;
  105.     }
  106.    
  107.     private void retrieveCryptoInfo(PdDContext pddContext) throws UtilsException, DriverConfigurazioneException, ProtocolException, ConnettoreException {
  108.        
  109.         RequestInfo reqInfo = (RequestInfo) pddContext.getObject(org.openspcoop2.core.constants.Costanti.REQUEST_INFO);
  110.         IDServizio idServizio = reqInfo.getIdServizio();
  111.        
  112.         // ottengo il driver di configurazione
  113.         Object db = ConfigurazionePdDReader.getDriverConfigurazionePdD();
  114.         if (!(db instanceof DriverConfigurazioneDB))
  115.             throw new UtilsException("driver trovato non di tipo db");
  116.        
  117.        
  118.         // cerco di ottenere l'id del segnale per fare una ricerca puntuale delle informazioni crittografiche
  119.         String signalIdRaw = reqInfo.getProtocolContext().getParameterFirstValue(ModICostanti.MODIPA_SIGNAL_HUB_ID_SIGNAL_ID);
  120.         DigestServiceParams param = null;
  121.        
  122.         try {
  123.             Long signalId = signalIdRaw != null ? Long.parseLong(signalIdRaw) : null;
  124.             DigestServiceParamsDriver driver = new DigestServiceParamsDriver((DriverConfigurazioneDB) db);
  125.            
  126.             // se signalId risulta uguale a null ritornero le informazioni critoogtafiche piu recenti
  127.             param = driver.getEntry(idServizio, signalId);
  128.            
  129.             // se non esistno informazioni crittografiche nel db lo inizializzo
  130.             if (param == null && signalId == null) {
  131.                 param = this.initCryptoInfo(driver, pddContext);
  132.             }
  133.            
  134.         } catch (NumberFormatException e) {
  135.             throw new ConnettoreException("signalId params non int64");
  136.         }
  137.        
  138.        
  139.         // se non ho trovato alcuna informazione crittografica ritorno 404
  140.         if (param == null) {
  141.             ProblemRFC7807 problemRFC7807 = new ProblemRFC7807();
  142.             problemRFC7807.setStatus(404);
  143.             problemRFC7807.setDetail("Informazioni di pseudoanonimizzazione non trovate");
  144.             problemRFC7807.setTitle("Not Found");
  145.             problemRFC7807.setType("https://httpstatuses.com/404");
  146.            
  147.             JsonSerializer jsonSerializer = new JsonSerializer();
  148.             this.isResponse = new ByteArrayInputStream(jsonSerializer.toByteArray(problemRFC7807));
  149.             this.tipoRisposta = HttpConstants.CONTENT_TYPE_JSON_PROBLEM_DETAILS_RFC_7807;
  150.             this.codice = 404;
  151.             return;
  152.         }

  153.         // serializzo il messsaggio
  154.         JSONUtils jsonUtils = JSONUtils.getInstance();
  155.         ObjectNode node = jsonUtils.newObjectNode();
  156.         node.put("seed", new String(param.getSeed()));
  157.         node.put("cryptoHashFunction", param.getDigestAlgorithm().toString());
  158.        
  159.         this.isResponse = new ByteArrayInputStream(jsonUtils.toByteArray(node));
  160.         this.tipoRisposta = HttpConstants.CONTENT_TYPE_JSON;
  161.         this.codice = 200;
  162.     }
  163.    
  164.     /* ********  METODI  ******** */

  165.     @Override
  166.     protected boolean initializePreSend(ResponseCachingConfigurazione responseCachingConfig, ConnettoreMsg request) {
  167.         return this.initialize(request, false, responseCachingConfig);
  168.     }
  169.    
  170.    
  171.     @Override
  172.     protected boolean send(ConnettoreMsg request) {
  173.         PdDContext pddContext = request.getOutRequestContext().getPddContext();
  174.                
  175.         this.codice = 200;
  176.        
  177.         try{
  178.            
  179.             // Tipologia di servizio
  180.             MessageType requestMessageType = this.requestMsg.getMessageType();
  181.             OpenSPCoop2SoapMessage soapMessageRequest = null;
  182.             if(this.debug)
  183.                 this.logger.debug("Tipologia Servizio: "+this.requestMsg.getServiceBinding());
  184.             if(this.isSoap){
  185.                 soapMessageRequest = this.requestMsg.castAsSoap();
  186.             }
  187.            
  188.            
  189.             // Collezione header di trasporto per dump
  190.             Map<String, List<String>> propertiesTrasportoDebug = null;
  191.             if(this.isDumpBinarioRichiesta()) {
  192.                 propertiesTrasportoDebug = new HashMap<>();
  193.             }
  194.            
  195.            
  196.             // Impostazione Content-Type
  197.             String contentTypeRichiesta = null;
  198.             if(this.debug)
  199.                 this.logger.debug("Impostazione content type...");
  200.             if(this.isSoap){
  201.                 if(this.sbustamentoSoap && soapMessageRequest.countAttachments()>0 && TunnelSoapUtils.isTunnelOpenSPCoopSoap(soapMessageRequest)){
  202.                     contentTypeRichiesta = TunnelSoapUtils.getContentTypeTunnelOpenSPCoopSoap(soapMessageRequest.getSOAPBody());
  203.                 }else{
  204.                     contentTypeRichiesta = this.requestMsg.getContentType();
  205.                 }
  206.                 if(contentTypeRichiesta==null){
  207.                     throw new ConnettoreException("Content-Type del messaggio da spedire non definito");
  208.                 }
  209.             }
  210.             else{
  211.                 contentTypeRichiesta = this.requestMsg.getContentType();
  212.                 // Content-Type non obbligatorio in REST
  213.             }
  214.             if(this.debug)
  215.                 this.logger.info("Impostazione Content-Type ["+contentTypeRichiesta+"]",false);
  216.             if(contentTypeRichiesta!=null){
  217.                 setRequestHeader(HttpConstants.CONTENT_TYPE, contentTypeRichiesta, this.logger, propertiesTrasportoDebug);
  218.             }
  219.            
  220.            
  221.            
  222.             // Impostazione timeout
  223.             if(this.debug)
  224.                 this.logger.debug("Impostazione timeout...");
  225.             int readConnectionTimeout = -1;
  226.             boolean readConnectionTimeoutConfigurazioneGlobale = true;
  227.             if(this.properties.get(CostantiConnettori.CONNETTORE_READ_CONNECTION_TIMEOUT)!=null){
  228.                 try{
  229.                     readConnectionTimeout = Integer.parseInt(this.properties.get(CostantiConnettori.CONNETTORE_READ_CONNECTION_TIMEOUT));
  230.                     readConnectionTimeoutConfigurazioneGlobale = this.properties.containsKey(CostantiConnettori.CONNETTORE_READ_CONNECTION_TIMEOUT_GLOBALE);
  231.                 }catch(Exception e){
  232.                     this.logger.error("Parametro "+CostantiConnettori.CONNETTORE_READ_CONNECTION_TIMEOUT+" errato",e);
  233.                 }
  234.             }
  235.             if(readConnectionTimeout==-1){
  236.                 readConnectionTimeout = HttpUtilities.HTTP_READ_CONNECTION_TIMEOUT;
  237.             }
  238.             if(this.debug)
  239.                 this.logger.info("Impostazione read timeout ["+readConnectionTimeout+"]",false);
  240.            
  241.            
  242.             // Impostazione Proprieta del trasporto
  243.             if(this.debug)
  244.                 this.logger.debug("Impostazione header di trasporto...");
  245.             this.forwardHttpRequestHeader();
  246.             if(this.propertiesTrasporto != null){
  247.                 Iterator<String> keys = this.propertiesTrasporto.keySet().iterator();
  248.                 while (keys.hasNext()) {
  249.                     String key = keys.next();
  250.                     List<String> values = this.propertiesTrasporto.get(key);
  251.                     if(this.debug && values!=null && !values.isEmpty()) {
  252.                             for (String value : values) {
  253.                                 this.logger.info("Set proprietà trasporto ["+key+"]=["+value+"]",false);
  254.                             }
  255.                         }
  256.                     setRequestHeader(key, values, this.logger, propertiesTrasportoDebug);
  257.                 }
  258.             }
  259.            
  260.            
  261.            
  262.             // Aggiunga del SoapAction Header in caso di richiesta SOAP
  263.             // spostato sotto il forwardHeader per consentire alle trasformazioni di modificarla
  264.             if(this.isSoap && !this.sbustamentoSoap){
  265.                 if(this.debug)
  266.                     this.logger.debug("Impostazione soap action...");
  267.                 boolean existsTransportProperties = false;
  268.                 if(TransportUtils.containsKey(this.propertiesTrasporto, Costanti.SOAP11_MANDATORY_HEADER_HTTP_SOAP_ACTION)){
  269.                     this.soapAction = TransportUtils.getFirstValue(this.propertiesTrasporto, Costanti.SOAP11_MANDATORY_HEADER_HTTP_SOAP_ACTION);
  270.                     existsTransportProperties = (this.soapAction!=null);
  271.                 }
  272.                 if(!existsTransportProperties) {
  273.                     this.soapAction = soapMessageRequest.getSoapAction();
  274.                 }
  275.                 if(this.soapAction==null){
  276.                     this.soapAction="\"OpenSPCoop\"";
  277.                 }
  278.                 if(MessageType.SOAP_11.equals(this.requestMsg.getMessageType()) && !existsTransportProperties){
  279.                     // NOTA non quotare la soap action, per mantenere la trasparenza della PdD
  280.                     setRequestHeader(Costanti.SOAP11_MANDATORY_HEADER_HTTP_SOAP_ACTION,this.soapAction, propertiesTrasportoDebug);
  281.                 }
  282.                 if(this.debug)
  283.                     this.logger.info("SOAP Action inviata ["+this.soapAction+"]",false);
  284.             }
  285.            
  286.            
  287.            
  288.             // SIMULAZIONE WRITE_TO
  289.             boolean consumeRequestMessage = true;
  290.             if(this.debug)
  291.                 this.logger.debug("Serializzazione (consume-request-message:"+consumeRequestMessage+")...");
  292.             if(this.isDumpBinarioRichiesta()) {
  293.                 this.requestBout = new DumpByteArrayOutputStream(this.dumpBinario_soglia, this.dumpBinario_repositoryFile, this.idTransazione,
  294.                         "NullEcho-"+TipoMessaggio.RICHIESTA_USCITA_DUMP_BINARIO.getValue());
  295.                
  296.                 this.emitDiagnosticStartDumpBinarioRichiestaUscita();
  297.                
  298.                 if(this.isSoap && this.sbustamentoSoap){
  299.                     this.logger.debug("Sbustamento...");
  300.                     TunnelSoapUtils.sbustamentoMessaggio(soapMessageRequest,this.requestBout);
  301.                 }else{
  302.                     this.requestMsg.writeTo(this.requestBout, consumeRequestMessage);
  303.                 }
  304.                 this.requestBout.flush();
  305.                 this.requestBout.close();
  306.                                    
  307.                 this.dataRichiestaInoltrata = DateManager.getDate();
  308.                
  309.                 this.dumpBinarioRichiestaUscita(this.requestBout, requestMessageType, contentTypeRichiesta, this.location, propertiesTrasportoDebug);
  310.             }
  311.             else {
  312.                 this.requestBout = new DumpByteArrayOutputStream(this.dumpBinario_soglia, this.dumpBinario_repositoryFile, this.idTransazione,
  313.                         "NullEcho-"+TipoMessaggio.RICHIESTA_USCITA_DUMP_BINARIO.getValue());
  314.                 if(this.isSoap && this.sbustamentoSoap){
  315.                     this.logger.debug("Sbustamento...");
  316.                     TunnelSoapUtils.sbustamentoMessaggio(soapMessageRequest,this.requestBout);
  317.                 }else{
  318.                     this.requestMsg.writeTo(this.requestBout, consumeRequestMessage);
  319.                 }
  320.                 this.requestBout.flush();
  321.                 this.requestBout.close();
  322.                
  323.                 this.dataRichiestaInoltrata = DateManager.getDate();
  324.             }
  325.            
  326.             /* ------------  PostOutRequestHandler ------------- */
  327.             this.postOutRequest();
  328.            
  329.            
  330.            
  331.             /* ------------  PreInResponseHandler ------------- */
  332.             this.preInResponse();
  333.            
  334.             // Lettura risposta parametri NotifierInputStream per la risposta
  335.             org.openspcoop2.utils.io.notifier.NotifierInputStreamParams notifierInputStreamParams = null;
  336.             if(this.preInResponseContext!=null){
  337.                 notifierInputStreamParams = this.preInResponseContext.getNotifierInputStreamParams();
  338.             }
  339.            
  340.             // operazione di gestione delle informaizoni crittografiche
  341.             this.retrieveCryptoInfo(pddContext);
  342.            

  343.             this.normalizeInputStreamResponse(readConnectionTimeout, readConnectionTimeoutConfigurazioneGlobale);
  344.            
  345.             this.initCheckContentTypeConfiguration();
  346.            
  347.             this.messageTypeResponse = this.requestMsg.getMessageType();
  348.            
  349.             if(this.isDumpBinarioRisposta()){
  350.                 this.dumpResponse(this.propertiesTrasportoRisposta);
  351.             }
  352.            
  353.             if(this.isResponse!=null) {
  354.                 this.emitDiagnosticResponseRead(this.isResponse);
  355.             }
  356.            
  357.             OpenSPCoop2MessageFactory messageFactory = Utilities.getOpenspcoop2MessageFactory(this.logger.getLogger(),this.requestMsg, this.requestInfo, MessageRole.RESPONSE);
  358.             OpenSPCoop2MessageParseResult pr;
  359.            
  360.             if (this.isResponse != null) {
  361.                
  362.                 TransportResponseContext responseContext = new TransportResponseContext(this.logger.getLogger());
  363.                 responseContext.setCodiceTrasporto(this.codice+"");
  364.                 responseContext.setContentLength(this.contentLength);
  365.                 TransportUtils.addHeader(this.propertiesTrasportoRisposta, HttpConstants.CONTENT_TYPE, this.tipoRisposta);
  366.                 responseContext.setHeaders(this.propertiesTrasportoRisposta);
  367.                
  368.                 pr = messageFactory.createMessage(this.messageTypeResponse, responseContext,
  369.                         this.isResponse,notifierInputStreamParams,
  370.                         this.openspcoopProperties.getAttachmentsProcessingMode());
  371.             } else {
  372.                 TransportResponseContext responseContext = new TransportResponseContext(this.logger.getLogger());
  373.                 responseContext.setContentLength(0);
  374.                
  375.                 pr = messageFactory.createMessage(this.messageTypeResponse,responseContext,
  376.                         this.isResponse,notifierInputStreamParams,
  377.                         this.openspcoopProperties.getAttachmentsProcessingMode());
  378.             }
  379.             if(pr.getParseException()!=null){
  380.                 this.getPddContext().addObject(org.openspcoop2.core.constants.Costanti.CONTENUTO_RISPOSTA_NON_RICONOSCIUTO_PARSE_EXCEPTION, pr.getParseException());
  381.             }
  382.            
  383.             this.responseMsg = pr.getMessage_throwParseException();
  384.            
  385.             // content length
  386.             if(this.responseMsg!=null){
  387.                 this.contentLength = this.responseMsg.getIncomingMessageContentLength();
  388.             }
  389.            
  390.         }catch(Exception e){
  391.             this.eccezioneProcessamento = e;
  392.             String msgErrore = this.readExceptionMessageFromException(e);
  393.             if(this.generateErrorWithConnectorPrefix) {
  394.                 this.errore = "rilevata anomalia; "+msgErrore;
  395.             }
  396.             else {
  397.                 this.errore = msgErrore;
  398.             }
  399.             this.logger.error("Rilevata anomalia: "+msgErrore,e);
  400.             return false;
  401.         }
  402.        
  403.         return true;
  404.     }
  405.    
  406.     private void setRequestHeader(String key, String value, ConnettoreLogger logger, Map<String, List<String>> propertiesTrasportoDebug) throws Exception {
  407.         List<String> list = new ArrayList<>();
  408.         list.add(value);
  409.         this.setRequestHeader(key, list, logger, propertiesTrasportoDebug);
  410.     }
  411.    
  412.     private void setRequestHeader(String key, List<String> values, ConnettoreLogger logger, Map<String, List<String>> propertiesTrasportoDebug) throws Exception {
  413.        
  414.         if(this.debug && values!=null && !values.isEmpty()) {
  415.             for (String value : values) {
  416.                 logger.info("Set proprietà trasporto ["+key+"]=["+value+"]",false);    
  417.             }
  418.         }
  419.         setRequestHeader(key, values, propertiesTrasportoDebug);
  420.        
  421.     }
  422.     @Override
  423.     protected void setRequestHeader(String key,List<String> values) throws Exception {
  424.         this.propertiesTrasportoRisposta.put(key, values);
  425.     }
  426.    
  427.     /**
  428.      * Ritorna l'informazione su dove il connettore sta spedendo il messaggio
  429.      *
  430.      * @return location di inoltro del messaggio
  431.      */
  432.     @Override
  433.     public String getLocation() throws ConnettoreException {
  434.         return LOCATION;
  435.     }

  436.     @Override
  437.     public void disconnect() throws ConnettoreException {
  438.         try {
  439.             if(this.requestBout!=null) {
  440.                 this.requestBout.clearResources();
  441.             }
  442.         }catch(Exception e) {
  443.             this.logger.error("Release resources failed: "+e.getMessage(), e);
  444.         }
  445.     }
  446. }