aboutsummaryrefslogtreecommitdiff
path: root/id/server/modules/moa-id-module-eIDAS
diff options
context:
space:
mode:
Diffstat (limited to 'id/server/modules/moa-id-module-eIDAS')
-rw-r--r--id/server/modules/moa-id-module-eIDAS/pom.xml16
-rw-r--r--id/server/modules/moa-id-module-eIDAS/src/main/java/at/gv/egovernment/moa/id/auth/modules/eidas/Constants.java18
-rw-r--r--id/server/modules/moa-id-module-eIDAS/src/main/java/at/gv/egovernment/moa/id/auth/modules/eidas/config/MOAExtendedSWSigner.java479
-rw-r--r--id/server/modules/moa-id-module-eIDAS/src/main/java/at/gv/egovernment/moa/id/auth/modules/eidas/config/ModifiedEncryptionSW.java8
-rw-r--r--id/server/modules/moa-id-module-eIDAS/src/main/java/at/gv/egovernment/moa/id/auth/modules/eidas/engine/MOAProtocolEngine.java68
-rw-r--r--id/server/modules/moa-id-module-eIDAS/src/main/java/at/gv/egovernment/moa/id/auth/modules/eidas/tasks/GenerateAuthnRequestTask.java61
-rw-r--r--id/server/modules/moa-id-module-eIDAS/src/main/java/at/gv/egovernment/moa/id/auth/modules/eidas/tasks/ReceiveAuthnResponseTask.java14
-rw-r--r--id/server/modules/moa-id-module-eIDAS/src/main/java/at/gv/egovernment/moa/id/auth/modules/eidas/utils/MOAProtocolEngineFactory.java17
-rw-r--r--id/server/modules/moa-id-module-eIDAS/src/main/java/at/gv/egovernment/moa/id/auth/modules/eidas/utils/MOAWhiteListConfigurator.java12
-rw-r--r--id/server/modules/moa-id-module-eIDAS/src/main/java/at/gv/egovernment/moa/id/auth/modules/eidas/utils/MOAeIDASMetadataGenerator.java33
-rw-r--r--id/server/modules/moa-id-module-eIDAS/src/main/java/at/gv/egovernment/moa/id/auth/modules/eidas/utils/SAMLEngineUtils.java6
-rw-r--r--id/server/modules/moa-id-module-eIDAS/src/main/java/at/gv/egovernment/moa/id/auth/modules/eidas/utils/eIDASAttributeProcessingUtils.java75
-rw-r--r--id/server/modules/moa-id-module-eIDAS/src/main/java/at/gv/egovernment/moa/id/protocols/eidas/EIDASProtocol.java53
-rw-r--r--id/server/modules/moa-id-module-eIDAS/src/main/java/at/gv/egovernment/moa/id/protocols/eidas/EidasMetaDataRequest.java16
-rw-r--r--id/server/modules/moa-id-module-eIDAS/src/main/java/at/gv/egovernment/moa/id/protocols/eidas/eIDASAuthenticationRequest.java53
-rw-r--r--id/server/modules/moa-id-module-eIDAS/src/main/java/at/gv/egovernment/moa/id/protocols/eidas/validator/eIDASResponseValidator.java130
-rw-r--r--id/server/modules/moa-id-module-eIDAS/src/main/resources/resources/templates/eidas_postbinding_template.vm2
17 files changed, 950 insertions, 111 deletions
diff --git a/id/server/modules/moa-id-module-eIDAS/pom.xml b/id/server/modules/moa-id-module-eIDAS/pom.xml
index 174ce40cb..55d02e82a 100644
--- a/id/server/modules/moa-id-module-eIDAS/pom.xml
+++ b/id/server/modules/moa-id-module-eIDAS/pom.xml
@@ -12,11 +12,11 @@
<properties>
<repositoryPath>${basedir}/../../../../repository</repositoryPath>
- <eidas-commons.version>1.1.0</eidas-commons.version>
- <eidas-light-commons.version>1.1.0</eidas-light-commons.version>
- <eidas-saml-engine.version>1.1.0</eidas-saml-engine.version>
- <eidas-encryption.version>1.1.0</eidas-encryption.version>
- <eidas-configmodule.version>1.1.0</eidas-configmodule.version>
+ <eidas-commons.version>1.2.0</eidas-commons.version>
+ <eidas-light-commons.version>1.2.0</eidas-light-commons.version>
+ <eidas-saml-engine.version>1.2.0</eidas-saml-engine.version>
+ <eidas-encryption.version>1.2.0</eidas-encryption.version>
+ <eidas-configmodule.version>1.2.0</eidas-configmodule.version>
</properties>
@@ -166,6 +166,12 @@
<!-- <scope>provided</scope> -->
</dependency>
+ <dependency>
+ <groupId>com.ibm.icu</groupId>
+ <artifactId>icu4j</artifactId>
+ <version>58.2</version>
+ </dependency>
+
</dependencies>
diff --git a/id/server/modules/moa-id-module-eIDAS/src/main/java/at/gv/egovernment/moa/id/auth/modules/eidas/Constants.java b/id/server/modules/moa-id-module-eIDAS/src/main/java/at/gv/egovernment/moa/id/auth/modules/eidas/Constants.java
index 02c9a8f5d..369d77863 100644
--- a/id/server/modules/moa-id-module-eIDAS/src/main/java/at/gv/egovernment/moa/id/auth/modules/eidas/Constants.java
+++ b/id/server/modules/moa-id-module-eIDAS/src/main/java/at/gv/egovernment/moa/id/auth/modules/eidas/Constants.java
@@ -22,6 +22,7 @@
*/
package at.gv.egovernment.moa.id.auth.modules.eidas;
+import org.apache.xml.security.signature.XMLSignature;
import org.opensaml.xml.encryption.EncryptionConstants;
import org.opensaml.xml.signature.SignatureConstants;
//import eu.eidas.auth.engine.core.validator.eidas.EIDASAttributes;
@@ -45,7 +46,8 @@ public class Constants {
public static final String eIDAS_SAML_ENGINE_NAME_ID_CLASS = "class";
//default implementations for eIDAS SAML-engine functionality
- public static final String SAML_SIGNING_IMPLENTATION = "at.gv.egovernment.moa.id.auth.modules.eidas.config.MOASWSigner";
+ //public static final String SAML_SIGNING_IMPLENTATION = "at.gv.egovernment.moa.id.auth.modules.eidas.config.MOASWSigner";
+ public static final String SAML_SIGNING_IMPLENTATION = "at.gv.egovernment.moa.id.auth.modules.eidas.config.MOAExtendedSWSigner";
public static final String SAML_ENCRYPTION_IMPLENTATION = "at.gv.egovernment.moa.id.auth.modules.eidas.config.ModifiedEncryptionSW";
//configuration property keys
@@ -96,8 +98,6 @@ public class Constants {
public static final int eIDAS_REVERSIONSLOG_METADATA = 3400;
public static final int eIDAS_REVERSIONSLOG_IDP_AUTHREQUEST = 3401;
public static final int eIDAS_REVERSIONSLOG_IDP_AUTHRESPONSE = 3402;
- public static final int eIDAS_REVERSIONSLOG_SP_AUTHREQUEST= 3403;
- public static final int eIDAS_REVERSIONSLOG_SP_AUTHRESPONSE= 3404;
//metadata constants
// public final static Map<String, EidasAttributesTypes> METADATA_POSSIBLE_ATTRIBUTES = Collections.unmodifiableMap(
@@ -133,16 +133,20 @@ public class Constants {
public static final String METADATA_ALLOWED_ALG_DIGIST =
- SignatureConstants.ALGO_ID_SIGNATURE_RSA_SHA256 + ";" +
- SignatureConstants.ALGO_ID_SIGNATURE_RSA_SHA512 ;
+ SignatureConstants.ALGO_ID_DIGEST_SHA256 + ";" +
+ SignatureConstants.ALGO_ID_DIGEST_SHA512 ;
public static final String METADATA_ALLOWED_ALG_SIGN =
SignatureConstants.ALGO_ID_SIGNATURE_RSA_SHA256 + ";" +
- SignatureConstants.ALGO_ID_SIGNATURE_RSA_SHA512;
+ SignatureConstants.ALGO_ID_SIGNATURE_RSA_SHA512 + ";" +
+ XMLSignature.ALGO_ID_SIGNATURE_RSA_SHA256_MGF1 + ";" +
+ XMLSignature.ALGO_ID_SIGNATURE_RSA_SHA512_MGF1;
public static final String METADATA_ALLOWED_ALG_ENCRYPT =
EncryptionConstants.ALGO_ID_BLOCKCIPHER_AES128_GCM + ";" +
EncryptionConstants.ALGO_ID_BLOCKCIPHER_AES192_GCM + ";" +
- EncryptionConstants.ALGO_ID_BLOCKCIPHER_AES256_GCM;
+ EncryptionConstants.ALGO_ID_BLOCKCIPHER_AES256_GCM + ";" +
+ EncryptionConstants.ALGO_ID_BLOCKCIPHER_AES128 + ";" +
+ EncryptionConstants.ALGO_ID_BLOCKCIPHER_AES256;
}
diff --git a/id/server/modules/moa-id-module-eIDAS/src/main/java/at/gv/egovernment/moa/id/auth/modules/eidas/config/MOAExtendedSWSigner.java b/id/server/modules/moa-id-module-eIDAS/src/main/java/at/gv/egovernment/moa/id/auth/modules/eidas/config/MOAExtendedSWSigner.java
new file mode 100644
index 000000000..e08d302f6
--- /dev/null
+++ b/id/server/modules/moa-id-module-eIDAS/src/main/java/at/gv/egovernment/moa/id/auth/modules/eidas/config/MOAExtendedSWSigner.java
@@ -0,0 +1,479 @@
+/*
+ * Copyright 2014 Federal Chancellery Austria
+ * MOA-ID has been developed in a cooperation between BRZ, the Federal
+ * Chancellery Austria - ICT staff unit, and Graz University of Technology.
+ *
+ * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by
+ * the European Commission - subsequent versions of the EUPL (the "Licence");
+ * You may not use this work except in compliance with the Licence.
+ * You may obtain a copy of the Licence at:
+ * http://www.osor.eu/eupl/
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the Licence is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the Licence for the specific language governing permissions and
+ * limitations under the Licence.
+ *
+ * This product combines work with different licenses. See the "NOTICE" text
+ * file for details on the various modules and licenses.
+ * The "NOTICE" text file is part of the distribution. Any derivative works
+ * that you distribute must include a readable copy of the "NOTICE" text file.
+ */
+package at.gv.egovernment.moa.id.auth.modules.eidas.config;
+
+import java.security.KeyStore;
+import java.security.cert.X509Certificate;
+import java.util.Collection;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.commons.collections.CollectionUtils;
+import org.apache.commons.lang.StringUtils;
+import org.apache.xml.security.signature.XMLSignature;
+import org.opensaml.Configuration;
+import org.opensaml.common.impl.SAMLObjectContentReference;
+import org.opensaml.security.SAMLSignatureProfileValidator;
+import org.opensaml.xml.io.MarshallingException;
+import org.opensaml.xml.security.SecurityConfiguration;
+import org.opensaml.xml.security.SecurityException;
+import org.opensaml.xml.security.SecurityHelper;
+import org.opensaml.xml.security.credential.Credential;
+import org.opensaml.xml.security.keyinfo.KeyInfoGenerator;
+import org.opensaml.xml.security.keyinfo.KeyInfoGeneratorFactory;
+import org.opensaml.xml.security.keyinfo.KeyInfoGeneratorManager;
+import org.opensaml.xml.security.keyinfo.NamedKeyInfoGeneratorManager;
+import org.opensaml.xml.security.x509.X509Credential;
+import org.opensaml.xml.signature.KeyInfo;
+import org.opensaml.xml.signature.SignableXMLObject;
+import org.opensaml.xml.signature.Signature;
+import org.opensaml.xml.signature.SignatureException;
+import org.opensaml.xml.signature.SignatureValidator;
+import org.opensaml.xml.signature.Signer;
+import org.opensaml.xml.validation.ValidationException;
+
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.ImmutableSet;
+import com.sun.istack.Nullable;
+
+import at.gv.egovernment.moa.id.auth.modules.eidas.Constants;
+import at.gv.egovernment.moa.id.auth.modules.eidas.utils.MOAWhiteListConfigurator;
+import at.gv.egovernment.moa.logging.Logger;
+import eu.eidas.auth.commons.EidasErrorKey;
+import eu.eidas.auth.engine.configuration.SamlEngineConfigurationException;
+import eu.eidas.auth.engine.configuration.dom.ConfigurationAdapter;
+import eu.eidas.auth.engine.configuration.dom.ConfigurationKey;
+import eu.eidas.auth.engine.configuration.dom.KeyStoreSignatureConfigurator;
+import eu.eidas.auth.engine.configuration.dom.SignatureConfiguration;
+import eu.eidas.auth.engine.core.ProtocolSignerI;
+import eu.eidas.auth.engine.core.impl.BouncyCastleBootstrap;
+import eu.eidas.auth.engine.core.impl.CertificateValidator;
+import eu.eidas.auth.engine.metadata.MetadataSignerI;
+import eu.eidas.auth.engine.xml.opensaml.CertificateUtil;
+import eu.eidas.engine.exceptions.EIDASSAMLEngineException;
+import eu.eidas.samlengineconfig.CertificateConfigurationManager;
+import eu.eidas.util.Preconditions;
+
+/**
+ * @author tlenz
+ *
+ */
+public class MOAExtendedSWSigner implements ProtocolSignerI, MetadataSignerI {
+
+ private static final String DEFAULT_SIGNATURE_ALGORITHM = "http://www.w3.org/2001/04/xmldsig-more#rsa-sha512";
+ private static final ImmutableSet<String> ALLOWED_ALGORITHMS_FOR_SIGNING;
+ private static final ImmutableSet<String> ALLOWED_ALGORITHMS_FOR_VERIFYING;
+ private static final ImmutableSet<String> DEFAULT_ALGORITHM_WHITE_LIST;
+ private static final String DEFAULT_DIGEST_ALGORITHM = "http://www.w3.org/2001/04/xmlenc#sha512";
+ private static final ImmutableMap<Object, Object> SIGNATURE_TO_DIGEST_ALGORITHM_MAP;
+ private final boolean checkedValidityPeriod;
+ private final boolean disallowedSelfSignedCertificate;
+ private final boolean responseSignAssertions;
+ private final ImmutableSet<String> signatureAlgorithmWhiteList;
+ private final X509Credential privateSigningCredential;
+ private final X509Credential publicSigningCredential;
+ private final X509Credential privateMetadataSigningCredential;
+ private final X509Credential publicMetadataSigningCredential;
+ private final ImmutableList<X509Credential> trustedCredentials;
+ private final String signatureAlgorithm;
+
+ public MOAExtendedSWSigner(Map<String, String> properties) throws SamlEngineConfigurationException {
+ this(new KeyStoreSignatureConfigurator().getSignatureConfiguration(properties));
+
+ }
+
+ /**
+ * @param configManager
+ * @throws SamlEngineConfigurationException
+ */
+ public MOAExtendedSWSigner(CertificateConfigurationManager configManager) throws SamlEngineConfigurationException {
+ this(new KeyStoreSignatureConfigurator().getSignatureConfiguration(
+ ConfigurationAdapter.adapt(configManager).getInstances().get(Constants.eIDAS_SAML_ENGINE_NAME).getConfigurationEntries().get(ConfigurationKey.SIGNATURE_CONFIGURATION.getKey()).getParameters()));
+
+ }
+
+ protected MOAExtendedSWSigner(SignatureConfiguration signatureConfiguration)
+ throws SamlEngineConfigurationException {
+ this(signatureConfiguration.isCheckedValidityPeriod(),
+ signatureConfiguration.isDisallowedSelfSignedCertificate(),
+ signatureConfiguration.isResponseSignAssertions(),
+ signatureConfiguration.getSignatureKeyAndCertificate(), signatureConfiguration.getTrustedCertificates(),
+ signatureConfiguration.getSignatureAlgorithm(), signatureConfiguration.getSignatureAlgorithmWhiteList(),
+ signatureConfiguration.getMetadataSigningKeyAndCertificate());
+ }
+
+ protected MOAExtendedSWSigner(boolean checkedValidityPeriod, boolean disallowedSelfSignedCertificate,
+ boolean responseSignAssertions, KeyStore.PrivateKeyEntry signatureKeyAndCertificate,
+ ImmutableSet<X509Certificate> trustedCertificates, String signatureAlgorithmVal,
+ String signatureAlgorithmWhiteListStr,
+ KeyStore.PrivateKeyEntry metadataSigningKeyAndCertificate)
+ throws SamlEngineConfigurationException {
+ Preconditions.checkNotNull(signatureKeyAndCertificate, "signatureKeyAndCertificate");
+ Preconditions.checkNotNull(trustedCertificates, "trustedCertificates");
+ String signatureAlg = signatureAlgorithmVal;
+
+ if (StringUtils.isBlank(signatureAlg))
+ signatureAlg = DEFAULT_SIGNATURE_ALGORITHM;
+
+ else {
+ signatureAlg = validateSigningAlgorithm(signatureAlg);
+
+ }
+
+ ImmutableSet signatureAlgorithmWhiteSet = MOAWhiteListConfigurator.getAllowedAlgorithms(
+ DEFAULT_ALGORITHM_WHITE_LIST, ALLOWED_ALGORITHMS_FOR_VERIFYING, signatureAlgorithmWhiteListStr);
+
+ this.checkedValidityPeriod = checkedValidityPeriod;
+ this.disallowedSelfSignedCertificate = disallowedSelfSignedCertificate;
+ this.responseSignAssertions = responseSignAssertions;
+ this.trustedCredentials = CertificateUtil.getListOfCredential(trustedCertificates);
+ this.signatureAlgorithmWhiteList = signatureAlgorithmWhiteSet;
+ this.signatureAlgorithm = signatureAlg;
+ this.privateSigningCredential = CertificateUtil.createCredential(signatureKeyAndCertificate);
+ this.publicSigningCredential = CertificateUtil
+ .toCredential((X509Certificate) signatureKeyAndCertificate.getCertificate());
+
+ if (null != metadataSigningKeyAndCertificate) {
+ this.privateMetadataSigningCredential = CertificateUtil.createCredential(metadataSigningKeyAndCertificate);
+ this.publicMetadataSigningCredential = CertificateUtil
+ .toCredential((X509Certificate) metadataSigningKeyAndCertificate.getCertificate());
+ } else {
+ this.privateMetadataSigningCredential = null;
+ this.publicMetadataSigningCredential = null;
+ }
+ }
+
+ private static X509Certificate getSignatureCertificate(Signature signature) throws EIDASSAMLEngineException {
+ KeyInfo keyInfo = signature.getKeyInfo();
+ return CertificateUtil.toCertificate(keyInfo);
+ }
+
+ public static String validateDigestAlgorithm(String signatureAlgorithmName)
+ throws SamlEngineConfigurationException {
+
+ if (StringUtils.isBlank(signatureAlgorithmName)) {
+ return DEFAULT_DIGEST_ALGORITHM;
+
+ }
+
+ //BUGFIX: toLowerCase from original eIDAS SAML-engine produce problems with MGF1 signature algorithms
+ String canonicalAlgorithm = signatureAlgorithmName.trim();
+ String digestAlgorithm = (String) SIGNATURE_TO_DIGEST_ALGORITHM_MAP.get(canonicalAlgorithm);
+ if (null != digestAlgorithm) {
+ return digestAlgorithm;
+
+ }
+ String msg = "Signing algorithm \"" + signatureAlgorithmName
+ + "\" does not contain an allowed digest algorithm";
+
+ Logger.error(msg);
+ throw new SamlEngineConfigurationException(msg);
+
+ }
+
+ public static String validateSigningAlgorithm(@Nullable String signatureAlgorithmName)
+ throws SamlEngineConfigurationException {
+ if ((signatureAlgorithmName == null) || (StringUtils.isBlank(signatureAlgorithmName))) {
+ return DEFAULT_SIGNATURE_ALGORITHM;
+
+ }
+
+ //BUGFIX:: toLowerCase from original eIDAS SAML-engine produce problems with MGF1 signature algorithms
+ String canonicalAlgorithm = signatureAlgorithmName.trim();
+ if (ALLOWED_ALGORITHMS_FOR_SIGNING.contains(canonicalAlgorithm)) {
+ return canonicalAlgorithm;
+
+ }
+ String msg = "Signing algorithm \"" + signatureAlgorithmName + "\" is not allowed";
+ Logger.error(msg);
+ throw new SamlEngineConfigurationException(msg);
+
+ }
+
+ protected void checkCertificateIssuer(X509Certificate certificate) throws EIDASSAMLEngineException {
+ CertificateValidator.checkCertificateIssuer(this.disallowedSelfSignedCertificate, certificate);
+
+ }
+
+ protected void checkCertificateValidityPeriod(X509Certificate certificate) throws EIDASSAMLEngineException {
+ CertificateValidator.checkCertificateValidityPeriod(this.checkedValidityPeriod, certificate);
+
+ }
+
+ protected Signature createSignature(X509Credential credential) throws EIDASSAMLEngineException {
+ checkCertificateValidityPeriod(credential.getEntityCertificate());
+ checkCertificateIssuer(credential.getEntityCertificate());
+ Signature signature;
+ try {
+ Logger.debug("Creating an OpenSAML signature object");
+
+ signature = (Signature) Configuration.getBuilderFactory().getBuilder(Signature.DEFAULT_ELEMENT_NAME)
+ .buildObject(Signature.DEFAULT_ELEMENT_NAME);
+
+ signature.setSigningCredential(credential);
+
+ signature.setSignatureAlgorithm(getSignatureAlgorithm());
+
+ SecurityConfiguration secConfiguration = Configuration.getGlobalSecurityConfiguration();
+ NamedKeyInfoGeneratorManager keyInfoManager = secConfiguration.getKeyInfoGeneratorManager();
+ KeyInfoGeneratorManager keyInfoGenManager = keyInfoManager.getDefaultManager();
+ KeyInfoGeneratorFactory keyInfoGenFac = keyInfoGenManager.getFactory(credential);
+ KeyInfoGenerator keyInfoGenerator = keyInfoGenFac.newInstance();
+
+ KeyInfo keyInfo = keyInfoGenerator.generate(credential);
+
+ signature.setKeyInfo(keyInfo);
+ signature.setCanonicalizationAlgorithm("http://www.w3.org/2001/10/xml-exc-c14n#");
+ } catch (SecurityException e) {
+ Logger.error("ERROR : Security exception: " + e, e);
+ throw new EIDASSAMLEngineException(e);
+
+ }
+ return signature;
+ }
+
+ public X509Credential getPublicMetadataSigningCredential() {
+ return this.publicMetadataSigningCredential;
+
+ }
+
+ public X509Credential getPublicSigningCredential() {
+ return this.publicSigningCredential;
+
+ }
+
+ protected String getSignatureAlgorithm() {
+ return this.signatureAlgorithm;
+
+ }
+
+ protected ImmutableSet<String> getSignatureAlgorithmWhiteList() {
+ return this.signatureAlgorithmWhiteList;
+
+ }
+
+ private X509Credential getTrustedCertificate(Signature signature,
+ List<? extends Credential> trustedCredentialList) throws EIDASSAMLEngineException {
+ X509Certificate cert = getSignatureCertificate(signature);
+
+ X509Credential entityX509Cred = CertificateUtil.toCredential(cert);
+
+ CertificateUtil.checkTrust(entityX509Cred, trustedCredentialList);
+ checkCertificateValidityPeriod(cert);
+ checkCertificateIssuer(cert);
+ return entityX509Cred;
+
+ }
+
+ protected ImmutableList<X509Credential> getTrustedCredentials() {
+ return this.trustedCredentials;
+
+ }
+
+ private boolean isAlgorithmAllowedForVerifying(String signatureAlgorithm) {
+ return ((StringUtils.isNotBlank(signatureAlgorithm))
+ && (getSignatureAlgorithmWhiteList().contains(signatureAlgorithm.trim())));
+
+ }
+
+ public <T extends SignableXMLObject> T sign(T signableObject) throws EIDASSAMLEngineException {
+ return sign(signableObject, this.privateSigningCredential);
+
+ }
+
+ protected <T extends SignableXMLObject> T sign(T signableObject, X509Credential signingCredential)
+ throws EIDASSAMLEngineException {
+ Logger.trace("Start Sign process.");
+ try {
+ Signature signature = createSignature(signingCredential);
+ signableObject.setSignature(signature);
+
+ String digestAlgorithm = validateDigestAlgorithm(getSignatureAlgorithm());
+ List contentReferences = signature.getContentReferences();
+ if (CollectionUtils.isNotEmpty(contentReferences))
+ ((SAMLObjectContentReference) contentReferences.get(0)).setDigestAlgorithm(digestAlgorithm);
+
+ else {
+ Logger.error("Unable to set DigestMethodAlgorithm - algorithm " + digestAlgorithm + " not set");
+
+ }
+
+ Logger.trace("Marshall samlToken.");
+ Configuration.getMarshallerFactory().getMarshaller(signableObject).marshall(signableObject);
+
+ Logger.trace("Sign samlToken.");
+ Signer.signObject(signature);
+
+ } catch (MarshallingException e) {
+ Logger.error("ERROR : MarshallingException: " + e, e);
+ throw new EIDASSAMLEngineException(e);
+
+ } catch (SignatureException e) {
+ Logger.error("ERROR : Signature exception: " + e, e);
+ throw new EIDASSAMLEngineException(e);
+
+ }
+
+ return signableObject;
+ }
+
+ public <T extends SignableXMLObject> T signMetadata(T signableObject) throws EIDASSAMLEngineException {
+ if (null == this.privateMetadataSigningCredential) {
+ throw new SamlEngineConfigurationException("No metadataSigningCredential configured");
+
+ }
+ return sign(signableObject, this.privateMetadataSigningCredential);
+ }
+
+ public <T extends SignableXMLObject> T validateMetadataSignature(T signedMetadata)
+ throws EIDASSAMLEngineException {
+ return validateSignature(signedMetadata, null);
+
+ }
+
+ private SAMLSignatureProfileValidator validateSamlSignatureStructure(SignableXMLObject signableObject)
+ throws EIDASSAMLEngineException {
+ SAMLSignatureProfileValidator sigProfValidator = new SAMLSignatureProfileValidator();
+ try {
+ sigProfValidator.validate(signableObject.getSignature());
+
+ } catch (ValidationException e) {
+ Logger.error("ERROR : ValidationException: signature isn't conform to SAML Signature profile: " + e, e);
+ throw new EIDASSAMLEngineException(e);
+
+ }
+ return sigProfValidator;
+ }
+
+ public <T extends SignableXMLObject> T validateSignature(T signedObject,
+ Collection<X509Certificate> trustedCertificateCollection) throws EIDASSAMLEngineException {
+ List trustedCreds;
+ if (CollectionUtils.isEmpty(trustedCertificateCollection))
+ trustedCreds = getTrustedCredentials();
+
+ else {
+ trustedCreds = CertificateUtil.getListOfCredential(trustedCertificateCollection);
+
+ }
+ return (T) validateSignatureWithCredentials(signedObject, trustedCreds);
+ }
+
+ private <T extends SignableXMLObject> T validateSignatureWithCredentials(T signedObject,
+ List<? extends Credential> trustedCredentialList) throws EIDASSAMLEngineException {
+ Logger.debug("Start signature validation.");
+
+ validateSamlSignatureStructure(signedObject);
+
+ verifyCryptographicSignature(signedObject.getSignature(), trustedCredentialList);
+
+ return signedObject;
+
+ }
+
+ private void verifyCryptographicSignature(Signature signature,
+ List<? extends Credential> trustedCredentialList) throws EIDASSAMLEngineException {
+ String signatureAlgorithmVal = signature.getSignatureAlgorithm();
+ Logger.trace("Key algorithm " + SecurityHelper.getKeyAlgorithmFromURI(signatureAlgorithmVal));
+
+ if (!(isAlgorithmAllowedForVerifying(signatureAlgorithmVal))) {
+ Logger.error("ERROR : the algorithm " + signatureAlgorithmVal + " used by the signature is not allowed");
+ throw new EIDASSAMLEngineException(EidasErrorKey.INVALID_SIGNATURE_ALGORITHM.errorCode());
+
+ }
+
+ X509Credential entityX509Cred = getTrustedCertificate(signature, trustedCredentialList);
+ SignatureValidator sigValidator = new SignatureValidator(entityX509Cred);
+
+ try {
+ sigValidator.validate(signature);
+
+ } catch (ValidationException e) {
+ Logger.error("ERROR : Signature Validation Exception: " + e, e);
+ throw new EIDASSAMLEngineException(e);
+
+ }
+ }
+
+ public boolean isResponseSignAssertions() {
+ return this.responseSignAssertions;
+ }
+
+ static {
+ BouncyCastleBootstrap.bootstrap();
+
+ ALLOWED_ALGORITHMS_FOR_SIGNING = ImmutableSet.of("http://www.w3.org/2001/04/xmldsig-more#rsa-sha256",
+ "http://www.w3.org/2001/04/xmldsig-more#rsa-sha384",
+ "http://www.w3.org/2001/04/xmldsig-more#rsa-sha512",
+ "http://www.w3.org/2001/04/xmldsig-more#ecdsa-sha256",
+ "http://www.w3.org/2001/04/xmldsig-more#ecdsa-sha384",
+ "http://www.w3.org/2001/04/xmldsig-more#ecdsa-sha512",
+
+ //Set other algorithms which are not supported by openSAML in default
+ XMLSignature.ALGO_ID_SIGNATURE_RSA_SHA256_MGF1,
+ XMLSignature.ALGO_ID_SIGNATURE_RSA_SHA512_MGF1);
+
+ ALLOWED_ALGORITHMS_FOR_VERIFYING = ImmutableSet.of("http://www.w3.org/2001/04/xmldsig-more#rsa-sha256",
+ "http://www.w3.org/2001/04/xmldsig-more#rsa-sha384",
+ "http://www.w3.org/2001/04/xmldsig-more#rsa-sha512",
+ "http://www.w3.org/2001/04/xmldsig-more#rsa-ripemd160",
+ "http://www.w3.org/2001/04/xmldsig-more#ecdsa-sha256",
+ "http://www.w3.org/2001/04/xmldsig-more#ecdsa-sha384",
+ "http://www.w3.org/2001/04/xmldsig-more#ecdsa-sha512",
+
+ //Set other algorithms which are not supported by openSAML in default
+ XMLSignature.ALGO_ID_SIGNATURE_RSA_SHA1_MGF1,
+ XMLSignature.ALGO_ID_SIGNATURE_RSA_SHA224_MGF1,
+ XMLSignature.ALGO_ID_SIGNATURE_RSA_SHA256_MGF1,
+ XMLSignature.ALGO_ID_SIGNATURE_RSA_SHA384_MGF1,
+ XMLSignature.ALGO_ID_SIGNATURE_RSA_SHA512_MGF1);
+
+ DEFAULT_ALGORITHM_WHITE_LIST = ImmutableSet.of("http://www.w3.org/2001/04/xmldsig-more#rsa-sha256",
+ "http://www.w3.org/2001/04/xmldsig-more#rsa-sha384",
+ "http://www.w3.org/2001/04/xmldsig-more#rsa-sha512",
+ "http://www.w3.org/2001/04/xmldsig-more#ecdsa-sha256",
+ "http://www.w3.org/2001/04/xmldsig-more#ecdsa-sha384",
+ "http://www.w3.org/2001/04/xmldsig-more#ecdsa-sha512",
+
+ //Set other algorithms which are not supported by openSAML in default
+ XMLSignature.ALGO_ID_SIGNATURE_RSA_SHA256_MGF1);
+
+ SIGNATURE_TO_DIGEST_ALGORITHM_MAP = ImmutableMap.builder()
+ .put("http://www.w3.org/2001/04/xmldsig-more#rsa-sha256", "http://www.w3.org/2001/04/xmlenc#sha256")
+ .put("http://www.w3.org/2001/04/xmldsig-more#rsa-sha384",
+ "http://www.w3.org/2001/04/xmldsig-more#sha384")
+ .put("http://www.w3.org/2001/04/xmldsig-more#rsa-sha512", "http://www.w3.org/2001/04/xmlenc#sha512")
+ .put("http://www.w3.org/2001/04/xmldsig-more#rsa-ripemd160",
+ "http://www.w3.org/2001/04/xmlenc#ripemd160")
+ .put("http://www.w3.org/2001/04/xmldsig-more#ecdsa-sha256", "http://www.w3.org/2001/04/xmlenc#sha256")
+ .put("http://www.w3.org/2001/04/xmldsig-more#ecdsa-sha384",
+ "http://www.w3.org/2001/04/xmldsig-more#sha384")
+ .put("http://www.w3.org/2001/04/xmldsig-more#ecdsa-sha512", "http://www.w3.org/2001/04/xmlenc#sha512")
+
+ //Set other algorithms which are not supported by openSAML in default
+ .put(XMLSignature.ALGO_ID_SIGNATURE_RSA_SHA256_MGF1, "http://www.w3.org/2001/04/xmlenc#sha256")
+ .put(XMLSignature.ALGO_ID_SIGNATURE_RSA_SHA512_MGF1, "http://www.w3.org/2001/04/xmlenc#sha512")
+
+ .build();
+ }
+}
diff --git a/id/server/modules/moa-id-module-eIDAS/src/main/java/at/gv/egovernment/moa/id/auth/modules/eidas/config/ModifiedEncryptionSW.java b/id/server/modules/moa-id-module-eIDAS/src/main/java/at/gv/egovernment/moa/id/auth/modules/eidas/config/ModifiedEncryptionSW.java
index 9ad5f0db3..de4f3fc9c 100644
--- a/id/server/modules/moa-id-module-eIDAS/src/main/java/at/gv/egovernment/moa/id/auth/modules/eidas/config/ModifiedEncryptionSW.java
+++ b/id/server/modules/moa-id-module-eIDAS/src/main/java/at/gv/egovernment/moa/id/auth/modules/eidas/config/ModifiedEncryptionSW.java
@@ -90,17 +90,21 @@ public class ModifiedEncryptionSW extends KeyStoreSamlEngineEncryption {
*/
@Override
public boolean isEncryptionEnabled(String countryCode) {
- // - encrypt if so configured
+ //encryption is enabled by default in MOA-ID configuration object
try {
AuthConfiguration moaconfig = AuthConfigurationProviderFactory.getInstance();
Boolean useEncryption = moaconfig.getStorkConfig().getCPEPS(countryCode).isXMLSignatureSupported();
- Logger.info(useEncryption ? "using encryption" : "do not use encrpytion");
+ String logResult = useEncryption ? " using encryption" : " do not use encrpytion";
+ Logger.debug("eIDAS respone for country " + countryCode + logResult);
return useEncryption;
+
} catch(NullPointerException | ConfigurationException e) {
Logger.warn("failed to gather information about encryption for countryCode " + countryCode + " - thus, enabling encryption");
if(Logger.isDebugEnabled())
e.printStackTrace();
return true;
+
}
+
}
}
diff --git a/id/server/modules/moa-id-module-eIDAS/src/main/java/at/gv/egovernment/moa/id/auth/modules/eidas/engine/MOAProtocolEngine.java b/id/server/modules/moa-id-module-eIDAS/src/main/java/at/gv/egovernment/moa/id/auth/modules/eidas/engine/MOAProtocolEngine.java
new file mode 100644
index 000000000..d8fcd1694
--- /dev/null
+++ b/id/server/modules/moa-id-module-eIDAS/src/main/java/at/gv/egovernment/moa/id/auth/modules/eidas/engine/MOAProtocolEngine.java
@@ -0,0 +1,68 @@
+package at.gv.egovernment.moa.id.auth.modules.eidas.engine;
+
+import java.security.cert.X509Certificate;
+
+import org.apache.commons.lang3.StringUtils;
+import org.opensaml.saml2.core.Response;
+
+import at.gv.egovernment.moa.logging.Logger;
+import eu.eidas.auth.commons.EidasErrorKey;
+import eu.eidas.auth.commons.protocol.IAuthenticationRequest;
+import eu.eidas.auth.engine.ProtocolEngine;
+import eu.eidas.auth.engine.configuration.ProtocolConfigurationAccessor;
+import eu.eidas.auth.engine.xml.opensaml.SAMLEngineUtils;
+import eu.eidas.engine.exceptions.EIDASSAMLEngineException;
+
+public class MOAProtocolEngine extends ProtocolEngine {
+
+ public MOAProtocolEngine(ProtocolConfigurationAccessor configurationAccessor) {
+ super(configurationAccessor);
+
+ }
+
+// @Override
+// protected X509Certificate getEncryptionCertificate(String requestIssuer,
+// String destinationCountryCode) throws EIDASSAMLEngineException {
+// if ((StringUtils.isNotBlank(destinationCountryCode)) && (null != getProtocolEncrypter())
+// && (getProtocolEncrypter().isEncryptionEnabled(destinationCountryCode))) {
+// X509Certificate encryptionCertificate = getProtocolProcessor().getEncryptionCertificate(requestIssuer);
+//
+// if (null == encryptionCertificate) {
+// return getProtocolEncrypter().getEncryptionCertificate(destinationCountryCode);
+//
+// }
+// return encryptionCertificate;
+// }
+// return null;
+// }
+//
+// @Override
+// protected Response signResponse(IAuthenticationRequest request, Response response)
+// throws EIDASSAMLEngineException {
+// Response responseToSign = response;
+//
+// if ((null != getProtocolEncrypter()) && (!(SAMLEngineUtils.isErrorSamlResponse(responseToSign)))) {
+// X509Certificate destinationCertificate = getEncryptionCertificate(request.getIssuer(),
+// request.getOriginCountryCode());
+//
+// if (null != destinationCertificate) {
+// responseToSign = getProtocolEncrypter().encryptSamlResponse(responseToSign, destinationCertificate);
+//
+// } else if (getProtocolEncrypter().isEncryptionEnabled(request.getOriginCountryCode())) {
+//// Logger.error(SAML_EXCHANGE,
+//// "BUSINESS EXCEPTION : encryption cannot be performed, no matching certificate for issuer="
+//// + request.getIssuer() + " and country=" + request.getOriginCountryCode());
+//
+// throw new EIDASSAMLEngineException(EidasErrorKey.SAML_ENGINE_INVALID_CERTIFICATE.errorCode(),
+// EidasErrorKey.SAML_ENGINE_INVALID_CERTIFICATE.errorMessage());
+// }
+//
+// } else if (!(SAMLEngineUtils.isErrorSamlResponse(responseToSign))) {
+// checkSendingUnencryptedResponsesAllowed();
+//
+// }
+//
+// Logger.debug("Signing SAML Response.");
+// return ((Response) getSigner().sign(responseToSign));
+// }
+}
diff --git a/id/server/modules/moa-id-module-eIDAS/src/main/java/at/gv/egovernment/moa/id/auth/modules/eidas/tasks/GenerateAuthnRequestTask.java b/id/server/modules/moa-id-module-eIDAS/src/main/java/at/gv/egovernment/moa/id/auth/modules/eidas/tasks/GenerateAuthnRequestTask.java
index a9c4d5d3a..7155040c6 100644
--- a/id/server/modules/moa-id-module-eIDAS/src/main/java/at/gv/egovernment/moa/id/auth/modules/eidas/tasks/GenerateAuthnRequestTask.java
+++ b/id/server/modules/moa-id-module-eIDAS/src/main/java/at/gv/egovernment/moa/id/auth/modules/eidas/tasks/GenerateAuthnRequestTask.java
@@ -22,13 +22,10 @@
*/
package at.gv.egovernment.moa.id.auth.modules.eidas.tasks;
-import java.io.ByteArrayOutputStream;
import java.io.StringWriter;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
-import java.util.zip.Deflater;
-import java.util.zip.DeflaterOutputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@@ -42,7 +39,6 @@ import org.opensaml.common.xml.SAMLConstants;
import org.opensaml.saml2.metadata.EntityDescriptor;
import org.opensaml.saml2.metadata.SingleSignOnService;
import org.opensaml.saml2.metadata.provider.MetadataProviderException;
-import org.opensaml.xml.util.Base64;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
@@ -197,7 +193,17 @@ public class GenerateAuthnRequestTask extends AbstractAuthServletTask {
}
}
- //build requested attribute set
+ //request
+ if (reqAttrList.isEmpty()) {
+ Logger.info("No attributes requested by OA:" + pendingReq.getOnlineApplicationConfiguration().getPublicURLPrefix()
+ + " --> Request attr:" + Constants.eIDAS_ATTR_PERSONALIDENTIFIER + " by default");
+ AttributeDefinition<?> newAttribute = SAMLEngineUtils.getMapOfAllAvailableAttributes().get(Constants.eIDAS_ATTR_PERSONALIDENTIFIER);
+ Builder<?> attrBuilder = AttributeDefinition.builder(newAttribute).required(true);
+ reqAttrList.add(attrBuilder.build());
+
+ }
+
+ //build requested attribute set
ImmutableAttributeMap reqAttrMap = new ImmutableAttributeMap.Builder().putAll(reqAttrList).build();
//build eIDAS AuthnRequest
@@ -211,8 +217,13 @@ public class GenerateAuthnRequestTask extends AbstractAuthServletTask {
authnRequestBuilder.nameIdFormat(Constants.eIDAS_REQ_NAMEID_FORMAT);
- //set minimum required eIDAS LoA from OA config
- authnRequestBuilder.levelOfAssurance(LevelOfAssurance.fromString(oaConfig.getQaaLevel()));
+ //set minimum required eIDAS LoA from OA config
+ String LoA = oaConfig.getQaaLevel();
+ if (MiscUtil.isNotEmpty(LoA))
+ authnRequestBuilder.levelOfAssurance(LevelOfAssurance.fromString(oaConfig.getQaaLevel()));
+ else
+ authnRequestBuilder.levelOfAssurance(LevelOfAssurance.HIGH);
+
authnRequestBuilder.levelOfAssuranceComparison(LevelOfAssuranceComparison.MINIMUM);
//set correct SPType for this online application
@@ -234,7 +245,7 @@ public class GenerateAuthnRequestTask extends AbstractAuthServletTask {
IRequestMessage authnRequest = engine.generateRequestMessage(authnRequestBuilder.build(), issur);
-
+
//encode AuthnRequest
byte[] token = authnRequest.getMessageBytes();
String SAMLRequest = EidasStringUtil.encodeToBase64(token);
@@ -269,40 +280,6 @@ public class GenerateAuthnRequestTask extends AbstractAuthServletTask {
}
}
-
- /**
- * Encode the eIDAS request with Redirect binding
- *
- * @param pendingReq
- * @param authnReqEndpoint
- * @param token
- * @param authnRequest
- * @param response
- * @throws MOAIDException
- */
- private void buildRedirecttBindingRequest(IRequest pendingReq, SingleSignOnService authnReqEndpoint,
- byte[] token, IRequestMessage authnRequest, HttpServletResponse response)
- throws MOAIDException {
-
- //FIXME: implement correct deflat encoding accodring to SAML2 Redirect Binding specification
-
- try {
- ByteArrayOutputStream bytesOut = new ByteArrayOutputStream();
- Deflater deflater = new Deflater(Deflater.DEFLATED, true);
- DeflaterOutputStream deflaterStream = new DeflaterOutputStream(bytesOut, deflater);
- deflaterStream.write(token);
- deflaterStream.finish();
- String samlReqBase64 = Base64.encodeBytes(bytesOut.toByteArray(), Base64.DONT_BREAK_LINES);
-
-
-
- } catch (Exception e) {
- Logger.error("eIDAS Redirect-Binding request encoding error: " + e.getMessage());
- throw new MOAIDException("eIDAS.02", new Object[]{e.getMessage()}, e);
-
- }
-
- }
/**
* Encode the eIDAS request with POST binding
diff --git a/id/server/modules/moa-id-module-eIDAS/src/main/java/at/gv/egovernment/moa/id/auth/modules/eidas/tasks/ReceiveAuthnResponseTask.java b/id/server/modules/moa-id-module-eIDAS/src/main/java/at/gv/egovernment/moa/id/auth/modules/eidas/tasks/ReceiveAuthnResponseTask.java
index c4b2bfeae..45ba3d64e 100644
--- a/id/server/modules/moa-id-module-eIDAS/src/main/java/at/gv/egovernment/moa/id/auth/modules/eidas/tasks/ReceiveAuthnResponseTask.java
+++ b/id/server/modules/moa-id-module-eIDAS/src/main/java/at/gv/egovernment/moa/id/auth/modules/eidas/tasks/ReceiveAuthnResponseTask.java
@@ -19,12 +19,12 @@ import at.gv.egovernment.moa.id.auth.modules.eidas.utils.SAMLEngineUtils;
import at.gv.egovernment.moa.id.commons.api.exceptions.MOAIDException;
import at.gv.egovernment.moa.id.commons.db.ex.MOADatabaseException;
import at.gv.egovernment.moa.id.process.api.ExecutionContext;
+import at.gv.egovernment.moa.id.protocols.eidas.validator.eIDASResponseValidator;
import at.gv.egovernment.moa.id.protocols.pvp2x.PVPConstants;
import at.gv.egovernment.moa.logging.Logger;
import at.gv.egovernment.moa.util.MiscUtil;
import eu.eidas.auth.commons.EidasStringUtil;
import eu.eidas.auth.commons.protocol.IAuthenticationResponse;
-import eu.eidas.auth.commons.protocol.eidas.LevelOfAssurance;
import eu.eidas.auth.engine.ProtocolEngineI;
import eu.eidas.engine.exceptions.EIDASSAMLEngineException;
@@ -78,16 +78,8 @@ public class ReceiveAuthnResponseTask extends AbstractAuthServletTask {
// **********************************************************
// ******* MOA-ID specific response validation **********
// **********************************************************
-
- //validate received LoA against minimum required LoA
- LevelOfAssurance reqLoA = LevelOfAssurance.fromString(pendingReq.getOnlineApplicationConfiguration().getQaaLevel());
- LevelOfAssurance respLoA = LevelOfAssurance.fromString(samlResp.getLevelOfAssurance());
- if (respLoA.numericValue() < reqLoA.numericValue()) {
- Logger.error("eIDAS Response LevelOfAssurance is lower than the required! "
- + "(Resp-LoA:" + respLoA.getValue() + " Req-LoA:" + reqLoA.getValue() + ")");
- throw new MOAIDException("eIDAS.14", new Object[]{respLoA.getValue()});
-
- }
+ String spCountry = authConfig.getBasicMOAIDConfiguration(Constants.CONIG_PROPS_EIDAS_NODE_COUNTRYCODE, "AT");
+ eIDASResponseValidator.validateResponse(pendingReq, samlResp, spCountry);
// **********************************************************
diff --git a/id/server/modules/moa-id-module-eIDAS/src/main/java/at/gv/egovernment/moa/id/auth/modules/eidas/utils/MOAProtocolEngineFactory.java b/id/server/modules/moa-id-module-eIDAS/src/main/java/at/gv/egovernment/moa/id/auth/modules/eidas/utils/MOAProtocolEngineFactory.java
index f29d2bb65..47cdb4ade 100644
--- a/id/server/modules/moa-id-module-eIDAS/src/main/java/at/gv/egovernment/moa/id/auth/modules/eidas/utils/MOAProtocolEngineFactory.java
+++ b/id/server/modules/moa-id-module-eIDAS/src/main/java/at/gv/egovernment/moa/id/auth/modules/eidas/utils/MOAProtocolEngineFactory.java
@@ -95,5 +95,22 @@ public class MOAProtocolEngineFactory extends ProtocolEngineFactory {
}
+// public static ProtocolEngineI createProtocolEngine(String instanceName,
+// ProtocolEngineConfigurationFactory protocolEngineConfigurationFactory,
+// ProtocolProcessorI protocolProcessor, SamlEngineClock samlEngineClock)
+// throws SamlEngineConfigurationException {
+//
+// ProtocolEngineConfiguration preConfiguration = protocolEngineConfigurationFactory
+// .getConfiguration(instanceName);
+//
+// protocolProcessor.configure();
+//
+// ProtocolEngineConfiguration configuration = ProtocolEngineConfiguration.builder(preConfiguration)
+// .protocolProcessor(protocolProcessor).clock(samlEngineClock).build();
+//
+// ProtocolEngineI samlEngine = new MOAProtocolEngine(new FixedProtocolConfigurationAccessor(configuration));
+//
+// return samlEngine;
+// }
}
diff --git a/id/server/modules/moa-id-module-eIDAS/src/main/java/at/gv/egovernment/moa/id/auth/modules/eidas/utils/MOAWhiteListConfigurator.java b/id/server/modules/moa-id-module-eIDAS/src/main/java/at/gv/egovernment/moa/id/auth/modules/eidas/utils/MOAWhiteListConfigurator.java
index 7d647ff15..a2c6a3ad9 100644
--- a/id/server/modules/moa-id-module-eIDAS/src/main/java/at/gv/egovernment/moa/id/auth/modules/eidas/utils/MOAWhiteListConfigurator.java
+++ b/id/server/modules/moa-id-module-eIDAS/src/main/java/at/gv/egovernment/moa/id/auth/modules/eidas/utils/MOAWhiteListConfigurator.java
@@ -22,7 +22,6 @@
*/
package at.gv.egovernment.moa.id.auth.modules.eidas.utils;
-import java.util.Locale;
import java.util.regex.Pattern;
import org.apache.commons.collections.CollectionUtils;
@@ -48,6 +47,11 @@ public class MOAWhiteListConfigurator {
}
ImmutableSet.Builder<String> allowed = ImmutableSet.builder();
String[] wlAlgorithms = WHITE_LIST_SPLITTER.split(algorithmWhiteListValue);
+
+ //BugFix: remove newlines from configuration
+ for (int i=0; i<wlAlgorithms.length; i++)
+ wlAlgorithms[i] = StringUtils.trimToNull(KeyValueUtils.removeAllNewlineFromString(wlAlgorithms[i]));
+
if (null != wlAlgorithms && wlAlgorithms.length > 0) {
return getAllowedAlgorithms(defaultWhiteList, allowedValues, ImmutableSet.<String>copyOf(wlAlgorithms));
}
@@ -72,7 +76,11 @@ public class MOAWhiteListConfigurator {
candidateValue = StringUtils.trimToNull(
KeyValueUtils.removeAllNewlineFromString(candidateValue));
if (StringUtils.isNotBlank(candidateValue)) {
- String candidateAlgorithm = StringUtils.lowerCase(candidateValue, Locale.ENGLISH);
+
+ //BUGFIX: eIDAS SAML-engine MPF1 signature schemes problem
+ String candidateAlgorithm = candidateValue;
+ //String candidateAlgorithm = StringUtils.lowerCase(candidateValue, Locale.ENGLISH);
+
if (allowedValues.contains(candidateAlgorithm)) {
allowed.add(candidateValue);
if (!modified && !candidateAlgorithm.equals(candidateValue)) {
diff --git a/id/server/modules/moa-id-module-eIDAS/src/main/java/at/gv/egovernment/moa/id/auth/modules/eidas/utils/MOAeIDASMetadataGenerator.java b/id/server/modules/moa-id-module-eIDAS/src/main/java/at/gv/egovernment/moa/id/auth/modules/eidas/utils/MOAeIDASMetadataGenerator.java
index dd14972e3..8faaf1874 100644
--- a/id/server/modules/moa-id-module-eIDAS/src/main/java/at/gv/egovernment/moa/id/auth/modules/eidas/utils/MOAeIDASMetadataGenerator.java
+++ b/id/server/modules/moa-id-module-eIDAS/src/main/java/at/gv/egovernment/moa/id/auth/modules/eidas/utils/MOAeIDASMetadataGenerator.java
@@ -210,10 +210,15 @@ public class MOAeIDASMetadataGenerator extends MetadataGenerator {
addAssertionConsumerService();
}
fillNameIDFormat(spSSODescriptor);
- if (params.getSpEngine() != null) {
- ProtocolEngineI spEngine = params.getSpEngine();
- ((MetadataSignerI) spEngine.getSigner()).signMetadata(spSSODescriptor);
- }
+
+ /**FIXME:
+ * Double signing of SPSSODescribtor is not required
+ */
+// if (params.getSpEngine() != null) {
+// ProtocolEngineI spEngine = params.getSpEngine();
+// ((MetadataSignerI) spEngine.getSigner()).signMetadata(spSSODescriptor);
+// }
+
entityDescriptor.getRoleDescriptors().add(spSSODescriptor);
}
@@ -266,6 +271,8 @@ public class MOAeIDASMetadataGenerator extends MetadataGenerator {
}
idpSSODescriptor.addSupportedProtocol(params.getIdpSamlProtocol());
fillNameIDFormat(idpSSODescriptor);
+
+
if (params.getIdpEngine() != null) {
if (params.getIdpEngine().getProtocolProcessor() != null
&& params.getIdpEngine().getProtocolProcessor().getFormat() == SAMLExtensionFormat.EIDAS10) {
@@ -277,8 +284,13 @@ public class MOAeIDASMetadataGenerator extends MetadataGenerator {
*/
generateSupportedAttributes(idpSSODescriptor, getAllSupportedAttributes());
}
- ProtocolEngineI idpEngine = params.getIdpEngine();
- ((MetadataSignerI) idpEngine.getSigner()).signMetadata(idpSSODescriptor);
+
+
+ /**FIXME:
+ * Double signing of IDPSSODescribtor is not required
+ */
+// ProtocolEngineI idpEngine = params.getIdpEngine();
+// ((MetadataSignerI) idpEngine.getSigner()).signMetadata(idpSSODescriptor);
}
idpSSODescriptor.getSingleSignOnServices().addAll(buildSingleSignOnServicesBindingLocations());
@@ -465,7 +477,7 @@ public class MOAeIDASMetadataGenerator extends MetadataGenerator {
X509Certificate decryptionCertificate = engine.getDecryptionCertificate();
if (null != decryptionCertificate) {
- params.setEncryptionCredential(CertificateUtil.toCredential(decryptionCertificate));
+ params.setSpEncryptionCredential(CertificateUtil.toCredential(decryptionCertificate));
}
params.setSigningCredential(CertificateUtil.toCredential(engine.getSigningCertificate()));
params.setIdpEngine(engine);
@@ -530,7 +542,10 @@ public class MOAeIDASMetadataGenerator extends MetadataGenerator {
Set<String> signatureMethods = EIDASUtil.parseSemicolonSeparatedList(params.getDigestMethods());
Set<String> digestMethods = new HashSet<String>();
for (String signatureMethod : signatureMethods) {
- digestMethods.add(CertificateUtil.validateDigestAlgorithm(signatureMethod));
+
+ //BUGFIX: eIDAS implementation does not allow MGF1 signature schemes
+ digestMethods.add(signatureMethod);
+ //digestMethods.add(CertificateUtil.validateDigestAlgorithm(signatureMethod));
}
for (String digestMethod : digestMethods) {
final DigestMethod dm = (DigestMethod) BuilderFactoryUtil.buildXmlObject(DigestMethod.DEF_ELEMENT_NAME);
@@ -569,7 +584,7 @@ public class MOAeIDASMetadataGenerator extends MetadataGenerator {
generateDigest(eidasExtensions);
if (!StringUtils.isEmpty(params.getSigningMethods())) {
- Set<String> signMethods = EIDASUtil.parseSemicolonSeparatedList(params.getDigestMethods());
+ Set<String> signMethods = EIDASUtil.parseSemicolonSeparatedList(params.getSigningMethods());
for (String signMethod : signMethods) {
final SigningMethod sm =
(SigningMethod) BuilderFactoryUtil.buildXmlObject(SigningMethod.DEF_ELEMENT_NAME);
diff --git a/id/server/modules/moa-id-module-eIDAS/src/main/java/at/gv/egovernment/moa/id/auth/modules/eidas/utils/SAMLEngineUtils.java b/id/server/modules/moa-id-module-eIDAS/src/main/java/at/gv/egovernment/moa/id/auth/modules/eidas/utils/SAMLEngineUtils.java
index eb50c113f..70135c06f 100644
--- a/id/server/modules/moa-id-module-eIDAS/src/main/java/at/gv/egovernment/moa/id/auth/modules/eidas/utils/SAMLEngineUtils.java
+++ b/id/server/modules/moa-id-module-eIDAS/src/main/java/at/gv/egovernment/moa/id/auth/modules/eidas/utils/SAMLEngineUtils.java
@@ -30,8 +30,8 @@ import org.opensaml.xml.ConfigurationException;
import org.opensaml.xml.XMLConfigurator;
import at.gv.egovernment.moa.id.auth.modules.eidas.Constants;
+import at.gv.egovernment.moa.id.auth.modules.eidas.config.MOAExtendedSWSigner;
import at.gv.egovernment.moa.id.auth.modules.eidas.config.MOAIDCertificateManagerConfigurationImpl;
-import at.gv.egovernment.moa.id.auth.modules.eidas.config.MOASWSigner;
import at.gv.egovernment.moa.id.auth.modules.eidas.engine.MOAEidasProtocolProcesser;
import at.gv.egovernment.moa.id.auth.modules.eidas.engine.MOAeIDASChainingMetadataProvider;
import at.gv.egovernment.moa.id.auth.modules.eidas.engine.MOAeIDASMetadataProviderDecorator;
@@ -69,8 +69,8 @@ public class SAMLEngineUtils {
metadataFetcher = new MOAeIDASMetadataProviderDecorator(moaeIDASMetadataProvider);
//set metadata signer
- metadataSigner = new MOASWSigner(configManager);
-
+ metadataSigner = new MOAExtendedSWSigner(configManager);
+
//build eIDAS SAML eninge
ProtocolEngineI engine = MOAProtocolEngineFactory.createProtocolEngine(
Constants.eIDAS_SAML_ENGINE_NAME,
diff --git a/id/server/modules/moa-id-module-eIDAS/src/main/java/at/gv/egovernment/moa/id/auth/modules/eidas/utils/eIDASAttributeProcessingUtils.java b/id/server/modules/moa-id-module-eIDAS/src/main/java/at/gv/egovernment/moa/id/auth/modules/eidas/utils/eIDASAttributeProcessingUtils.java
new file mode 100644
index 000000000..30e1e4505
--- /dev/null
+++ b/id/server/modules/moa-id-module-eIDAS/src/main/java/at/gv/egovernment/moa/id/auth/modules/eidas/utils/eIDASAttributeProcessingUtils.java
@@ -0,0 +1,75 @@
+/*
+ * Copyright 2014 Federal Chancellery Austria
+ * MOA-ID has been developed in a cooperation between BRZ, the Federal
+ * Chancellery Austria - ICT staff unit, and Graz University of Technology.
+ *
+ * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by
+ * the European Commission - subsequent versions of the EUPL (the "Licence");
+ * You may not use this work except in compliance with the Licence.
+ * You may obtain a copy of the Licence at:
+ * http://www.osor.eu/eupl/
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the Licence is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the Licence for the specific language governing permissions and
+ * limitations under the Licence.
+ *
+ * This product combines work with different licenses. See the "NOTICE" text
+ * file for details on the various modules and licenses.
+ * The "NOTICE" text file is part of the distribution. Any derivative works
+ * that you distribute must include a readable copy of the "NOTICE" text file.
+ */
+package at.gv.egovernment.moa.id.auth.modules.eidas.utils;
+
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import at.gv.egovernment.moa.id.auth.modules.eidas.Constants;
+import at.gv.egovernment.moa.id.data.Trible;
+import at.gv.egovernment.moa.logging.Logger;
+
+/**
+ * @author tlenz
+ *
+ */
+public class eIDASAttributeProcessingUtils {
+ public static final String PERSONALIDENIFIER_VALIDATION_PATTERN = "^[A-Z,a-z]{2}/[A-Z,a-z]{2}/.*";
+
+ /**
+ * Validate a eIDAS PersonalIdentifier attribute value
+ * This validation is done according to eIDAS SAML Attribute Profile - Section 2.2.3 Unique Identifier
+ *
+ * @param uniqueID eIDAS attribute value of a unique identifier
+ * @return true if the uniqueID matches to eIDAS to Unique Identifier specification, otherwise false
+ */
+ public static boolean validateEidasPersonalIdentifier(String uniqueID) {
+ Pattern pattern = Pattern.compile(PERSONALIDENIFIER_VALIDATION_PATTERN );
+ Matcher matcher = pattern.matcher(uniqueID);
+ return matcher.matches();
+
+ }
+
+
+ /**
+ * Parse an eIDAS PersonalIdentifier attribute value into it components.
+ * This processing is done according to eIDAS SAML Attribute Profile - Section 2.2.3 Unique Identifier
+ *
+ * @param uniqueID eIDAS attribute value of a unique identifier
+ * @return {@link Trible} that contains:
+ * <br> First : citizen country
+ * <br> Second: destination country
+ * <br> Third : unique identifier
+ * <br> or null if the attribute value has a wrong format
+ */
+ public static Trible<String, String, String> parseEidasPersonalIdentifier(String uniqueID) {
+ if (!validateEidasPersonalIdentifier(uniqueID)) {
+ Logger.error("eIDAS attribute value for " + Constants.eIDAS_ATTR_PERSONALIDENTIFIER
+ + " looks wrong formated. Value:" + ((String)uniqueID));
+ return null;
+
+ }
+ return Trible.newInstance(uniqueID.substring(0, 2), uniqueID.substring(3, 5), uniqueID.substring(6));
+
+ }
+}
diff --git a/id/server/modules/moa-id-module-eIDAS/src/main/java/at/gv/egovernment/moa/id/protocols/eidas/EIDASProtocol.java b/id/server/modules/moa-id-module-eIDAS/src/main/java/at/gv/egovernment/moa/id/protocols/eidas/EIDASProtocol.java
index 13e64cdd0..388d65963 100644
--- a/id/server/modules/moa-id-module-eIDAS/src/main/java/at/gv/egovernment/moa/id/protocols/eidas/EIDASProtocol.java
+++ b/id/server/modules/moa-id-module-eIDAS/src/main/java/at/gv/egovernment/moa/id/protocols/eidas/EIDASProtocol.java
@@ -25,6 +25,8 @@ package at.gv.egovernment.moa.id.protocols.eidas;
import java.io.IOException;
import java.io.StringWriter;
import java.util.List;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@@ -36,7 +38,6 @@ import org.opensaml.saml2.core.StatusCode;
import org.opensaml.saml2.metadata.AssertionConsumerService;
import org.opensaml.saml2.metadata.EntityDescriptor;
import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.http.MediaType;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
@@ -51,6 +52,7 @@ import at.gv.egovernment.moa.id.auth.modules.eidas.exceptions.EIDASAuthnRequestV
import at.gv.egovernment.moa.id.auth.modules.eidas.exceptions.EIDASException;
import at.gv.egovernment.moa.id.auth.modules.eidas.utils.SAMLEngineUtils;
import at.gv.egovernment.moa.id.commons.MOAIDAuthConstants;
+import at.gv.egovernment.moa.id.commons.MOAIDConstants;
import at.gv.egovernment.moa.id.commons.api.IOAAuthParameters;
import at.gv.egovernment.moa.id.commons.api.IRequest;
import at.gv.egovernment.moa.id.commons.api.exceptions.MOAIDException;
@@ -149,7 +151,8 @@ public class EIDASProtocol extends AbstractAuthProtocolModulController {
//preProcess eIDAS request
preProcess(req, resp, pendingReq);
- revisionsLogger.logEvent(pendingReq, Constants.eIDAS_REVERSIONSLOG_IDP_AUTHREQUEST);
+ revisionsLogger.logEvent(pendingReq, Constants.eIDAS_REVERSIONSLOG_IDP_AUTHREQUEST,
+ pendingReq.getEidasRequest().getId());
//AuthnRequest needs authentication
pendingReq.setNeedAuthentication(true);
@@ -213,6 +216,11 @@ public class EIDASProtocol extends AbstractAuthProtocolModulController {
}
+ //check eIDAS node configuration
+ IOAAuthParameters oaConfig = authConfig.getOnlineApplicationParameter(samlReq.getIssuer());
+ if (oaConfig == null)
+ throw new EIDASAuthnRequestProcessingException("eIDAS.08", new Object[]{samlReq.getIssuer()});
+
//validate AssertionConsumerServiceURL against metadata
EntityDescriptor eIDASNodeEntityDesc = new MOAeIDASMetadataProviderDecorator(eIDASMetadataProvider)
.getEntityDescriptor(eIDASSamlReq.getIssuer(), SAMLEngineUtils.getMetadataSigner());
@@ -258,8 +266,33 @@ public class EIDASProtocol extends AbstractAuthProtocolModulController {
}
+ //validate request country-code against eIDAS node config
+ String reqCC = samlReq.getOriginCountryCode();
+ String eIDASTarget = oaConfig.getIdentityLinkDomainIdentifier();
+
+ //validate eIDAS target
+ Pattern pattern = Pattern.compile("^" + at.gv.egovernment.moa.util.Constants.URN_PREFIX_EIDAS
+ + "\\+[A-Z,a-z]{2}\\+[A-Z,a-z]{2}$");
+ Matcher matcher = pattern.matcher(eIDASTarget);
+ if (MiscUtil.isEmpty(eIDASTarget) || !matcher.matches()) {
+ Logger.error("Configuration for eIDAS-node:" + samlReq.getIssuer()
+ + " contains wrong formated eIDAS target:" + eIDASTarget);
+ throw new MOAIDException("config.08", new Object[]{samlReq.getIssuer()});
+
+ } else {
+ String[] splittedTarget = eIDASTarget.split("\\+");
+ if (!splittedTarget[2].equalsIgnoreCase(reqCC)) {
+ Logger.error("Configuration for eIDAS-node:" + samlReq.getIssuer()
+ + " Destination Country from request (" + reqCC
+ + ") does not match to configuration:" + eIDASTarget);
+ throw new MOAIDException("eIDAS.01",
+ new Object[]{"Destination Country from request does not match to configuration"});
+
+ }
+ Logger.debug("CountryCode from request matches eIDAS-node configuration target");
+ }
-
+
//*************************************************
//***** store eIDAS request information *********
//*************************************************
@@ -269,10 +302,6 @@ public class EIDASProtocol extends AbstractAuthProtocolModulController {
// - memorize relaystate
String relayState = request.getParameter("RelayState");
pendingReq.setRemoteRelayState(relayState);
-
- // - memorize country code of target country
- pendingReq.setGenericDataToSession(
- RequestImpl.eIDAS_GENERIC_REQ_DATA_COUNTRY, samlReq.getOriginCountryCode());
//store level of assurance
pendingReq.setGenericDataToSession(RequestImpl.eIDAS_GENERIC_REQ_DATA_LEVELOFASSURENCE,
@@ -288,10 +317,6 @@ public class EIDASProtocol extends AbstractAuthProtocolModulController {
pendingReq.setOAURL(samlReq.getIssuer());
// - memorize OA config
- IOAAuthParameters oaConfig = authConfig.getOnlineApplicationParameter(pendingReq.getOAURL());
- if (oaConfig == null)
- throw new EIDASAuthnRequestProcessingException("eIDAS.08", new Object[]{pendingReq.getOAURL()});
-
pendingReq.setOnlineApplicationConfiguration(oaConfig);
// - memorize service-provider type from eIDAS request
@@ -302,7 +327,7 @@ public class EIDASProtocol extends AbstractAuthProtocolModulController {
if (MiscUtil.isEmpty(spType))
spType = MetadataUtil.getSPTypeFromMetadata(eIDASNodeEntityDesc);
- if (MiscUtil.isEmpty(spType))
+ if (MiscUtil.isNotEmpty(spType))
Logger.debug("eIDAS request has SPType:" + spType);
else
Logger.info("eIDAS request and eIDAS metadata contains NO 'SPType' element.");
@@ -367,7 +392,7 @@ public class EIDASProtocol extends AbstractAuthProtocolModulController {
String token = EidasStringUtil.encodeToBase64(eIDASRespMsg.getMessageBytes());
VelocityEngine velocityEngine = VelocityProvider.getClassPathVelocityEngine();
- Template template = velocityEngine.getTemplate("/resources/templates/stork2_postbinding_template.html");
+ Template template = velocityEngine.getTemplate("/resources/templates/eidas_postbinding_template.vm");
VelocityContext context = new VelocityContext();
context.put("RelayState", eidasReq.getRemoteRelayState());
@@ -387,7 +412,7 @@ public class EIDASProtocol extends AbstractAuthProtocolModulController {
Logger.trace("Sending html content : " + new String(writer.getBuffer()));
byte[] content = writer.getBuffer().toString().getBytes("UTF-8");
- response.setContentType(MediaType.TEXT_HTML.getType());
+ response.setContentType(MOAIDConstants.DEFAULT_CONTENT_TYPE_HTML_UTF8);
response.setContentLength(content.length);
response.getOutputStream().write(content);
diff --git a/id/server/modules/moa-id-module-eIDAS/src/main/java/at/gv/egovernment/moa/id/protocols/eidas/EidasMetaDataRequest.java b/id/server/modules/moa-id-module-eIDAS/src/main/java/at/gv/egovernment/moa/id/protocols/eidas/EidasMetaDataRequest.java
index 174fa2c17..df96bef12 100644
--- a/id/server/modules/moa-id-module-eIDAS/src/main/java/at/gv/egovernment/moa/id/protocols/eidas/EidasMetaDataRequest.java
+++ b/id/server/modules/moa-id-module-eIDAS/src/main/java/at/gv/egovernment/moa/id/protocols/eidas/EidasMetaDataRequest.java
@@ -72,13 +72,19 @@ public class EidasMetaDataRequest implements IAction {
String metadata_url = pubURLPrefix + Constants.eIDAS_HTTP_ENDPOINT_METADATA;
String sp_return_url = pubURLPrefix + Constants.eIDAS_HTTP_ENDPOINT_SP_POST;
+ //generate eIDAS metadata
String metaData = generateMetadata(req, metadata_url, sp_return_url);
-
+
+ //write content to response
+ byte[] content = metaData.getBytes("UTF-8");
+ httpResp.setStatus(HttpServletResponse.SC_OK);
+ httpResp.setContentType(MediaType.APPLICATION_XML.toString());
+ httpResp.setContentLength(content.length);
+ httpResp.getOutputStream().write(content);
+
+ //write log if required
Logger.trace(metaData);
-
- httpResp.setContentType(MediaType.APPLICATION_XML.getType());
- httpResp.getWriter().print(metaData);
- httpResp.flushBuffer();
+
} catch (Exception e) {
Logger.error("eIDAS Metadata generation FAILED.", e);
throw new MOAIDException("eIDAS.05", new Object[]{e.getMessage()}, e);
diff --git a/id/server/modules/moa-id-module-eIDAS/src/main/java/at/gv/egovernment/moa/id/protocols/eidas/eIDASAuthenticationRequest.java b/id/server/modules/moa-id-module-eIDAS/src/main/java/at/gv/egovernment/moa/id/protocols/eidas/eIDASAuthenticationRequest.java
index 22ac37604..2fe52bb4f 100644
--- a/id/server/modules/moa-id-module-eIDAS/src/main/java/at/gv/egovernment/moa/id/protocols/eidas/eIDASAuthenticationRequest.java
+++ b/id/server/modules/moa-id-module-eIDAS/src/main/java/at/gv/egovernment/moa/id/protocols/eidas/eIDASAuthenticationRequest.java
@@ -34,7 +34,6 @@ import org.apache.velocity.VelocityContext;
import org.apache.velocity.app.VelocityEngine;
import org.opensaml.saml2.core.StatusCode;
import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.http.MediaType;
import org.springframework.stereotype.Service;
import com.google.common.collect.ImmutableSet;
@@ -44,11 +43,14 @@ import at.gv.egovernment.moa.id.auth.frontend.velocity.VelocityProvider;
import at.gv.egovernment.moa.id.auth.modules.eidas.Constants;
import at.gv.egovernment.moa.id.auth.modules.eidas.engine.MOAeIDASChainingMetadataProvider;
import at.gv.egovernment.moa.id.auth.modules.eidas.utils.SimpleEidasAttributeGenerator;
+import at.gv.egovernment.moa.id.auth.modules.eidas.utils.eIDASAttributeProcessingUtils;
+import at.gv.egovernment.moa.id.commons.MOAIDConstants;
import at.gv.egovernment.moa.id.commons.api.IRequest;
import at.gv.egovernment.moa.id.commons.api.exceptions.MOAIDException;
import at.gv.egovernment.moa.id.data.IAuthData;
import at.gv.egovernment.moa.id.data.SLOInformationImpl;
import at.gv.egovernment.moa.id.data.SLOInformationInterface;
+import at.gv.egovernment.moa.id.data.Trible;
import at.gv.egovernment.moa.id.moduls.IAction;
import at.gv.egovernment.moa.id.protocols.builder.attributes.IAttributeGenerator;
import at.gv.egovernment.moa.id.protocols.builder.attributes.MandateLegalPersonFullNameAttributeBuilder;
@@ -121,12 +123,28 @@ public class eIDASAuthenticationRequest implements IAction {
newValue = authData.getBPK();
isUniqueID = true;
+ //generate eIDAS conform 'PersonalIdentifier' attribute
+ if (!eIDASAttributeProcessingUtils.validateEidasPersonalIdentifier(newValue)) {
+ Logger.debug("preCalculated PersonalIdentifier does not include eIDAS conform prefixes ... add prefix now");
+ if (MiscUtil.isEmpty(authData.getBPKType())
+ || !authData.getBPKType().startsWith(at.gv.egovernment.moa.util.Constants.URN_PREFIX_EIDAS)) {
+ Logger.error("BPKType is empty or does not start with eIDAS bPKType prefix! bPKType:" + authData.getBPKType());
+ throw new MOAIDException("builder.08", new Object[]{"Suspect bPKType for eIDAS identifier generation"});
+
+ }
+
+ String prefix = authData.getBPKType().substring(at.gv.egovernment.moa.util.Constants.URN_PREFIX_EIDAS.length() + 1);
+ newValue = prefix.replaceAll("\\+", "/") + "/" + newValue;
+
+ }
+
//generate a transient unique identifier if it is requested
String reqNameIDFormat = eidasRequest.getEidasRequest().getNameIdFormat();
if (MiscUtil.isNotEmpty(reqNameIDFormat)
&& reqNameIDFormat.equals(SamlNameIdFormat.TRANSIENT.getNameIdFormat()))
newValue = generateTransientNameID(newValue);
-
+
+
subjectNameID = newValue;
break;
case Constants.eIDAS_ATTR_LEGALPERSONIDENTIFIER:
@@ -145,8 +163,14 @@ public class eIDASAuthenticationRequest implements IAction {
}
- if(MiscUtil.isEmpty(newValue)) {
- Logger.info("eIDAS Attr:" + attr.getNameUri() + " is not available.");
+ if(MiscUtil.isEmpty(newValue)) {
+ if (attr.isRequired()) {
+ Logger.info("eIDAS Attr:" + attr.getNameUri() + " is marked as 'Required' but not available.");
+ throw new MOAIDException("eIDAS.15", new Object[]{attr.getFriendlyName()});
+
+ } else
+ Logger.info("eIDAS Attr:" + attr.getNameUri() + " is not available.");
+
} else {
//set uniqueIdentifier attribute, because eIDAS SAMLEngine use this flag to select the
@@ -228,12 +252,13 @@ public class eIDASAuthenticationRequest implements IAction {
}
- revisionsLogger.logEvent(req, Constants.eIDAS_REVERSIONSLOG_IDP_AUTHREQUEST);
+ revisionsLogger.logEvent(req, Constants.eIDAS_REVERSIONSLOG_IDP_AUTHRESPONSE,
+ eIDASRespMsg.getResponse().getId());
// send the response
try {
VelocityEngine velocityEngine = VelocityProvider.getClassPathVelocityEngine();
- Template template = velocityEngine.getTemplate("/resources/templates/stork2_postbinding_template.html");
+ Template template = velocityEngine.getTemplate("/resources/templates/eidas_postbinding_template.vm");
VelocityContext context = new VelocityContext();
context.put("RelayState", eidasRequest.getRemoteRelayState());
@@ -253,7 +278,7 @@ public class eIDASAuthenticationRequest implements IAction {
Logger.trace("Sending html content : " + new String(writer.getBuffer()));
byte[] content = writer.getBuffer().toString().getBytes("UTF-8");
- httpResp.setContentType(MediaType.TEXT_HTML.getType());
+ httpResp.setContentType(MOAIDConstants.DEFAULT_CONTENT_TYPE_HTML_UTF8);
httpResp.setContentLength(content.length);
httpResp.getOutputStream().write(content);
@@ -295,12 +320,20 @@ public class eIDASAuthenticationRequest implements IAction {
private String generateTransientNameID(String nameID) {
- String random = Random.nextLongRandom();
+ //extract source-country and destination country from persistent identifier
+ Trible<String, String, String> split = eIDASAttributeProcessingUtils.parseEidasPersonalIdentifier(nameID);
+ if (split == null) {
+ Logger.error("eIDAS 'PersonalIdentifier' has a wrong format. There had to be a ERROR in implementation!!!!");
+ throw new IllegalStateException("eIDAS 'PersonalIdentifier' has a wrong format. There had to be a ERROR in implementation!!!!");
+
+ }
+ //build correct formated transient identifier
+ String random = Random.nextLongRandom();
try {
MessageDigest md = MessageDigest.getInstance("SHA-1");
- byte[] hash = md.digest((nameID + random).getBytes("ISO-8859-1"));
- return Base64Utils.encode(hash);
+ byte[] hash = md.digest((split.getThird() + random).getBytes("ISO-8859-1"));
+ return split.getFirst() + "/" + split.getSecond() + "/" + Base64Utils.encode(hash);
} catch (Exception e) {
Logger.error("Can not generate transient personal identifier!", e);
diff --git a/id/server/modules/moa-id-module-eIDAS/src/main/java/at/gv/egovernment/moa/id/protocols/eidas/validator/eIDASResponseValidator.java b/id/server/modules/moa-id-module-eIDAS/src/main/java/at/gv/egovernment/moa/id/protocols/eidas/validator/eIDASResponseValidator.java
new file mode 100644
index 000000000..f0527bc5e
--- /dev/null
+++ b/id/server/modules/moa-id-module-eIDAS/src/main/java/at/gv/egovernment/moa/id/protocols/eidas/validator/eIDASResponseValidator.java
@@ -0,0 +1,130 @@
+/*
+ * Copyright 2014 Federal Chancellery Austria
+ * MOA-ID has been developed in a cooperation between BRZ, the Federal
+ * Chancellery Austria - ICT staff unit, and Graz University of Technology.
+ *
+ * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by
+ * the European Commission - subsequent versions of the EUPL (the "Licence");
+ * You may not use this work except in compliance with the Licence.
+ * You may obtain a copy of the Licence at:
+ * http://www.osor.eu/eupl/
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the Licence is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the Licence for the specific language governing permissions and
+ * limitations under the Licence.
+ *
+ * This product combines work with different licenses. See the "NOTICE" text
+ * file for details on the various modules and licenses.
+ * The "NOTICE" text file is part of the distribution. Any derivative works
+ * that you distribute must include a readable copy of the "NOTICE" text file.
+ */
+package at.gv.egovernment.moa.id.protocols.eidas.validator;
+
+import at.gv.egovernment.moa.id.auth.modules.eidas.Constants;
+import at.gv.egovernment.moa.id.auth.modules.eidas.utils.SAMLEngineUtils;
+import at.gv.egovernment.moa.id.auth.modules.eidas.utils.eIDASAttributeProcessingUtils;
+import at.gv.egovernment.moa.id.commons.api.IRequest;
+import at.gv.egovernment.moa.id.commons.api.exceptions.MOAIDException;
+import at.gv.egovernment.moa.id.data.Trible;
+import at.gv.egovernment.moa.logging.Logger;
+import at.gv.egovernment.moa.util.MiscUtil;
+import eu.eidas.auth.commons.protocol.IAuthenticationResponse;
+import eu.eidas.auth.commons.protocol.eidas.LevelOfAssurance;
+
+/**
+ * @author tlenz
+ *
+ */
+public class eIDASResponseValidator {
+
+
+ public static void validateResponse(IRequest pendingReq, IAuthenticationResponse samlResp, String spCountry) throws MOAIDException {
+
+ /*-----------------------------------------------------|
+ * validate received LoA against minimum required LoA |
+ *_____________________________________________________|
+ */
+ LevelOfAssurance reqLoA = LevelOfAssurance.fromString(pendingReq.getOnlineApplicationConfiguration().getQaaLevel());
+ LevelOfAssurance respLoA = LevelOfAssurance.fromString(samlResp.getLevelOfAssurance());
+ if (respLoA.numericValue() < reqLoA.numericValue()) {
+ Logger.error("eIDAS Response LevelOfAssurance is lower than the required! "
+ + "(Resp-LoA:" + respLoA.getValue() + " Req-LoA:" + reqLoA.getValue() + ")");
+ throw new MOAIDException("eIDAS.14", new Object[]{respLoA.getValue()});
+
+ }
+
+ /*-----------------------------------------------------|
+ * validate 'PersonalIdentifier' attribute |
+ *_____________________________________________________|
+ */
+ String respCC = samlResp.getCountry();
+ Object personalIdObj = samlResp.getAttributes().getFirstValue(
+ SAMLEngineUtils.getMapOfAllAvailableAttributes().get(
+ Constants.eIDAS_ATTR_PERSONALIDENTIFIER));
+
+ //check attribute type
+ if (personalIdObj == null || !(personalIdObj instanceof String))
+ Logger.warn("eIDAS Response include NO 'PersonalIdentifier' attriubte "
+ + ".... That can be a BIG problem in further processing steps");
+
+ else {
+ //validate attribute value format
+ Trible<String, String, String> split =
+ eIDASAttributeProcessingUtils.parseEidasPersonalIdentifier((String)personalIdObj);
+ if (split == null) {
+ throw new MOAIDException("eIDAS.16",
+ new Object[]{
+ Constants.eIDAS_ATTR_PERSONALIDENTIFIER,
+ "Wrong identifier format"});
+
+ } else {
+ //validation according to eIDAS SAML Attribute Profile, Section 2.2.3
+ if (MiscUtil.isEmpty(split.getSecond())) {
+ Logger.error("eIDAS attribute value for " + Constants.eIDAS_ATTR_PERSONALIDENTIFIER
+ + " includes NO destination country. Value:" + ((String)personalIdObj));
+ throw new MOAIDException("eIDAS.16",
+ new Object[]{
+ Constants.eIDAS_ATTR_PERSONALIDENTIFIER,
+ "No or empty destination country"});
+
+ }
+ if (!split.getSecond().equalsIgnoreCase(spCountry)) {
+ Logger.error("eIDAS attribute value for " + Constants.eIDAS_ATTR_PERSONALIDENTIFIER
+ + " includes wrong destination country. Value:" + ((String)personalIdObj)
+ + " SP-Country:" + spCountry);
+ throw new MOAIDException("eIDAS.16",
+ new Object[]{
+ Constants.eIDAS_ATTR_PERSONALIDENTIFIER,
+ "Destination country does not match to SP country"});
+
+ }
+
+ if (MiscUtil.isEmpty(split.getFirst())) {
+ Logger.error("eIDAS attribute value for " + Constants.eIDAS_ATTR_PERSONALIDENTIFIER
+ + " includes NO citizen country. Value:" + ((String)personalIdObj));
+ throw new MOAIDException("eIDAS.16",
+ new Object[]{
+ Constants.eIDAS_ATTR_PERSONALIDENTIFIER,
+ "No or empty citizen country"});
+
+ }
+ if (!split.getFirst().equalsIgnoreCase(respCC)) {
+ Logger.error("eIDAS attribute value for " + Constants.eIDAS_ATTR_PERSONALIDENTIFIER
+ + " includes a citizen country that does not match to eIDAS Response node. "
+ + " Value:" + ((String)personalIdObj)
+ + " Response-Node Country:" + respCC);
+ throw new MOAIDException("eIDAS.16",
+ new Object[]{
+ Constants.eIDAS_ATTR_PERSONALIDENTIFIER,
+ "Citizen country does not match to eIDAS-node country that generates the response"});
+
+ }
+ }
+ }
+
+
+
+ }
+}
diff --git a/id/server/modules/moa-id-module-eIDAS/src/main/resources/resources/templates/eidas_postbinding_template.vm b/id/server/modules/moa-id-module-eIDAS/src/main/resources/resources/templates/eidas_postbinding_template.vm
index 3bd225b00..0535d48b6 100644
--- a/id/server/modules/moa-id-module-eIDAS/src/main/resources/resources/templates/eidas_postbinding_template.vm
+++ b/id/server/modules/moa-id-module-eIDAS/src/main/resources/resources/templates/eidas_postbinding_template.vm
@@ -7,7 +7,7 @@
## SAMLRequest - String - the Base64 encoded SAML Request
## SAMLResponse - String - the Base64 encoded SAML Response
## Contains target attribute to delegate PEPS authentication out of iFrame
-
+<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>