MessageSecurityReceiver_impl.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.security.message.engine;

  21. import java.util.ArrayList;
  22. import java.util.Iterator;
  23. import java.util.List;
  24. import java.util.Map;

  25. import javax.xml.namespace.QName;
  26. import javax.xml.soap.SOAPElement;
  27. import javax.xml.soap.SOAPHeaderElement;

  28. import org.openspcoop2.message.OpenSPCoop2Message;
  29. import org.openspcoop2.message.constants.ServiceBinding;
  30. import org.openspcoop2.message.soap.reference.Reference;
  31. import org.openspcoop2.protocol.sdk.Busta;
  32. import org.openspcoop2.protocol.sdk.constants.CodiceErroreCooperazione;
  33. import org.openspcoop2.security.SecurityException;
  34. import org.openspcoop2.security.message.IMessageSecurityReceiver;
  35. import org.openspcoop2.security.message.MessageSecurityContext;
  36. import org.openspcoop2.security.message.MessageSecurityUtilities;
  37. import org.openspcoop2.security.message.SubErrorCodeSecurity;
  38. import org.openspcoop2.security.message.authorization.IMessageSecurityAuthorization;
  39. import org.openspcoop2.security.message.authorization.MessageSecurityAuthorizationRequest;
  40. import org.openspcoop2.security.message.authorization.MessageSecurityAuthorizationResult;
  41. import org.openspcoop2.security.message.constants.SecurityConstants;
  42. import org.openspcoop2.security.message.saml.SAMLBuilderConfigConstants;



  43. /**
  44.  * Classe per la gestione della Sicurezza  (role:Receiver)
  45.  *
  46.  * @author Lorenzo Nardi (nardi@link.it)
  47.  * @author $Author$
  48.  * @version $Rev$, $Date$
  49.  *
  50.  */
  51. public class MessageSecurityReceiver_impl extends MessageSecurityReceiver{


  52.     protected MessageSecurityReceiver_impl(MessageSecurityContext messageSecurityContext) {
  53.         super(messageSecurityContext);
  54.     }

  55.     @Override
  56.     protected boolean process(OpenSPCoop2Message message,Busta busta, org.openspcoop2.utils.Map<Object> ctx) {
  57.         try{
  58.            
  59.            
  60.             IMessageSecurityReceiver receiverInterface = this.messageSecurityContext.getMessageSecurityReceiver();
  61.            
  62.            
  63.            
  64.            
  65.             // ** Fix per SOAPFault (quando ci sono le encryptionParts o le signatureParts, la Sicurezza fallisce se c'e' un SOAPFault) **
  66.             if(ServiceBinding.SOAP.equals(message.getServiceBinding())){
  67.                 if(message.isFault() || message.castAsSoap().getSOAPBody().hasFault()){
  68.                    
  69.                     if(MessageSecurityUtilities.processSOAPFault(this.messageSecurityContext.getIncomingProperties()) == false){
  70.                         return true; // non devo applicare la sicurezza.
  71.                     }
  72.                    
  73.                 }  
  74.             }
  75.             else if(ServiceBinding.REST.equals(message.getServiceBinding())){
  76.                 if(message.isFault() || message.castAsRest().isProblemDetailsForHttpApis_RFC7807()){
  77.                    
  78.                     if(MessageSecurityUtilities.processProblemDetails(this.messageSecurityContext.getIncomingProperties()) == false){
  79.                         return true; // non devo applicare la sicurezza.
  80.                     }
  81.                    
  82.                 }  
  83.             }
  84.            
  85.             String action = (String) this.messageSecurityContext.getIncomingProperties().get(SecurityConstants.ACTION);
  86.             if(action==null || "".equals(action.trim())){
  87.                 return true; // nessuna action: non devo applicare la sicurezza.
  88.             }
  89.            
  90.            
  91.            
  92.            
  93.             // ** Inizializzazione parametri **
  94.            
  95.             // Authentication class from properties
  96.             String authClass = (String) this.messageSecurityContext.getIncomingProperties().get(SecurityConstants.AUTHORIZATION_CLASS);
  97.             // MustUnderstand from properties
  98. //          boolean mustUnderstandValue = false;
  99. //          Object mustUnderstand = this.messageSecurityContext.getIncomingProperties().get(SecurityConstants.MUST_UNDERSTAND);
  100. //          if(mustUnderstand!=null){
  101. //              mustUnderstandValue = Boolean.parseBoolean((String)mustUnderstand);
  102. //          }
  103.             String actor = this.messageSecurityContext.getActor();
  104.             if("".equals(this.messageSecurityContext.getActor()))
  105.                 actor = null;
  106.            
  107.            
  108.            
  109.            
  110.             // ** Verifico presenza header sicurezza ** /
  111.             if(receiverInterface.checkExistsWSSecurityHeader()) {
  112.                 if(this.messageSecurityContext.existsSecurityHeader(message, actor)==false){
  113.                     this.msgErrore =  "Header Message Security, richiesto dalla configurazione (action:"+action+"), non riscontrato nella SOAPEnvelope ricevuta";
  114.                     if(action.contains(SecurityConstants.ACTION_SIGNATURE)){
  115.                         this.codiceErrore = CodiceErroreCooperazione.SICUREZZA_FIRMA_NON_PRESENTE;
  116.                     }
  117.                     else if(SecurityConstants.containsActionEncryption(action) ||
  118.                             SecurityConstants.containsActionDecryption(action)){
  119.                         this.codiceErrore = CodiceErroreCooperazione.SICUREZZA_CIFRATURA_NON_PRESENTE;
  120.                     }
  121.                     else{
  122.                         this.codiceErrore = CodiceErroreCooperazione.SICUREZZA_NON_PRESENTE;
  123.                     }
  124.                     return false;
  125.                 }
  126.                
  127.                 // se e' richiesta la verifica SAML la faccio.
  128.                 if(action.contains(SecurityConstants.ACTION_SAML_TOKEN_SIGNED) || action.contains(SecurityConstants.ACTION_SAML_TOKEN_UNSIGNED)) {
  129.                     String samlVersion = (String) this.messageSecurityContext.getIncomingProperties().get(SecurityConstants.SAML_VERSION_XMLCONFIG_ID);
  130.                     if(samlVersion!=null && !"".equals(samlVersion)) {
  131.                        
  132.                         SOAPHeaderElement securityHeader = this.messageSecurityContext.getSecurityHeader(message, actor); // verificato prima
  133.                         SOAPElement samlToken = this.messageSecurityContext.getSAMLTokenInSecurityHeader(message.getFactory(), securityHeader, samlVersion);
  134.                         if(samlToken==null) {
  135.                             this.msgErrore =  "SAMLToken (versione:"+samlVersion+"), richiesto dalla configurazione (action:"+action+"), non riscontrato nell'header Message Security presente all'interno della SOAPEnvelope ricevuta";
  136.                             this.codiceErrore = CodiceErroreCooperazione.SICUREZZA_TOKEN_NON_PRESENTE;
  137.                             return false;
  138.                         }
  139.                        
  140.                         String samlConfirmationType = (String) this.messageSecurityContext.getIncomingProperties().get(SecurityConstants.SAML_SUBJECT_CONFIRMATION_VALIDATION_METHOD_XMLCONFIG_ID);
  141.                         if(samlConfirmationType!=null && !"".equals(samlConfirmationType)) {
  142.                             String confirmationMethod = this.messageSecurityContext.getSAMLTokenSubjectConfirmationMethodInSecurityHeader(message.getFactory(), samlToken, samlVersion);
  143.                             if(confirmationMethod==null) {
  144.                                 this.msgErrore =  "SAMLToken (versione:"+samlVersion+"), richiesto dalla configurazione (action:"+action+"), non possiede un metodo di subject confirmation";
  145.                                 this.codiceErrore = CodiceErroreCooperazione.SICUREZZA_TOKEN_NON_VALIDO;
  146.                                 return false;
  147.                             }
  148.                            
  149.                             String atteso = null;
  150.                             if(SecurityConstants.SAML_SUBJECT_CONFIRMATION_VALIDATION_METHOD_XMLCONFIG_ID_HOLDER_OF_KEY.equals(samlConfirmationType)) {
  151.                                 atteso = SecurityConstants.SAML_VERSION_XMLCONFIG_ID_VALUE_20.equals(samlVersion) ?
  152.                                         SAMLBuilderConfigConstants.SAML_CONFIG_BUILDER_SUBJECT_CONFIRMATION_METHOD_HOLDER_OF_KEY_SAML_20 :
  153.                                             SAMLBuilderConfigConstants.SAML_CONFIG_BUILDER_SUBJECT_CONFIRMATION_METHOD_HOLDER_OF_KEY_SAML_10;
  154.                             }
  155.                             else if(SecurityConstants.SAML_SUBJECT_CONFIRMATION_VALIDATION_METHOD_XMLCONFIG_ID_SENDER_VOUCHES.equals(samlConfirmationType)) {
  156.                                 atteso = SecurityConstants.SAML_VERSION_XMLCONFIG_ID_VALUE_20.equals(samlVersion) ?
  157.                                         SAMLBuilderConfigConstants.SAML_CONFIG_BUILDER_SUBJECT_CONFIRMATION_METHOD_SENDER_VOUCHES_SAML_20 :
  158.                                             SAMLBuilderConfigConstants.SAML_CONFIG_BUILDER_SUBJECT_CONFIRMATION_METHOD_SENDER_VOUCHES_SAML_10;
  159.                             }
  160.                             if(atteso!=null) {
  161.                                 if(atteso.equals(confirmationMethod)==false) {
  162.                                     this.msgErrore =  "SAMLToken (versione:"+samlVersion+"), richiesto dalla configurazione (action:"+action+"), possiede un metodo di subject confirmation ("+confirmationMethod+") diverso da quello atteso ("+atteso+")";
  163.                                     this.codiceErrore = CodiceErroreCooperazione.SICUREZZA_TOKEN_NON_VALIDO;
  164.                                     return false;
  165.                                 }
  166.                             }
  167.                         }
  168.                        
  169.                     }
  170.                 }
  171.             }
  172.            
  173.            
  174.            
  175.            
  176.             // ** Raccolgo elementi "toccati" da Security per pulirli ** /
  177.             List<Reference> elementsToClean = null;
  178.             if(ServiceBinding.SOAP.equals(message.getServiceBinding())){
  179.                 elementsToClean = receiverInterface.getDirtyElements(this.messageSecurityContext, message.castAsSoap());
  180.             }
  181.            
  182.            
  183.            
  184.            
  185.             // ** Verifica cifratura/firma elementi richiesti dalla configurazione ** /
  186.             List<SubErrorCodeSecurity> listaErroriRiscontrati = new ArrayList<SubErrorCodeSecurity>();
  187.             Map<QName, QName> notResolved = null;
  188.             if(ServiceBinding.SOAP.equals(message.getServiceBinding())){
  189.                 notResolved = receiverInterface.checkEncryptSignatureParts(this.messageSecurityContext,elementsToClean, message.castAsSoap(),listaErroriRiscontrati);
  190.             }
  191.             if(listaErroriRiscontrati.size()>0){
  192.                 StringBuilder bf = new StringBuilder();
  193.                 for (Iterator<?> iterator = listaErroriRiscontrati.iterator(); iterator.hasNext();) {
  194.                     SubErrorCodeSecurity subCodiceErroreSicurezza = (SubErrorCodeSecurity) iterator.next();
  195.                     if(bf.length()>0){
  196.                         bf.append(" ; ");
  197.                     }
  198.                     bf.append(subCodiceErroreSicurezza.getMsgErrore());
  199.                 }
  200.                 this.messageSecurityContext.getLog().error(bf.toString());
  201.                 this.msgErrore =  bf.toString();
  202.                 this.codiceErrore = CodiceErroreCooperazione.SICUREZZA_NON_PRESENTE;
  203.                 this.listaSubCodiceErrore.addAll(listaErroriRiscontrati);
  204.                 return false;
  205.             }
  206.            
  207.            
  208.            
  209.            
  210.             // ** Applico sicurezza tramite engine **/
  211.             receiverInterface.process(this.messageSecurityContext, message, busta, ctx);
  212.            
  213.            
  214.            
  215.            
  216.            
  217.             // ** Verifica elementi cifrati come element, possibile solo dopo la decifratura ** //
  218.             List<SubErrorCodeSecurity> listaErroriInElementi = new ArrayList<SubErrorCodeSecurity>();
  219.             if(ServiceBinding.SOAP.equals(message.getServiceBinding())){
  220.                 receiverInterface.checkEncryptionPartElements(notResolved, message.castAsSoap(), listaErroriInElementi);
  221.             }
  222.             if(listaErroriInElementi.size()>0){
  223.                 StringBuilder bf = new StringBuilder();
  224.                 for (Iterator<?> iterator = listaErroriInElementi.iterator(); iterator.hasNext();) {
  225.                     SubErrorCodeSecurity subCodiceErroreSicurezza = (SubErrorCodeSecurity) iterator.next();
  226.                     if(bf.length()>0){
  227.                         bf.append(" ; ");
  228.                     }
  229.                     bf.append(subCodiceErroreSicurezza.getMsgErrore());
  230.                 }
  231.                 this.messageSecurityContext.getLog().error(bf.toString());
  232.                 this.msgErrore =  bf.toString();
  233.                 this.codiceErrore = CodiceErroreCooperazione.SICUREZZA_NON_PRESENTE;
  234.                 this.listaSubCodiceErrore.addAll(listaErroriInElementi);
  235.                 return false;
  236.             }
  237.            
  238.            
  239.            
  240.            
  241.             // ** Lettura Subject Certificato **/
  242.             try{
  243.                 this.subject=receiverInterface.getCertificate();
  244.             }catch(Exception e){
  245.                 this.messageSecurityContext.getLog().error("GetPrincipal Message-Security(Receiver) error: "+e.getMessage(),e);
  246.             }

  247.            
  248.            
  249.            
  250.             // ** Autorizzazione Message Security **/
  251.             if (authClass != null) {
  252.                 try {
  253.                     IMessageSecurityAuthorization auth = (IMessageSecurityAuthorization)org.openspcoop2.utils.resources.Loader.getInstance().newInstance(authClass);
  254.                     MessageSecurityAuthorizationRequest req = new MessageSecurityAuthorizationRequest();
  255.                     req.setBusta(busta);
  256.                     req.setSecurityPrincipal(this.subject);
  257.                     req.setMessageSecurityContext(this.messageSecurityContext);
  258.                     req.setMessage(message);
  259.                     MessageSecurityAuthorizationResult result = auth.authorize(req);
  260.                     if(!result.isAuthorized()){
  261.                         this.msgErrore =  "Mittente della busta ["+busta.getTipoMittente()+busta.getMittente()+
  262.                                 "] (subject:"+this.subject+") non autorizzato ad invocare il servizio ["+busta.getServizio()+"] erogato dal soggetto ["+busta.getTipoDestinatario()+busta.getDestinatario()+"]";
  263.                         if(result.getErrorMessage()!=null){
  264.                                 this.msgErrore = this.msgErrore + "(" +result.getErrorMessage()+")";
  265.                         }
  266.                         if(result.getException()!=null){
  267.                             this.messageSecurityContext.getLog().error(this.msgErrore,result.getException());
  268.                         }
  269.                         this.codiceErrore = CodiceErroreCooperazione.SICUREZZA_AUTORIZZAZIONE_FALLITA;
  270.                         return false;
  271.                     }
  272.                 }
  273.                 catch (Exception e) {
  274.                     throw new Exception("Errore di Processamento durante l'autorizzazione: " + e.getMessage());
  275.                 }
  276.             }
  277.            
  278.            
  279.            
  280.            
  281.            
  282.             // ** Pulizia elementi "toccati" da MessageSecurity per pulirli ** /
  283.             // NOTA: Clean dipendente dall'implementazione
  284.             try{
  285.                 boolean detachValue = true; // per default l'header WSS viene eliminato
  286.                 Object detach = this.messageSecurityContext.getIncomingProperties().get(SecurityConstants.DETACH_HEADER_WSS); // per backward compatibility
  287.                 if(detach!=null){
  288.                     detachValue = Boolean.parseBoolean((String)detach);
  289.                 }
  290.                 if(detach==null) {
  291.                     detach = this.messageSecurityContext.getIncomingProperties().get(SecurityConstants.DETACH_SECURITY_INFO);
  292.                     if(detach!=null){
  293.                         detachValue = Boolean.parseBoolean((String)detach);
  294.                     }
  295.                 }
  296.                
  297.                 boolean removeAllIdRefValue = this.messageSecurityContext.isRemoveAllWsuIdRef();
  298.                 Object removeAllIdRef = this.messageSecurityContext.getIncomingProperties().get(SecurityConstants.REMOVE_ALL_WSU_ID_REF);
  299.                 if(removeAllIdRef!=null){
  300.                     removeAllIdRefValue = Boolean.parseBoolean((String)removeAllIdRef);
  301.                 }
  302.                
  303.                 if(ServiceBinding.SOAP.equals(message.getServiceBinding())){
  304.                     receiverInterface.cleanDirtyElements(this.messageSecurityContext, message.castAsSoap(), elementsToClean, detachValue, removeAllIdRefValue);
  305.                 }
  306.                 else {
  307.                     if(detachValue) {
  308.                         receiverInterface.detachSecurity(this.messageSecurityContext, message.castAsRest());
  309.                     }
  310.                 }

  311.             } catch (SecurityException e) {
  312.                 this.messageSecurityContext.getLog().error("Errore durante il clean del messaggio: " + e.getMessage(), e);
  313.                 throw new Exception("Errore durante la cleanMessage: " + e.getMessage());
  314.             }
  315.            
  316.            
  317.            
  318.         } catch (Exception e) {
  319.            
  320.             String prefix = "Generatosi errore durante il processamento Message-Security(Receiver): ";
  321.            
  322.             this.messageSecurityContext.getLog().error(prefix+e.getMessage(),e);
  323.            
  324.             this.msgErrore =  prefix+"Generatosi errore durante il processamento Message-Security(Receiver): "+e.getMessage();
  325.             this.codiceErrore = CodiceErroreCooperazione.SICUREZZA;
  326.            
  327.             if(e instanceof SecurityException){
  328.                 SecurityException securityException = (SecurityException) e;
  329.                 if(securityException.getMsgErrore()!=null){
  330.                     this.msgErrore = prefix+securityException.getMsgErrore();
  331.                 }
  332.                 if(securityException.getCodiceErrore()!=null){
  333.                     this.codiceErrore = securityException.getCodiceErrore();
  334.                 }
  335.             }
  336.            
  337.             return false;
  338.         }
  339.         return true;
  340.     }

  341.    
  342. }