AutenticazioneSsl.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.pdd.core.autenticazione.pd;

import java.security.cert.CertStore;
import java.util.List;

import org.openspcoop2.core.commons.CoreException;
import org.openspcoop2.core.config.Proprieta;
import org.openspcoop2.core.id.IDServizioApplicativo;
import org.openspcoop2.core.id.IDSoggetto;
import org.openspcoop2.pdd.config.ConfigurazionePdDManager;
import org.openspcoop2.pdd.config.CostantiProprieta;
import org.openspcoop2.pdd.config.OpenSPCoop2Properties;
import org.openspcoop2.pdd.core.autenticazione.AutenticazioneException;
import org.openspcoop2.pdd.core.autenticazione.WWWAuthenticateConfig;
import org.openspcoop2.pdd.core.credenziali.Credenziali;
import org.openspcoop2.pdd.core.keystore.GestoreKeystoreCaching;
import org.openspcoop2.pdd.logger.OpenSPCoop2Logger;
import org.openspcoop2.protocol.engine.ConfigurazioneFiltroServiziApplicativi;
import org.openspcoop2.protocol.sdk.constants.CodiceErroreIntegrazione;
import org.openspcoop2.protocol.sdk.constants.CostantiProtocollo;
import org.openspcoop2.protocol.sdk.constants.ErroriIntegrazione;
import org.openspcoop2.protocol.sdk.constants.IntegrationFunctionError;
import org.openspcoop2.protocol.sdk.state.RequestInfo;
import org.openspcoop2.security.keystore.cache.GestoreOCSPResource;
import org.openspcoop2.security.keystore.cache.GestoreOCSPValidator;
import org.openspcoop2.utils.LoggerBuffer;
import org.openspcoop2.utils.certificate.CertificateInfo;
import org.openspcoop2.utils.certificate.KeyStore;
import org.openspcoop2.utils.transport.http.IOCSPValidator;
import org.openspcoop2.utils.transport.http.OCSPResponseException;

/**
 * Classe che implementa una autenticazione BASIC.
 *
 * @author Andrea Poli (apoli@link.it)
 * @author $Author$
 * @version $Rev$, $Date$
 */

public class AutenticazioneSsl extends AbstractAutenticazioneBase {

	private boolean logError = true;
	@Override
	public void setLogError(boolean logError) {
		this.logError = logError;
	}
	
    @Override
    public EsitoAutenticazionePortaDelegata process(DatiInvocazionePortaDelegata datiInvocazione) throws AutenticazioneException{

    	EsitoAutenticazionePortaDelegata esito = new EsitoAutenticazionePortaDelegata();
    	
    	OpenSPCoop2Properties op2Properties = OpenSPCoop2Properties.getInstance();
    	WWWAuthenticateConfig wwwAuthenticateConfig = op2Properties.getRealmAutenticazioneHttpsWWWAuthenticateConfig();
    	
    	if(datiInvocazione==null) {
    		throw new AutenticazioneException("Param datiInvocazione is null");
    	}
    	
    	IDSoggetto soggettoFruitore = null;
    	if(datiInvocazione.getPd()!=null) {
    		soggettoFruitore = new IDSoggetto(datiInvocazione.getPd().getTipoSoggettoProprietario(), datiInvocazione.getPd().getNomeSoggettoProprietario());
    	}
    	    	
    	Credenziali credenziali = datiInvocazione.getInfoConnettoreIngresso().getCredenziali();
		
    	String subject = credenziali.getSubject();
    	String issuer = credenziali.getIssuer();
    	CertificateInfo certificate = null;
    	if(credenziali.getCertificate()!=null) {
    		certificate = credenziali.getCertificate().getCertificate();
    	}
    	
    	RequestInfo requestInfo = datiInvocazione.getRequestInfo();
    	
		// Controllo credenziali fornite
    	if( subject==null || "".equals(subject) ){
			esito.setErroreIntegrazione(IntegrationFunctionError.AUTHENTICATION_CREDENTIALS_NOT_FOUND, ErroriIntegrazione.ERRORE_402_AUTENTICAZIONE_FALLITA.getErrore402_AutenticazioneFallitaSsl(CostantiProtocollo.CREDENZIALI_NON_FORNITE,subject));
			esito.setClientAuthenticated(false);
			esito.setClientIdentified(false);
			if(wwwAuthenticateConfig!=null) {
    			esito.setWwwAuthenticateErrorHeader(wwwAuthenticateConfig.buildWWWAuthenticateHeaderValue_notFound());
    		}
			return esito;
		}
    	if(credenziali.getCertificate()!=null) {
    		certificate = credenziali.getCertificate().getCertificate();
    		
    		List<Proprieta> proprieta = null;
    		if(datiInvocazione.getPd()!=null) {
    			proprieta = datiInvocazione.getPd().getProprietaList();
    		}

    		boolean checkValid = false;
    		boolean trustStore = false;
    		KeyStore trustStoreCertificatiX509 = null;
    		CertStore trustStoreCertificatiX509crls = null;
    		IOCSPValidator ocspValidator = null;
    		try {
    			checkValid = CostantiProprieta.isAutenticazioneHttpsValidityCheck(proprieta, op2Properties.isAutenticazioneHttpsPortaDelegataValidityCheck());
    			trustStore = CostantiProprieta.isAutenticazioneHttpsTrustStore(proprieta, op2Properties.getAutenticazioneHttpsPortaDelegataTruststorePath());
    			if(trustStore) {
    				String path = CostantiProprieta.getAutenticazioneHttpsTrustStorePath(proprieta, op2Properties.getAutenticazioneHttpsPortaDelegataTruststorePath());
    				if(path!=null) {
    					try {
    						String password = CostantiProprieta.getAutenticazioneHttpsTrustStorePassword(proprieta, op2Properties.getAutenticazioneHttpsPortaDelegataTruststorePassword());
    						String type = CostantiProprieta.getAutenticazioneHttpsTrustStoreType(proprieta, op2Properties.getAutenticazioneHttpsPortaDelegataTruststoreType());
    	    				trustStoreCertificatiX509 = GestoreKeystoreCaching.getMerlinTruststore(requestInfo, path, 
    	    						type, 
    								password).getTrustStore();
    					}catch(Exception e){
    						throw new CoreException("Errore durante la lettura del truststore indicato ("+path+"): "+e.getMessage());
    					}
    				}
    				
    				if(trustStoreCertificatiX509!=null) {
    					String crl = CostantiProprieta.getAutenticazioneHttpsTrustStoreCRLs(proprieta, op2Properties.getAutenticazioneHttpsPortaDelegataTruststoreCRLs());
    					
						boolean crlByOcsp = false;
						String ocspPolicy = CostantiProprieta.getAutenticazioneHttpsTrustStoreOCSPPolicy(proprieta, op2Properties.getAutenticazioneHttpsPortaDelegataTruststoreOCSPPolicy());
						if(ocspPolicy!=null) {
							LoggerBuffer lb = new LoggerBuffer();
							lb.setLogDebug(OpenSPCoop2Logger.getLoggerOpenSPCoopCore());
							lb.setLogError(OpenSPCoop2Logger.getLoggerOpenSPCoopCore());
							GestoreOCSPResource ocspResourceReader = new GestoreOCSPResource(requestInfo);
							try {
								ocspValidator = new GestoreOCSPValidator(requestInfo, lb, 
										trustStoreCertificatiX509,
										crl, 
										ocspPolicy, 
										ocspResourceReader);
							}catch(Exception e){
								throw new CoreException("Errore durante l'inizializzazione del gestore della policy OCSP ("+ocspPolicy+"): "+e.getMessage());
							}
							if(ocspValidator!=null) {
								GestoreOCSPValidator gOcspValidator = (GestoreOCSPValidator) ocspValidator;
								if(gOcspValidator.getOcspConfig()!=null) {
									crlByOcsp = gOcspValidator.getOcspConfig().isCrl();
								}
							}
						}
						
						if(crl!=null && !crlByOcsp) {
    						try {
    							trustStoreCertificatiX509crls = GestoreKeystoreCaching.getCRLCertstore(requestInfo, crl).getCertStore();
    						}catch(Exception e){
    							throw new CoreException("Errore durante la lettura delle CRLs ("+crl+"): "+e.getMessage());
    						}
    					}
    				}
    			}
    		}catch(Exception e) {
    			if(this.logError) {
        			OpenSPCoop2Logger.getLoggerOpenSPCoopCore().error("AutenticazioneSsl non riuscita",e);
    			}
    			esito.setErroreIntegrazione(IntegrationFunctionError.INTERNAL_REQUEST_ERROR, ErroriIntegrazione.ERRORE_5XX_GENERICO_PROCESSAMENTO_MESSAGGIO.
    					get5XX_ErroreProcessamento(CodiceErroreIntegrazione.CODICE_536_CONFIGURAZIONE_NON_DISPONIBILE));
    			esito.setClientIdentified(false);
    			esito.setEccezioneProcessamento(e);
    			return esito;
    		}
    		
    		if(checkValid 
    				&&
    				trustStoreCertificatiX509crls==null) { // altrimenti la validita' viene verificata insieme alle CRL
	    		try {
	    			certificate.checkValid();
	    		}catch(Exception e) {
	    			esito.setErroreIntegrazione(IntegrationFunctionError.AUTHENTICATION_INVALID_CREDENTIALS, 
	    					ErroriIntegrazione.ERRORE_402_AUTENTICAZIONE_FALLITA.getErrore402_AutenticazioneFallitaSsl(CostantiProtocollo.CREDENZIALI_FORNITE_NON_CORRETTE+": "+e.getMessage(),subject));
	    			esito.setClientAuthenticated(false);
	    			esito.setClientIdentified(false);
	    			if(wwwAuthenticateConfig!=null) {
	    				esito.setWwwAuthenticateErrorHeader(wwwAuthenticateConfig.buildWWWAuthenticateHeaderValue_invalid());
	    			}
	    			return esito;
	    		}
    		}
    		
    		if(trustStoreCertificatiX509!=null) {
	    		try {
		    		if(!certificate.isVerified(trustStoreCertificatiX509, true)) {
						throw new CoreException("Certificato non verificabile rispetto alle CA conosciute");
					}
					if(trustStoreCertificatiX509crls!=null) {
						try {
							certificate.checkValid(trustStoreCertificatiX509crls, trustStoreCertificatiX509);
						}catch(Throwable t) {
							throw new CoreException("Certificato non valido: "+t.getMessage());
						}
					}
	    		}catch(Exception e) {
	    			esito.setErroreIntegrazione(IntegrationFunctionError.AUTHENTICATION_INVALID_CREDENTIALS, 
	    					ErroriIntegrazione.ERRORE_402_AUTENTICAZIONE_FALLITA.getErrore402_AutenticazioneFallitaSsl(CostantiProtocollo.CREDENZIALI_FORNITE_NON_CORRETTE+": "+e.getMessage(),subject));
	    			esito.setClientAuthenticated(false);
	    			esito.setClientIdentified(false);
	    			if(wwwAuthenticateConfig!=null) {
	    				esito.setWwwAuthenticateErrorHeader(wwwAuthenticateConfig.buildWWWAuthenticateHeaderValue_invalid());
	    			}
	    			return esito;
	    		}
    		}
    		
    		if(ocspValidator!=null) {
				try {
					ocspValidator.valid(certificate.getCertificate());
				}catch(Throwable t) {
					esito.setErroreIntegrazione(IntegrationFunctionError.AUTHENTICATION_INVALID_CREDENTIALS, 
	    					ErroriIntegrazione.ERRORE_402_AUTENTICAZIONE_FALLITA.getErrore402_AutenticazioneFallitaSsl(CostantiProtocollo.CREDENZIALI_FORNITE_NON_CORRETTE+": "+t.getMessage(),subject));
	    			esito.setClientAuthenticated(false);
	    			esito.setClientIdentified(false);
	    			if(!(t instanceof OCSPResponseException)) {
	    				esito.setNoCache(true);
	    			}
	    			if(wwwAuthenticateConfig!=null) {
	    				esito.setWwwAuthenticateErrorHeader(wwwAuthenticateConfig.buildWWWAuthenticateHeaderValue_invalid());
	    			}
	    			return esito;
				}
			}

    	}
    	
    	// Essendoci l'identita' del chiamante, il client e' stato autenticato o da un frontend o dall'application server stesso
    	esito.setClientAuthenticated(true);
    	esito.setCredential(subject);
		
    	// Provo a identificare il chiamante rispetto ad una entita' del registro
		IDServizioApplicativo idServizioApplicativo = null;
		try{
			ConfigurazionePdDManager configurazionePdDManager = ConfigurazionePdDManager.getInstance(datiInvocazione.getState());
			
			// NOTA: il fatto di essersi registrati come strict o come non strict รจ insito nella registrazione dell'applicativo
			
			ConfigurazioneFiltroServiziApplicativi filtroHttps = ConfigurazioneFiltroServiziApplicativi.getFiltroApplicativiHttps();
			
			// 1. Prima si cerca per certificato strict
			if(certificate!=null) {
				idServizioApplicativo = configurazionePdDManager.getIdServizioApplicativoByCredenzialiSsl(certificate, true,
						filtroHttps.getTipiSoggetti(), filtroHttps.isIncludiApplicativiNonModI(), filtroHttps.isIncludiApplicativiModIEsterni(), filtroHttps.isIncludiApplicativiModIInterni());
			}
			if(idServizioApplicativo==null &&
				// 2. Poi per certificato no strict
				certificate!=null) {
				idServizioApplicativo = configurazionePdDManager.getIdServizioApplicativoByCredenzialiSsl(certificate, false,
						filtroHttps.getTipiSoggetti(), filtroHttps.isIncludiApplicativiNonModI(), filtroHttps.isIncludiApplicativiModIEsterni(), filtroHttps.isIncludiApplicativiModIInterni());
			}
			if(idServizioApplicativo==null) {
				// 3. per subject/issuer
				idServizioApplicativo = configurazionePdDManager.getIdServizioApplicativoByCredenzialiSsl(subject, issuer,
						filtroHttps.getTipiSoggetti(), filtroHttps.isIncludiApplicativiNonModI(), filtroHttps.isIncludiApplicativiModIEsterni(), filtroHttps.isIncludiApplicativiModIInterni());	
			}
			if(idServizioApplicativo==null) {
				// 4. solo per subject
				idServizioApplicativo = configurazionePdDManager.getIdServizioApplicativoByCredenzialiSsl(subject, null,
						filtroHttps.getTipiSoggetti(), filtroHttps.isIncludiApplicativiNonModI(), filtroHttps.isIncludiApplicativiModIEsterni(), filtroHttps.isIncludiApplicativiModIInterni());	
			}
			
			if(idServizioApplicativo!=null && soggettoFruitore==null) {
				soggettoFruitore = idServizioApplicativo.getIdSoggettoProprietario();
			}
		}catch(Exception e){
			if(this.logError) {
    			OpenSPCoop2Logger.getLoggerOpenSPCoopCore().error("AutenticazioneSsl non riuscita",e);
			}
			esito.setErroreIntegrazione(IntegrationFunctionError.INTERNAL_REQUEST_ERROR, ErroriIntegrazione.ERRORE_5XX_GENERICO_PROCESSAMENTO_MESSAGGIO.
					get5XX_ErroreProcessamento(CodiceErroreIntegrazione.CODICE_536_CONFIGURAZIONE_NON_DISPONIBILE));
			esito.setClientIdentified(false);
			esito.setEccezioneProcessamento(e);
			return esito;
		}
		
		if(idServizioApplicativo == null){
			// L'identificazione in ssl non e' obbligatoria
			/**esito.setErroreIntegrazione(ErroriIntegrazione.ERRORE_402_AUTENTICAZIONE_FALLITA.getErrore402_AutenticazioneFallitaSsl(CostantiProtocollo.CREDENZIALI_FORNITE_NON_CORRETTE,subject));*/
			esito.setClientIdentified(false);
		}
		else {
			if(OpenSPCoop2Properties.getInstance().isAutenticazioneHttpsPortaDelegataCheckSoggettiProprietari() && !idServizioApplicativo.getIdSoggettoProprietario().equals(soggettoFruitore)) {
				esito.setErroreIntegrazione(IntegrationFunctionError.AUTHENTICATION_INVALID_CREDENTIALS, 
						ErroriIntegrazione.ERRORE_402_AUTENTICAZIONE_FALLITA.getErrore402_AutenticazioneFallitaSsl(
								"soggetto proprietario ("+idServizioApplicativo.getIdSoggettoProprietario()+") dell'applicativo identificato ("+idServizioApplicativo.getNome()+") differente dal soggetto proprietario della porta invocata ("+soggettoFruitore+")",subject));
				esito.setClientIdentified(false);
				return esito;
			}
			else {
				esito.setClientIdentified(true);
				esito.setIdServizioApplicativo(idServizioApplicativo);
			}
		}
		
		return esito;
		
    }

}