VaultTools.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.config.vault.cli;

import java.io.File;
import java.io.InputStream;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;

import org.apache.commons.lang.StringUtils;
import org.openspcoop2.core.commons.CoreException;
import org.openspcoop2.core.config.driver.ExtendedInfoManager;
import org.openspcoop2.pdd.core.byok.BYOKMapProperties;
import org.openspcoop2.pdd.core.dynamic.DynamicInfo;
import org.openspcoop2.pdd.core.dynamic.DynamicUtils;
import org.openspcoop2.protocol.engine.ProtocolFactoryManager;
import org.openspcoop2.protocol.sdk.ConfigurazionePdD;
import org.openspcoop2.utils.LoggerWrapperFactory;
import org.openspcoop2.utils.certificate.byok.BYOKManager;
import org.openspcoop2.utils.certificate.hsm.HSMManager;
import org.openspcoop2.utils.certificate.hsm.HSMUtils;
import org.openspcoop2.utils.properties.MapProperties;
import org.openspcoop2.utils.security.ProviderUtils;
import org.slf4j.Logger;

/**
 *  VaultTools
 *
 * @author Poli Andrea (apoli@link.it)
 * @author $Author$
 * @version $Rev$, $Date$
 */
public class VaultTools {

	private static Logger logCore = LoggerWrapperFactory.getLogger(VaultTools.class);
	public static Logger getLogCore() {
		return logCore;
	}
	public static void logCoreDebug(String msg) {
		logCore.debug(msg);
	}
	public static void logCoreInfo(String msg) {
		logCore.info(msg);
	}
	public static void logCoreError(String msg, Exception e) {
		logCore.error(msg,e);
	}
	private static Logger logOutput = LoggerWrapperFactory.getLogger(VaultTools.class);
	public static void logOutput(String msg) {
		logOutput.info(msg);
	}
	
	public static void main(String[] args) throws CoreException {
		
		VaultOperationType opType = null;
		VaultUpdateConfig updateConfig = null;
		VaultEncDecConfig encDecConfig = null;
		String[] argsConfig = null;
		String utilizzoErrato = null;
		try {
		
			// Logger
			initLogger();
			logCore=LoggerWrapperFactory.getLogger("govway_vault.core");	
			logOutput=LoggerWrapperFactory.getLogger("govway_vault.output");	
			
			
			logCoreDebug("Raccolta parametri in corso...");
									
			// args
			utilizzoErrato = "Usage error: VaultTools <operationType> <options>\n"+
					"- <operationType>: "+VaultOperationType.UPDATE_CONFIG.getValue()+","+VaultOperationType.ENCRYPT.getValue()+","+VaultOperationType.DECRYPT.getValue()+"\n"+
					"- <options>: \n"+
					"\t- "+VaultOperationType.UPDATE_CONFIG.getValue()+": "+VaultUpdateConfig.getUsage()+"\n"+
					"\t- "+VaultOperationType.ENCRYPT.getValue()+": "+VaultEncDecConfig.getUsage()+"\n"+
					"\t- "+VaultOperationType.DECRYPT.getValue()+": "+VaultEncDecConfig.getUsage()+"";
			
		}
		catch(Exception t) {
			if(logCore!=null) {
				logCore.error(t.getMessage(),t);
			}
			throw new CoreException(t.getMessage(),t);
		}
			
		if(args.length<1 || args[0]==null) {
			throw new CoreException(utilizzoErrato);
		}
		
		try {
			opType = parseOperationType(utilizzoErrato, args);
			argsConfig = new String[args.length - 1];
	        System.arraycopy(args, 1, argsConfig, 0, args.length - 1);
		}
		catch(Exception t) {
			if(logCore!=null) {
				logCore.error(t.getMessage(),t);
			}
			throw new CoreException(t.getMessage(),t);
		}
		
		switch (opType) {
		case UPDATE_CONFIG:
			utilizzoErrato = "Usage error: update "+VaultUpdateConfig.getUsage();			
			updateConfig = new VaultUpdateConfig(argsConfig, utilizzoErrato);
			break;
		case ENCRYPT:
			utilizzoErrato = "Usage error: encrypt "+VaultEncDecConfig.getUsage();			
			encDecConfig = new VaultEncDecConfig(argsConfig, utilizzoErrato, true);
			break;
		case DECRYPT:
			utilizzoErrato = "Usage error: decrypt "+VaultEncDecConfig.getUsage();			
			encDecConfig = new VaultEncDecConfig(argsConfig, utilizzoErrato, false);
			break;
		}
		
		try {
			process(updateConfig, encDecConfig);
		}
		catch(Exception t) {
			if(logCore!=null) {
				logCore.error(t.getMessage(),t);
			}
			throw new CoreException(t.getMessage(),t);
		}

	}
	
	private static void process(VaultUpdateConfig updateConfig, VaultEncDecConfig encDecConfig) throws CoreException {
		logCoreDebug("Raccolta parametri terminata");
		
		// properties
		VaultProperties vaultProperties = VaultProperties.getInstance();
		/**String confDir = null;*/ // non sembra servire
		String protocolloDefault = vaultProperties.getProtocolloDefault();
		
		// Map (environment)
		initMap(vaultProperties);
		
		// Load Security Provider
		if(vaultProperties.isSecurityLoadBouncyCastleProvider()) {
			initBouncyCastle();
		}
		
		// inizializzo HSM Manager
		initHsm(vaultProperties);
		
		// inizializzo BYOK Manager
		BYOKManager byokManager = initBYOK(vaultProperties);
		
		// Secrets (environment)
		initSecrets(vaultProperties, byokManager);
		
		// Init GovWay
		logCoreDebug("Inizializzazione risorse libreria in corso...");
		
		initProtocolFactory(protocolloDefault);
		
		initExtendedInfoManager();
		
		logCoreDebug("Inizializzazione risorse libreria terminata");
		
		// Validazione configurazioni
		if(updateConfig!=null) {
			
			logCoreInfo("Aggiornamento informazioni sensibili in corso ...");
			
			updateConfig.validate(byokManager);
			VaultUpdateConfigUtilities utils = new VaultUpdateConfigUtilities(updateConfig);
			utils.process();
			
			logCoreInfo("Aggiornamento informazioni sensibili completato");
		}
		else if(encDecConfig!=null) {
			
			String op = encDecConfig.isEncode() ? "Cifratura" : "Decrifratura";
			logCoreInfo(op+" in corso ...");
			
			encDecConfig.validate(byokManager);
			VaultEncDecUtilities utils = new VaultEncDecUtilities(encDecConfig);
			utils.process();
			
			logCoreInfo(op+" completata");
		}
	}

	private static void initLogger() throws CoreException {
		Properties propertiesLog4j = new Properties();
		try (InputStream inPropLog4j = VaultTools.class.getResourceAsStream("/govway_vault.cli.log4j2.properties");){
			propertiesLog4j.load(inPropLog4j);
			LoggerWrapperFactory.setLogConfiguration(propertiesLog4j);
		} catch(java.lang.Exception e) {
			throw new CoreException("Impossibile leggere i dati dal file 'govway_vault.cli.log4j2.properties': "+e.getMessage());
		} 
	}
	private static VaultOperationType parseOperationType(String utilizzoErrato,String [] args) throws CoreException{
		VaultOperationType opType = null;
		try {
			opType = VaultOperationType.toEnumConstant(args[0].trim(), true);
		}catch(Exception e) {
			throw new CoreException(utilizzoErrato+"\nIl tipo di operazione indicato ("+args[0].trim()+") non รจ gestito, valori ammessi: "+
					VaultOperationType.UPDATE_CONFIG.getValue()+","+VaultOperationType.ENCRYPT.getValue()+","+VaultOperationType.DECRYPT.getValue());
		}
		return opType;
	}
	private static void initBouncyCastle() throws CoreException {
		try{
			ProviderUtils.addBouncyCastleAfterSun(true);
			logCoreInfo("Aggiunto Security Provider org.bouncycastle.jce.provider.BouncyCastleProvider");
		}catch(Exception e){
			throw new CoreException(e.getMessage(),e);
		}
	}
	private static void initMap(VaultProperties loaderProperties) throws CoreException {
		try {
			String mapConfig = loaderProperties.getEnvMapConfig();
			if(StringUtils.isNotEmpty(mapConfig)) {
				logCoreInfo("Inizializzazione environment in corso...");
				MapProperties.initialize(logCore, mapConfig, loaderProperties.isEnvMapConfigRequired());
				MapProperties mapProperties = MapProperties.getInstance();
				mapProperties.initEnvironment();
				String msgInit = "Environment inizializzato con le variabili definite nel file '"+mapConfig+"'"+
						"\n\tJavaProperties: "+mapProperties.getJavaMap().keys()+
						"\n\tEnvProperties: "+mapProperties.getEnvMap().keys()+
						"\n\tObfuscateMode: "+mapProperties.getObfuscateModeDescription()+
						"\n\tObfuscatedJavaKeys: "+mapProperties.getObfuscatedJavaKeys()+
						"\n\tObfuscatedEnvKeys: "+mapProperties.getObfuscatedEnvKeys();
				logCoreInfo(msgInit);
			}
		} catch (Exception e) {
			doError("Errore durante l'inizializzazione dell'ambiente",e);
		}
	}
	private static void initHsm(VaultProperties loaderProperties) throws CoreException {
		// inizializzo HSM Manager
		try {
			String hsmConfig = loaderProperties.getHSMConfigurazione();
			if(StringUtils.isNotEmpty(hsmConfig)) {
				logCoreInfo("Inizializzazione HSM in corso...");
				File f = new File(hsmConfig);
				HSMManager.init(f, loaderProperties.isHSMRequired(), logCore, false);
				HSMUtils.setHsmConfigurableKeyPassword(loaderProperties.isHSMKeyPasswordConfigurable());
				logCoreInfo("Inizializzazione HSM effettuata con successo");
			}
		} catch (Exception e) {
			doError("Errore durante l'inizializzazione del manager HSM",e);
		}
	}
	private static BYOKManager initBYOK(VaultProperties loaderProperties) throws CoreException {
		BYOKManager byokManager = null;
		try {
			String byokConfig = loaderProperties.getBYOKConfigurazione();
			if(StringUtils.isNotEmpty(byokConfig)) {
				logCoreInfo("Inizializzazione BYOK in corso...");
				File f = new File(byokConfig);
				BYOKManager.init(f, loaderProperties.isBYOKRequired(), logCore);
				byokManager = BYOKManager.getInstance();
				String msgInit = "Gestore BYOK inizializzato;"+
						"\n\tHSM registrati: "+byokManager.getKeystoreTypes()+
						"\n\tSecurityEngine registrati: "+byokManager.getSecurityEngineTypes()+
						"\n\tGovWaySecurityEngine: "+byokManager.getSecurityEngineGovWayDescription();
				logCoreInfo(msgInit);
			}
		} catch (Exception e) {
			doError("Errore durante l'inizializzazione del manager BYOK",e);
		}
		return byokManager;
	}
	private static void initSecrets(VaultProperties loaderProperties, BYOKManager byokManager) throws CoreException {
		try {
			String secretsConfig = loaderProperties.getBYOKEnvSecretsConfig();
			if(byokManager!=null && StringUtils.isNotEmpty(secretsConfig)) {
				logCoreInfo("Inizializzazione secrets in corso...");
				
				Map<String, Object> dynamicMap = new HashMap<>();
				DynamicInfo dynamicInfo = new  DynamicInfo();
				DynamicUtils.fillDynamicMap(logCore, dynamicMap, dynamicInfo);
				
				BYOKMapProperties.initialize(logCore, secretsConfig, loaderProperties.isBYOKEnvSecretsConfigRequired(), 
						true, 
						dynamicMap, true);
				BYOKMapProperties secretsProperties = BYOKMapProperties.getInstance();
				secretsProperties.initEnvironment();
				String msgInit = "Environment inizializzato con i secrets definiti nel file '"+secretsConfig+"'"+
						"\n\tJavaProperties: "+secretsProperties.getJavaMap().keys()+
						"\n\tEnvProperties: "+secretsProperties.getEnvMap().keys()+
						"\n\tObfuscateMode: "+secretsProperties.getObfuscateModeDescription();
				logCoreInfo(msgInit);
			}
		} catch (Exception e) {
			doError("Errore durante l'inizializzazione dell'ambiente (secrets)",e);
		}	
	}
	private static ConfigurazionePdD initProtocolFactory(String protocolloDefault) throws CoreException {
		ConfigurazionePdD configPdD = null;
		try {
			configPdD = new ConfigurazionePdD();
			configPdD.setAttesaAttivaJDBC(-1);
			configPdD.setCheckIntervalJDBC(-1);
			configPdD.setLoader(new org.openspcoop2.utils.resources.Loader(VaultTools.class.getClassLoader()));
			configPdD.setLog(logCore);
			ProtocolFactoryManager.initialize(logCore, configPdD,
					protocolloDefault);
		} catch (Exception e) {
			throw new CoreException("Errore (InitConfigurazione - ProtocolFactoryManager): "+e.getMessage(),e);
		}
		return configPdD;
	}
	private static void initExtendedInfoManager() throws CoreException {
		try{
			ExtendedInfoManager.initialize(new org.openspcoop2.utils.resources.Loader(VaultTools.class.getClassLoader()), null, null, null);
		}catch(Exception e){
			throw new CoreException("Inizializzazione [ExtendedInfoManager] fallita",e);
		}
	}

	private static void doError(String msg,Exception e) throws CoreException {
		String msgErrore = msg+": " + e.getMessage();
		logCoreError(msgErrore,e);
		throw new CoreException(msgErrore,e);
	}
	
}