MessageSecuritySender_jose.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.jose;


  21. import java.util.Map;
  22. import java.util.Properties;

  23. import org.openspcoop2.core.commons.DBUtils;
  24. import org.openspcoop2.core.constants.Costanti;
  25. import org.openspcoop2.generic_project.exception.NotFoundException;
  26. import org.openspcoop2.message.OpenSPCoop2Message;
  27. import org.openspcoop2.message.OpenSPCoop2RestJsonMessage;
  28. import org.openspcoop2.message.constants.MessageType;
  29. import org.openspcoop2.message.constants.ServiceBinding;
  30. import org.openspcoop2.protocol.sdk.state.RequestInfo;
  31. import org.openspcoop2.security.SecurityException;
  32. import org.openspcoop2.security.message.AbstractRESTMessageSecuritySender;
  33. import org.openspcoop2.security.message.MessageSecurityContext;
  34. import org.openspcoop2.security.message.constants.SecurityConstants;
  35. import org.openspcoop2.security.message.utils.EncryptionBean;
  36. import org.openspcoop2.security.message.utils.KeystoreUtils;
  37. import org.openspcoop2.security.message.utils.PropertiesUtils;
  38. import org.openspcoop2.security.message.utils.SignatureBean;
  39. import org.openspcoop2.utils.Utilities;
  40. import org.openspcoop2.utils.certificate.JWKSet;
  41. import org.openspcoop2.utils.certificate.KeyStore;
  42. import org.openspcoop2.utils.certificate.KeystoreType;
  43. import org.openspcoop2.utils.security.JOSESerialization;
  44. import org.openspcoop2.utils.security.JWEOptions;
  45. import org.openspcoop2.utils.security.JWSOptions;
  46. import org.openspcoop2.utils.security.JsonEncrypt;
  47. import org.openspcoop2.utils.security.JsonSignature;
  48. import org.openspcoop2.utils.security.JwtHeaders;

  49. /**
  50.  * MessageSecuritySender_jose
  51.  *
  52.  * @author Andrea Poli (apoli@link.it)
  53.  * @author $Author$
  54.  * @version $Rev$, $Date$
  55.  */

  56. public class MessageSecuritySender_jose extends AbstractRESTMessageSecuritySender{

  57.    
  58.      @Override
  59.     public void process(MessageSecurityContext messageSecurityContext,OpenSPCoop2Message messageParam, org.openspcoop2.utils.Map<Object> ctx) throws SecurityException{
  60.         try{    
  61.            
  62.             if(ServiceBinding.REST.equals(messageParam.getServiceBinding())==false){
  63.                 throw new SecurityException(JOSECostanti.JOSE_ENGINE_DESCRIPTION+" usable only with REST Binding");
  64.             }
  65.             if(MessageType.JSON.equals(messageParam.getMessageType())==false) {
  66.                 throw new SecurityException(JOSECostanti.JOSE_ENGINE_DESCRIPTION+" usable only with REST Binding and a json message, found: "+messageParam.getMessageType());
  67.             }
  68.             OpenSPCoop2RestJsonMessage restJsonMessage = messageParam.castAsRestJson();
  69.            
  70.             RequestInfo requestInfo = null;
  71.             if(ctx!=null && ctx.containsKey(Costanti.REQUEST_INFO)) {
  72.                 requestInfo = (RequestInfo) ctx.get(Costanti.REQUEST_INFO);
  73.             }
  74.            
  75.            
  76.            
  77.             // ********** Leggo operazioni ***************
  78.             boolean encrypt = false;
  79.             boolean signature = false;

  80.             String[]actions = ((String)messageSecurityContext.getOutgoingProperties().get(SecurityConstants.ACTION)).split(" ");
  81.             for (int i = 0; i < actions.length; i++) {
  82.                 if(SecurityConstants.isActionEncryption(actions[i].trim())){
  83.                     encrypt = true;
  84.                 }
  85.                 else if(SecurityConstants.SIGNATURE_ACTION.equals(actions[i].trim())){
  86.                     signature = true;
  87.                 }
  88.                 else {
  89.                     throw new SecurityException(JOSECostanti.JOSE_ENGINE_DESCRIPTION+"; action '"+actions[i]+"' unsupported");
  90.                 }
  91.             }
  92.            
  93.             if(encrypt && signature) {
  94.                 throw new SecurityException(JOSECostanti.JOSE_ENGINE_DESCRIPTION+" usable only with one function beetwen encrypt or signature");
  95.             }
  96.             if(!encrypt && !signature) {
  97.                 throw new SecurityException(JOSECostanti.JOSE_ENGINE_DESCRIPTION+" require one function beetwen encrypt or signature");
  98.             }
  99.            

  100.            
  101.            
  102.             if(signature) {
  103.                
  104.                
  105.                 // **************** Leggo parametri signature store **************************

  106.                 JOSESerialization joseSerialization = null;
  107.                 String mode = (String) messageSecurityContext.getOutgoingProperties().get(SecurityConstants.SIGNATURE_MODE);
  108.                 if(mode==null || "".equals(mode.trim())){
  109.                     throw new SecurityException(JOSECostanti.JOSE_ENGINE_SIGNATURE_DESCRIPTION+" require '"+SecurityConstants.SIGNATURE_MODE+"' property");
  110.                 }
  111.                 try {
  112.                     joseSerialization = JOSEUtils.toJOSESerialization(mode);
  113.                 }catch(Exception e) {
  114.                     throw new SecurityException(JOSECostanti.JOSE_ENGINE_SIGNATURE_DESCRIPTION+", '"+SecurityConstants.SIGNATURE_MODE+"' property error: "+e.getMessage(),e);
  115.                 }
  116.                 JWSOptions jwsOptions = new JWSOptions(joseSerialization);
  117.                
  118.                 String signatureDetachedParam = (String) messageSecurityContext.getOutgoingProperties().get(SecurityConstants.SIGNATURE_DETACHED);
  119.                 if(signatureDetachedParam!=null) {
  120.                     jwsOptions.setDetached(SecurityConstants.SIGNATURE_DETACHED_TRUE.equalsIgnoreCase(signatureDetachedParam));
  121.                 }
  122.                
  123.                 String signaturePayloadEncodingParam = (String) messageSecurityContext.getOutgoingProperties().get(SecurityConstants.SIGNATURE_PAYLOAD_ENCODING);
  124.                 if(signaturePayloadEncodingParam!=null) {
  125.                     jwsOptions.setPayloadEncoding(SecurityConstants.SIGNATURE_PAYLOAD_ENCODING_TRUE.equalsIgnoreCase(signaturePayloadEncodingParam));
  126.                 }
  127.                                
  128.                 JsonSignature jsonSignature = null;
  129.                 SignatureBean bean = null;
  130.                 NotFoundException notFound = null;
  131.                 try {
  132.                     bean = PropertiesUtils.getSenderSignatureBean(messageSecurityContext);
  133.                 }catch(NotFoundException e) {
  134.                     notFound = e;
  135.                 }
  136.                 if(bean!=null) {
  137.                     Properties signatureProperties = bean.getProperties();
  138.                     boolean throwError = true;
  139.                     Map<String,Object> dynamicMap = Costanti.readDynamicMap(ctx);
  140.                     JOSEUtils.injectKeystore(requestInfo, dynamicMap, signatureProperties, messageSecurityContext.getLog(), throwError); // serve per leggere il keystore dalla cache
  141.                     JwtHeaders jwtHeaders = JOSEUtils.getJwtHeaders(messageSecurityContext.getOutgoingProperties(), messageParam); // la configurazione per kid, jwk e x5c viene configurata via properties
  142.                     jsonSignature = new JsonSignature(signatureProperties, jwtHeaders, jwsOptions);
  143.                 }
  144.                 else {  
  145.                     KeyStore signatureKS = null;
  146.                     //KeyStore signatureTrustStoreKS = null;
  147.                     JWKSet signatureJWKSet = null;
  148.                     String aliasSignatureUser = null;
  149.                     String aliasSignaturePassword = null;
  150.                     try {
  151.                         bean = KeystoreUtils.getSenderSignatureBean(messageSecurityContext, ctx);
  152.                     }catch(Exception e) {
  153.                         // Lancio come messaggio eccezione precedente
  154.                         if(notFound!=null) {
  155.                             messageSecurityContext.getLog().error(e.getMessage(),e);
  156.                             throw notFound;
  157.                         }
  158.                         else {
  159.                             throw e;
  160.                         }
  161.                     }
  162.                    
  163.                     signatureKS = bean.getKeystore();
  164.                     //signatureTrustStoreKS = bean.getTruststore();
  165.                     signatureJWKSet = bean.getJwkSet();
  166.                     aliasSignatureUser = bean.getUser();
  167.                     aliasSignaturePassword = bean.getPassword();

  168.                     if(signatureKS==null && signatureJWKSet==null) {
  169.                         throw new SecurityException(JOSECostanti.JOSE_ENGINE_SIGNATURE_DESCRIPTION+" require keystore");
  170.                     }
  171.                     if(aliasSignatureUser==null) {
  172.                         throw new SecurityException(JOSECostanti.JOSE_ENGINE_SIGNATURE_DESCRIPTION+" require alias private key");
  173.                     }
  174.                     if(signatureKS!=null && aliasSignaturePassword==null) {
  175.                         boolean required = true;
  176.                         if(KeystoreType.JKS.isType(signatureKS.getKeystoreType())) {
  177.                             required = DBUtils.isKeystoreJksKeyPasswordRequired();
  178.                         }
  179.                         else if(KeystoreType.PKCS12.isType(signatureKS.getKeystoreType())) {
  180.                             required = DBUtils.isKeystorePkcs12KeyPasswordRequired();
  181.                         }
  182.                         if(required) {
  183.                             throw new SecurityException(JOSECostanti.JOSE_ENGINE_SIGNATURE_DESCRIPTION+" require password private key");
  184.                         }
  185.                     }
  186.                    
  187.                     String signatureAlgorithm = (String) messageSecurityContext.getOutgoingProperties().get(SecurityConstants.SIGNATURE_ALGORITHM);
  188.                     if(signatureAlgorithm==null || "".equals(signatureAlgorithm.trim())){
  189.                         throw new SecurityException(JOSECostanti.JOSE_ENGINE_SIGNATURE_DESCRIPTION+" require '"+SecurityConstants.SIGNATURE_ALGORITHM+"' property");
  190.                     }
  191.                    
  192.                     String symmetricKeyParam = (String) messageSecurityContext.getOutgoingProperties().get(SecurityConstants.SYMMETRIC_KEY);
  193.                     boolean symmetricKey = false;
  194.                     if(symmetricKeyParam!=null) {
  195.                         symmetricKey = SecurityConstants.SYMMETRIC_KEY_TRUE.equalsIgnoreCase(symmetricKeyParam);
  196.                     }
  197.                    
  198.                     if(signatureKS!=null) {
  199.                         JwtHeaders jwtHeaders = JOSEUtils.getJwtHeaders(messageSecurityContext.getOutgoingProperties(), messageParam, aliasSignatureUser, signatureKS);
  200.                         jsonSignature = new JsonSignature(signatureKS, symmetricKey, aliasSignatureUser, aliasSignaturePassword, signatureAlgorithm, jwtHeaders, jwsOptions);  
  201.                     }
  202.                     else {
  203.                         JwtHeaders jwtHeaders = JOSEUtils.getJwtHeaders(messageSecurityContext.getOutgoingProperties(), messageParam, aliasSignatureUser, signatureJWKSet);
  204.                         jsonSignature = new JsonSignature(signatureJWKSet.getJsonWebKeys(), symmetricKey, aliasSignatureUser, signatureAlgorithm, jwtHeaders, jwsOptions);  
  205.                     }
  206.                 }
  207.                

  208.                
  209.                
  210.                
  211.                
  212.                 // **************** Process **************************
  213.                
  214.                 String contentSign = jsonSignature.sign(restJsonMessage.getContent());
  215.                 if(jwsOptions.isDetached()) {
  216.                     this.setDetachedSignatureInMessage(messageSecurityContext.getOutgoingProperties(),
  217.                             restJsonMessage,
  218.                             JOSECostanti.JOSE_ENGINE_SIGNATURE_DESCRIPTION,
  219.                             contentSign);
  220.                 }else {
  221.                     restJsonMessage.updateContent(contentSign);
  222.                 }
  223.                
  224.                
  225.                
  226.             } // fine signature
  227.            
  228.            
  229.            
  230.            
  231.            
  232.             else if(encrypt){
  233.            
  234.                 // **************** Leggo parametri encryption store **************************
  235.                
  236.                 JOSESerialization joseSerialization = null;
  237.                 String mode = (String) messageSecurityContext.getOutgoingProperties().get(SecurityConstants.ENCRYPTION_MODE);
  238.                 if(mode==null || "".equals(mode.trim())){
  239.                     throw new SecurityException(JOSECostanti.JOSE_ENGINE_ENCRYPT_DESCRIPTION+" require '"+SecurityConstants.ENCRYPTION_MODE+"' property");
  240.                 }
  241.                 try {
  242.                     joseSerialization = JOSEUtils.toJOSESerialization(mode);
  243.                 }catch(Exception e) {
  244.                     throw new SecurityException(JOSECostanti.JOSE_ENGINE_ENCRYPT_DESCRIPTION+", '"+SecurityConstants.ENCRYPTION_MODE+"' property error: "+e.getMessage(),e);
  245.                 }
  246.                 JWEOptions jweOptions = new JWEOptions(joseSerialization);
  247.                
  248.                 String encryptionDeflateParam = (String) messageSecurityContext.getOutgoingProperties().get(SecurityConstants.ENCRYPTION_DEFLATE);
  249.                 if(encryptionDeflateParam!=null) {
  250.                     jweOptions.setDeflate(SecurityConstants.ENCRYPTION_DEFLATE_TRUE.equalsIgnoreCase(encryptionDeflateParam));
  251.                 }
  252.                
  253.                 JsonEncrypt jsonEncrypt = null;
  254.                 EncryptionBean bean = null;
  255.                 NotFoundException notFound = null;
  256.                 try {
  257.                     bean = PropertiesUtils.getSenderEncryptionBean(messageSecurityContext);
  258.                 }catch(NotFoundException e) {
  259.                     notFound = e;
  260.                 }
  261.                 if(bean!=null) {
  262.                     Properties encryptionProperties = bean.getProperties();
  263.                     boolean throwError = true;
  264.                     Map<String,Object> dynamicMap = Costanti.readDynamicMap(ctx);
  265.                     JOSEUtils.injectKeystore(requestInfo, dynamicMap, encryptionProperties, messageSecurityContext.getLog(), throwError); // serve per leggere il keystore dalla cache
  266.                     JwtHeaders jwtHeaders = JOSEUtils.getJwtHeaders(messageSecurityContext.getOutgoingProperties(), messageParam); // la configurazione per kid, jwk e x5c viene configurata via properties
  267.                     jsonEncrypt = new JsonEncrypt(encryptionProperties, jwtHeaders, jweOptions);
  268.                 }
  269.                 else {  
  270.                     KeyStore encryptionKS = null;
  271.                     KeyStore encryptionTrustStoreKS = null;
  272.                     boolean encryptionSymmetric = false;
  273.                     JWKSet encryptionJWKSet = null;
  274.                     String aliasEncryptUser = null;
  275.                     String aliasEncryptPassword = null;
  276.                     try {
  277.                         bean = KeystoreUtils.getSenderEncryptionBean(messageSecurityContext, ctx);
  278.                     }catch(Exception e) {
  279.                         // Lancio come messaggio eccezione precedente
  280.                         if(notFound!=null) {
  281.                             messageSecurityContext.getLog().error(e.getMessage(),e);
  282.                             throw notFound;
  283.                         }
  284.                         else {
  285.                             throw e;
  286.                         }
  287.                     }
  288.                    
  289.                     encryptionKS = bean.getKeystore();
  290.                     encryptionTrustStoreKS = bean.getTruststore();
  291.                     encryptionSymmetric = bean.isEncryptionSimmetric();
  292.                     encryptionJWKSet = bean.getJwkSet();
  293.                     aliasEncryptUser = bean.getUser();
  294.                     aliasEncryptPassword = bean.getPassword();

  295.                     if(encryptionSymmetric) {
  296.                         if(encryptionKS==null) {
  297.                             throw new SecurityException(JOSECostanti.JOSE_ENGINE_ENCRYPT_DESCRIPTION+" require keystore");
  298.                         }
  299.                         if(aliasEncryptUser==null) {
  300.                             throw new SecurityException(JOSECostanti.JOSE_ENGINE_ENCRYPT_DESCRIPTION+" require alias secret key");
  301.                         }
  302.                         if(aliasEncryptPassword==null) {
  303.                             throw new SecurityException(JOSECostanti.JOSE_ENGINE_ENCRYPT_DESCRIPTION+" require password secret key");
  304.                         }
  305.                     }
  306.                     else {
  307.                         if(encryptionTrustStoreKS==null && encryptionJWKSet==null) {
  308.                             throw new SecurityException(JOSECostanti.JOSE_ENGINE_ENCRYPT_DESCRIPTION+" require truststore");
  309.                         }
  310.                         if(aliasEncryptUser==null) {
  311.                             throw new SecurityException(JOSECostanti.JOSE_ENGINE_ENCRYPT_DESCRIPTION+" require alias public key");
  312.                         }
  313.                     }

  314.                    
  315.                     String encryptionKeyAlgorithm = (String) messageSecurityContext.getOutgoingProperties().get(SecurityConstants.ENCRYPTION_KEY_ALGORITHM);
  316.                     if(encryptionKeyAlgorithm==null || "".equals(encryptionKeyAlgorithm.trim())){
  317.                         throw new SecurityException(JOSECostanti.JOSE_ENGINE_ENCRYPT_DESCRIPTION+" require '"+SecurityConstants.ENCRYPTION_KEY_ALGORITHM+"' property");
  318.                     }
  319.                    
  320.                     String encryptionContentAlgorithm = (String) messageSecurityContext.getOutgoingProperties().get(SecurityConstants.ENCRYPTION_CONTENT_ALGORITHM);
  321.                     if(encryptionContentAlgorithm==null || "".equals(encryptionContentAlgorithm.trim())){
  322.                         throw new SecurityException(JOSECostanti.JOSE_ENGINE_ENCRYPT_DESCRIPTION+" require '"+SecurityConstants.ENCRYPTION_CONTENT_ALGORITHM+"' property");
  323.                     }

  324.                     if(encryptionSymmetric) {
  325.                         JwtHeaders jwtHeaders = JOSEUtils.getJwtHeaders(messageSecurityContext.getOutgoingProperties(), messageParam, aliasEncryptUser);
  326.                         jsonEncrypt = new JsonEncrypt(encryptionKS, aliasEncryptUser, aliasEncryptPassword, encryptionKeyAlgorithm, encryptionContentAlgorithm,  jwtHeaders, jweOptions);
  327.                     }else {
  328.                         if(encryptionTrustStoreKS!=null) {
  329.                             JwtHeaders jwtHeaders = JOSEUtils.getJwtHeaders(messageSecurityContext.getOutgoingProperties(), messageParam, aliasEncryptUser, encryptionTrustStoreKS);
  330.                             jsonEncrypt = new JsonEncrypt(encryptionTrustStoreKS, aliasEncryptUser, encryptionKeyAlgorithm, encryptionContentAlgorithm, jwtHeaders, jweOptions);
  331.                         }
  332.                         else {
  333.                             JwtHeaders jwtHeaders = JOSEUtils.getJwtHeaders(messageSecurityContext.getOutgoingProperties(), messageParam, aliasEncryptUser, encryptionJWKSet);
  334.                             jsonEncrypt = new JsonEncrypt(encryptionJWKSet.getJsonWebKeys(), encryptionSymmetric, aliasEncryptUser, encryptionKeyAlgorithm, encryptionContentAlgorithm, jwtHeaders, jweOptions);
  335.                         }
  336.                     }
  337.                 }
  338.        

  339.                
  340.                
  341.                 // **************** Process **************************
  342.                
  343.                 String contentEncrypted = jsonEncrypt.encrypt(restJsonMessage.getContent());
  344.                 restJsonMessage.updateContent(contentEncrypted);
  345.                

  346.             } // fine encrypt


  347.         }
  348.         catch(Exception e){
  349.            
  350.             String msg = Utilities.getInnerNotEmptyMessageException(e).getMessage();
  351.            
  352.             Throwable innerExc = Utilities.getLastInnerException(e);
  353.             String innerMsg = null;
  354.             if(innerExc!=null){
  355.                 innerMsg = innerExc.getMessage();
  356.             }
  357.            
  358.             String messaggio = null;
  359.             if(msg!=null){
  360.                 messaggio = new String(msg);
  361.                 if(innerMsg!=null && !innerMsg.equals(msg)){
  362.                     messaggio = messaggio + " ; " + innerMsg;
  363.                 }
  364.             }
  365.             else{
  366.                 if(innerMsg!=null){
  367.                     messaggio = innerMsg;
  368.                 }
  369.             }
  370.            
  371.             SecurityException wssException = new SecurityException(e.getMessage(), e);
  372.             wssException.setMsgErrore(messaggio);
  373.             throw wssException;
  374.         }
  375.        
  376.     }

  377.  
  378. }