diff options
author | Thomas Lenz <thomas.lenz@egiz.gv.at> | 2020-02-17 08:10:16 +0100 |
---|---|---|
committer | Thomas Lenz <thomas.lenz@egiz.gv.at> | 2020-02-17 08:10:16 +0100 |
commit | b8b5d79f36c0d51a10dc820b09833179442b5155 (patch) | |
tree | 7f4ff3c66c8b57b919cd83a4fc8a0247e9c7c0ab /eaaf_modules | |
parent | 8fd4b91b8da067055133b2feb97e726c6a834c78 (diff) | |
parent | c4e1a45e7958cab402d83f6f4ae208df1bb2ab58 (diff) | |
download | EAAF-Components-b8b5d79f36c0d51a10dc820b09833179442b5155.tar.gz EAAF-Components-b8b5d79f36c0d51a10dc820b09833179442b5155.tar.bz2 EAAF-Components-b8b5d79f36c0d51a10dc820b09833179442b5155.zip |
Merge branch 'feature/hsmfacade' into nightlyBuild
# Conflicts:
# eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/metadata/AbstractChainingMetadataProvider.java
# eaaf_modules/eaaf_module_pvp2_idp/src/test/resources/spring/test_eaaf_core.beans.xml
Diffstat (limited to 'eaaf_modules')
13 files changed, 314 insertions, 221 deletions
diff --git a/eaaf_modules/eaaf_module_auth_sl20/src/main/java/at/gv/egiz/eaaf/modules/auth/sl20/Constants.java b/eaaf_modules/eaaf_module_auth_sl20/src/main/java/at/gv/egiz/eaaf/modules/auth/sl20/Constants.java index f607f8cb..11fd41fb 100644 --- a/eaaf_modules/eaaf_module_auth_sl20/src/main/java/at/gv/egiz/eaaf/modules/auth/sl20/Constants.java +++ b/eaaf_modules/eaaf_module_auth_sl20/src/main/java/at/gv/egiz/eaaf/modules/auth/sl20/Constants.java @@ -7,17 +7,37 @@ public class Constants { public static final String CONFIG_PROP_VDA_AUTHBLOCK_TRANSFORMATION_ID = CONFIG_PROP_PREFIX + ".vda.authblock.transformation.id"; - public static final String CONFIG_PROP_SECURITY_KEYSTORE_PATH = CONFIG_PROP_PREFIX + ".security.keystore.path"; - public static final String CONFIG_PROP_SECURITY_KEYSTORE_PASSWORD = CONFIG_PROP_PREFIX - + ".security.keystore.password"; - public static final String CONFIG_PROP_SECURITY_KEYSTORE_KEY_SIGN_ALIAS = CONFIG_PROP_PREFIX + ".security.sign.alias"; - public static final String CONFIG_PROP_SECURITY_KEYSTORE_KEY_SIGN_PASSWORD = CONFIG_PROP_PREFIX - + ".security.sign.password"; - public static final String CONFIG_PROP_SECURITY_KEYSTORE_KEY_ENCRYPTION_ALIAS = CONFIG_PROP_PREFIX - + ".security.encryption.alias"; - public static final String CONFIG_PROP_SECURITY_KEYSTORE_KEY_ENCRYPTION_PASSWORD = CONFIG_PROP_PREFIX - + ".security.encryption.password"; + + //KeyStore configuration + public static final String CONFIG_PROP_SECURITY_KEYSTORE_TYPE = + CONFIG_PROP_PREFIX + ".security.keystore.type"; + public static final String CONFIG_PROP_SECURITY_KEYSTORE_NAME = + CONFIG_PROP_PREFIX + ".security.keystore.name"; + public static final String CONFIG_PROP_SECURITY_KEYSTORE_PATH = + CONFIG_PROP_PREFIX + ".security.keystore.path"; + public static final String CONFIG_PROP_SECURITY_KEYSTORE_PASSWORD = + CONFIG_PROP_PREFIX + ".security.keystore.password"; + + public static final String CONFIG_PROP_SECURITY_KEYSTORE_KEY_SIGN_ALIAS = + CONFIG_PROP_PREFIX + ".security.sign.alias"; + public static final String CONFIG_PROP_SECURITY_KEYSTORE_KEY_SIGN_PASSWORD = + CONFIG_PROP_PREFIX + ".security.sign.password"; + public static final String CONFIG_PROP_SECURITY_KEYSTORE_KEY_ENCRYPTION_ALIAS = + CONFIG_PROP_PREFIX + ".security.encryption.alias"; + public static final String CONFIG_PROP_SECURITY_KEYSTORE_KEY_ENCRYPTION_PASSWORD = + CONFIG_PROP_PREFIX + ".security.encryption.password"; + //TrustStore configuration + public static final String CONFIG_PROP_SECURITY_TRUSTSTORE_TYPE = + CONFIG_PROP_PREFIX + ".security.truststore.type"; + public static final String CONFIG_PROP_SECURITY_TRUSTSTORE_NAME = + CONFIG_PROP_PREFIX + ".security.truststore.name"; + public static final String CONFIG_PROP_SECURITY_TRUSTSTORE_PATH = + CONFIG_PROP_PREFIX + ".security.truststore.path"; + public static final String CONFIG_PROP_SECURITY_TRUSTSTORE_PASSWORD = + CONFIG_PROP_PREFIX + ".security.truststore.password"; + + public static final String CONFIG_PROP_VDA_ENDPOINT_QUALeID_DEFAULT_ELEMENT = "default"; public static final String CONFIG_PROP_VDA_ENDPOINT_QUALeID_DEFAULT = CONFIG_PROP_VDA_ENDPOINT_QUALeID + CONFIG_PROP_VDA_ENDPOINT_QUALeID_DEFAULT_ELEMENT; diff --git a/eaaf_modules/eaaf_module_auth_sl20/src/main/java/at/gv/egiz/eaaf/modules/auth/sl20/utils/JsonSecurityUtils.java b/eaaf_modules/eaaf_module_auth_sl20/src/main/java/at/gv/egiz/eaaf/modules/auth/sl20/utils/JsonSecurityUtils.java index 0d2c1815..259c21bf 100644 --- a/eaaf_modules/eaaf_module_auth_sl20/src/main/java/at/gv/egiz/eaaf/modules/auth/sl20/utils/JsonSecurityUtils.java +++ b/eaaf_modules/eaaf_module_auth_sl20/src/main/java/at/gv/egiz/eaaf/modules/auth/sl20/utils/JsonSecurityUtils.java @@ -1,17 +1,12 @@ package at.gv.egiz.eaaf.modules.auth.sl20.utils; import java.io.IOException; -import java.net.MalformedURLException; import java.security.Key; import java.security.KeyStore; import java.security.KeyStoreException; -import java.security.PrivateKey; -import java.security.cert.Certificate; import java.security.cert.CertificateEncodingException; import java.security.cert.X509Certificate; -import java.util.ArrayList; import java.util.Collections; -import java.util.Enumeration; import java.util.List; import javax.annotation.Nonnull; @@ -38,9 +33,13 @@ import com.fasterxml.jackson.core.JsonParseException; import com.fasterxml.jackson.databind.JsonNode; import at.gv.egiz.eaaf.core.api.idp.IConfiguration; +import at.gv.egiz.eaaf.core.exception.EaafKeyAccessException; import at.gv.egiz.eaaf.core.exceptions.EaafConfigurationException; -import at.gv.egiz.eaaf.core.impl.utils.FileUtils; -import at.gv.egiz.eaaf.core.impl.utils.KeyStoreUtils; +import at.gv.egiz.eaaf.core.impl.credential.EaafKeyStoreFactory; +import at.gv.egiz.eaaf.core.impl.credential.EaafKeyStoreUtils; +import at.gv.egiz.eaaf.core.impl.credential.KeyStoreConfiguration; +import at.gv.egiz.eaaf.core.impl.credential.KeyStoreConfiguration.KeyStoreType; +import at.gv.egiz.eaaf.core.impl.data.Pair; import at.gv.egiz.eaaf.core.impl.utils.X509Utils; import at.gv.egiz.eaaf.modules.auth.sl20.Constants; import at.gv.egiz.eaaf.modules.auth.sl20.data.VerificationResult; @@ -53,88 +52,60 @@ import at.gv.egiz.eaaf.modules.auth.sl20.exceptions.SlCommandoParserException; public class JsonSecurityUtils implements IJoseTools { private static final Logger log = LoggerFactory.getLogger(JsonSecurityUtils.class); - @Autowired(required = true) - IConfiguration authConfig; - private Key signPrivKey = null; - private X509Certificate[] signCertChain = null; - - private Key encPrivKey = null; - private X509Certificate[] encCertChain = null; - - private List<X509Certificate> trustedCerts = new ArrayList<>(); - + private static final String FRIENDLYNAME_KEYSTORE = "SL2.0 KeyStore"; + private static final String FRIENDLYNAME_TRUSTSTORE = "SL2.0 TrustStore"; + + @Autowired(required = true) IConfiguration authConfig; + @Autowired(required = true) EaafKeyStoreFactory keystoreFactory; + + private KeyStore keyStore; + private KeyStore trustStore; + private static JsonMapper mapper = new JsonMapper(); @PostConstruct - protected void initalize() { + protected void initalize() throws SL20Exception { log.info("Initialize SL2.0 authentication security constrains ... "); try { - if (getKeyStoreFilePath() != null) { - final KeyStore keyStore = KeyStoreUtils.loadKeyStore(getKeyStoreFilePath(), getKeyStorePassword()); - - // load signing key - signPrivKey = keyStore.getKey(getSigningKeyAlias(), getSigningKeyPassword().toCharArray()); - final Certificate[] certChainSigning = keyStore.getCertificateChain(getSigningKeyAlias()); - signCertChain = new X509Certificate[certChainSigning.length]; - for (int i = 0; i < certChainSigning.length; i++) { - if (certChainSigning[i] instanceof X509Certificate) { - signCertChain[i] = (X509Certificate) certChainSigning[i]; - } else { - log.warn("NO X509 certificate for signing: " + certChainSigning[i].getType()); - } - - } - - // load encryption key - try { - encPrivKey = keyStore.getKey(getEncryptionKeyAlias(), getEncryptionKeyPassword().toCharArray()); - if (encPrivKey != null) { - final Certificate[] certChainEncryption = keyStore.getCertificateChain(getEncryptionKeyAlias()); - encCertChain = new X509Certificate[certChainEncryption.length]; - for (int i = 0; i < certChainEncryption.length; i++) { - if (certChainEncryption[i] instanceof X509Certificate) { - encCertChain[i] = (X509Certificate) certChainEncryption[i]; - } else { - log.warn("NO X509 certificate for encryption: " + certChainEncryption[i].getType()); - } - } - } else { - log.info("No encryption key for SL2.0 found. End-to-End encryption is not used."); - } - - } catch (final Exception e) { - log.warn("No encryption key for SL2.0 found. End-to-End encryption is not used. Reason: " + e.getMessage(), - e); - - } - - // load trusted certificates - trustedCerts = readCertsFromKeyStore(keyStore); - - // some short validation - if (signPrivKey == null || !(signPrivKey instanceof PrivateKey)) { - log.info("Can NOT open privateKey for SL2.0 signing. KeyStore=" + getKeyStoreFilePath()); - throw new SL20Exception("sl20.03", new Object[] { "Can NOT open private key for signing" }); - - } - - if (signCertChain == null || signCertChain.length == 0) { - log.info("NO certificate for SL2.0 signing. KeyStore=" + getKeyStoreFilePath()); - throw new SL20Exception("sl20.03", new Object[] { "NO certificate for SL2.0 signing" }); - - } - - log.info("SL2.0 authentication security constrains initialized."); - + //load KeyStore + KeyStoreConfiguration keyStoreConfig = buildKeyStoreConfiguration(); + keyStore = keystoreFactory.buildNewKeyStore(keyStoreConfig); + + //load TrustStore + KeyStoreConfiguration trustStoreConfig = buildTrustStoreConfiguration(); + trustStore = keystoreFactory.buildNewKeyStore(trustStoreConfig); + + //validate KeyStore entries + EaafKeyStoreUtils.getPrivateKeyAndCertificates(keyStore, getSigningKeyAlias(), + getSigningKeyPassword(), true, FRIENDLYNAME_KEYSTORE); + Pair<Key, X509Certificate[]> encCredentials = + EaafKeyStoreUtils.getPrivateKeyAndCertificates(keyStore, getEncryptionKeyAlias(), + getEncryptionKeyPassword(), false, FRIENDLYNAME_TRUSTSTORE); + if (encCredentials == null) { + log.info("No encryption key for SL2.0 found. End-to-End encryption is not used."); + + } + + //validate TrustStore + List<X509Certificate> trustedCerts = EaafKeyStoreUtils.readCertsFromKeyStore(trustStore); + if (trustedCerts.isEmpty()) { + log.info("No certificates in TrustStore: {}. Signature validation will FAIL!", + FRIENDLYNAME_TRUSTSTORE); + } else { - log.info("NO SL2.0 authentication security configuration. Initialization was skipped"); + log.info("Find #{} certificates in TrustStore: {}", + trustedCerts.size(), FRIENDLYNAME_TRUSTSTORE); + } + + log.info("SL2.0 authentication security constrains initialized."); } catch (final RuntimeException e) { throw e; } catch (final Exception e) { - log.error("SL2.0 security constrains initialization FAILED.", e); + log.error("SL2.0 security constrains initialization FAILED."); + throw new SL20Exception("sl20.11", new Object[] {e.getMessage()}, e); } @@ -153,15 +124,18 @@ public class JsonSecurityUtils implements IJoseTools { // set signing information jws.setAlgorithmHeaderValue(AlgorithmIdentifiers.RSA_USING_SHA256); - jws.setKey(signPrivKey); + Pair<Key, X509Certificate[]> signingCred = EaafKeyStoreUtils.getPrivateKeyAndCertificates(keyStore, + getSigningKeyAlias(), getSigningKeyPassword(), true, FRIENDLYNAME_KEYSTORE); + + jws.setKey(signingCred.getFirst()); // TODO: - jws.setCertificateChainHeaderValue(signCertChain); - jws.setX509CertSha256ThumbprintHeaderValue(signCertChain[0]); + jws.setCertificateChainHeaderValue(signingCred.getSecond()); + jws.setX509CertSha256ThumbprintHeaderValue(signingCred.getSecond()[0]); return jws.getCompactSerialization(); - } catch (final JoseException e) { + } catch (final JoseException | EaafKeyAccessException e) { log.warn("Can NOT sign SL2.0 command.", e); throw new SlCommandoBuildException("Can NOT sign SL2.0 command.", e); @@ -172,7 +146,7 @@ public class JsonSecurityUtils implements IJoseTools { @Override public VerificationResult validateSignature(final String serializedContent, final KeyStore trustStore, final AlgorithmConstraints algconstraints) throws JoseException, IOException, KeyStoreException { - final List<X509Certificate> trustedCertificates = readCertsFromKeyStore(trustStore); + final List<X509Certificate> trustedCertificates = EaafKeyStoreUtils.readCertsFromKeyStore(trustStore); return validateSignature(serializedContent, trustedCertificates, algconstraints); } @@ -244,7 +218,8 @@ public class JsonSecurityUtils implements IJoseTools { SL20Constants.SL20_ALGORITHM_WHITELIST_SIGNING .toArray(new String[SL20Constants.SL20_ALGORITHM_WHITELIST_SIGNING.size()])); - final VerificationResult result = validateSignature(serializedContent, trustedCerts, algConstraints); + final VerificationResult result = + validateSignature(serializedContent, EaafKeyStoreUtils.readCertsFromKeyStore(trustStore), algConstraints); if (!result.isValidSigned()) { log.info("JWS signature invalide. Stopping authentication process ..."); @@ -256,7 +231,7 @@ public class JsonSecurityUtils implements IJoseTools { log.debug("SL2.0 commando signature validation sucessfull"); return result; - } catch (JoseException | JsonParseException e) { + } catch (JoseException | JsonParseException | KeyStoreException e) { log.warn("SL2.0 commando signature validation FAILED", e); throw new SL20SecurityException(new Object[] { e.getMessage() }, e); @@ -284,6 +259,9 @@ public class JsonSecurityUtils implements IJoseTools { // set payload receiverJwe.setCompactSerialization(compactSerialization); + Pair<Key, X509Certificate[]> encryptionCred = EaafKeyStoreUtils.getPrivateKeyAndCertificates(keyStore, + getEncryptionKeyAlias(), getEncryptionKeyPassword(), true, FRIENDLYNAME_KEYSTORE); + // validate key from header against key from config final List<X509Certificate> x5cCerts = receiverJwe.getCertificateChainHeaderValue(); final String x5t256 = receiverJwe.getX509CertSha256ThumbprintHeaderValue(); @@ -292,7 +270,7 @@ public class JsonSecurityUtils implements IJoseTools { log.trace("Sorting received X509 certificates ... "); final List<X509Certificate> sortedX5cCerts = X509Utils.sortCertificates(x5cCerts); - if (!sortedX5cCerts.get(0).equals(encCertChain[0])) { + if (!sortedX5cCerts.get(0).equals(encryptionCred.getSecond()[0])) { log.info("Certificate from JOSE header does NOT match encryption certificate"); try { @@ -307,7 +285,7 @@ public class JsonSecurityUtils implements IJoseTools { } else if (StringUtils.isNotEmpty(x5t256)) { log.debug("Found x5t256 fingerprint in JOSE header .... "); - final String certFingerPrint = X509Util.x5tS256(encCertChain[0]); + final String certFingerPrint = X509Util.x5tS256(encryptionCred.getSecond()[0]); if (!certFingerPrint.equals(x5t256)) { log.info("X5t256 from JOSE header does NOT match encryption certificate"); log.debug("X5t256 from JOSE header: " + x5t256 + " Encrytption cert: " + certFingerPrint); @@ -324,12 +302,12 @@ public class JsonSecurityUtils implements IJoseTools { } // set key - receiverJwe.setKey(encPrivKey); + receiverJwe.setKey(encryptionCred.getFirst()); // decrypt payload return mapper.getMapper().readTree(receiverJwe.getPlaintextString()); - } catch (final JoseException e) { + } catch (final JoseException | EaafKeyAccessException e) { log.warn("SL2.0 result decryption FAILED", e); throw new SL20SecurityException(new Object[] { e.getMessage() }, e); @@ -340,37 +318,74 @@ public class JsonSecurityUtils implements IJoseTools { } catch (final IOException e) { log.warn("Decrypted SL2.0 result can not be parsed.", e); throw new SlCommandoParserException("Decrypted SL2.0 result can not be parsed", e); + } - } @Override public X509Certificate getEncryptionCertificate() { - // TODO: maybe update after SL2.0 update on encryption certificate parts - if (encCertChain != null && encCertChain.length > 0) { - return encCertChain[0]; - } else { - return null; + Pair<Key, X509Certificate[]> encryptionCred; + try { + encryptionCred = EaafKeyStoreUtils.getPrivateKeyAndCertificates(keyStore, + getEncryptionKeyAlias(), getEncryptionKeyPassword(), false, FRIENDLYNAME_KEYSTORE); + if (encryptionCred != null && encryptionCred.getSecond().length > 0) { + return encryptionCred.getSecond()[0]; + + } + + } catch (EaafKeyAccessException e) { + log.trace("Exception is skipped because Encryption is not mandatory on this level", e); + } + + return null; + } - private String getKeyStoreFilePath() throws EaafConfigurationException, MalformedURLException { - return FileUtils.makeAbsoluteUrl(authConfig.getBasicConfiguration(Constants.CONFIG_PROP_SECURITY_KEYSTORE_PATH), - authConfig.getConfigurationRootDirectory()); + private KeyStoreConfiguration buildKeyStoreConfiguration() throws EaafConfigurationException { + KeyStoreConfiguration config = new KeyStoreConfiguration(); + config.setFriendlyName(FRIENDLYNAME_KEYSTORE); + + config.setKeyStoreType(authConfig.getBasicConfiguration( + authConfig.getBasicConfiguration(Constants.CONFIG_PROP_SECURITY_KEYSTORE_TYPE), + KeyStoreType.JKS.getKeyStoreType())); + config.setKeyStoreName( + authConfig.getBasicConfiguration(Constants.CONFIG_PROP_SECURITY_KEYSTORE_NAME)); + config.setSoftKeyStoreFilePath( + authConfig.getBasicConfiguration(Constants.CONFIG_PROP_SECURITY_KEYSTORE_PATH)); + config.setSoftKeyStorePassword( + authConfig.getBasicConfiguration(Constants.CONFIG_PROP_SECURITY_KEYSTORE_PASSWORD)); + + //validate configuration state + config.validate(); + + return config; + } - - private String getKeyStorePassword() { - String value = authConfig.getBasicConfiguration(Constants.CONFIG_PROP_SECURITY_KEYSTORE_PASSWORD); - if (value != null) { - value = value.trim(); - } - - return value; - + + private KeyStoreConfiguration buildTrustStoreConfiguration() throws EaafConfigurationException { + KeyStoreConfiguration config = new KeyStoreConfiguration(); + config.setFriendlyName(FRIENDLYNAME_TRUSTSTORE); + + config.setKeyStoreType(authConfig.getBasicConfiguration( + authConfig.getBasicConfiguration(Constants.CONFIG_PROP_SECURITY_TRUSTSTORE_TYPE), + KeyStoreType.JKS.getKeyStoreType())); + config.setKeyStoreName( + authConfig.getBasicConfiguration(Constants.CONFIG_PROP_SECURITY_TRUSTSTORE_NAME)); + config.setSoftKeyStoreFilePath( + authConfig.getBasicConfiguration(Constants.CONFIG_PROP_SECURITY_TRUSTSTORE_PATH)); + config.setSoftKeyStorePassword( + authConfig.getBasicConfiguration(Constants.CONFIG_PROP_SECURITY_TRUSTSTORE_PASSWORD)); + + //validate configuration state + config.validate(); + + return config; } + private String getSigningKeyAlias() { - String value = authConfig.getBasicConfiguration(Constants.CONFIG_PROP_SECURITY_KEYSTORE_KEY_SIGN_ALIAS).trim(); + String value = authConfig.getBasicConfiguration(Constants.CONFIG_PROP_SECURITY_KEYSTORE_KEY_SIGN_ALIAS); if (value != null) { value = value.trim(); } @@ -378,18 +393,17 @@ public class JsonSecurityUtils implements IJoseTools { return value; } - private String getSigningKeyPassword() { - String value = authConfig.getBasicConfiguration(Constants.CONFIG_PROP_SECURITY_KEYSTORE_KEY_SIGN_PASSWORD).trim(); + private char[] getSigningKeyPassword() { + String value = authConfig.getBasicConfiguration(Constants.CONFIG_PROP_SECURITY_KEYSTORE_KEY_SIGN_PASSWORD); if (value != null) { - value = value.trim(); + return value.trim().toCharArray(); } - return value; + return null; } private String getEncryptionKeyAlias() { - String value = authConfig.getBasicConfiguration(Constants.CONFIG_PROP_SECURITY_KEYSTORE_KEY_ENCRYPTION_ALIAS) - .trim(); + String value = authConfig.getBasicConfiguration(Constants.CONFIG_PROP_SECURITY_KEYSTORE_KEY_ENCRYPTION_ALIAS); if (value != null) { value = value.trim(); } @@ -397,36 +411,13 @@ public class JsonSecurityUtils implements IJoseTools { return value; } - private String getEncryptionKeyPassword() { - String value = authConfig.getBasicConfiguration(Constants.CONFIG_PROP_SECURITY_KEYSTORE_KEY_ENCRYPTION_PASSWORD) - .trim(); + private char[] getEncryptionKeyPassword() { + String value = authConfig.getBasicConfiguration(Constants.CONFIG_PROP_SECURITY_KEYSTORE_KEY_ENCRYPTION_PASSWORD); if (value != null) { - value = value.trim(); - } - - return value; - } - - @Nonnull - private List<X509Certificate> readCertsFromKeyStore(@Nonnull final KeyStore keyStore) throws KeyStoreException { - final List<X509Certificate> result = new ArrayList<>(); - - final Enumeration<String> aliases = keyStore.aliases(); - while (aliases.hasMoreElements()) { - final String el = aliases.nextElement(); - log.trace("Process TrustStoreEntry: " + el); - if (keyStore.isCertificateEntry(el)) { - final Certificate cert = keyStore.getCertificate(el); - if (cert != null && cert instanceof X509Certificate) { - result.add((X509Certificate) cert); - } else { - log.info("Can not process entry: {}. Reason: {}", el, cert != null ? cert.getType() : "cert is null"); - } - - } + return value.trim().toCharArray(); } - return Collections.unmodifiableList(result); + return null; } } diff --git a/eaaf_modules/eaaf_module_pvp2_core/pom.xml b/eaaf_modules/eaaf_module_pvp2_core/pom.xml index c9aac506..a81ad889 100644 --- a/eaaf_modules/eaaf_module_pvp2_core/pom.xml +++ b/eaaf_modules/eaaf_module_pvp2_core/pom.xml @@ -22,7 +22,6 @@ <artifactId>eaaf-core</artifactId> <version>${egiz.eaaf.version}</version> </dependency> - <dependency> <groupId>org.opensaml</groupId> <artifactId>opensaml-core</artifactId> @@ -82,6 +81,12 @@ <artifactId>mockwebserver</artifactId> <scope>test</scope> </dependency> + <dependency> + <groupId>xml-apis</groupId> + <artifactId>xml-apis</artifactId> + <version>1.4.01</version> + <scope>test</scope> + </dependency> </dependencies> diff --git a/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/metadata/AbstractChainingMetadataProvider.java b/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/metadata/AbstractChainingMetadataProvider.java index 8a33b205..902f84c7 100644 --- a/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/metadata/AbstractChainingMetadataProvider.java +++ b/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/metadata/AbstractChainingMetadataProvider.java @@ -406,6 +406,7 @@ public abstract class AbstractChainingMetadataProvider implements IGarbageCollec private void addAndRemoveMetadataProvider() throws EaafConfigurationException { log.info("EAAF chaining metadata resolver starting internal managment task .... "); + // get all actually loaded metadata providers final Map<String, MetadataResolver> loadedproviders = getAllActuallyLoadedResolvers(); @@ -428,6 +429,7 @@ public abstract class AbstractChainingMetadataProvider implements IGarbageCollec try { if (StringUtils.isNotEmpty(metadataurl) && loadedproviders.containsKey(metadataurl)) { + // SAML2 SP is actually loaded, to nothing loadedproviders.remove(metadataurl); } diff --git a/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/utils/AbstractCredentialProvider.java b/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/utils/AbstractCredentialProvider.java index 6959b6bd..cd77228c 100644 --- a/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/utils/AbstractCredentialProvider.java +++ b/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/utils/AbstractCredentialProvider.java @@ -19,8 +19,6 @@ package at.gv.egiz.eaaf.modules.pvp2.impl.utils; -import java.io.IOException; -import java.io.InputStream; import java.security.KeyStore; import java.security.KeyStoreException; import java.security.cert.Certificate; @@ -33,24 +31,24 @@ import java.util.List; import javax.annotation.Nonnull; import javax.annotation.PostConstruct; +import org.apache.commons.lang3.StringUtils; +import org.apache.xml.security.algorithms.JCEMapper; +import org.opensaml.security.credential.UsageType; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.core.io.ResourceLoader; + import at.gv.egiz.eaaf.core.api.idp.IConfiguration; import at.gv.egiz.eaaf.core.exceptions.EaafConfigurationException; import at.gv.egiz.eaaf.core.exceptions.EaafException; -import at.gv.egiz.eaaf.core.impl.utils.KeyStoreUtils; +import at.gv.egiz.eaaf.core.impl.credential.EaafKeyStoreFactory; +import at.gv.egiz.eaaf.core.impl.credential.KeyStoreConfiguration; +import at.gv.egiz.eaaf.core.impl.credential.KeyStoreConfiguration.KeyStoreType; import at.gv.egiz.eaaf.modules.pvp2.PvpConstants; import at.gv.egiz.eaaf.modules.pvp2.api.credential.EaafX509Credential; import at.gv.egiz.eaaf.modules.pvp2.api.utils.IPvp2CredentialProvider; import at.gv.egiz.eaaf.modules.pvp2.exception.CredentialsNotAvailableException; import at.gv.egiz.eaaf.modules.pvp2.exception.SamlSigningException; import at.gv.egiz.eaaf.modules.pvp2.impl.opensaml.EaafKeyStoreX509CredentialAdapter; - -import org.apache.commons.lang3.StringUtils; -import org.opensaml.security.credential.UsageType; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.context.annotation.Lazy; -import org.springframework.core.io.Resource; -import org.springframework.core.io.ResourceLoader; - import lombok.extern.slf4j.Slf4j; @Slf4j @@ -63,6 +61,9 @@ public abstract class AbstractCredentialProvider implements IPvp2CredentialProvi @Autowired protected IConfiguration basicConfig; + @Autowired + private EaafKeyStoreFactory keyStoreFactory; + private KeyStore keyStore = null; /** @@ -71,23 +72,25 @@ public abstract class AbstractCredentialProvider implements IPvp2CredentialProvi * * @return keyStore friendlyName */ - public abstract String getFriendlyName(); + public final String getFriendlyName() { + try { + return getBasicKeyStoreConfig().getFriendlyName(); + + } catch (EaafConfigurationException e) { + return "No KeyStoreName"; + + } - /** - * Get KeyStore. - * - * @return URL to the keyStore - * @throws EaafException In case of an invalid filepath - */ - @Nonnull - public abstract String getKeyStoreFilePath() throws EaafException; + } /** - * Get keyStore password. + * Get the basic KeyStore configuration object for this SAML2 credential. * - * @return Password of the keyStore + * @return KeyStore configuration object + * @throws EaafConfigurationException In case of a configuration error */ - public abstract String getKeyStorePassword(); + @Nonnull + public abstract KeyStoreConfiguration getBasicKeyStoreConfig() throws EaafConfigurationException; /** * Get alias of key for metadata signing. @@ -154,8 +157,6 @@ public abstract class AbstractCredentialProvider implements IPvp2CredentialProvi } } - - /** * Get Credentials to sign SAML2 messages, like AuthnRequest, Response, * Assertions as some examples. @@ -250,21 +251,36 @@ public abstract class AbstractCredentialProvider implements IPvp2CredentialProvi } - @Lazy @PostConstruct private void initialize() throws Exception { try { - final Resource ressource = resourceLoader.getResource(getKeyStoreFilePath()); - final InputStream is = ressource.getInputStream(); - keyStore = KeyStoreUtils.loadKeyStore(is, getKeyStorePassword()); + final KeyStoreConfiguration keyStoreConfig = getBasicKeyStoreConfig(); + keyStore = keyStoreFactory.buildNewKeyStore(keyStoreConfig); + + if (JCEMapper.getProviderId() != null + && !JCEMapper.getProviderId().equals(keyStore.getProvider().getName())) { + log.error("OpenSAML3.x can ONLY use a single type of CryptoProvider in an application. " + + "Can NOT set: {}, because {} was already set", keyStore.getProvider().getName(), + JCEMapper.getProviderId()); + throw new EaafConfigurationException(EaafKeyStoreFactory.ERRORCODE_06, + new Object[] { keyStoreConfig.getFriendlyName(), + "OpenSAML3.x can ONLY use a single type of CryptoProvider" }); + + } - if (keyStore == null) { - throw new EaafConfigurationException("module.00", - new Object[] { getFriendlyName(), "KeyStore initialization failed. Maybe wrong password" }); + // Set JCEMapper only in case of HSM based KeyStores because Software KeyStores + // can use + // the default SecurityProvider system in OpenSAML3.x signing engine + if (!KeyStoreType.JKS.equals(keyStoreConfig.getKeyStoreType()) + && !KeyStoreType.PKCS12.equals(keyStoreConfig.getKeyStoreType()) + && JCEMapper.getProviderId() == null) { + log.info("Register CryptoProvider: {} as defaut for OpenSAML3.x", + keyStore.getProvider().getName()); + JCEMapper.setProviderId(keyStore.getProvider().getName()); } - } catch (IOException | KeyStoreException | EaafException e) { + } catch (final EaafException e) { log.error("Can not initialize KeyStore for eIDAS authentication client.", e); throw e; diff --git a/eaaf_modules/eaaf_module_pvp2_core/src/test/java/at/gv/egiz/eaaf/modules/pvp2/test/CredentialProviderTest.java b/eaaf_modules/eaaf_module_pvp2_core/src/test/java/at/gv/egiz/eaaf/modules/pvp2/test/CredentialProviderTest.java index b6171e97..22ee389f 100644 --- a/eaaf_modules/eaaf_module_pvp2_core/src/test/java/at/gv/egiz/eaaf/modules/pvp2/test/CredentialProviderTest.java +++ b/eaaf_modules/eaaf_module_pvp2_core/src/test/java/at/gv/egiz/eaaf/modules/pvp2/test/CredentialProviderTest.java @@ -3,14 +3,8 @@ package at.gv.egiz.eaaf.modules.pvp2.test; import java.security.cert.X509Certificate; import java.util.List; -import at.gv.egiz.eaaf.core.exceptions.EaafConfigurationException; -import at.gv.egiz.eaaf.core.impl.idp.module.test.DummyAuthConfigMap; -import at.gv.egiz.eaaf.modules.pvp2.PvpConstants; -import at.gv.egiz.eaaf.modules.pvp2.api.credential.EaafX509Credential; -import at.gv.egiz.eaaf.modules.pvp2.exception.CredentialsNotAvailableException; -import at.gv.egiz.eaaf.modules.pvp2.test.dummy.DummyCredentialProvider; - import org.apache.commons.lang3.RandomStringUtils; +import org.apache.xml.security.algorithms.JCEMapper; import org.junit.Assert; import org.junit.Before; import org.junit.Test; @@ -23,6 +17,14 @@ import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.TestPropertySource; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; +import at.gv.egiz.eaaf.core.exceptions.EaafConfigurationException; +import at.gv.egiz.eaaf.core.exceptions.EaafFactoryException; +import at.gv.egiz.eaaf.core.impl.idp.module.test.DummyAuthConfigMap; +import at.gv.egiz.eaaf.modules.pvp2.PvpConstants; +import at.gv.egiz.eaaf.modules.pvp2.api.credential.EaafX509Credential; +import at.gv.egiz.eaaf.modules.pvp2.exception.CredentialsNotAvailableException; +import at.gv.egiz.eaaf.modules.pvp2.test.dummy.DummyCredentialProvider; + @RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration({ @@ -34,9 +36,14 @@ public class CredentialProviderTest { private static final String PATH_JKS_WITH_TRUST_CERTS = "src/test/resources/data/junit.jks"; private static final String PATH_JKS_WITHOUT_TRUST_CERTS = "src/test/resources/data/junit_without_trustcerts.jks"; + //private static final String HSMF_ALIAS_METADATA = "shibboleth-sign"; + //private static final String HSMF_ALIAS_SIGN = "shibboleth-sign"; + //private static final String HSMF_ALIAS_ENC = "shibboleth-sign"; + private static final String ALIAS_METADATA = "meta"; private static final String ALIAS_SIGN = "sig"; private static final String ALIAS_ENC = "meta"; + private static final String PASSWORD = "password"; @@ -59,6 +66,8 @@ public class CredentialProviderTest { config.removeConfigValue(DummyCredentialProvider.KEY_ENCRYPTION_ALIAS); config.removeConfigValue(DummyCredentialProvider.KEY_ENCRYPTION_PASSWORD); + + JCEMapper.setProviderId(null); } @@ -86,7 +95,7 @@ public class CredentialProviderTest { Assert.fail("No KeyStore not detected"); } catch (final BeansException e) { - org.springframework.util.Assert.isInstanceOf(java.io.FileNotFoundException.class, + org.springframework.util.Assert.isInstanceOf(EaafConfigurationException.class, e.getCause(), "Wrong exception"); } @@ -101,7 +110,7 @@ public class CredentialProviderTest { Assert.fail("No KeyStore not detected"); } catch (final BeansException e) { - org.springframework.util.Assert.isInstanceOf(EaafConfigurationException.class, + org.springframework.util.Assert.isInstanceOf(EaafFactoryException.class, e.getCause(), "Wrong exception"); } @@ -384,6 +393,33 @@ public class CredentialProviderTest { @Test @DirtiesContext + public void otherKeyStoreTypeAlreadyLoaded() throws CredentialsNotAvailableException { + config.putConfigValue(DummyCredentialProvider.KEYSTORE_PATH, PATH_JKS_WITHOUT_TRUST_CERTS); + + config.putConfigValue(PvpConstants.CONFIG_PROP_SEC_SIGNING_RSA_ALG, + "RSA-SIG_" + RandomStringUtils.randomAlphabetic(10)); + config.putConfigValue(PvpConstants.CONFIG_PROP_SEC_SIGNING_EC_ALG, + "EC-SIG_" + RandomStringUtils.randomAlphabetic(10)); + config.putConfigValue(PvpConstants.CONFIG_PROP_SEC_ENCRYPTION_KEY_RSA_ALG, + "RSA_ENC_" + RandomStringUtils.randomAlphabetic(10)); + config.putConfigValue(PvpConstants.CONFIG_PROP_SEC_ENCRYPTION_KEY_EC_ALG, + "EC-ENC_" + RandomStringUtils.randomAlphabetic(10)); + + try { + JCEMapper.setProviderId(RandomStringUtils.randomAlphabetic(5)); + + context.getBean(DummyCredentialProvider.class); + + } catch (final BeansException e) { + org.springframework.util.Assert.isInstanceOf(EaafConfigurationException.class, + e.getCause(), "Wrong exception"); + + } + + } + + @Test + @DirtiesContext public void notKeyConfiguration() { final DummyCredentialProvider credential = context.getBean(DummyCredentialProvider.class); diff --git a/eaaf_modules/eaaf_module_pvp2_core/src/test/java/at/gv/egiz/eaaf/modules/pvp2/test/dummy/DummyCredentialProvider.java b/eaaf_modules/eaaf_module_pvp2_core/src/test/java/at/gv/egiz/eaaf/modules/pvp2/test/dummy/DummyCredentialProvider.java index b9f1326d..0f8eff72 100644 --- a/eaaf_modules/eaaf_module_pvp2_core/src/test/java/at/gv/egiz/eaaf/modules/pvp2/test/dummy/DummyCredentialProvider.java +++ b/eaaf_modules/eaaf_module_pvp2_core/src/test/java/at/gv/egiz/eaaf/modules/pvp2/test/dummy/DummyCredentialProvider.java @@ -1,15 +1,12 @@ package at.gv.egiz.eaaf.modules.pvp2.test.dummy; -import java.net.MalformedURLException; +import org.springframework.beans.factory.annotation.Autowired; import at.gv.egiz.eaaf.core.api.idp.IConfiguration; -import at.gv.egiz.eaaf.core.exceptions.EaafConfigurationException; -import at.gv.egiz.eaaf.core.exceptions.EaafException; -import at.gv.egiz.eaaf.core.impl.utils.FileUtils; +import at.gv.egiz.eaaf.core.impl.credential.KeyStoreConfiguration; +import at.gv.egiz.eaaf.core.impl.credential.KeyStoreConfiguration.KeyStoreType; import at.gv.egiz.eaaf.modules.pvp2.impl.utils.AbstractCredentialProvider; -import org.springframework.beans.factory.annotation.Autowired; - public class DummyCredentialProvider extends AbstractCredentialProvider { @Autowired IConfiguration basicConfig; @@ -26,32 +23,26 @@ public class DummyCredentialProvider extends AbstractCredentialProvider { public static final String KEY_ENCRYPTION_ALIAS = "key.enc.alias"; public static final String KEY_ENCRYPTION_PASSWORD = "key.enc.pass"; + private static final String KEYSTORENAME = "jUnit test credential provider"; + @Override - public String getFriendlyName() { - return "jUnit test credential provider"; + public KeyStoreConfiguration getBasicKeyStoreConfig() { + KeyStoreConfiguration keyStoreConfig = new KeyStoreConfiguration(); + keyStoreConfig.setKeyStoreType(KeyStoreType.JKS); + keyStoreConfig.setFriendlyName(KEYSTORENAME); + + keyStoreConfig.setSoftKeyStoreFilePath(getKeyStoreFilePath()); + keyStoreConfig.setSoftKeyStorePassword(getKeyStorePassword()); + + return keyStoreConfig; } - @Override - public String getKeyStoreFilePath() throws EaafException { + public String getKeyStoreFilePath() { final String path = basicConfig.getBasicConfiguration(KEYSTORE_PATH); - - if (path != null) { - try { - return FileUtils.makeAbsoluteUrl( - path, - basicConfig.getConfigurationRootDirectory()); - - } catch (final MalformedURLException e) { - throw new EaafConfigurationException("internel test error", null, e); - - } - } - - throw new EaafConfigurationException("No keyStore path", null); - + return path; + } - @Override public String getKeyStorePassword() { return basicConfig.getBasicConfiguration(KEYSTORE_PASSWORD); } @@ -86,4 +77,5 @@ public class DummyCredentialProvider extends AbstractCredentialProvider { return basicConfig.getBasicConfiguration(KEY_ENCRYPTION_PASSWORD); } + } diff --git a/eaaf_modules/eaaf_module_pvp2_core/src/test/resources/config/config_2.props b/eaaf_modules/eaaf_module_pvp2_core/src/test/resources/config/config_2.props new file mode 100644 index 00000000..60cecebb --- /dev/null +++ b/eaaf_modules/eaaf_module_pvp2_core/src/test/resources/config/config_2.props @@ -0,0 +1,12 @@ +keystore.path=classpath:/data/junit.jks +keystore.pass=password +key.metadata.alias=shibboleth-sign +key.metadata.pass=password +key.sig.alias=shibboleth-sign +key.sig.pass=password +key.enc.alias= +key.enc.pass= + +client.http.connection.timeout.socket=2 +client.http.connection.timeout.connection=2 +client.http.connection.timeout.request=2
\ No newline at end of file diff --git a/eaaf_modules/eaaf_module_pvp2_core/src/test/resources/spring/test_eaaf_core.beans.xml b/eaaf_modules/eaaf_module_pvp2_core/src/test/resources/spring/test_eaaf_core.beans.xml index 3b2d0a28..5e3f0b9b 100644 --- a/eaaf_modules/eaaf_module_pvp2_core/src/test/resources/spring/test_eaaf_core.beans.xml +++ b/eaaf_modules/eaaf_module_pvp2_core/src/test/resources/spring/test_eaaf_core.beans.xml @@ -19,4 +19,7 @@ <bean id="httpClientFactory" class="at.gv.egiz.eaaf.core.impl.utils.HttpClientFactory" /> + <bean id="eaafKeyStoreFactory" + class="at.gv.egiz.eaaf.core.impl.credential.EaafKeyStoreFactory" /> + </beans>
\ No newline at end of file diff --git a/eaaf_modules/eaaf_module_pvp2_core/src/test/resources/spring/test_eaaf_core_spring_config.beans.xml b/eaaf_modules/eaaf_module_pvp2_core/src/test/resources/spring/test_eaaf_core_spring_config.beans.xml index 5c1a6095..5319236b 100644 --- a/eaaf_modules/eaaf_module_pvp2_core/src/test/resources/spring/test_eaaf_core_spring_config.beans.xml +++ b/eaaf_modules/eaaf_module_pvp2_core/src/test/resources/spring/test_eaaf_core_spring_config.beans.xml @@ -14,4 +14,7 @@ class="at.gv.egiz.eaaf.core.impl.idp.module.test.DummyAuthConfig" /> + <bean id="eaafKeyStoreFactory" + class="at.gv.egiz.eaaf.core.impl.credential.EaafKeyStoreFactory" /> + </beans>
\ No newline at end of file diff --git a/eaaf_modules/eaaf_module_pvp2_idp/src/test/resources/config/config_1.props b/eaaf_modules/eaaf_module_pvp2_idp/src/test/resources/config/config_1.props index 6324f190..164b8807 100644 --- a/eaaf_modules/eaaf_module_pvp2_idp/src/test/resources/config/config_1.props +++ b/eaaf_modules/eaaf_module_pvp2_idp/src/test/resources/config/config_1.props @@ -7,8 +7,6 @@ key.sig.pass=password key.enc.alias= key.enc.pass= -pvp2.assertion.encryption.active=true - client.http.connection.timeout.socket=2 client.http.connection.timeout.connection=2 client.http.connection.timeout.request=2
\ No newline at end of file diff --git a/eaaf_modules/eaaf_module_pvp2_idp/src/test/resources/config/config_2.props b/eaaf_modules/eaaf_module_pvp2_idp/src/test/resources/config/config_2.props new file mode 100644 index 00000000..60cecebb --- /dev/null +++ b/eaaf_modules/eaaf_module_pvp2_idp/src/test/resources/config/config_2.props @@ -0,0 +1,12 @@ +keystore.path=classpath:/data/junit.jks +keystore.pass=password +key.metadata.alias=shibboleth-sign +key.metadata.pass=password +key.sig.alias=shibboleth-sign +key.sig.pass=password +key.enc.alias= +key.enc.pass= + +client.http.connection.timeout.socket=2 +client.http.connection.timeout.connection=2 +client.http.connection.timeout.request=2
\ No newline at end of file diff --git a/eaaf_modules/eaaf_module_pvp2_idp/src/test/resources/spring/test_eaaf_core.beans.xml b/eaaf_modules/eaaf_module_pvp2_idp/src/test/resources/spring/test_eaaf_core.beans.xml index f46b7747..99552053 100644 --- a/eaaf_modules/eaaf_module_pvp2_idp/src/test/resources/spring/test_eaaf_core.beans.xml +++ b/eaaf_modules/eaaf_module_pvp2_idp/src/test/resources/spring/test_eaaf_core.beans.xml @@ -25,4 +25,7 @@ <bean id="dummyRevisionLogger" class="at.gv.egiz.eaaf.core.impl.logging.DummyRevisionsLogger" /> + <bean id="eaafKeyStoreFactory" + class="at.gv.egiz.eaaf.core.impl.credential.EaafKeyStoreFactory" /> + </beans>
\ No newline at end of file |