MessageSecurityReceiver_wss4j.java

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


package org.openspcoop2.security.message.wss4j;

import java.io.ByteArrayOutputStream;
import java.io.FileNotFoundException;
import java.io.PrintStream;
import java.net.URISyntaxException;
import java.security.KeyStore;
import java.security.Principal;
import java.security.PublicKey;
import java.security.cert.Certificate;
import java.security.cert.X509Certificate;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Properties;

import javax.security.auth.callback.CallbackHandler;
import javax.xml.namespace.QName;
import javax.xml.soap.SOAPMessage;

import org.apache.cxf.binding.soap.SoapMessage;
import org.apache.cxf.message.Attachment;
import org.apache.cxf.message.Exchange;
import org.apache.cxf.message.ExchangeImpl;
import org.apache.cxf.message.MessageImpl;
import org.apache.cxf.ws.security.wss4j.WSS4JInInterceptor;
import org.apache.wss4j.common.crypto.Merlin;
import org.apache.wss4j.common.ext.WSSecurityException;
import org.apache.wss4j.dom.WSConstants;
import org.apache.wss4j.dom.WSDataRef;
import org.apache.wss4j.dom.engine.WSSecurityEngineResult;
import org.apache.wss4j.dom.handler.WSHandlerConstants;
import org.apache.wss4j.dom.handler.WSHandlerResult;
import org.apache.wss4j.dom.message.token.Timestamp;
import org.apache.wss4j.dom.str.STRParser;
import org.openspcoop2.core.constants.Costanti;
import org.openspcoop2.message.MessageUtils;
import org.openspcoop2.message.OpenSPCoop2Message;
import org.openspcoop2.message.OpenSPCoop2SoapMessage;
import org.openspcoop2.message.constants.MessageType;
import org.openspcoop2.message.constants.ServiceBinding;
import org.openspcoop2.message.soap.reference.Reference;
import org.openspcoop2.protocol.sdk.Busta;
import org.openspcoop2.protocol.sdk.constants.CodiceErroreCooperazione;
import org.openspcoop2.protocol.sdk.state.RequestInfo;
import org.openspcoop2.security.SecurityException;
import org.openspcoop2.security.keystore.CRLCertstore;
import org.openspcoop2.security.keystore.KeystoreConstants;
import org.openspcoop2.security.keystore.MerlinTruststore;
import org.openspcoop2.security.keystore.cache.GestoreKeystoreCache;
import org.openspcoop2.security.keystore.cache.GestoreOCSPResource;
import org.openspcoop2.security.keystore.cache.GestoreOCSPValidator;
import org.openspcoop2.security.message.AbstractSOAPMessageSecurityReceiver;
import org.openspcoop2.security.message.MessageSecurityContext;
import org.openspcoop2.security.message.SubErrorCodeSecurity;
import org.openspcoop2.security.message.constants.SecurityConstants;
import org.openspcoop2.security.message.engine.MessageUtilities;
import org.openspcoop2.security.message.engine.WSSUtilities;
import org.openspcoop2.security.message.utils.AttachmentProcessingPart;
import org.openspcoop2.security.message.utils.AttachmentsConfigReaderUtils;
import org.openspcoop2.security.message.utils.EncryptionBean;
import org.openspcoop2.security.message.utils.KeystoreUtils;
import org.openspcoop2.utils.LoggerBuffer;
import org.openspcoop2.utils.Utilities;
import org.openspcoop2.utils.UtilsException;
import org.openspcoop2.utils.certificate.CertificateInfo;
import org.openspcoop2.utils.id.IDUtilities;
import org.openspcoop2.utils.transport.http.IOCSPValidator;



/**
 * Classe per la gestione della WS-Security (WSDoAllReceiver).
 *
 * @author Lorenzo Nardi (nardi@link.it)
 * @author Tommaso Burlon (tommaso.burlon@link.it)
 * @author $Author$
 * @version $Rev$, $Date$
 * 
 */
public class MessageSecurityReceiver_wss4j extends AbstractSOAPMessageSecurityReceiver{


	@Override
	public void process(MessageSecurityContext wssContext,OpenSPCoop2Message messageParam,Busta busta, org.openspcoop2.utils.Map<Object> ctx) throws SecurityException{
		process(wssContext, messageParam, busta,
				false, null, ctx);
	}
	public void process(MessageSecurityContext wssContext,OpenSPCoop2Message messageParam,Busta busta,
			boolean bufferMessage_readOnly, String idTransazione, org.openspcoop2.utils.Map<Object> ctx) throws SecurityException{
		boolean certError = false;
		boolean ocspError = false;
		try{
			
			if(ServiceBinding.SOAP.equals(messageParam.getServiceBinding())==false){
				throw new SecurityException("WSS4J Engine usable only with SOAP Binding");
			}
			OpenSPCoop2SoapMessage message = messageParam.castAsSoap();
			SOAPMessage soapMessage = MessageUtils.getSOAPMessage(message, bufferMessage_readOnly, idTransazione);
			
    		RequestInfo requestInfo = null;
    		if(ctx!=null && ctx.containsKey(Costanti.REQUEST_INFO)) {
    			requestInfo = (RequestInfo) ctx.get(Costanti.REQUEST_INFO);
    		}
			
			
			// ** Inizializzo handler CXF **/
			
			WSS4JInInterceptor inHandler = new WSS4JInInterceptor();
			SoapMessage msgCtx = new SoapMessage(new MessageImpl());
			msgCtx.setVersion(MessageType.SOAP_12.equals(message.getMessageType()) ? org.apache.cxf.binding.soap.Soap12.getInstance() : org.apache.cxf.binding.soap.Soap11.getInstance());
			Exchange ex = new ExchangeImpl();
	        ex.setInMessage(msgCtx);
			msgCtx.setContent(SOAPMessage.class, soapMessage);
	        setIncomingProperties(wssContext,inHandler,msgCtx,requestInfo,ctx);
	        
	        
	        // ** Registro attachments da trattare **/
	        
	        AttachmentProcessingPart app = AttachmentsConfigReaderUtils.getSecurityOnAttachments(wssContext);
	        List<Attachment> listAttachments = null;
	        if(app!=null){
	        	// Non è possibile effettuare il controllo della posizione puntuale sulla ricezione. 
	        	// Può essere usato solo per specificare quale attach firmare/cifrare in spedizione
	        	// Alcune implementazioni modificano l'ordine degli attachments una volta applicata la sicurezza
	        	if(app.isAllAttachments()==false){
	        		List<String> cidAttachmentsForSecurity = AttachmentsConfigReaderUtils.getListCIDAttachmentsForSecurity(wssContext);
	        		listAttachments = org.openspcoop2.security.message.wss4j.WSSUtilities.readAttachments(cidAttachmentsForSecurity, message, msgCtx);
	        	}
	        	else{
	        		listAttachments = org.openspcoop2.security.message.wss4j.WSSUtilities.readAttachments(app, message, msgCtx);
	        	}
	        	if(listAttachments!=null && listAttachments.size()>0){
	        		msgCtx.setAttachments(listAttachments);
	        	}
	        }
	        
	        
	        // ** Applico sicurezza tramite CXF **/
	        
			inHandler.handleMessage(msgCtx);
			List<?> results = (List<?>) msgCtx.getContextualProperty(WSHandlerConstants.RECV_RESULTS);
			wssContext.getLog().debug("Print wssRecever results...");
			org.openspcoop2.security.message.wss4j.WSSUtilities.printWSResult(wssContext.getLog(), results);
			
			
			// ** Riporto modifica degli attachments **/
			
			org.openspcoop2.security.message.wss4j.WSSUtilities.updateAttachments(listAttachments, message, msgCtx);
			
			
			// ** Lettura Subject Certificato e informazioni relative al processamento effettuato **/
			
			boolean validateX509 = this.examineResults(msgCtx, wssContext.getActor());
			
			
			// ** Validazione CRL se non effettuata dall'handler (indicazione arriva dal metodo examineResults) **
			
			if(validateX509) {
				if(this.x509Certificate!=null && this.crlX509!=null) {
					try {
						CertificateInfo certificatoInfo = new CertificateInfo(this.x509Certificate, "x509");
						certificatoInfo.checkValid(this.crlX509.getCertStore(), this.trustStore);
					}catch(Throwable e) {
						certError = true;
						throw new Exception(e.getMessage(),e);
					}
				}	
			}
			
			// ** Lettura Subject Certificato e informazioni relative al processamento effettuato **/
			
			if(this.ocspValidator!=null) {
				X509Certificate cert = this.x509Certificate;
				if(cert==null && this.x509Certificates!=null && this.x509Certificates.length>0) {
					cert = this.x509Certificates[0];
				}
				if(cert!=null) {
					try {
						this.ocspValidator.valid(cert);
					}catch(Throwable e) {
						ocspError = true;
						throw e;
					}
				}
			}			
			
		} catch (Throwable e) {
			
			SecurityException wssException = null;
			
			
			/* **** MESSAGGIO ***** */
			String msg = Utilities.getInnerNotEmptyMessageException(e).getMessage();
			
			Throwable innerExc = Utilities.getLastInnerException(e);
			String innerMsg = null;
			if(innerExc!=null){
				innerMsg = innerExc.getMessage();
			}
			
			String messaggio = null;
			if(msg!=null){
				messaggio = new String(msg);
				if(innerMsg!=null && !innerMsg.equals(msg)){
					messaggio = messaggio + " ; " + innerMsg;
				}
			}
			else{
				if(innerMsg!=null){
					messaggio = innerMsg;
				}
			}
			
			// L'if scopre l'eventuale motivo preciso riguardo al fallimento della cifratura/firma.
			if(Utilities.existsInnerException(e, WSSecurityException.class)){
				Throwable t = Utilities.getLastInnerException(e);
				if(t instanceof WSSecurityException){
					if(messaggio!=null){
						messaggio = messaggio + " ; " + t.getMessage();
					}
					else{
						messaggio = t.getMessage();
					}
				}
			}
			
			wssException = new SecurityException(messaggio, e);
			wssException.setMsgErrore(messaggio);
			
			
			/* ***** CODICE **** */
			
			boolean signature = false;
			boolean encrypt = false;
			try{
				ByteArrayOutputStream bout = new ByteArrayOutputStream();
				PrintStream printStream = new PrintStream(bout);
				e.printStackTrace(printStream);
				bout.flush();
				printStream.flush();
				bout.close();
				printStream.close();
				
				if(certError) {
					signature = true; // per adesso avviene solo con SAML
				}
				else if(ocspError) {
					signature = true;
				}
				else if(bout.toString().contains(".processor.SignatureProcessor")){
					signature = true;
				}
				else if(bout.toString().contains(".processor.SignatureConfirmationProcessor")){
					signature = true;
				}
				else if(bout.toString().contains(".processor.EncryptedKeyProcessor")){
					encrypt = true;
				}
				else if(bout.toString().contains(".processor.EncryptedDataProcessor")){
					encrypt = true;
				}
				
			}catch(Exception eClose){}
			
			if(signature){
				wssException.setCodiceErrore(CodiceErroreCooperazione.SICUREZZA_FIRMA_NON_VALIDA);
			}
			else if(encrypt){
				wssException.setCodiceErrore(CodiceErroreCooperazione.SICUREZZA_CIFRATURA_NON_VALIDA);
			}
			else if(Utilities.existsInnerMessageException(e, "The signature or decryption was invalid", true)){
				wssException.setCodiceErrore(CodiceErroreCooperazione.SICUREZZA_FIRMA_NON_VALIDA);
			} else {
				wssException.setCodiceErrore(CodiceErroreCooperazione.SICUREZZA);
			}
			
			
			throw wssException;
		}

	}

	private Timestamp timestamp;
	public Timestamp getTimestamp() {
		return this.timestamp;
	}
	
	private List<WSDataRef> signatureRefs;
	public List<WSDataRef> getSignatureRefs() {
		return this.signatureRefs;
	}

	private List<WSDataRef> encryptionRefs;
	public List<WSDataRef> getEncryptionRefs() {
		return this.encryptionRefs;
	}
	
	private String certificate;
	private STRParser.REFERENCE_TYPE x509ReferenceType;
	private X509Certificate x509Certificate;
	private X509Certificate [] x509Certificates;
	private PublicKey publicKey;
	@Override
	public String getCertificate() throws SecurityException{
		return this.certificate;
	}
	public STRParser.REFERENCE_TYPE getX509ReferenceType() {
		return this.x509ReferenceType;
	}
	@Override
	public X509Certificate getX509Certificate() throws SecurityException {
		return this.x509Certificate;
	}
	public X509Certificate[] getX509Certificates() {
		return this.x509Certificates;
	}
	@Override
	public PublicKey getPublicKey() {
		return this.publicKey;
	}
	@Override
	public String getCertificateId() throws SecurityException{
		return null;
	}

	private IOCSPValidator ocspValidator;
	private org.openspcoop2.utils.certificate.KeyStore trustStore = null;
	private CRLCertstore crlX509 = null;
	private void setIncomingProperties(MessageSecurityContext wssContext,WSS4JInInterceptor interceptor, SoapMessage msgCtx, RequestInfo requestInfo,
			org.openspcoop2.utils.Map<Object> ctx) throws SecurityException {
		Map<String,Object> wssIncomingProperties =  wssContext.getIncomingProperties();
		String ocspPolicy = null;
		String crls = null;
		Properties pTrustStore = null;
		boolean samlSigned = false;
		if (wssIncomingProperties != null && wssIncomingProperties.size() > 0) {
			
			// preprocess per multipropfile
			try {
				preprocessMultipropFile(wssContext, msgCtx, wssIncomingProperties, requestInfo, ctx);
			}catch(Exception e) {
				throw new SecurityException(e.getMessage(),e);
			}
			
			for (String key : wssIncomingProperties.keySet()) {
				Object oValue = wssIncomingProperties.get(key);
				String value = null;
				if(oValue!=null && oValue instanceof String) {
					value = (String) oValue;
				}
				if(SecurityConstants.ACTION.equals(key)) {
					msgCtx.put(key, value);
					interceptor.setProperty(key, value);
					if(value!=null && value.contains(SecurityConstants.ACTION_SAML_TOKEN_SIGNED)) {
						samlSigned = true;
					}
				}
				else if(SecurityConstants.PASSWORD_CALLBACK_REF.equals(key)) {
					msgCtx.put(key, oValue);
				}
				else if(SecurityConstants.SIGNATURE_PROPERTY_REF_ID.equals(key) || 
						SecurityConstants.SIGNATURE_VERIFICATION_PROPERTY_REF_ID.equals(key) || 
						SecurityConstants.SIGNATURE_TRUSTSTORE_PROPERTY_REF_ID.equals(key) || 
						SecurityConstants.ENCRYPTION_PROPERTY_REF_ID.equals(key) || 
						SecurityConstants.DECRYPTION_PROPERTY_REF_ID.equals(key) ) {
					if(value!=null) {
						msgCtx.put(key, value);
					}
					else { 
						String id = key+"_"+IDUtilities.getUniqueSerialNumber("wssSecurity.setIncomingProperties");
						msgCtx.put(key, id);
						msgCtx.put(id, oValue);
						if(oValue!=null && oValue instanceof Properties) {
							Properties p = (Properties) oValue;
							p.put(KeystoreConstants.PROPERTY_REQUEST_INFO, requestInfo);
							if(SecurityConstants.SIGNATURE_PROPERTY_REF_ID.equals(key) || 
									SecurityConstants.SIGNATURE_VERIFICATION_PROPERTY_REF_ID.equals(key) || 
									SecurityConstants.SIGNATURE_TRUSTSTORE_PROPERTY_REF_ID.equals(key) ) {
								pTrustStore = p;
							}
						}
					}
				}
				else if(SecurityConstants.ENCRYPT_ACTION_OLD.equals(key)) {
					// backward compatibility per adeguamento costante rispetto a wss4j 2.3.x
					msgCtx.put(SecurityConstants.ENCRYPTION_ACTION, value);
					interceptor.setProperty(SecurityConstants.ENCRYPTION_ACTION, value);
				}
				else if(SecurityConstants.SIGNATURE_OCSP.equals(key)) {
					ocspPolicy = value;
				}
				else if(SecurityConstants.SIGNATURE_CRL.equals(key)) {
					crls = value;
				}
				else{
					msgCtx.put(key, value);
					interceptor.setProperty(key, value);
				}
			}
		}
		if(wssContext.getActor()!=null){
			interceptor.setProperty(SecurityConstants.ACTOR, wssContext.getActor());
			msgCtx.put(SecurityConstants.ACTOR, wssContext.getActor());
		}
		
		String prefixTrustStore = null;
		if(pTrustStore!=null && !pTrustStore.isEmpty()) {
			String trustStoreLocation = null;
			try {
				//
				// Load the TrustStore (serve ad avere x509 in alcuni casi durante l'esamina della risposta)
				//
				prefixTrustStore = org.openspcoop2.security.keystore.MerlinProvider.readPrefix(pTrustStore);
				
				trustStoreLocation = pTrustStore.getProperty(prefixTrustStore + Merlin.TRUSTSTORE_FILE);
				String trustStorePassword = null;
				String trustStoreType = null;
				if (trustStoreLocation == null) {
					trustStoreLocation = pTrustStore.getProperty(prefixTrustStore + Merlin.KEYSTORE_FILE);
					if (trustStoreLocation == null) {
						trustStoreLocation = pTrustStore.getProperty(prefixTrustStore + Merlin.OLD_KEYSTORE_FILE);
					}
					if (trustStoreLocation != null) {
						trustStorePassword = pTrustStore.getProperty(prefixTrustStore + Merlin.KEYSTORE_PASSWORD);
						if (trustStorePassword != null) {
							trustStorePassword = trustStorePassword.trim();
						}
						trustStoreType = pTrustStore.getProperty(prefixTrustStore + Merlin.KEYSTORE_TYPE, KeyStore.getDefaultType());
						if (trustStoreType != null) {
							trustStoreType = trustStoreType.trim();
						}
					}
				}
				else {
					trustStorePassword = pTrustStore.getProperty(prefixTrustStore + Merlin.TRUSTSTORE_PASSWORD);
					if (trustStorePassword != null) {
						trustStorePassword = trustStorePassword.trim();
					}
					trustStoreType = pTrustStore.getProperty(prefixTrustStore + Merlin.TRUSTSTORE_TYPE, KeyStore.getDefaultType());
					if (trustStoreType != null) {
						trustStoreType = trustStoreType.trim();
					}
				}
				if (trustStoreLocation != null) {
					trustStoreLocation = trustStoreLocation.trim();
					MerlinTruststore merlinTs = GestoreKeystoreCache.getMerlinTruststore(requestInfo, trustStoreLocation, trustStoreType, 
							trustStorePassword);
					if(merlinTs==null) {
						throw new Exception("Accesso al truststore '"+trustStoreLocation+"' non riuscito");
					}
					if(merlinTs.getTrustStore()==null) {
						throw new Exception("Accesso al truststore '"+trustStoreLocation+"' non riuscito");
					}
					this.trustStore = merlinTs.getTrustStore();
				}
			}catch(Exception e) {
				throw new SecurityException("[Truststore-File] '"+trustStoreLocation+"': "+e.getMessage(),e);
			}
		}
		
		boolean crlByOcsp = false;
		if(ocspPolicy!=null&& !"".equals(ocspPolicy)) {
			
			if(this.trustStore!=null) {
				LoggerBuffer lb = new LoggerBuffer();
				lb.setLogDebug(wssContext.getLog());
				lb.setLogError(wssContext.getLog());
				GestoreOCSPResource ocspResourceReader = new GestoreOCSPResource(requestInfo);
				IOCSPValidator ocspValidator = null;
				try {
					ocspValidator = new GestoreOCSPValidator(requestInfo, lb, 
							this.trustStore,
							crls, 
							ocspPolicy, 
							ocspResourceReader);
				}catch(Exception e){
					throw new SecurityException("SignatureVerifier; ocsp initialization (policy:'"+ocspPolicy+"') failed: "+e.getMessage(),e);
				}
				if(ocspValidator!=null) {
					this.ocspValidator = ocspValidator;
					GestoreOCSPValidator gOcspValidator = (GestoreOCSPValidator) ocspValidator;
					if(gOcspValidator.getOcspConfig()!=null) {
						crlByOcsp = gOcspValidator.getOcspConfig().isCrl();
					}
				}
			}
			
			if(crlByOcsp) {
				// la validazione crl viene fatta tramite tool ocsp
				msgCtx.put(SecurityConstants.ENABLE_REVOCATION, SecurityConstants.FALSE);
				interceptor.setProperty(SecurityConstants.ENABLE_REVOCATION, SecurityConstants.FALSE);
			}
		}
		
		if(samlSigned && !crlByOcsp && this.trustStore!=null && pTrustStore!=null) {
			String trustStoreCRLs = null;
			try {
				trustStoreCRLs = pTrustStore.getProperty(prefixTrustStore + Merlin.X509_CRL_FILE);
				if(trustStoreCRLs!=null) {
					trustStoreCRLs = trustStoreCRLs.trim();
					this.crlX509 = GestoreKeystoreCache.getCRLCertstore(requestInfo, trustStoreCRLs);
				}
			}catch(Exception e) {
				throw new SecurityException("[Truststore-CRLs] '"+trustStoreCRLs+"': "+e.getMessage(),e);
			}
		}
    }

	private void preprocessMultipropFile(MessageSecurityContext wssContext,SoapMessage msgCtx,Map<String,Object> wssIncomingProperties, RequestInfo requestInfo,org.openspcoop2.utils.Map<Object> ctx) throws FileNotFoundException, UtilsException, SecurityException, URISyntaxException {

		Properties pTrustStoreSignatureVerification = null;
		
		String signatureCrls = null;
		for (Map.Entry<String,Object> entry : wssIncomingProperties.entrySet()) {
	    	if(SecurityConstants.SIGNATURE_CRL.equals(entry.getKey())) {
	    		signatureCrls = (String) entry.getValue();
	    		break;
	    	}
		}
		String signatureCrlsValidateOnlyEndEntity = null;
		if(signatureCrls!=null) {
			for (Map.Entry<String,Object> entry : wssIncomingProperties.entrySet()) {
				if(SecurityConstants.SIGNATURE_CRL_VALIDATE_ONLY_END_ENTITY.equals(entry.getKey())) {
					signatureCrlsValidateOnlyEndEntity = (String) entry.getValue();
		    		break;
		    	}
			}
		}
		
		String forceDecryptionUser = null;
		
		for (Map.Entry<String,Object> entry : wssIncomingProperties.entrySet()) {
			String key = entry.getKey();
	    	if(SecurityConstants.SIGNATURE_TRUSTSTORE_PROPERTY_FILE.equals(key)) {
	    		Object o = wssIncomingProperties.get(key);
	    		if(o instanceof String) {
	    			String path = (String) o;
	    			MerlinTruststore merlinTruststore = GestoreKeystoreCache.getMerlinTruststore(requestInfo, path);
	    			
	    			pTrustStoreSignatureVerification = new Properties();
	    			pTrustStoreSignatureVerification.put(KeystoreConstants.PROPERTY_TRUSTSTORE_PATH, merlinTruststore.getPathStore());
	    			pTrustStoreSignatureVerification.put(KeystoreConstants.PROPERTY_TRUSTSTORE_PASSWORD, merlinTruststore.getPasswordStore());
	    			pTrustStoreSignatureVerification.put(KeystoreConstants.PROPERTY_TRUSTSTORE_TYPE, merlinTruststore.getTipoStore());
	    			pTrustStoreSignatureVerification.put(KeystoreConstants.PROPERTY_PROVIDER, KeystoreConstants.PROVIDER_GOVWAY);
	    			if(signatureCrls!=null) {
	    				pTrustStoreSignatureVerification.put(KeystoreConstants.PROPERTY_CRL, signatureCrls);
	    				if(signatureCrlsValidateOnlyEndEntity!=null) {
	    					pTrustStoreSignatureVerification.put(KeystoreConstants.PROPERTY_CRL_VALIDATE_ONLY_END_ENTITY, signatureCrlsValidateOnlyEndEntity);
	    				}
	    			}
	    		}
			}
			else if(SecurityConstants.DECRYPTION_MULTI_PROPERTY_FILE.equals(key)) {
				EncryptionBean bean = KeystoreUtils.getReceiverEncryptionBean(wssContext, ctx);
				if(bean.getMultiKeystore()==null) {
					throw new SecurityException("Multiproperty config not exists");
				}
				String keyAlias = bean.getUser();
				String internalAlias = bean.getMultiKeystore().getInternalConfigAlias(keyAlias);
				Properties p = new Properties();
				p.put(KeystoreConstants.PROPERTY_KEYSTORE_PATH, bean.getMultiKeystore().getKeystorePath(internalAlias));
				p.put(KeystoreConstants.PROPERTY_KEYSTORE_PASSWORD, bean.getMultiKeystore().getKeystorePassword(internalAlias));
				p.put(KeystoreConstants.PROPERTY_KEYSTORE_TYPE, bean.getMultiKeystore().getKeystoreType(internalAlias));
				p.put(KeystoreConstants.PROPERTY_PROVIDER, KeystoreConstants.PROVIDER_GOVWAY);
				p.put(KeystoreConstants.PROPERTY_REQUEST_INFO, requestInfo);
				String id = SecurityConstants.DECRYPTION_PROPERTY_REF_ID +"_"+IDUtilities.getUniqueSerialNumber("wssSecurity.setOutgoingProperties");
				msgCtx.put(SecurityConstants.DECRYPTION_PROPERTY_REF_ID , id);
				msgCtx.put(id, p);
				
				HashMap<String, String> mapAliasToPassword = new HashMap<>();
				String password = bean.getPassword();
				msgCtx.put(SecurityConstants.DECRYPTION_PASSWORD, bean.getPassword());
				mapAliasToPassword.put(keyAlias, password);
				CallbackHandler pwCallbackHandler = MessageSecurityContext.newCallbackHandler(mapAliasToPassword);
				msgCtx.put(SecurityConstants.PASSWORD_CALLBACK_REF, pwCallbackHandler);
				
				forceDecryptionUser = keyAlias;
			}
    	}
		
		if(pTrustStoreSignatureVerification!=null) {
			wssIncomingProperties.put(SecurityConstants.SIGNATURE_VERIFICATION_PROPERTY_REF_ID, pTrustStoreSignatureVerification);
			if(signatureCrls!=null) {
				wssIncomingProperties.put(SecurityConstants.ENABLE_REVOCATION, SecurityConstants.TRUE);
			}
		}
		
    	if(forceDecryptionUser!=null) {
    		wssIncomingProperties.remove(SecurityConstants.DECRYPTION_USER);
    		wssIncomingProperties.put(SecurityConstants.DECRYPTION_USER, forceDecryptionUser);
    	}
    	
	}
	
	private boolean examineResults(SoapMessage msgCtx, String actor) {
				
		boolean validateX509 = false;
		
		List<?> results = (List<?>) msgCtx.get(WSHandlerConstants.RECV_RESULTS);
		//System.out.println("Potential number of usernames: " + results.size());
		for (int i = 0; results != null && i < results.size(); i++) {
			//System.out.println("RESULT["+i+"]: "+results.get(i).getClass().getName());
			WSHandlerResult hResult = (WSHandlerResult)results.get(i);
			//System.out.println("RESULT["+i+"] actor: "+hResult.getActor());
			
			boolean actorCompatibile = false;
			if(actor==null) {
				actorCompatibile = hResult.getActor()==null;
			}
			else {
				actorCompatibile = actor.equals(hResult.getActor());
			}
			
			if(actorCompatibile) {
				
				//System.out.println("RESULT["+i+"] ESAMINO SENZA ["+actor+"]");
				
				List<WSSecurityEngineResult> hResults = hResult.getResults();
				for (int j = 0; j < hResults.size(); j++) {
					WSSecurityEngineResult eResult = hResults.get(j);
					
					/*
					Iterator<String> resultIt = eResult.keySet().iterator();
					while (resultIt.hasNext()) {
						String resultItKey = (String) resultIt.next();
						Object resultItObject = eResult.get(resultItKey);
						System.out.println("RESULT-INTERNAL ["+i+"]["+j+"] ["+resultItKey+"]["+resultItObject+"]["+(resultItObject!=null ? resultItObject.getClass().getName() : "n.d.")+"]");
					}*/
					
					int actionGet = ((java.lang.Integer)  eResult.get(WSSecurityEngineResult.TAG_ACTION)).intValue();
					
					// An encryption or timestamp action does not have an associated principal,
					// only Signature and UsernameToken actions return a principal
					if ((actionGet == WSConstants.SIGN) || 
							(actionGet == WSConstants.UT) || 
							(actionGet == WSConstants.UT_SIGN) || 
							(actionGet == WSConstants.ST_SIGNED)) {
						
						Object oPrincipal = eResult.get(WSSecurityEngineResult.TAG_PRINCIPAL);
						if(oPrincipal!=null && oPrincipal instanceof Principal) {
							Principal principal =  (Principal) oPrincipal;
							if(principal!=null) {
								this.certificate = principal.getName();
							}
							if(oPrincipal instanceof org.apache.wss4j.common.principal.SAMLTokenPrincipalImpl) {
								org.apache.wss4j.common.principal.SAMLTokenPrincipalImpl samlPrincipal = (org.apache.wss4j.common.principal.SAMLTokenPrincipalImpl) oPrincipal;
								if(samlPrincipal.getToken()!=null) {
									if(samlPrincipal.getToken().getSignatureKeyInfo()!=null) {
										if(samlPrincipal.getToken().getSignatureKeyInfo().getCerts()!=null) {
											if(this.x509Certificates==null) {
												this.x509Certificates = samlPrincipal.getToken().getSignatureKeyInfo().getCerts();
											}
										}
										else if(samlPrincipal.getToken().getSignatureKeyInfo().getPublicKey()!=null) {
											if(this.x509Certificate==null && this.trustStore!=null) {
												try {
													Certificate c = this.trustStore.getCertificateByPublicKey(samlPrincipal.getToken().getSignatureKeyInfo().getPublicKey());
													if(c!=null && (c instanceof X509Certificate)) {
														this.x509Certificate = (X509Certificate) c;
														validateX509 = true; // in saml handler non viene validato il certificato rispetto alla crl
													}
												}catch(Throwable t) {
													// ignore
												}
											}
										}
									}
								}
							}
						}
	
						Object oX509Certificate = eResult.get(WSSecurityEngineResult.TAG_X509_CERTIFICATE);
						if(oX509Certificate!=null && oX509Certificate instanceof X509Certificate) {
							this.x509Certificate = (X509Certificate) oX509Certificate;
							if(this.x509Certificate!=null) {
								this.publicKey = this.x509Certificate.getPublicKey();
							}
						}
							
						Object oListX509Certificates = eResult.get(WSSecurityEngineResult.TAG_X509_CERTIFICATES);
						if(oListX509Certificates!=null && oListX509Certificates instanceof X509Certificate []){
							this.x509Certificates = (X509Certificate []) oListX509Certificates;
							
							/*
							if(this.x509Certificates!=null && this.x509Certificates.length>0) {
								System.out.println("CERTS: "+this.x509Certificates.length);
								int index = 0;
								for (X509Certificate X509Certificate : this.x509Certificates) {
									System.out.println("CERT["+index+"]: "+X509Certificate.getSubjectX500Principal().toString());	
									index ++;
								}
							}
							*/
							
						}
						
						Object oX509ReferenceType = eResult.get(WSSecurityEngineResult.TAG_X509_REFERENCE_TYPE);
						if(oX509ReferenceType!=null && oX509ReferenceType instanceof STRParser.REFERENCE_TYPE) {
							this.x509ReferenceType = (STRParser.REFERENCE_TYPE) oX509ReferenceType;
							
							//System.out.println("REFERENCE TYPE: "+this.x509ReferenceType);
						}
						
						Object oSignatureRefs = eResult.get(WSSecurityEngineResult.TAG_DATA_REF_URIS);
						if(oSignatureRefs!=null && oSignatureRefs instanceof List<?>) {
							List<WSDataRef> l = new ArrayList<WSDataRef>();
							List<?> lRefs = (List<?>) oSignatureRefs;
							for (Object oRef : lRefs) {
								if(oRef!=null && oRef instanceof WSDataRef) {
									l.add((WSDataRef)oRef);
								}
							}
							if(!l.isEmpty()) {
								this.signatureRefs = l;
							}
						}
					}
					
					if( actionGet == WSConstants.ENCR ) {
						
						Object oEncryptionRefs = eResult.get(WSSecurityEngineResult.TAG_DATA_REF_URIS);
						if(oEncryptionRefs!=null && oEncryptionRefs instanceof List<?>) {
							List<WSDataRef> l = new ArrayList<WSDataRef>();
							List<?> lRefs = (List<?>) oEncryptionRefs;
							for (Object oRef : lRefs) {
								if(oRef!=null && oRef instanceof WSDataRef) {
									l.add((WSDataRef)oRef);
								}
							}
							if(!l.isEmpty()) {
								this.encryptionRefs = l;
							}
						}
						
					}
					
					if( actionGet == WSConstants.TS ) {
						
						Object oTimestamp = eResult.get(WSSecurityEngineResult.TAG_TIMESTAMP);
						if(oTimestamp!=null && oTimestamp instanceof Timestamp) {
							this.timestamp =  (Timestamp) oTimestamp;
						}
						
					}
					
					if( actionGet == WSConstants.ST_SIGNED ) {
						
					}
					
				}
				
			}

		}

		/*
		String key = "org.apache.cxf.headers.Header.list";
		if(msgCtx.containsKey(key)) {
			Object o = msgCtx.get(key);
			if(o instanceof List<?> ) {
				List<?> l = (List<?>) o;
				System.out.println("SIZE ["+l.size()+"]");
				if(!l.isEmpty()) {
					int index = 0;
					for (Object entry : l) {
						if(entry!=null) {
							System.out.println("ENTRY ["+index+"]: "+entry.getClass().getName());
							if(entry instanceof org.apache.cxf.binding.soap.SoapHeader) {
								org.apache.cxf.binding.soap.SoapHeader soapHdr = (org.apache.cxf.binding.soap.SoapHeader) entry;
								System.out.println("HDR ("+soapHdr.getActor()+") ("+soapHdr.getObject().getClass().getName()+"): "+soapHdr.getName());
							}
							
						}
						index++;
					}
				}
			}
		}
		*/
		
		return validateX509;
	}
	

	@Override
	public List<Reference> getDirtyElements(
			org.openspcoop2.security.message.MessageSecurityContext messageSecurityContext,
			OpenSPCoop2SoapMessage message) throws SecurityException {
		return WSSUtilities.getDirtyElements(messageSecurityContext, message);
	}

	@Override
	public Map<QName, QName> checkEncryptSignatureParts(
			org.openspcoop2.security.message.MessageSecurityContext messageSecurityContext,
			List<Reference> elementsToClean, OpenSPCoop2SoapMessage message,
			List<SubErrorCodeSecurity> codiciErrore) throws SecurityException {
		return MessageUtilities.checkEncryptSignatureParts(messageSecurityContext, elementsToClean, message, codiciErrore, SecurityConstants.QNAME_WSS_ELEMENT_SECURITY);
	}

	@Override
	public void checkEncryptionPartElements(Map<QName, QName> notResolved,
			OpenSPCoop2SoapMessage message,
			List<SubErrorCodeSecurity> erroriRilevati) throws SecurityException {
		MessageUtilities.checkEncryptionPartElements(notResolved, message, erroriRilevati);
	}

	@Override
	public void cleanDirtyElements(
			org.openspcoop2.security.message.MessageSecurityContext messageSecurityContext,
			OpenSPCoop2SoapMessage message, List<Reference> elementsToClean,
			boolean detachHeaderWSSecurity, boolean removeAllIdRef)
			throws SecurityException {
		WSSUtilities.cleanDirtyElements(messageSecurityContext, message, elementsToClean,detachHeaderWSSecurity,removeAllIdRef);
		
	}
}