aboutsummaryrefslogtreecommitdiff
path: root/id/server/modules/moa-id-module-sl20_authentication/src/main
diff options
context:
space:
mode:
authorThomas Lenz <tlenz@iaik.tugraz.at>2018-07-12 16:16:29 +0200
committerThomas Lenz <tlenz@iaik.tugraz.at>2018-07-12 16:16:29 +0200
commit132681b9f3e00158b1671f50b23517462aa54afd (patch)
treecda5e6b321a44fbb54a959693a4afe71eb25bd6a /id/server/modules/moa-id-module-sl20_authentication/src/main
parent3535ae9500b29d0b2d0f317ea7f47a6c25c6f70e (diff)
parent3b1130e2366138871a92a1f83124a27fa83885dd (diff)
downloadmoa-id-spss-132681b9f3e00158b1671f50b23517462aa54afd.tar.gz
moa-id-spss-132681b9f3e00158b1671f50b23517462aa54afd.tar.bz2
moa-id-spss-132681b9f3e00158b1671f50b23517462aa54afd.zip
Merge branch 'eIDAS_node_2.0_tests' into huge_refactoring
# Conflicts: # id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/builder/AuthenticationDataBuilder.java # id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/builder/BPKBuilder.java # id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/parser/VerifyXMLSignatureResponseParser.java # id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/validator/VerifyXMLSignatureResponseValidator.java # id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/config/auth/OAAuthParameterDecorator.java # id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/config/auth/data/DynamicOAAuthParameters.java # id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/data/AuthenticationData.java # id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/moduls/AuthenticationManager.java # id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/builder/attributes/EncryptedBPKAttributeBuilder.java # id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/pvp2x/utils/AssertionAttributeExtractor.java # id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/pvp2x/utils/SAML2Utils.java # id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/pvp2x/verification/metadata/SchemaValidationFilter.java # id/server/idserverlib/src/main/resources/moaid.authentication.beans.xml # id/server/idserverlib/src/test/java/at/gv/egovernment/moa/id/module/test/TestRequestImpl.java # id/server/moa-id-commons/src/main/java/at/gv/egovernment/moa/id/commons/MOAIDAuthConstants.java # id/server/moa-id-commons/src/main/java/at/gv/egovernment/moa/id/commons/api/IOAAuthParameters.java # id/server/moa-id-commons/src/main/java/at/gv/egovernment/moa/id/commons/config/ConfigurationMigrationUtils.java # id/server/moa-id-commons/src/main/java/at/gv/egovernment/moa/id/commons/utils/KeyValueUtils.java # id/server/modules/moa-id-module-bkaMobilaAuthSAML2Test/src/main/java/at/gv/egovernment/moa/id/auth/modules/bkamobileauthtests/BKAMobileAuthModule.java # id/server/modules/moa-id-module-bkaMobilaAuthSAML2Test/src/main/java/at/gv/egovernment/moa/id/auth/modules/bkamobileauthtests/tasks/FirstBKAMobileAuthTask.java # id/server/modules/moa-id-module-sl20_authentication/src/main/java/at/gv/egovernment/moa/id/auth/modules/sl20_auth/sl20/JsonSecurityUtils.java # id/server/modules/moa-id-module-sl20_authentication/src/main/java/at/gv/egovernment/moa/id/auth/modules/sl20_auth/tasks/CreateQualeIDRequestTask.java # id/server/modules/moa-id-module-sl20_authentication/src/main/java/at/gv/egovernment/moa/id/auth/modules/sl20_auth/tasks/ReceiveQualeIDTask.java # id/server/modules/module-monitoring/src/main/java/at/gv/egovernment/moa/id/monitoring/IdentityLinkTestModule.java
Diffstat (limited to 'id/server/modules/moa-id-module-sl20_authentication/src/main')
-rw-r--r--id/server/modules/moa-id-module-sl20_authentication/src/main/java/at/gv/egovernment/moa/id/auth/modules/sl20_auth/Constants.java15
-rw-r--r--id/server/modules/moa-id-module-sl20_authentication/src/main/java/at/gv/egovernment/moa/id/auth/modules/sl20_auth/SL20AuthenticationModulImpl.java48
-rw-r--r--id/server/modules/moa-id-module-sl20_authentication/src/main/java/at/gv/egovernment/moa/id/auth/modules/sl20_auth/SL20SignalServlet.java7
-rw-r--r--id/server/modules/moa-id-module-sl20_authentication/src/main/java/at/gv/egovernment/moa/id/auth/modules/sl20_auth/exceptions/SL20eIDDataValidationException.java16
-rw-r--r--id/server/modules/moa-id-module-sl20_authentication/src/main/java/at/gv/egovernment/moa/id/auth/modules/sl20_auth/sl20/JsonSecurityUtils.java124
-rw-r--r--id/server/modules/moa-id-module-sl20_authentication/src/main/java/at/gv/egovernment/moa/id/auth/modules/sl20_auth/sl20/SL20Constants.java51
-rw-r--r--id/server/modules/moa-id-module-sl20_authentication/src/main/java/at/gv/egovernment/moa/id/auth/modules/sl20_auth/sl20/SL20HttpBindingUtils.java6
-rw-r--r--id/server/modules/moa-id-module-sl20_authentication/src/main/java/at/gv/egovernment/moa/id/auth/modules/sl20_auth/sl20/SL20JSONBuilderUtils.java15
-rw-r--r--id/server/modules/moa-id-module-sl20_authentication/src/main/java/at/gv/egovernment/moa/id/auth/modules/sl20_auth/sl20/SL20JSONExtractorUtils.java196
-rw-r--r--id/server/modules/moa-id-module-sl20_authentication/src/main/java/at/gv/egovernment/moa/id/auth/modules/sl20_auth/sl20/verifier/QualifiedeIDVerifier.java221
-rw-r--r--id/server/modules/moa-id-module-sl20_authentication/src/main/java/at/gv/egovernment/moa/id/auth/modules/sl20_auth/tasks/CreateQualeIDRequestTask.java93
-rw-r--r--id/server/modules/moa-id-module-sl20_authentication/src/main/java/at/gv/egovernment/moa/id/auth/modules/sl20_auth/tasks/ReceiveQualeIDTask.java309
-rw-r--r--id/server/modules/moa-id-module-sl20_authentication/src/main/java/at/gv/egovernment/moa/id/auth/modules/sl20_auth/tasks/VerifyQualifiedeIDTask.java136
-rw-r--r--id/server/modules/moa-id-module-sl20_authentication/src/main/resources/moaid_sl20_auth.beans.xml4
-rw-r--r--id/server/modules/moa-id-module-sl20_authentication/src/main/resources/sl20.Authentication.process.xml18
15 files changed, 1042 insertions, 217 deletions
diff --git a/id/server/modules/moa-id-module-sl20_authentication/src/main/java/at/gv/egovernment/moa/id/auth/modules/sl20_auth/Constants.java b/id/server/modules/moa-id-module-sl20_authentication/src/main/java/at/gv/egovernment/moa/id/auth/modules/sl20_auth/Constants.java
index 7a58648cc..f474461bf 100644
--- a/id/server/modules/moa-id-module-sl20_authentication/src/main/java/at/gv/egovernment/moa/id/auth/modules/sl20_auth/Constants.java
+++ b/id/server/modules/moa-id-module-sl20_authentication/src/main/java/at/gv/egovernment/moa/id/auth/modules/sl20_auth/Constants.java
@@ -3,11 +3,13 @@ package at.gv.egovernment.moa.id.auth.modules.sl20_auth;
public class Constants {
public static final String HTTP_ENDPOINT_DATAURL = "/sl20/dataUrl";
+ public static final String HTTP_ENDPOINT_RESUME = "/sl20/resume";
public static final String CONFIG_PROP_PREFIX = "modules.sl20";
- public static final String CONFIG_PROP_VDA_ENDPOINT_QUALeID = CONFIG_PROP_PREFIX + ".vda.urls.qualeID.endpoint";
+ public static final String CONFIG_PROP_VDA_ENDPOINT_QUALeID = CONFIG_PROP_PREFIX + ".vda.urls.qualeID.endpoint.";
+ public static final String CONFIG_PROP_VDA_ENDPOINT_QUALeID_DEFAULT = "default";
public static final String CONFIG_PROP_VDA_AUTHBLOCK_ID = CONFIG_PROP_PREFIX + ".vda.authblock.id";
-
+ 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";
@@ -15,6 +17,15 @@ public class Constants {
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";
+ public static final String CONFIG_PROP_VDA_ENDPOINT_QUALeID_LIST = CONFIG_PROP_VDA_ENDPOINT_QUALeID;
+ public static final String CONFIG_PROP_SP_LIST = CONFIG_PROP_PREFIX + ".sp.entityIds.";
+
+ public static final String CONFIG_PROP_DISABLE_EID_VALIDATION = CONFIG_PROP_PREFIX + ".security.eID.validation.disable";
+ public static final String CONFIG_PROP_ENABLE_EID_ENCRYPTION = CONFIG_PROP_PREFIX + ".security.eID.encryption.enabled";
+ public static final String CONFIG_PROP_FORCE_EID_ENCRYPTION = CONFIG_PROP_PREFIX + ".security.eID.encryption.required";
+ public static final String CONFIG_PROP_FORCE_EID_SIGNED_RESULT = CONFIG_PROP_PREFIX + ".security.eID.signed.result.required";
+
+ public static final String CONFIG_PROP_IPC_RETURN_URL = CONFIG_PROP_PREFIX + ".ipc.return.url";
public static final String PENDING_REQ_STORAGE_PREFIX = "SL20_AUTH_";
diff --git a/id/server/modules/moa-id-module-sl20_authentication/src/main/java/at/gv/egovernment/moa/id/auth/modules/sl20_auth/SL20AuthenticationModulImpl.java b/id/server/modules/moa-id-module-sl20_authentication/src/main/java/at/gv/egovernment/moa/id/auth/modules/sl20_auth/SL20AuthenticationModulImpl.java
index a2b58931e..9c2d47ca7 100644
--- a/id/server/modules/moa-id-module-sl20_authentication/src/main/java/at/gv/egovernment/moa/id/auth/modules/sl20_auth/SL20AuthenticationModulImpl.java
+++ b/id/server/modules/moa-id-module-sl20_authentication/src/main/java/at/gv/egovernment/moa/id/auth/modules/sl20_auth/SL20AuthenticationModulImpl.java
@@ -22,26 +22,32 @@
*/
package at.gv.egovernment.moa.id.auth.modules.sl20_auth;
+import java.util.Arrays;
+import java.util.List;
+
import javax.annotation.PostConstruct;
-import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
+import at.gv.egiz.eaaf.core.api.data.EAAFConstants;
+import at.gv.egiz.eaaf.core.api.idp.ISPConfiguration;
import at.gv.egiz.eaaf.core.api.idp.auth.modules.AuthModule;
import at.gv.egiz.eaaf.core.api.idp.process.ExecutionContext;
import at.gv.egovernment.moa.id.auth.modules.sl20_auth.sl20.SL20Constants;
import at.gv.egovernment.moa.id.commons.api.AuthConfiguration;
+import at.gv.egovernment.moa.id.commons.config.MOAIDConfigurationConstants;
import at.gv.egovernment.moa.id.moduls.AuthenticationManager;
import at.gv.egovernment.moa.logging.Logger;
+import at.gv.egovernment.moa.util.MiscUtil;
/**
* @author tlenz
*
*/
-public class SL20AuthenticationModulImpl implements AuthModule {
-
+public class SL20AuthenticationModulImpl implements AuthModule {
private int priority = 3;
-
+ public static final List<String> VDA_TYPE_IDS = Arrays.asList("1", "2", "3", "4");
+
@Autowired(required=true) protected AuthConfiguration authConfig;
@Autowired(required=true) private AuthenticationManager authManager;
@@ -62,6 +68,7 @@ public class SL20AuthenticationModulImpl implements AuthModule {
protected void initalSL20Authentication() {
//parameter to whiteList
authManager.addHeaderNameToWhiteList(SL20Constants.HTTP_HEADER_SL20_CLIENT_TYPE);
+ authManager.addHeaderNameToWhiteList(SL20Constants.HTTP_HEADER_SL20_VDA_TYPE);
}
@@ -71,17 +78,42 @@ public class SL20AuthenticationModulImpl implements AuthModule {
*/
@Override
public String selectProcess(ExecutionContext context) {
- if (StringUtils.isNotBlank((String) context.get(SL20Constants.HTTP_HEADER_SL20_CLIENT_TYPE.toLowerCase())) ||
- StringUtils.isNotBlank((String) context.get(SL20Constants.HTTP_HEADER_SL20_CLIENT_TYPE))) {
- Logger.trace(SL20Constants.HTTP_HEADER_SL20_CLIENT_TYPE + "' header found");
+ ISPConfiguration spConfig = (ISPConfiguration) context.get(EAAFConstants.PROCESSCONTEXT_SP_CONFIG);
+// if (spConfigObj != null && spConfigObj instanceof IOAAuthParameters)
+// spConfig = (IOAAuthParameters)spConfigObj;
+
+ String sl20ClientTypeHeader = (String) context.get(SL20Constants.HTTP_HEADER_SL20_CLIENT_TYPE.toLowerCase());
+ String sl20VDATypeHeader = (String) context.get(SL20Constants.HTTP_HEADER_SL20_VDA_TYPE.toLowerCase());
+
+ if (spConfig != null &&
+ MiscUtil.isNotEmpty(spConfig.getConfigurationValue(MOAIDConfigurationConstants.SERVICE_AUTH_SL20_ENABLED)) &&
+ Boolean.valueOf(spConfig.getConfigurationValue(MOAIDConfigurationConstants.SERVICE_AUTH_SL20_ENABLED))) {
+ Logger.debug("SL2.0 is enabled for " + spConfig.getUniqueIdentifier());
+ Logger.trace(SL20Constants.HTTP_HEADER_SL20_CLIENT_TYPE + ": " + sl20ClientTypeHeader);
+ Logger.trace(SL20Constants.HTTP_HEADER_SL20_VDA_TYPE + ": " + sl20VDATypeHeader);
return "SL20Authentication";
} else {
- Logger.trace("No '" + SL20Constants.HTTP_HEADER_SL20_CLIENT_TYPE + "' header found");
+ Logger.trace("SL2.0 is NOT enabled for " + spConfig.getUniqueIdentifier());
return null;
}
+
+// if ( StringUtils.isNotBlank(sl20ClientTypeHeader)
+//// && (
+//// StringUtils.isNotBlank(sl20VDATypeHeader)
+//// //&& VDA_TYPE_IDS.contains(sl20VDATypeHeader.trim())
+//// )
+// ) {
+// Logger.trace(SL20Constants.HTTP_HEADER_SL20_CLIENT_TYPE + "' header found");
+// return "SL20Authentication";
+//
+// } else {
+// Logger.trace("No '" + SL20Constants.HTTP_HEADER_SL20_CLIENT_TYPE + "' header found");
+// return null;
+//
+// }
}
/* (non-Javadoc)
diff --git a/id/server/modules/moa-id-module-sl20_authentication/src/main/java/at/gv/egovernment/moa/id/auth/modules/sl20_auth/SL20SignalServlet.java b/id/server/modules/moa-id-module-sl20_authentication/src/main/java/at/gv/egovernment/moa/id/auth/modules/sl20_auth/SL20SignalServlet.java
index ab7eb0830..87e9e933d 100644
--- a/id/server/modules/moa-id-module-sl20_authentication/src/main/java/at/gv/egovernment/moa/id/auth/modules/sl20_auth/SL20SignalServlet.java
+++ b/id/server/modules/moa-id-module-sl20_authentication/src/main/java/at/gv/egovernment/moa/id/auth/modules/sl20_auth/SL20SignalServlet.java
@@ -44,11 +44,14 @@ public class SL20SignalServlet extends AbstractProcessEngineSignalController {
public SL20SignalServlet() {
super();
Logger.debug("Registering servlet " + getClass().getName() +
- " with mappings '"+ Constants.HTTP_ENDPOINT_DATAURL + "'.");
+ " with mappings '"+ Constants.HTTP_ENDPOINT_DATAURL +
+ " and " + Constants.HTTP_ENDPOINT_RESUME +
+ "'.");
}
- @RequestMapping(value = { Constants.HTTP_ENDPOINT_DATAURL
+ @RequestMapping(value = { Constants.HTTP_ENDPOINT_DATAURL,
+ Constants.HTTP_ENDPOINT_RESUME
},
method = {RequestMethod.POST, RequestMethod.GET})
public void performCitizenCardAuthentication(HttpServletRequest req, HttpServletResponse resp) throws IOException {
diff --git a/id/server/modules/moa-id-module-sl20_authentication/src/main/java/at/gv/egovernment/moa/id/auth/modules/sl20_auth/exceptions/SL20eIDDataValidationException.java b/id/server/modules/moa-id-module-sl20_authentication/src/main/java/at/gv/egovernment/moa/id/auth/modules/sl20_auth/exceptions/SL20eIDDataValidationException.java
new file mode 100644
index 000000000..957ace0fb
--- /dev/null
+++ b/id/server/modules/moa-id-module-sl20_authentication/src/main/java/at/gv/egovernment/moa/id/auth/modules/sl20_auth/exceptions/SL20eIDDataValidationException.java
@@ -0,0 +1,16 @@
+package at.gv.egovernment.moa.id.auth.modules.sl20_auth.exceptions;
+
+public class SL20eIDDataValidationException extends SL20Exception {
+ private static final long serialVersionUID = 1L;
+
+ public SL20eIDDataValidationException(Object[] parameters) {
+ super("sl20.07", parameters);
+
+ }
+
+ public SL20eIDDataValidationException(Object[] parameters, Throwable e) {
+ super("sl20.07", parameters, e);
+
+ }
+
+}
diff --git a/id/server/modules/moa-id-module-sl20_authentication/src/main/java/at/gv/egovernment/moa/id/auth/modules/sl20_auth/sl20/JsonSecurityUtils.java b/id/server/modules/moa-id-module-sl20_authentication/src/main/java/at/gv/egovernment/moa/id/auth/modules/sl20_auth/sl20/JsonSecurityUtils.java
index 92a08e411..42783468d 100644
--- a/id/server/modules/moa-id-module-sl20_authentication/src/main/java/at/gv/egovernment/moa/id/auth/modules/sl20_auth/sl20/JsonSecurityUtils.java
+++ b/id/server/modules/moa-id-module-sl20_authentication/src/main/java/at/gv/egovernment/moa/id/auth/modules/sl20_auth/sl20/JsonSecurityUtils.java
@@ -1,10 +1,15 @@
package at.gv.egovernment.moa.id.auth.modules.sl20_auth.sl20;
+import java.io.IOException;
import java.security.Key;
import java.security.KeyStore;
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.PostConstruct;
@@ -14,6 +19,9 @@ import org.jose4j.jwa.AlgorithmConstraints.ConstraintType;
import org.jose4j.jwe.JsonWebEncryption;
import org.jose4j.jws.AlgorithmIdentifiers;
import org.jose4j.jws.JsonWebSignature;
+import org.jose4j.jwx.JsonWebStructure;
+import org.jose4j.keys.X509Util;
+import org.jose4j.keys.resolvers.X509VerificationKeyResolver;
import org.jose4j.lang.JoseException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@@ -34,6 +42,8 @@ import at.gv.egovernment.moa.id.commons.api.AuthConfiguration;
import at.gv.egovernment.moa.id.commons.api.exceptions.ConfigurationException;
import at.gv.egovernment.moa.id.commons.utils.X509Utils;
import at.gv.egovernment.moa.logging.Logger;
+import at.gv.egovernment.moa.util.Base64Utils;
+import at.gv.egovernment.moa.util.MiscUtil;
@Service
public class JsonSecurityUtils implements IJOSETools{
@@ -45,6 +55,8 @@ public class JsonSecurityUtils implements IJOSETools{
private Key encPrivKey = null;
private X509Certificate[] encCertChain = null;
+ private List<X509Certificate> trustedCerts = new ArrayList<X509Certificate>();
+
@PostConstruct
protected void initalize() {
Logger.info("Initialize SL2.0 authentication security constrains ... ");
@@ -68,7 +80,7 @@ public class JsonSecurityUtils implements IJOSETools{
try {
encPrivKey = keyStore.getKey(getEncryptionKeyAlias(), getEncryptionKeyPassword().toCharArray());
if (encPrivKey != null) {
- Certificate[] certChainEncryption = keyStore.getCertificateChain(getSigningKeyAlias());
+ Certificate[] certChainEncryption = keyStore.getCertificateChain(getEncryptionKeyAlias());
encCertChain = new X509Certificate[certChainEncryption.length];
for (int i=0; i<certChainEncryption.length; i++) {
if (certChainEncryption[i] instanceof X509Certificate) {
@@ -84,6 +96,21 @@ public class JsonSecurityUtils implements IJOSETools{
}
+ //load trusted certificates
+ Enumeration<String> aliases = keyStore.aliases();
+ while(aliases.hasMoreElements()) {
+ String el = aliases.nextElement();
+ Logger.trace("Process TrustStoreEntry: " + el);
+ if (keyStore.isCertificateEntry(el)) {
+ Certificate cert = keyStore.getCertificate(el);
+ if (cert != null && cert instanceof X509Certificate)
+ trustedCerts.add((X509Certificate) cert);
+ else
+ Logger.info("Can not process entry: " + el + ". Reason: " + cert.toString());
+
+ }
+ }
+
//some short validation
if (signPrivKey == null || !(signPrivKey instanceof PrivateKey)) {
Logger.info("Can NOT open privateKey for SL2.0 signing. KeyStore=" + getKeyStoreFilePath());
@@ -121,7 +148,10 @@ public class JsonSecurityUtils implements IJOSETools{
//set signing information
jws.setAlgorithmHeaderValue(AlgorithmIdentifiers.RSA_USING_SHA256);
jws.setKey(signPrivKey);
+
+ //TODO:
jws.setCertificateChainHeaderValue(signCertChain);
+ jws.setX509CertSha256ThumbprintHeaderValue(signCertChain[0]);
return jws.getCompactSerialization();
@@ -145,18 +175,47 @@ public class JsonSecurityUtils implements IJOSETools{
SL20Constants.SL20_ALGORITHM_WHITELIST_SIGNING.toArray(new String[SL20Constants.SL20_ALGORITHM_WHITELIST_SIGNING.size()])));
//load signinc certs
+ Key selectedKey = null;
List<X509Certificate> x5cCerts = jws.getCertificateChainHeaderValue();
- List<X509Certificate> sortedX5cCerts = null;
- if (x5cCerts == null || x5cCerts.size() < 1) {
- Logger.info("Signed SL2.0 response contains NO signature certificate");
- throw new SLCommandoParserException("Signed SL2.0 response contains NO signature certificate");
-
- }
+ String x5t256 = jws.getX509CertSha256ThumbprintHeaderValue();
+ if (x5cCerts != null) {
+ Logger.debug("Found x509 certificate in JOSE header ... ");
Logger.trace("Sorting received X509 certificates ... ");
- sortedX5cCerts = X509Utils.sortCertificates(x5cCerts);
+ List<X509Certificate> sortedX5cCerts = X509Utils.sortCertificates(x5cCerts);
+ if (trustedCerts.contains(sortedX5cCerts.get(0))) {
+ selectedKey = sortedX5cCerts.get(0).getPublicKey();
+
+ } else {
+ Logger.info("Can NOT find JOSE certificate in truststore.");
+ Logger.debug("JOSE certificate: " + sortedX5cCerts.get(0).toString());
+ try {
+ Logger.debug("Cert: " + Base64Utils.encode(sortedX5cCerts.get(0).getEncoded()));
+ } catch (CertificateEncodingException | IOException e) {
+ e.printStackTrace();
+ }
+
+ }
+
+ } else if (MiscUtil.isNotEmpty(x5t256)) {
+ Logger.debug("Found x5t256 fingerprint in JOSE header .... ");
+ X509VerificationKeyResolver x509VerificationKeyResolver = new X509VerificationKeyResolver(trustedCerts);
+ selectedKey = x509VerificationKeyResolver.resolveKey(jws, Collections.<JsonWebStructure>emptyList());
+
+ } else {
+ Logger.info("Signed SL2.0 response contains NO signature certificate or NO certificate fingerprint");
+ throw new SLCommandoParserException("Signed SL2.0 response contains NO signature certificate or NO certificate fingerprint");
+
+ }
+
+ if (selectedKey == null) {
+ Logger.info("Can NOT select verification key for JWS. Signature verification FAILED.");
+ throw new SLCommandoParserException("Can NOT select verification key for JWS. Signature verification FAILED");
+
+ }
+
//set verification key
- jws.setKey(sortedX5cCerts.get(0).getPublicKey());
+ jws.setKey(selectedKey);
//validate signature
boolean valid = jws.verifySignature();
@@ -167,10 +226,12 @@ public class JsonSecurityUtils implements IJOSETools{
}
+
//load payLoad
+ Logger.debug("SL2.0 commando signature validation sucessfull");
JsonElement sl20Req = new JsonParser().parse(jws.getPayload());
- return new VerificationResult(sl20Req.getAsJsonObject(), sortedX5cCerts, valid) ;
+ return new VerificationResult(sl20Req.getAsJsonObject(), null, valid) ;
} catch (JoseException e) {
Logger.warn("SL2.0 commando signature validation FAILED", e);
@@ -183,7 +244,7 @@ public class JsonSecurityUtils implements IJOSETools{
@Override
public JsonElement decryptPayload(String compactSerialization) throws SL20Exception {
- try {
+ try {
JsonWebEncryption receiverJwe = new JsonWebEncryption();
//set security constrains
@@ -196,12 +257,49 @@ public class JsonSecurityUtils implements IJOSETools{
//set payload
receiverJwe.setCompactSerialization(compactSerialization);
+
- //TODO: validate key from header against key from config
+ //validate key from header against key from config
+ List<X509Certificate> x5cCerts = receiverJwe.getCertificateChainHeaderValue();
+ String x5t256 = receiverJwe.getX509CertSha256ThumbprintHeaderValue();
+ if (x5cCerts != null) {
+ Logger.debug("Found x509 certificate in JOSE header ... ");
+ Logger.trace("Sorting received X509 certificates ... ");
+ List<X509Certificate> sortedX5cCerts = X509Utils.sortCertificates(x5cCerts);
- //decrypt payload
+ if (!sortedX5cCerts.get(0).equals(encCertChain[0])) {
+ Logger.info("Certificate from JOSE header does NOT match encryption certificate");
+ Logger.debug("JOSE certificate: " + sortedX5cCerts.get(0).toString());
+
+ try {
+ Logger.debug("Cert: " + Base64Utils.encode(sortedX5cCerts.get(0).getEncoded()));
+ } catch (CertificateEncodingException | IOException e) {
+ e.printStackTrace();
+ }
+ throw new SL20Exception("sl20.05", new Object[]{"Certificate from JOSE header does NOT match encryption certificate"});
+ }
+
+ } else if (MiscUtil.isNotEmpty(x5t256)) {
+ Logger.debug("Found x5t256 fingerprint in JOSE header .... ");
+ String certFingerPrint = X509Util.x5tS256(encCertChain[0]);
+ if (!certFingerPrint.equals(x5t256)) {
+ Logger.info("X5t256 from JOSE header does NOT match encryption certificate");
+ Logger.debug("X5t256 from JOSE header: " + x5t256 + " Encrytption cert: " + certFingerPrint);
+ throw new SL20Exception("sl20.05", new Object[]{"X5t256 from JOSE header does NOT match encryption certificate"});
+
+ }
+
+ } else {
+ Logger.info("Signed SL2.0 response contains NO signature certificate or NO certificate fingerprint");
+ throw new SLCommandoParserException("Signed SL2.0 response contains NO signature certificate or NO certificate fingerprint");
+
+ }
+
+ //set key
receiverJwe.setKey(encPrivKey);
+
+ //decrypt payload
return new JsonParser().parse(receiverJwe.getPlaintextString());
} catch (JoseException e) {
diff --git a/id/server/modules/moa-id-module-sl20_authentication/src/main/java/at/gv/egovernment/moa/id/auth/modules/sl20_auth/sl20/SL20Constants.java b/id/server/modules/moa-id-module-sl20_authentication/src/main/java/at/gv/egovernment/moa/id/auth/modules/sl20_auth/sl20/SL20Constants.java
index b855c3cac..645b043ce 100644
--- a/id/server/modules/moa-id-module-sl20_authentication/src/main/java/at/gv/egovernment/moa/id/auth/modules/sl20_auth/sl20/SL20Constants.java
+++ b/id/server/modules/moa-id-module-sl20_authentication/src/main/java/at/gv/egovernment/moa/id/auth/modules/sl20_auth/sl20/SL20Constants.java
@@ -8,14 +8,17 @@ import org.jose4j.jwe.KeyManagementAlgorithmIdentifiers;
import org.jose4j.jws.AlgorithmIdentifiers;
public class SL20Constants {
- public static final String CURRENT_SL20_VERSION = "10";
+ public static final int CURRENT_SL20_VERSION = 10;
//http binding parameters
public static final String PARAM_SL20_REQ_COMMAND_PARAM = "slcommand";
+ public static final String PARAM_SL20_REQ_COMMAND_PARAM_OLD = "sl2command";
+
public static final String PARAM_SL20_REQ_ICP_RETURN_URL_PARAM = "slIPCReturnUrl";
public static final String PARAM_SL20_REQ_TRANSACTIONID = "slTransactionID";
public static final String HTTP_HEADER_SL20_CLIENT_TYPE = "SL2ClientType";
+ public static final String HTTP_HEADER_SL20_VDA_TYPE = "X-MOA-VDA";
public static final String HTTP_HEADER_VALUE_NATIVE = "nativeApp";
@@ -88,7 +91,11 @@ public class SL20Constants {
public static final String SL20_COMMAND_IDENTIFIER_CALL = "call";
public static final String SL20_COMMAND_IDENTIFIER_ERROR = "error";
public static final String SL20_COMMAND_IDENTIFIER_QUALIFIEDEID = "qualifiedeID";
- public static final String SL20_COMMAND_IDENTIFIER_QUALIFIEDSIG = "qualifiedSig";
+ //public static final String SL20_COMMAND_IDENTIFIER_QUALIFIEDSIG = "qualifiedSig";
+
+ public static final String SL20_COMMAND_IDENTIFIER_GETCERTIFICATE = "getCertificate";
+ public static final String SL20_COMMAND_IDENTIFIER_CREATE_SIG_CADES = "createCAdES";
+
public static final String SL20_COMMAND_IDENTIFIER_BINDING_CREATE_KEY = "createBindingKey";
public static final String SL20_COMMAND_IDENTIFIER_BINDING_STORE_CERT = "storeBindingCert";
@@ -103,6 +110,7 @@ public class SL20Constants {
public static final String SL20_COMMAND_PARAM_GENERAL_REQPARAMETER_KEY = "key";
public static final String SL20_COMMAND_PARAM_GENERAL_DATAURL = "dataUrl";
public static final String SL20_COMMAND_PARAM_GENERAL_RESPONSEENCRYPTIONCERTIFICATE = "x5cEnc";
+ public static final String SL20_COMMAND_PARAM_GENERAL_RESPONSEENCRYPTIONJWK = "jwkEnc";
//Redirect command
public static final String SL20_COMMAND_PARAM_GENERAL_REDIRECT_URL = "url";
@@ -127,17 +135,48 @@ public class SL20Constants {
public static final String SL20_COMMAND_PARAM_EID_DATAURL = SL20_COMMAND_PARAM_GENERAL_DATAURL;
public static final String SL20_COMMAND_PARAM_EID_ATTRIBUTES = "attributes";
public static final String SL20_COMMAND_PARAM_EID_ATTRIBUTES_MANDATEREFVALUE = "MANDATE-REFERENCE-VALUE";
- public static final String SL20_COMMAND_PARAM_EID_ATTRIBUTES_SPUNIQUEID = "SP-FRIENDLYNAME";
- public static final String SL20_COMMAND_PARAM_EID_ATTRIBUTES_SPFRIENDLYNAME = "SP-UNIQUEID";
+ public static final String SL20_COMMAND_PARAM_EID_ATTRIBUTES_SPUNIQUEID = "SP-UNIQUEID";
+ public static final String SL20_COMMAND_PARAM_EID_ATTRIBUTES_SPFRIENDLYNAME = "SP-FRIENDLYNAME";
+ public static final String SL20_COMMAND_PARAM_EID_ATTRIBUTES_SPCOUNTRYCODE = "SP-COUNTRYCODE";
public static final String SL20_COMMAND_PARAM_EID_X5CENC = SL20_COMMAND_PARAM_GENERAL_RESPONSEENCRYPTIONCERTIFICATE;
+ public static final String SL20_COMMAND_PARAM_EID_JWKCENC = SL20_COMMAND_PARAM_GENERAL_RESPONSEENCRYPTIONJWK;
public static final String SL20_COMMAND_PARAM_EID_RESULT_IDL = "EID-IDENTITY-LINK";
public static final String SL20_COMMAND_PARAM_EID_RESULT_AUTHBLOCK = "EID-AUTH-BLOCK";
public static final String SL20_COMMAND_PARAM_EID_RESULT_CCSURL = "EID-CCS-URL";
public static final String SL20_COMMAND_PARAM_EID_RESULT_LOA = "EID-CITIZEN-QAA-LEVEL";
//qualified Signature comamnd
- public static final String SL20_COMMAND_PARAM_QUALSIG_DATAURL = SL20_COMMAND_PARAM_GENERAL_DATAURL;
- public static final String SL20_COMMAND_PARAM_QUALSIG_X5CENC = SL20_COMMAND_PARAM_GENERAL_RESPONSEENCRYPTIONCERTIFICATE;
+// public static final String SL20_COMMAND_PARAM_QUALSIG_DATAURL = SL20_COMMAND_PARAM_GENERAL_DATAURL;
+// public static final String SL20_COMMAND_PARAM_QUALSIG_X5CENC = SL20_COMMAND_PARAM_GENERAL_RESPONSEENCRYPTIONCERTIFICATE;
+
+
+ //getCertificate
+ public static final String SL20_COMMAND_PARAM_GETCERTIFICATE_KEYID = "keyId";
+ public static final String SL20_COMMAND_PARAM_GETCERTIFICATE_DATAURL = SL20_COMMAND_PARAM_GENERAL_DATAURL;
+ public static final String SL20_COMMAND_PARAM_GETCERTIFICATE_X5CENC = SL20_COMMAND_PARAM_GENERAL_RESPONSEENCRYPTIONCERTIFICATE;
+ public static final String SL20_COMMAND_PARAM_GETCERTIFICATE_JWKCENC = SL20_COMMAND_PARAM_GENERAL_RESPONSEENCRYPTIONJWK;
+ public static final String SL20_COMMAND_PARAM_GETCERTIFICATE_RESULT_CERTIFICATE = "x5c";
+
+ //createCAdES Signture
+ public static final String SL20_COMMAND_PARAM_CREATE_SIG_CADES_KEYID = "keyId";
+ public static final String SL20_COMMAND_PARAM_CREATE_SIG_CADES_CONTENT = "content";
+ public static final String SL20_COMMAND_PARAM_CREATE_SIG_CADES_MIMETYPE = "mimeType";
+ public static final String SL20_COMMAND_PARAM_CREATE_SIG_CADES_PADES_COMBATIBILTY = "padesComatibility";
+ public static final String SL20_COMMAND_PARAM_CREATE_SIG_CADES_EXCLUDEBYTERANGE = "excludedByteRange";
+ public static final String SL20_COMMAND_PARAM_CREATE_SIG_CADES_CADESLEVEL = "cadesLevel";
+ public static final String SL20_COMMAND_PARAM_CREATE_SIG_CADES_DATAURL = SL20_COMMAND_PARAM_GENERAL_DATAURL;
+ public static final String SL20_COMMAND_PARAM_CREATE_SIG_CADES_X5CENC = SL20_COMMAND_PARAM_GENERAL_RESPONSEENCRYPTIONCERTIFICATE;
+ public static final String SL20_COMMAND_PARAM_CREATE_SIG_CADES_JWKCENC = SL20_COMMAND_PARAM_GENERAL_RESPONSEENCRYPTIONJWK;
+ public static final String SL20_COMMAND_PARAM_CREATE_SIG_CADES_RESULT_SIGNATURE = "signature";
+
+ public static final String SL20_COMMAND_PARAM_CREATE_SIG_CADES_CADESLEVEL_BASIC = "cAdES";
+ public static final String SL20_COMMAND_PARAM_CREATE_SIG_CADES_CADESLEVEL_T = "cAdES-T";
+ public static final String SL20_COMMAND_PARAM_CREATE_SIG_CADES_CADESLEVEL_C = "cAdES-C";
+ public static final String SL20_COMMAND_PARAM_CREATE_SIG_CADES_CADESLEVEL_X = "cAdES-X";
+ public static final String SL20_COMMAND_PARAM_CREATE_SIG_CADES_CADESLEVEL_XL = "cAdES-X-L";
+ public static final String SL20_COMMAND_PARAM_CREATE_SIG_CADES_CADESLEVEL_A = "cAdES-A";
+
+
//create binding key command
public static final String SL20_COMMAND_PARAM_BINDING_CREATE_KONTOID = "kontoID";
diff --git a/id/server/modules/moa-id-module-sl20_authentication/src/main/java/at/gv/egovernment/moa/id/auth/modules/sl20_auth/sl20/SL20HttpBindingUtils.java b/id/server/modules/moa-id-module-sl20_authentication/src/main/java/at/gv/egovernment/moa/id/auth/modules/sl20_auth/sl20/SL20HttpBindingUtils.java
index cc7137a0f..169cb8e73 100644
--- a/id/server/modules/moa-id-module-sl20_authentication/src/main/java/at/gv/egovernment/moa/id/auth/modules/sl20_auth/sl20/SL20HttpBindingUtils.java
+++ b/id/server/modules/moa-id-module-sl20_authentication/src/main/java/at/gv/egovernment/moa/id/auth/modules/sl20_auth/sl20/SL20HttpBindingUtils.java
@@ -2,7 +2,6 @@ package at.gv.egovernment.moa.id.auth.modules.sl20_auth.sl20;
import java.io.IOException;
import java.io.StringWriter;
-import java.io.UnsupportedEncodingException;
import java.net.URISyntaxException;
import javax.servlet.http.HttpServletRequest;
@@ -10,6 +9,7 @@ import javax.servlet.http.HttpServletResponse;
import org.apache.http.client.utils.URIBuilder;
import org.apache.http.entity.ContentType;
+import org.jose4j.base64url.Base64Url;
import com.google.gson.JsonObject;
@@ -33,7 +33,9 @@ public class SL20HttpBindingUtils {
} else {
Logger.debug("Client request containts is no native client ... ");
URIBuilder clientRedirectURI = new URIBuilder(redirectURL);
- clientRedirectURI.addParameter(SL20Constants.PARAM_SL20_REQ_COMMAND_PARAM, sl20Forward.toString());
+ clientRedirectURI.addParameter(
+ SL20Constants.PARAM_SL20_REQ_COMMAND_PARAM,
+ Base64Url.encode(sl20Forward.toString().getBytes()));
response.setStatus(307);
response.setHeader("Location", clientRedirectURI.build().toString());
diff --git a/id/server/modules/moa-id-module-sl20_authentication/src/main/java/at/gv/egovernment/moa/id/auth/modules/sl20_auth/sl20/SL20JSONBuilderUtils.java b/id/server/modules/moa-id-module-sl20_authentication/src/main/java/at/gv/egovernment/moa/id/auth/modules/sl20_auth/sl20/SL20JSONBuilderUtils.java
index 52d7e1e67..d5dec1fe1 100644
--- a/id/server/modules/moa-id-module-sl20_authentication/src/main/java/at/gv/egovernment/moa/id/auth/modules/sl20_auth/sl20/SL20JSONBuilderUtils.java
+++ b/id/server/modules/moa-id-module-sl20_authentication/src/main/java/at/gv/egovernment/moa/id/auth/modules/sl20_auth/sl20/SL20JSONBuilderUtils.java
@@ -387,7 +387,7 @@ public class SL20JSONBuilderUtils {
*/
public static JsonObject createGenericRequest(String reqId, String transactionId, JsonElement payLoad, String signedPayload) throws SLCommandoBuildException {
JsonObject req = new JsonObject();
- addSingleStringElement(req, SL20Constants.SL20_VERSION, SL20Constants.CURRENT_SL20_VERSION, true);
+ addSingleIntegerElement(req, SL20Constants.SL20_VERSION, SL20Constants.CURRENT_SL20_VERSION, true);
addSingleStringElement(req, SL20Constants.SL20_REQID, reqId, true);
addSingleStringElement(req, SL20Constants.SL20_TRANSACTIONID, transactionId, false);
addOnlyOnceOfTwo(req, SL20Constants.SL20_PAYLOAD, SL20Constants.SL20_SIGNEDPAYLOAD,
@@ -411,7 +411,7 @@ public class SL20JSONBuilderUtils {
JsonElement payLoad, String signedPayload) throws SLCommandoBuildException {
JsonObject req = new JsonObject();
- addSingleStringElement(req, SL20Constants.SL20_VERSION, SL20Constants.CURRENT_SL20_VERSION, true);
+ addSingleIntegerElement(req, SL20Constants.SL20_VERSION, SL20Constants.CURRENT_SL20_VERSION, true);
addSingleStringElement(req, SL20Constants.SL20_RESPID, respId, true);
addSingleStringElement(req, SL20Constants.SL20_INRESPTO, inResponseTo, true);
addSingleStringElement(req, SL20Constants.SL20_TRANSACTIONID, transactionId, false);
@@ -568,6 +568,17 @@ public class SL20JSONBuilderUtils {
}
+ private static void addSingleIntegerElement(JsonObject parent, String keyId, Integer value, boolean isRequired) throws SLCommandoBuildException {
+ validateParentAndKey(parent, keyId);
+
+ if (isRequired && value == null)
+ throw new SLCommandoBuildException(keyId + " has an empty value");
+
+ else if (value != null)
+ parent.addProperty(keyId, value);
+
+ }
+
private static void addSingleJSONElement(JsonObject parent, String keyId, JsonElement element, boolean isRequired) throws SLCommandoBuildException {
validateParentAndKey(parent, keyId);
diff --git a/id/server/modules/moa-id-module-sl20_authentication/src/main/java/at/gv/egovernment/moa/id/auth/modules/sl20_auth/sl20/SL20JSONExtractorUtils.java b/id/server/modules/moa-id-module-sl20_authentication/src/main/java/at/gv/egovernment/moa/id/auth/modules/sl20_auth/sl20/SL20JSONExtractorUtils.java
index e01945df0..759d9c838 100644
--- a/id/server/modules/moa-id-module-sl20_authentication/src/main/java/at/gv/egovernment/moa/id/auth/modules/sl20_auth/sl20/SL20JSONExtractorUtils.java
+++ b/id/server/modules/moa-id-module-sl20_authentication/src/main/java/at/gv/egovernment/moa/id/auth/modules/sl20_auth/sl20/SL20JSONExtractorUtils.java
@@ -1,17 +1,20 @@
package at.gv.egovernment.moa.id.auth.modules.sl20_auth.sl20;
import java.io.InputStreamReader;
-import java.net.URLDecoder;
+import java.util.ArrayList;
import java.util.Base64;
import java.util.HashMap;
import java.util.Iterator;
+import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import org.apache.http.Header;
+import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.client.utils.URIBuilder;
import org.apache.log4j.Logger;
+import org.jose4j.base64url.Base64Url;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
@@ -106,45 +109,95 @@ public class SL20JSONExtractorUtils {
}
/**
- * Extract Map of Key/Value pairs from a JSON Array
+ * Extract a List of String elements from a JSON element
*
* @param input
- * @param keyID
+ * @return
+ * @throws SLCommandoParserException
+ */
+ public static List<String> getListOfStringElements(JsonElement input) throws SLCommandoParserException {
+ List<String> result = new ArrayList<String>();
+ if (input != null) {
+ if (input.isJsonArray()) {
+ Iterator<JsonElement> arrayIterator = input.getAsJsonArray().iterator();
+ while(arrayIterator.hasNext()) {
+ JsonElement next = arrayIterator.next();
+ if (next.isJsonPrimitive())
+ result.add(next.getAsString());
+ }
+
+ } else if (input.isJsonPrimitive()) {
+ result.add(input.getAsString());
+
+ } else {
+ log.warn("JSON Element IS NOT a JSON array or a JSON Primitive");
+ throw new SLCommandoParserException("JSON Element IS NOT a JSON array or a JSON Primitive");
+
+ }
+ }
+
+ return result;
+ }
+
+ /**
+ * Extract Map of Key/Value pairs from a JSON Element
+ *
+ * @param input parent JSON object
+ * @param keyID KeyId of the child that should be parsed
* @param isRequired
* @return
* @throws SLCommandoParserException
*/
public static Map<String, String> getMapOfStringElements(JsonObject input, String keyID, boolean isRequired) throws SLCommandoParserException {
JsonElement internal = getAndCheck(input, keyID, isRequired);
+ return getMapOfStringElements(internal);
+ }
+
+ /**
+ * Extract Map of Key/Value pairs from a JSON Element
+ *
+ * @param input
+ * @return
+ * @throws SLCommandoParserException
+ */
+ public static Map<String, String> getMapOfStringElements(JsonElement input) throws SLCommandoParserException {
Map<String, String> result = new HashMap<String, String>();
- if (internal != null) {
- if (!internal.isJsonArray())
- throw new SLCommandoParserException("JSON Element IS NOT a JSON array");
-
- Iterator<JsonElement> arrayIterator = internal.getAsJsonArray().iterator();
- while(arrayIterator.hasNext()) {
- //JsonObject next = arrayIterator.next().getAsJsonObject();
- //result.put(
- // next.get(SL20Constants.SL20_COMMAND_PARAM_GENERAL_REQPARAMETER_KEY).getAsString(),
- // next.get(SL20Constants.SL20_COMMAND_PARAM_GENERAL_REQPARAMETER_VALUE).getAsString());
- JsonElement next = arrayIterator.next();
- Iterator<Entry<String, JsonElement>> entry = next.getAsJsonObject().entrySet().iterator();
- while (entry.hasNext()) {
- Entry<String, JsonElement> el = entry.next();
- if (result.containsKey(el.getKey()))
- log.info("Attr. Map already contains Element with Key: " + el.getKey() + ". Overwrite element ... ");
-
- result.put(el.getKey(), el.getValue().getAsString());
+ if (input != null) {
+ if (input.isJsonArray()) {
+ Iterator<JsonElement> arrayIterator = input.getAsJsonArray().iterator();
+ while(arrayIterator.hasNext()) {
+ JsonElement next = arrayIterator.next();
+ Iterator<Entry<String, JsonElement>> entry = next.getAsJsonObject().entrySet().iterator();
+ entitySetToMap(result, entry);
- }
- }
+ }
+
+ } else if (input.isJsonObject()) {
+ Iterator<Entry<String, JsonElement>> objectKeys = input.getAsJsonObject().entrySet().iterator();
+ entitySetToMap(result, objectKeys);
+
+ } else
+ throw new SLCommandoParserException("JSON Element IS NOT a JSON array or a JSON object");
+
}
return result;
}
+ private static void entitySetToMap(Map<String, String> result, Iterator<Entry<String, JsonElement>> entry) {
+ while (entry.hasNext()) {
+ Entry<String, JsonElement> el = entry.next();
+ if (result.containsKey(el.getKey()))
+ log.info("Attr. Map already contains Element with Key: " + el.getKey() + ". Overwrite element ... ");
+
+ result.put(el.getKey(), el.getValue().getAsString());
+
+ }
+
+ }
+
public static JsonElement extractSL20Result(JsonObject command, IJOSETools decrypter, boolean mustBeEncrypted) throws SL20Exception {
JsonElement result = command.get(SL20Constants.SL20_COMMAND_CONTAINER_RESULT);
@@ -152,31 +205,39 @@ public class SL20JSONExtractorUtils {
if (result == null && encryptedResult == null)
throw new SLCommandoParserException("NO result OR encryptedResult FOUND.");
-
- else if (result == null && encryptedResult == null)
- throw new SLCommandoParserException("result AND encryptedResultFOUND. Can not used twice");
-
+
else if (encryptedResult == null && mustBeEncrypted)
throw new SLCommandoParserException("result MUST be signed.");
-
- else if (result != null)
- return result;
-
+
else if (encryptedResult != null && encryptedResult.isJsonPrimitive()) {
- /*TODO:
- *
- * Remove dummy code and test real decryption!!!!!
- *
- */
+ try {
+ return decrypter.decryptPayload(encryptedResult.getAsString());
+
+ } catch (Exception e) {
+ log.info("Can NOT decrypt SL20 result. Reason:" + e.getMessage());
+ if (!mustBeEncrypted) {
+ log.warn("Decrypted results are disabled by configuration. Parse result in plain if it is possible");
- //return decrypter.decryptPayload(encryptedResult.getAsString());
+ //dummy code
+ try {
+ String[] signedPayload = encryptedResult.toString().split("\\.");
+ JsonElement payLoad = new JsonParser().parse(new String(Base64.getUrlDecoder().decode(signedPayload[1])));
+ return payLoad;
+
+ } catch (Exception e1) {
+ log.debug("DummyCode FAILED, Reason: " + e1.getMessage() + " Ignore it ...");
+ throw new SL20Exception(e.getMessage(), null, e);
+
+ }
+
+ } else
+ throw e;
+
+ }
+
+ } else if (result != null) {
+ return result;
- //dummy code
- String[] signedPayload = encryptedResult.toString().split("\\.");
- JsonElement payLoad = new JsonParser().parse(new String(Base64.getUrlDecoder().decode(signedPayload[1])));
- return payLoad;
-
-
} else
throw new SLCommandoParserException("Internal build error");
@@ -202,19 +263,16 @@ public class SL20JSONExtractorUtils {
if (sl20Payload == null && sl20SignedPayload == null)
throw new SLCommandoParserException("NO payLoad OR signedPayload FOUND.");
- else if (sl20Payload == null && sl20SignedPayload == null)
- throw new SLCommandoParserException("payLoad AND signedPayload FOUND. Can not used twice");
-
else if (sl20SignedPayload == null && mustBeSigned)
throw new SLCommandoParserException("payLoad MUST be signed.");
+
+ else if (joseTools != null && sl20SignedPayload != null && sl20SignedPayload.isJsonPrimitive()) {
+ return joseTools.validateSignature(sl20SignedPayload.getAsString());
- else if (sl20Payload != null)
+ } else if (sl20Payload != null)
return new VerificationResult(sl20Payload.getAsJsonObject());
- else if (sl20SignedPayload != null && sl20SignedPayload.isJsonPrimitive()) {
- return joseTools.validateSignature(sl20SignedPayload.getAsString());
-
- } else
+ else
throw new SLCommandoParserException("Internal build error");
@@ -237,17 +295,25 @@ public class SL20JSONExtractorUtils {
throw new SLCommandoParserException("Find Redirect statuscode but not Location header");
String sl20RespString = new URIBuilder(locationHeader[0].getValue()).getQueryParams().get(0).getValue();
- sl20Resp = new JsonParser().parse(URLDecoder.decode(sl20RespString)).getAsJsonObject();
+ sl20Resp = new JsonParser().parse(Base64Url.encode((sl20RespString.getBytes()))).getAsJsonObject();
} else if (httpResp.getStatusLine().getStatusCode() == 200) {
- if (!httpResp.getEntity().getContentType().getValue().equals("application/json;charset=UTF-8"))
- throw new SLCommandoParserException("SL20 response with a wrong ContentType: " + httpResp.getEntity().getContentType().getValue());
-
- sl20Resp = new JsonParser().parse(new InputStreamReader(httpResp.getEntity().getContent())).getAsJsonObject();
+ if (!httpResp.getEntity().getContentType().getValue().startsWith("application/json"))
+ throw new SLCommandoParserException("SL20 response with a wrong ContentType: " + httpResp.getEntity().getContentType().getValue());
+ sl20Resp = parseSL20ResultFromResponse(httpResp.getEntity());
+ } else if ( (httpResp.getStatusLine().getStatusCode() == 500) ||
+ (httpResp.getStatusLine().getStatusCode() == 401) ||
+ (httpResp.getStatusLine().getStatusCode() == 400) ) {
+ log.info("SL20 response with http-code: " + httpResp.getStatusLine().getStatusCode()
+ + ". Search for error message");
+ sl20Resp = parseSL20ResultFromResponse(httpResp.getEntity());
+
+
} else
throw new SLCommandoParserException("SL20 response with http-code: " + httpResp.getStatusLine().getStatusCode());
-
+
+ log.info("Find JSON object in http response");
return sl20Resp;
} catch (Exception e) {
@@ -256,6 +322,22 @@ public class SL20JSONExtractorUtils {
}
}
+ private static JsonObject parseSL20ResultFromResponse(HttpEntity resp) throws Exception {
+ if (resp != null && resp.getContent() != null) {
+ JsonElement sl20Resp = new JsonParser().parse(new InputStreamReader(resp.getContent()));
+ if (sl20Resp != null && sl20Resp.isJsonObject()) {
+ return sl20Resp.getAsJsonObject();
+
+ } else
+ throw new SLCommandoParserException("SL2.0 can NOT parse to a JSON object");
+
+
+ } else
+ throw new SLCommandoParserException("Can NOT find content in http response");
+
+ }
+
+
private static JsonElement getAndCheck(JsonObject input, String keyID, boolean isRequired) throws SLCommandoParserException {
JsonElement internal = input.get(keyID);
diff --git a/id/server/modules/moa-id-module-sl20_authentication/src/main/java/at/gv/egovernment/moa/id/auth/modules/sl20_auth/sl20/verifier/QualifiedeIDVerifier.java b/id/server/modules/moa-id-module-sl20_authentication/src/main/java/at/gv/egovernment/moa/id/auth/modules/sl20_auth/sl20/verifier/QualifiedeIDVerifier.java
new file mode 100644
index 000000000..599a67dfd
--- /dev/null
+++ b/id/server/modules/moa-id-module-sl20_authentication/src/main/java/at/gv/egovernment/moa/id/auth/modules/sl20_auth/sl20/verifier/QualifiedeIDVerifier.java
@@ -0,0 +1,221 @@
+package at.gv.egovernment.moa.id.auth.modules.sl20_auth.sl20.verifier;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.util.Date;
+import java.util.List;
+
+import org.opensaml.Configuration;
+import org.opensaml.saml2.core.Assertion;
+import org.opensaml.xml.XMLObject;
+import org.opensaml.xml.io.Unmarshaller;
+import org.opensaml.xml.io.UnmarshallerFactory;
+import org.w3c.dom.Element;
+import org.xml.sax.SAXException;
+
+import at.gv.egiz.eaaf.core.api.idp.auth.data.IIdentityLink;
+import at.gv.egiz.eaaf.core.impl.utils.DOMUtils;
+import at.gv.egiz.eaaf.core.impl.utils.KeyValueUtils;
+import at.gv.egiz.eaaf.modules.pvp2.impl.utils.SAML2Utils;
+import at.gv.egiz.eaaf.modules.pvp2.sp.impl.utils.AssertionAttributeExtractor;
+import at.gv.egovernment.moa.id.auth.builder.SignatureVerificationUtils;
+import at.gv.egovernment.moa.id.auth.invoke.SignatureVerificationInvoker;
+import at.gv.egovernment.moa.id.auth.modules.sl20_auth.exceptions.SL20eIDDataValidationException;
+import at.gv.egovernment.moa.id.auth.modules.sl20_auth.sl20.SL20Constants;
+import at.gv.egovernment.moa.id.auth.parser.VerifyXMLSignatureResponseParser;
+import at.gv.egovernment.moa.id.auth.validator.IdentityLinkValidator;
+import at.gv.egovernment.moa.id.auth.validator.VerifyXMLSignatureRequestBuilder;
+import at.gv.egovernment.moa.id.auth.validator.VerifyXMLSignatureResponseValidator;
+import at.gv.egovernment.moa.id.commons.api.AuthConfiguration;
+import at.gv.egovernment.moa.id.commons.api.IOAAuthParameters;
+import at.gv.egovernment.moa.id.commons.api.data.IVerifiyXMLSignatureResponse;
+import at.gv.egovernment.moa.id.commons.api.exceptions.MOAIDException;
+import at.gv.egovernment.moa.logging.Logger;
+import at.gv.egovernment.moa.sig.tsl.utils.MiscUtil;
+import at.gv.egovernment.moa.util.Base64Utils;
+
+
+public class QualifiedeIDVerifier {
+ public static void verifyIdentityLink(IIdentityLink idl, IOAAuthParameters oaParam, AuthConfiguration authConfig) throws MOAIDException {
+ // validates the identity link
+ IdentityLinkValidator.getInstance().validate(idl);
+
+ // builds a <VerifyXMLSignatureRequest> for a call of MOA-SP
+ Element domVerifyXMLSignatureRequest = new VerifyXMLSignatureRequestBuilder()
+ .build(idl, authConfig.getMoaSpIdentityLinkTrustProfileID(oaParam.isUseIDLTestTrustStore()));
+
+ // invokes the call
+ Element domVerifyXMLSignatureResponse = SignatureVerificationInvoker.getInstance()
+ .verifyXMLSignature(domVerifyXMLSignatureRequest);
+
+ // parses the <VerifyXMLSignatureResponse>
+ IVerifiyXMLSignatureResponse verifyXMLSignatureResponse = new VerifyXMLSignatureResponseParser(domVerifyXMLSignatureResponse).parseData();
+
+ // validates the <VerifyXMLSignatureResponse>
+ VerifyXMLSignatureResponseValidator.getInstance().validate(
+ verifyXMLSignatureResponse,
+ authConfig.getIdentityLinkX509SubjectNames(),
+ VerifyXMLSignatureResponseValidator.CHECK_IDENTITY_LINK,
+ oaParam,
+ authConfig);
+
+
+ }
+
+ public static IVerifiyXMLSignatureResponse verifyAuthBlock(String authBlockB64, IOAAuthParameters oaParam, AuthConfiguration authConfig) throws MOAIDException, IOException {
+ String trustProfileId = authConfig.getMoaSpAuthBlockTrustProfileID(oaParam.isUseAuthBlockTestTestStore());
+ List<String> verifyTransformsInfoProfileID =
+ KeyValueUtils.getListOfCSVValues(
+ KeyValueUtils.normalizeCSVValueString(
+ authConfig.getBasicConfiguration(
+ at.gv.egovernment.moa.id.auth.modules.sl20_auth.Constants.CONFIG_PROP_VDA_AUTHBLOCK_TRANSFORMATION_ID)));
+
+ SignatureVerificationUtils sigVerify = new SignatureVerificationUtils();
+ IVerifiyXMLSignatureResponse sigVerifyResult = sigVerify.verify(Base64Utils.decode(authBlockB64, false), trustProfileId , verifyTransformsInfoProfileID);
+
+ // validates the <VerifyXMLSignatureResponse>
+ VerifyXMLSignatureResponseValidator.getInstance().validate(sigVerifyResult,
+ null, VerifyXMLSignatureResponseValidator.CHECK_AUTH_BLOCK, oaParam, authConfig);
+
+ return sigVerifyResult;
+
+ }
+
+ public static boolean checkConsistencyOfeIDData(String sl20ReqId, IIdentityLink idl, AssertionAttributeExtractor authBlockExtractor, IVerifiyXMLSignatureResponse sigVerifyResult) throws SL20eIDDataValidationException {
+
+ try {
+ // compares the public keys from the identityLink with the AuthBlock
+ VerifyXMLSignatureResponseValidator.getInstance().validateCertificate(sigVerifyResult, idl);
+
+ //compare requestId from SL20 qualifiedeID command to ID from SAML2 assertion
+ String authBlockId = authBlockExtractor.getAssertionID();
+ if (MiscUtil.isEmpty(authBlockId)) {
+ Logger.info("AuthBlock containts no ID, but ID MUST be included");
+ throw new SL20eIDDataValidationException(new Object[] {
+ SL20Constants.SL20_COMMAND_PARAM_EID_RESULT_AUTHBLOCK,
+ "AuthBlock containts no ID, but ID MUST be included"
+ });
+ }
+
+ if (!authBlockId.equals(sl20ReqId)) {
+ Logger.info("SL20 'requestId' does NOT match to AuthBlock Id."
+ + " Expected : " + sl20ReqId
+ + " Authblock: " + authBlockId);
+ throw new SL20eIDDataValidationException(new Object[] {
+ SL20Constants.SL20_COMMAND_PARAM_EID_RESULT_AUTHBLOCK,
+ "SL20 'requestId' does NOT match to AuthBlock Id."
+ });
+ }
+
+
+ // Compare AuthBlock Data with information stored in session, especially
+ // date and time
+ validateSigningDateTime(sigVerifyResult, authBlockExtractor);
+
+ } catch ( Exception e) {
+ Logger.warn("Validation of eID information FAILED. ", e);
+ throw new SL20eIDDataValidationException(new Object[] {
+ SL20Constants.SL20_COMMAND_PARAM_EID_RESULT_IDL,
+ e.getMessage()
+ });
+
+ }
+
+
+ return false;
+
+ }
+
+ public static Assertion parseAuthBlockToSaml2Assertion(String authblockB64) throws SL20eIDDataValidationException {
+ try {
+ //parse authBlock into SAML2 Assertion
+ byte[] authBlockBytes = Base64Utils.decode(authblockB64, false);
+ Element authBlockDOM = DOMUtils.parseXmlValidating(new ByteArrayInputStream(authBlockBytes));
+
+ UnmarshallerFactory unmarshallerFactory = Configuration.getUnmarshallerFactory();
+ Unmarshaller unmarshaller = unmarshallerFactory.getUnmarshaller(authBlockDOM);
+ XMLObject samlAssertion = unmarshaller.unmarshall(authBlockDOM);
+
+ //validate SAML2 Assertion
+ SAML2Utils.schemeValidation(samlAssertion);
+
+ if (samlAssertion instanceof Assertion)
+ return (Assertion) samlAssertion;
+ else
+ throw new SL20eIDDataValidationException(
+ new Object[] {
+ SL20Constants.SL20_COMMAND_PARAM_EID_RESULT_AUTHBLOCK,
+ "AuthBlock is NOT of type SAML2 Assertion"
+ });
+
+ } catch (SL20eIDDataValidationException e) {
+ throw e;
+
+ } catch (SAXException e) {
+ Logger.info("Scheme validation of SAML2 AuthBlock FAILED. Reason: " + e.getMessage());
+ throw new SL20eIDDataValidationException(
+ new Object[] {
+ SL20Constants.SL20_COMMAND_PARAM_EID_RESULT_AUTHBLOCK,
+ e.getMessage()
+ },
+ e);
+
+ } catch (Exception e) {
+ Logger.info("Can not parse AuthBlock. Reason: " + e.getMessage());
+ Logger.trace("FullAuthBlock: " + authblockB64);
+ throw new SL20eIDDataValidationException(
+ new Object[] {
+ SL20Constants.SL20_COMMAND_PARAM_EID_RESULT_AUTHBLOCK,
+ e.getMessage()
+ },
+ e);
+
+ }
+
+ }
+
+ private static void validateSigningDateTime( IVerifiyXMLSignatureResponse sigVerifyResult, AssertionAttributeExtractor authBlockExtractor) throws SL20eIDDataValidationException {
+ Date signingDate = sigVerifyResult.getSigningDateTime();
+ Date notBefore = authBlockExtractor.getAssertionNotBefore();
+ Date notOrNotAfter = authBlockExtractor.getAssertionNotOnOrAfter();
+
+ if (signingDate == null) {
+ Logger.info("AuthBlock signature contains NO signing data");
+ throw new SL20eIDDataValidationException(new Object[] {
+ SL20Constants.SL20_COMMAND_PARAM_EID_RESULT_AUTHBLOCK,
+ "AuthBlock signature contains NO signing data"
+ });
+
+ }
+
+ Logger.debug("AuthBlock signing data: " + signingDate.toString());
+
+ if (notBefore == null || notOrNotAfter == null) {
+ Logger.info("AuthBlock contains NO 'notBefore' or 'notOrNotAfter' dates");
+ throw new SL20eIDDataValidationException(new Object[] {
+ SL20Constants.SL20_COMMAND_PARAM_EID_RESULT_AUTHBLOCK,
+ "AuthBlock contains NO 'notBefore' or 'notOrNotAfter' dates"
+ });
+
+ }
+
+ Logger.debug("AuthBlock valid period."
+ + " NotBefore:" + notBefore.toString()
+ + " NotOrNotAfter:" + notOrNotAfter.toString());
+
+ if ((signingDate.after(notBefore) || signingDate.equals(notBefore))
+ && signingDate.before(notOrNotAfter))
+ Logger.debug("Signing date validation successfull");
+
+
+ else {
+ Logger.info("AuthBlock signing date does NOT match to AuthBlock constrains");
+ throw new SL20eIDDataValidationException(new Object[] {
+ SL20Constants.SL20_COMMAND_PARAM_EID_RESULT_AUTHBLOCK,
+ "AuthBlock signing date does NOT match to AuthBlock constrains"
+ });
+
+ }
+ }
+
+}
diff --git a/id/server/modules/moa-id-module-sl20_authentication/src/main/java/at/gv/egovernment/moa/id/auth/modules/sl20_auth/tasks/CreateQualeIDRequestTask.java b/id/server/modules/moa-id-module-sl20_authentication/src/main/java/at/gv/egovernment/moa/id/auth/modules/sl20_auth/tasks/CreateQualeIDRequestTask.java
index 77ccb0720..fec78d88c 100644
--- a/id/server/modules/moa-id-module-sl20_authentication/src/main/java/at/gv/egovernment/moa/id/auth/modules/sl20_auth/tasks/CreateQualeIDRequestTask.java
+++ b/id/server/modules/moa-id-module-sl20_authentication/src/main/java/at/gv/egovernment/moa/id/auth/modules/sl20_auth/tasks/CreateQualeIDRequestTask.java
@@ -1,10 +1,10 @@
package at.gv.egovernment.moa.id.auth.modules.sl20_auth.tasks;
+import java.security.cert.X509Certificate;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
-import java.util.UUID;
import javax.net.ssl.SSLSocketFactory;
import javax.servlet.http.HttpServletRequest;
@@ -17,6 +17,7 @@ import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.utils.URIBuilder;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.message.BasicNameValuePair;
+import org.jose4j.base64url.Base64Url;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
@@ -27,10 +28,14 @@ import at.gv.egiz.eaaf.core.api.idp.process.ExecutionContext;
import at.gv.egiz.eaaf.core.exceptions.TaskExecutionException;
import at.gv.egiz.eaaf.core.impl.idp.auth.modules.AbstractAuthServletTask;
import at.gv.egiz.eaaf.core.impl.utils.DataURLBuilder;
+import at.gv.egiz.eaaf.core.impl.utils.KeyValueUtils;
import at.gv.egiz.eaaf.core.impl.utils.TransactionIDUtils;
+import at.gv.egiz.eaaf.modules.pvp2.impl.utils.SAML2Utils;
+import at.gv.egovernment.moa.id.advancedlogging.MOAIDEventConstants;
import at.gv.egovernment.moa.id.auth.modules.sl20_auth.Constants;
import at.gv.egovernment.moa.id.auth.modules.sl20_auth.data.VerificationResult;
import at.gv.egovernment.moa.id.auth.modules.sl20_auth.exceptions.SL20Exception;
+import at.gv.egovernment.moa.id.auth.modules.sl20_auth.exceptions.SLCommandoParserException;
import at.gv.egovernment.moa.id.auth.modules.sl20_auth.sl20.IJOSETools;
import at.gv.egovernment.moa.id.auth.modules.sl20_auth.sl20.SL20Constants;
import at.gv.egovernment.moa.id.auth.modules.sl20_auth.sl20.SL20HttpBindingUtils;
@@ -38,6 +43,7 @@ import at.gv.egovernment.moa.id.auth.modules.sl20_auth.sl20.SL20JSONBuilderUtils
import at.gv.egovernment.moa.id.auth.modules.sl20_auth.sl20.SL20JSONExtractorUtils;
import at.gv.egovernment.moa.id.commons.api.AuthConfiguration;
import at.gv.egovernment.moa.id.commons.api.exceptions.MOAIDException;
+import at.gv.egovernment.moa.id.commons.config.MOAIDConfigurationConstants;
import at.gv.egovernment.moa.id.commons.utils.HttpClientWithProxySupport;
import at.gv.egovernment.moa.id.util.SSLUtils;
import at.gv.egovernment.moa.util.MiscUtil;
@@ -54,18 +60,22 @@ public class CreateQualeIDRequestTask extends AbstractAuthServletTask {
throws TaskExecutionException {
Logger.debug("Starting SL2.0 authentication process .... ");
-
+
+ revisionsLogger.logEvent(pendingReq, MOAIDEventConstants.AUTHPROCESS_BKUTYPE_SELECTED, "sl20auth");
+
try {
//get service-provider configuration
ISPConfiguration oaConfig = pendingReq.getServiceProviderConfiguration();
//get basic configuration parameters
- String vdaQualeIDUrl = authConfig.getBasicConfiguration(Constants.CONFIG_PROP_VDA_ENDPOINT_QUALeID);
+ String vdaQualeIDUrl = extractVDAURLForSpecificOA(oaConfig, executionContext);
if (MiscUtil.isEmpty(vdaQualeIDUrl)) {
- Logger.error("NO VDA URL for qualified eID (" + Constants.CONFIG_PROP_VDA_ENDPOINT_QUALeID + ")");
+ Logger.error("NO VDA URL for qualified eID (" + Constants.CONFIG_PROP_VDA_ENDPOINT_QUALeID_DEFAULT + ")");
throw new SL20Exception("sl20.03", new Object[]{"NO VDA URL for qualified eID"});
}
+ revisionsLogger.logEvent(pendingReq, MOAIDEventConstants.AUTHPROCESS_BKU_URL, vdaQualeIDUrl);
+
String authBlockId = authConfig.getBasicConfiguration(Constants.CONFIG_PROP_VDA_AUTHBLOCK_ID);
if (MiscUtil.isEmpty(authBlockId)) {
@@ -81,16 +91,26 @@ public class CreateQualeIDRequestTask extends AbstractAuthServletTask {
//build qualifiedeID command
Map<String, String> qualifiedeIDParams = new HashMap<String, String>();
qualifiedeIDParams.put(SL20Constants.SL20_COMMAND_PARAM_EID_ATTRIBUTES_SPUNIQUEID, oaConfig.getUniqueIdentifier());
- qualifiedeIDParams.put(SL20Constants.SL20_COMMAND_PARAM_EID_ATTRIBUTES_SPFRIENDLYNAME, oaConfig.getFriendlyName());
+ qualifiedeIDParams.put(SL20Constants.SL20_COMMAND_PARAM_EID_ATTRIBUTES_SPFRIENDLYNAME, oaConfig.getFriendlyName());
+ qualifiedeIDParams.put(SL20Constants.SL20_COMMAND_PARAM_EID_ATTRIBUTES_SPCOUNTRYCODE, "AT");
//qualifiedeIDParams.put(SL20Constants.SL20_COMMAND_PARAM_EID_ATTRIBUTES_MANDATEREFVALUE, UUID.randomUUID().toString());
+
+ X509Certificate encCert = null;
+ if (authConfig.getBasicMOAIDConfigurationBoolean(Constants.CONFIG_PROP_ENABLE_EID_ENCRYPTION, true))
+ encCert = joseTools.getEncryptionCertificate();
+ else
+ Logger.info("eID data encryption is disabled by configuration");
+
JsonObject qualeIDCommandParams = SL20JSONBuilderUtils.createQualifiedeIDCommandParameters(
authBlockId,
dataURL,
qualifiedeIDParams,
- joseTools.getEncryptionCertificate());
+ encCert
+ );
- String qualeIDReqId = UUID.randomUUID().toString();
+ //String qualeIDReqId = UUID.randomUUID().toString();
+ String qualeIDReqId = SAML2Utils.getSecureIdentifier();
String signedQualeIDCommand = SL20JSONBuilderUtils.createSignedCommand(SL20Constants.SL20_COMMAND_IDENTIFIER_QUALIFIEDEID, qualeIDCommandParams, joseTools);
JsonObject sl20Req = SL20JSONBuilderUtils.createGenericRequest(qualeIDReqId, null, null, signedQualeIDCommand);
@@ -102,13 +122,22 @@ public class CreateQualeIDRequestTask extends AbstractAuthServletTask {
sslFactory,
moaAuthConfig.getBasicMOAIDConfigurationBoolean(AuthConfiguration.PROP_KEY_OVS_SSL_HOSTNAME_VALIDATION, true));
- //build post request
+ //build http POST request
HttpPost httpReq = new HttpPost(new URIBuilder(vdaQualeIDUrl).build());
- httpReq.addHeader(SL20Constants.HTTP_HEADER_SL20_CLIENT_TYPE, SL20Constants.HTTP_HEADER_VALUE_NATIVE);
List<NameValuePair> parameters = new ArrayList<NameValuePair>();;
- parameters.add(new BasicNameValuePair(SL20Constants.PARAM_SL20_REQ_COMMAND_PARAM, sl20Req.toString()));
+ parameters.add(new BasicNameValuePair(SL20Constants.PARAM_SL20_REQ_COMMAND_PARAM, Base64Url.encode(sl20Req.toString().getBytes())));
httpReq.setEntity(new UrlEncodedFormEntity(parameters ));
+ //build http GET request
+// URIBuilder sl20ReqUri = new URIBuilder(vdaQualeIDUrl);
+// sl20ReqUri.addParameter(SL20Constants.PARAM_SL20_REQ_COMMAND_PARAM, Base64Url.encode(sl20Req.toString().getBytes()));
+// HttpGet httpReq = new HttpGet(sl20ReqUri.build());
+
+ //set native client header
+ httpReq.addHeader(SL20Constants.HTTP_HEADER_SL20_CLIENT_TYPE, SL20Constants.HTTP_HEADER_VALUE_NATIVE);
+
+ Logger.trace("Request VDA via SL20 with: " + Base64Url.encode(sl20Req.toString().getBytes()));
+
//request VDA
HttpResponse httpResp = httpClient.execute(httpReq);
@@ -146,10 +175,22 @@ public class CreateQualeIDRequestTask extends AbstractAuthServletTask {
//TODO: maybe add SL2ClientType Header from execution context
SL20HttpBindingUtils.writeIntoResponse(request, response, sl20Forward, redirectURL);
+ } else if (respPayload.get(SL20Constants.SL20_COMMAND_CONTAINER_NAME).getAsString()
+ .equals(SL20Constants.SL20_COMMAND_IDENTIFIER_ERROR)) {
+ JsonObject result = SL20JSONExtractorUtils.getJSONObjectValue(respPayload, SL20Constants.SL20_COMMAND_CONTAINER_RESULT, false);
+ if (result == null)
+ result = SL20JSONExtractorUtils.getJSONObjectValue(respPayload, SL20Constants.SL20_COMMAND_CONTAINER_PARAMS, false);
+
+ String errorCode = SL20JSONExtractorUtils.getStringValue(result, SL20Constants.SL20_COMMAND_PARAM_GENERAL_RESPONSE_ERRORCODE, true);
+ String errorMsg = SL20JSONExtractorUtils.getStringValue(result, SL20Constants.SL20_COMMAND_PARAM_GENERAL_RESPONSE_ERRORMESSAGE, true);
+
+ Logger.info("Receive SL2.0 error. Code:" + errorCode + " Msg:" + errorMsg);
+ throw new SL20Exception("sl20.08", new Object[]{errorCode, errorMsg});
+
} else {
//TODO: update to add error handling
Logger.warn("Received an unrecognized command: " + respPayload.get(SL20Constants.SL20_COMMAND_CONTAINER_NAME).getAsString());
-
+ throw new SLCommandoParserException("Received an unrecognized command: \" + respPayload.get(SL20Constants.SL20_COMMAND_CONTAINER_NAME).getAsString()");
}
@@ -166,8 +207,36 @@ public class CreateQualeIDRequestTask extends AbstractAuthServletTask {
}
+ }
-
+ private String extractVDAURLForSpecificOA(ISPConfiguration oaConfig, ExecutionContext executionContext) {
+ String spSpecificVDAEndpoints = oaConfig.getConfigurationValue(MOAIDConfigurationConstants.SERVICE_AUTH_SL20_ENDPOINTS);
+ Map<String, String> endPointMap = authConfig.getBasicMOAIDConfigurationWithPrefix(Constants.CONFIG_PROP_VDA_ENDPOINT_QUALeID_LIST);
+ if (MiscUtil.isNotEmpty(spSpecificVDAEndpoints)) {
+ endPointMap.putAll(KeyValueUtils.convertListToMap(
+ KeyValueUtils.getListOfCSVValues(
+ KeyValueUtils.normalizeCSVValueString(spSpecificVDAEndpoints))));
+ Logger.debug("Find OA specific SL2.0 endpoints. Updating endPoint list ... ");
+
+ }
+
+ Logger.trace("Find #" + endPointMap.size() + " SL2.0 endpoints ... ");
+
+ //selection based on request Header
+ String sl20VDATypeHeader = (String) executionContext.get(SL20Constants.HTTP_HEADER_SL20_VDA_TYPE.toLowerCase());
+ if (MiscUtil.isNotEmpty(sl20VDATypeHeader)) {
+ String vdaURL = endPointMap.get(sl20VDATypeHeader);
+ if (MiscUtil.isNotEmpty(vdaURL))
+ return vdaURL.trim();
+
+ else
+ Logger.info("Can NOT find VDA with Id: " + sl20VDATypeHeader + ". Use default VDA");
+
+ }
+
+ Logger.info("NO SP specific VDA endpoint found. Use default VDA");
+ return endPointMap.getOrDefault(Constants.CONFIG_PROP_VDA_ENDPOINT_QUALeID_DEFAULT,
+ Constants.CONFIG_PROP_VDA_ENDPOINT_QUALeID + Constants.CONFIG_PROP_VDA_ENDPOINT_QUALeID_DEFAULT);
}
diff --git a/id/server/modules/moa-id-module-sl20_authentication/src/main/java/at/gv/egovernment/moa/id/auth/modules/sl20_auth/tasks/ReceiveQualeIDTask.java b/id/server/modules/moa-id-module-sl20_authentication/src/main/java/at/gv/egovernment/moa/id/auth/modules/sl20_auth/tasks/ReceiveQualeIDTask.java
index 8791da429..a3175713a 100644
--- a/id/server/modules/moa-id-module-sl20_authentication/src/main/java/at/gv/egovernment/moa/id/auth/modules/sl20_auth/tasks/ReceiveQualeIDTask.java
+++ b/id/server/modules/moa-id-module-sl20_authentication/src/main/java/at/gv/egovernment/moa/id/auth/modules/sl20_auth/tasks/ReceiveQualeIDTask.java
@@ -1,9 +1,8 @@
package at.gv.egovernment.moa.id.auth.modules.sl20_auth.tasks;
-import java.io.ByteArrayInputStream;
+import java.io.IOException;
import java.io.StringWriter;
import java.security.cert.X509Certificate;
-import java.util.Calendar;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@@ -13,6 +12,7 @@ import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.http.entity.ContentType;
+import org.jose4j.base64url.Base64Url;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
@@ -27,8 +27,9 @@ import at.gv.egiz.eaaf.core.exceptions.TaskExecutionException;
import at.gv.egiz.eaaf.core.impl.idp.auth.modules.AbstractAuthServletTask;
import at.gv.egiz.eaaf.core.impl.idp.controller.AbstractAuthProtocolModulController;
import at.gv.egiz.eaaf.core.impl.utils.DataURLBuilder;
+import at.gv.egiz.eaaf.core.impl.utils.StreamUtils;
import at.gv.egiz.eaaf.core.impl.utils.TransactionIDUtils;
-import at.gv.egovernment.moa.id.auth.data.AuthenticationSessionWrapper;
+import at.gv.egovernment.moa.id.advancedlogging.MOAIDEventConstants;
import at.gv.egovernment.moa.id.auth.modules.sl20_auth.Constants;
import at.gv.egovernment.moa.id.auth.modules.sl20_auth.data.VerificationResult;
import at.gv.egovernment.moa.id.auth.modules.sl20_auth.exceptions.SL20Exception;
@@ -38,13 +39,11 @@ import at.gv.egovernment.moa.id.auth.modules.sl20_auth.sl20.IJOSETools;
import at.gv.egovernment.moa.id.auth.modules.sl20_auth.sl20.SL20Constants;
import at.gv.egovernment.moa.id.auth.modules.sl20_auth.sl20.SL20JSONBuilderUtils;
import at.gv.egovernment.moa.id.auth.modules.sl20_auth.sl20.SL20JSONExtractorUtils;
-import at.gv.egovernment.moa.id.auth.parser.IdentityLinkAssertionParser;
import at.gv.egovernment.moa.id.commons.api.exceptions.MOAIDException;
-import at.gv.egovernment.moa.util.Base64Utils;
-import at.gv.egovernment.moa.util.DateTimeUtils;
import at.gv.egovernment.moa.util.MiscUtil;
import at.gv.egovernment.moaspss.logging.Logger;
+
@Component("ReceiveQualeIDTask")
public class ReceiveQualeIDTask extends AbstractAuthServletTask {
@@ -52,98 +51,197 @@ public class ReceiveQualeIDTask extends AbstractAuthServletTask {
@Override
public void execute(ExecutionContext executionContext, HttpServletRequest request, HttpServletResponse response)
- throws TaskExecutionException {
+ throws TaskExecutionException {
+ String sl20Result = null;
- Logger.debug("Receiving SL2.0 response process .... ");
try {
- //get SL2.0 command or result from HTTP request
- Map<String, String> reqParams = getParameters(request);
- String sl20Result = reqParams.get(SL20Constants.PARAM_SL20_REQ_COMMAND_PARAM);
- if (MiscUtil.isEmpty(sl20Result)) {
- Logger.info("NO SL2.0 commando or result FOUND.");
- throw new SL20Exception("sl20.04", null);
+ Logger.debug("Receiving SL2.0 response process .... ");
+ JsonObject sl20ReqObj = null;
+ try {
+ //get SL2.0 command or result from HTTP request
+ Map<String, String> reqParams = getParameters(request);
+ sl20Result = reqParams.get(SL20Constants.PARAM_SL20_REQ_COMMAND_PARAM);
- }
-
+ if (MiscUtil.isEmpty(sl20Result)) {
+ //Workaround for SIC Handy-Signature, because it sends result in InputStream
+ String isReqInput = StreamUtils.readStream(request.getInputStream(), "UTF-8");
+ if (MiscUtil.isNotEmpty(isReqInput)) {
+ Logger.info("Use SIC Handy-Signature work-around!");
+ sl20Result = isReqInput.substring("slcommand=".length());
+
+ } else {
+ Logger.info("NO SL2.0 commando or result FOUND.");
+ throw new SL20Exception("sl20.04", null);
+ }
+
+ }
+
+ Logger.trace("Received SL2.0 result: " + sl20Result);
+ revisionsLogger.logEvent(pendingReq, MOAIDEventConstants.AUTHPROCESS_BKU_DATAURL_IP, request.getRemoteAddr());
- //parse SL2.0 command/result into JSON
- JsonObject sl20ReqObj = null;
- try {
- JsonParser jsonParser = new JsonParser();
- JsonElement sl20Req = jsonParser.parse(sl20Result);
- sl20ReqObj = sl20Req.getAsJsonObject();
+ //parse SL2.0 command/result into JSON
+ try {
+ JsonParser jsonParser = new JsonParser();
+ JsonElement sl20Req = jsonParser.parse(Base64Url.decodeToUtf8String(sl20Result));
+ sl20ReqObj = sl20Req.getAsJsonObject();
- } catch (JsonSyntaxException e) {
- Logger.warn("SL2.0 command or result is NOT valid JSON.", e);
- Logger.debug("SL2.0 msg: " + sl20Result);
- throw new SL20Exception("sl20.02", new Object[]{"SL2.0 command or result is NOT valid JSON."}, e);
+ } catch (JsonSyntaxException e) {
+ Logger.warn("SL2.0 command or result is NOT valid JSON.", e);
+ Logger.debug("SL2.0 msg: " + sl20Result);
+ throw new SL20Exception("sl20.02", new Object[]{"SL2.0 command or result is NOT valid JSON."}, e);
- }
+ }
- //validate reqId with inResponseTo
- String sl20ReqId = pendingReq.getGenericData(Constants.PENDING_REQ_STORAGE_PREFIX + SL20Constants.SL20_REQID, String.class);
- String inRespTo = SL20JSONExtractorUtils.getStringValue(sl20ReqObj, SL20Constants.SL20_INRESPTO, true);
- if (sl20ReqId == null || !sl20ReqId.equals(inRespTo)) {
- Logger.info("SL20 'reqId': " + sl20ReqId + " does NOT match to 'inResponseTo':" + inRespTo);
- throw new SL20SecurityException("SL20 'reqId': " + sl20ReqId + " does NOT match to 'inResponseTo':" + inRespTo);
- }
+ //validate reqId with inResponseTo
+ String sl20ReqId = pendingReq.getGenericData(Constants.PENDING_REQ_STORAGE_PREFIX + SL20Constants.SL20_REQID, String.class);
+ String inRespTo = SL20JSONExtractorUtils.getStringValue(sl20ReqObj, SL20Constants.SL20_INRESPTO, true);
+ if (sl20ReqId == null || !sl20ReqId.equals(inRespTo)) {
+ Logger.info("SL20 'reqId': " + sl20ReqId + " does NOT match to 'inResponseTo':" + inRespTo);
+ throw new SL20SecurityException("SL20 'reqId': " + sl20ReqId + " does NOT match to 'inResponseTo':" + inRespTo);
+ }
- //validate signature
- VerificationResult payLoadContainer = SL20JSONExtractorUtils.extractSL20PayLoad(sl20ReqObj, joseTools, true);
- if (payLoadContainer.isValidSigned() == null ||
- !payLoadContainer.isValidSigned()) {
- Logger.info("SL20 result from VDA was not valid signed");
- throw new SL20SecurityException(new Object[]{"Signature on SL20 result NOT valid."});
+ //validate signature
+ VerificationResult payLoadContainer = SL20JSONExtractorUtils.extractSL20PayLoad(
+ sl20ReqObj, joseTools,
+ authConfig.getBasicMOAIDConfigurationBoolean(Constants.CONFIG_PROP_FORCE_EID_SIGNED_RESULT, true));
- }
-
- //TODO validate certificate
- List<X509Certificate> sigCertChain = payLoadContainer.getCertChain();
+ if ( (payLoadContainer.isValidSigned() == null || !payLoadContainer.isValidSigned())) {
+ if (authConfig.getBasicMOAIDConfigurationBoolean(Constants.CONFIG_PROP_FORCE_EID_SIGNED_RESULT, true)) {
+ Logger.info("SL20 result from VDA was not valid signed");
+ throw new SL20SecurityException(new Object[]{"Signature on SL20 result NOT valid."});
+
+ } else {
+ Logger.warn("SL20 result from VDA is NOT valid signed, but signatures-verification is DISABLED by configuration!");
+
+ }
+ }
+
+ /*TODO validate certificate by using MOA-SPSS
+ * currently, the certificate is validated in IJOSETools by using a pkcs12 or jks keystore
+ */
+ List<X509Certificate> sigCertChain = payLoadContainer.getCertChain();
- //extract payloaf
- JsonObject payLoad = payLoadContainer.getPayload();
+ //extract payloaf
+ JsonObject payLoad = payLoadContainer.getPayload();
- //check response type
- if (SL20JSONExtractorUtils.getStringValue(
- payLoad, SL20Constants.SL20_COMMAND_CONTAINER_NAME, true)
- .equals(SL20Constants.SL20_COMMAND_IDENTIFIER_QUALIFIEDEID)) {
- Logger.debug("Find " + SL20Constants.SL20_COMMAND_IDENTIFIER_QUALIFIEDEID + " result .... ");
+ //check response type
+ if (SL20JSONExtractorUtils.getStringValue(
+ payLoad, SL20Constants.SL20_COMMAND_CONTAINER_NAME, true)
+ .equals(SL20Constants.SL20_COMMAND_IDENTIFIER_QUALIFIEDEID)) {
+ Logger.debug("Find " + SL20Constants.SL20_COMMAND_IDENTIFIER_QUALIFIEDEID + " result .... ");
- //TODO: activate decryption in 'SL20JSONExtractorUtils.extractSL20Result'
- JsonElement qualeIDResult = SL20JSONExtractorUtils.extractSL20Result(payLoad, joseTools, false);
-
- //extract attributes from result
- String idlB64 = SL20JSONExtractorUtils.getStringValue(qualeIDResult.getAsJsonObject(),
- SL20Constants.SL20_COMMAND_PARAM_EID_RESULT_IDL, true);
- String authBlockB64 = SL20JSONExtractorUtils.getStringValue(qualeIDResult.getAsJsonObject(),
- SL20Constants.SL20_COMMAND_PARAM_EID_RESULT_AUTHBLOCK, true);
- String ccsURL = SL20JSONExtractorUtils.getStringValue(qualeIDResult.getAsJsonObject(),
- SL20Constants.SL20_COMMAND_PARAM_EID_RESULT_CCSURL, true);
- String LoA = SL20JSONExtractorUtils.getStringValue(qualeIDResult.getAsJsonObject(),
- SL20Constants.SL20_COMMAND_PARAM_EID_RESULT_LOA, true);
-
-
- //TODO: validate results
-
-
- //add into session
- AuthenticationSessionWrapper moasession = new AuthenticationSessionWrapper(pendingReq.genericFullDataStorage());
- moasession.setIdentityLink(new IdentityLinkAssertionParser(new ByteArrayInputStream(Base64Utils.decode(idlB64, false))).parseIdentityLink());
- moasession.setBkuURL(ccsURL);
- //TODO: from AuthBlock
- moasession.setIssueInstant(DateTimeUtils.buildDateTimeUTC(Calendar.getInstance()));
- moasession.setQAALevel(LoA);
-
- //mark as authenticated
- moasession.setAuthenticated(true);
- pendingReq.setAuthenticated(true);
+ JsonElement qualeIDResult = SL20JSONExtractorUtils.extractSL20Result(
+ payLoad, joseTools,
+ authConfig.getBasicMOAIDConfigurationBoolean(Constants.CONFIG_PROP_FORCE_EID_ENCRYPTION, true));
+
+ //extract attributes from result
+ Map<String, String> eIDData = SL20JSONExtractorUtils.getMapOfStringElements(qualeIDResult);
+ String idlB64 = eIDData.get(SL20Constants.SL20_COMMAND_PARAM_EID_RESULT_IDL);
+ String authBlockB64 = eIDData.get(SL20Constants.SL20_COMMAND_PARAM_EID_RESULT_AUTHBLOCK);
+ String ccsURL = eIDData.get(SL20Constants.SL20_COMMAND_PARAM_EID_RESULT_CCSURL);
+ String LoA = eIDData.get(SL20Constants.SL20_COMMAND_PARAM_EID_RESULT_LOA);
+
+
+
+ if (MiscUtil.isEmpty(idlB64) || MiscUtil.isEmpty(authBlockB64)
+ || MiscUtil.isEmpty(LoA) || MiscUtil.isEmpty(ccsURL)) {
+ Logger.info("SL20 'qualifiedeID' result does NOT contain all required attributes.");
+ throw new SLCommandoParserException("SL20 'qualifiedeID' result does NOT contain all required attributes.");
+
+ }
+
+ //cache qualified eID data into pending request
+ pendingReq.setGenericDataToSession(
+ Constants.PENDING_REQ_STORAGE_PREFIX + SL20Constants.SL20_COMMAND_PARAM_EID_RESULT_IDL,
+ idlB64);
+ pendingReq.setGenericDataToSession(
+ Constants.PENDING_REQ_STORAGE_PREFIX + SL20Constants.SL20_COMMAND_PARAM_EID_RESULT_AUTHBLOCK,
+ authBlockB64);
+ pendingReq.setGenericDataToSession(
+ Constants.PENDING_REQ_STORAGE_PREFIX + SL20Constants.SL20_COMMAND_PARAM_EID_RESULT_CCSURL,
+ ccsURL);
+ pendingReq.setGenericDataToSession(
+ Constants.PENDING_REQ_STORAGE_PREFIX + SL20Constants.SL20_COMMAND_PARAM_EID_RESULT_LOA,
+ LoA);
+ } else {
+ Logger.info("SL20 response is NOT a " + SL20Constants.SL20_COMMAND_IDENTIFIER_QUALIFIEDEID + " result");
+ throw new SLCommandoParserException("SL20 response is NOT a " + SL20Constants.SL20_COMMAND_IDENTIFIER_QUALIFIEDEID + " result");
+ }
+
+
+ } catch (MOAIDException e) {
+ Logger.warn("SL2.0 processing error:", e);
+ if (sl20Result != null)
+ Logger.debug("Received SL2.0 result: " + sl20Result);
+ pendingReq.setGenericDataToSession(
+ Constants.PENDING_REQ_STORAGE_PREFIX + SL20Constants.SL20_COMMAND_IDENTIFIER_ERROR,
+ new TaskExecutionException(pendingReq, "SL2.0 Authentication FAILED. Msg: " + e.getMessage(), e));
+
+ } catch (Exception e) {
+ Logger.warn("ERROR:", e);
+ Logger.warn("SL2.0 Authentication FAILED with a generic error.", e);
+ if (sl20Result != null)
+ Logger.debug("Received SL2.0 result: " + sl20Result);
+ pendingReq.setGenericDataToSession(
+ Constants.PENDING_REQ_STORAGE_PREFIX + SL20Constants.SL20_COMMAND_IDENTIFIER_ERROR,
+ new TaskExecutionException(pendingReq, e.getMessage(), e));
+
+ } finally {
//store pending request
- pendingReq.setGenericDataToSession(moasession.getKeyValueRepresentationFromAuthSession());
requestStoreage.storePendingRequest(pendingReq);
+ //write SL2.0 response
+ if (sl20ReqObj != null)
+ buildResponse(request, response, sl20ReqObj);
+ else
+ buildErrorResponse(request, response, "2000", "General transport Binding error");
+
+ }
+
+ } catch (Exception e) {
+ //write internal server errror 500 according to SL2.0 specification, chapter https transport binding
+ Logger.warn("Can NOT build SL2.0 response. Reason: " + e.getMessage(), e);
+ if (sl20Result != null)
+ Logger.debug("Received SL2.0 result: " + sl20Result);
+ try {
+ response.sendError(500, "Internal Server Error.");
+
+ } catch (IOException e1) {
+ Logger.error("Can NOT send error message. SOMETHING IS REALY WRONG!", e);
+
+ }
+
+ } finally {
+ TransactionIDUtils.removeTransactionId();
+ TransactionIDUtils.removeSessionId();
+
+ }
+ }
+
+ private void buildErrorResponse(HttpServletRequest request, HttpServletResponse response, String errorCode, String errorMsg) throws Exception {
+ JsonObject error = SL20JSONBuilderUtils.createErrorCommandResult(errorCode, errorMsg);
+ JsonObject respContainer = SL20JSONBuilderUtils.createGenericRequest(
+ UUID.randomUUID().toString(),
+ null,
+ error ,
+ null);
+
+ Logger.debug("Client request containts 'native client' header ... ");
+ Logger.trace("SL20 response to VDA: " + respContainer);
+ StringWriter writer = new StringWriter();
+ writer.write(respContainer.toString());
+ final byte[] content = writer.toString().getBytes("UTF-8");
+ response.setStatus(HttpServletResponse.SC_OK);
+ response.setContentLength(content.length);
+ response.setContentType(ContentType.APPLICATION_JSON.toString());
+ response.getOutputStream().write(content);
+
+ }
+
+ private void buildResponse(HttpServletRequest request, HttpServletResponse response, JsonObject sl20ReqObj) throws IOException, SL20Exception {
//create response
Map<String, String> reqParameters = new HashMap<String, String>();
reqParameters.put(EAAFConstants.PARAM_HTTP_TARGET_PENDINGREQUESTID, pendingReq.getPendingRequestId());
@@ -155,7 +253,9 @@ public class ReceiveQualeIDTask extends AbstractAuthServletTask {
JsonObject callCommand = SL20JSONBuilderUtils.createCommand(SL20Constants.SL20_COMMAND_IDENTIFIER_CALL, callReqParams);
//build first redirect command for app
- JsonObject redirectOneParams = SL20JSONBuilderUtils.createRedirectCommandParameters("", callCommand, null, true);
+ JsonObject redirectOneParams = SL20JSONBuilderUtils.createRedirectCommandParameters(
+ generateICPRedirectURLForDebugging(),
+ callCommand, null, true);
JsonObject redirectOneCommand = SL20JSONBuilderUtils.createCommand(SL20Constants.SL20_COMMAND_IDENTIFIER_REDIRECT, redirectOneParams);
//build second redirect command for IDP
@@ -172,9 +272,12 @@ public class ReceiveQualeIDTask extends AbstractAuthServletTask {
redirectTwoCommand,
null);
+ //workaround for A-Trust
if (request.getHeader(SL20Constants.HTTP_HEADER_SL20_CLIENT_TYPE) != null &&
- request.getHeader(SL20Constants.HTTP_HEADER_SL20_CLIENT_TYPE).equals(SL20Constants.HTTP_HEADER_VALUE_NATIVE)) {
- Logger.debug("Client request containts 'native client' header ... ");
+ request.getHeader(SL20Constants.HTTP_HEADER_SL20_CLIENT_TYPE).equals(SL20Constants.HTTP_HEADER_VALUE_NATIVE)
+ || true) {
+ Logger.debug("Client request containts 'native client' header ... ");
+ Logger.trace("SL20 response to VDA: " + respContainer);
StringWriter writer = new StringWriter();
writer.write(respContainer.toString());
final byte[] content = writer.toString().getBytes("UTF-8");
@@ -190,36 +293,32 @@ public class ReceiveQualeIDTask extends AbstractAuthServletTask {
new Object[] {"SL2.0 DataURL communication needs http header: '" + SL20Constants.HTTP_HEADER_SL20_CLIENT_TYPE + "'"});
}
-
- } else {
- Logger.info("SL20 response is NOT a " + SL20Constants.SL20_COMMAND_IDENTIFIER_QUALIFIEDEID + " result");
- throw new SLCommandoParserException("SL20 response is NOT a " + SL20Constants.SL20_COMMAND_IDENTIFIER_QUALIFIEDEID + " result");
}
+
+ /**
+ * Generates a IPC redirect URL that is configured on IDP side
+ *
+ * @return IPC ReturnURL, or null if no URL is configured
+ */
+ private String generateICPRedirectURLForDebugging() {
+ final String PATTERN_PENDING_REQ_ID = "#PENDINGREQID#";
+ String ipcRedirectURLConfig = authConfig.getBasicConfiguration(Constants.CONFIG_PROP_IPC_RETURN_URL);
+ if (MiscUtil.isNotEmpty(ipcRedirectURLConfig)) {
+ if (ipcRedirectURLConfig.contains(PATTERN_PENDING_REQ_ID)) {
+ Logger.trace("Find 'pendingReqId' pattern in IPC redirect URL. Update url ... ");
+ ipcRedirectURLConfig = ipcRedirectURLConfig.replaceAll(
+ "#PENDINGREQID#",
+ EAAFConstants.PARAM_HTTP_TARGET_PENDINGREQUESTID + "=" + pendingReq.getPendingRequestId());
- } catch (MOAIDException e) {
- Logger.warn("ERROR:", e);
- throw new TaskExecutionException(pendingReq, "SL2.0 Authentication FAILED. Msg: " + e.getMessage(), e);
-
- } catch (Exception e) {
- Logger.warn("ERROR:", e);
- Logger.warn("SL2.0 Authentication FAILED with a generic error.", e);
- throw new TaskExecutionException(pendingReq, e.getMessage(), e);
-
- } finally {
- TransactionIDUtils.removeTransactionId();
- TransactionIDUtils.removeSessionId();
+ }
+ return ipcRedirectURLConfig;
}
- }
-
- private JsonObject createRedirectCommand() {
-
-
return null;
-
}
+
}
diff --git a/id/server/modules/moa-id-module-sl20_authentication/src/main/java/at/gv/egovernment/moa/id/auth/modules/sl20_auth/tasks/VerifyQualifiedeIDTask.java b/id/server/modules/moa-id-module-sl20_authentication/src/main/java/at/gv/egovernment/moa/id/auth/modules/sl20_auth/tasks/VerifyQualifiedeIDTask.java
new file mode 100644
index 000000000..403423e46
--- /dev/null
+++ b/id/server/modules/moa-id-module-sl20_authentication/src/main/java/at/gv/egovernment/moa/id/auth/modules/sl20_auth/tasks/VerifyQualifiedeIDTask.java
@@ -0,0 +1,136 @@
+package at.gv.egovernment.moa.id.auth.modules.sl20_auth.tasks;
+
+import java.io.ByteArrayInputStream;
+import java.util.Calendar;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.opensaml.saml2.core.Assertion;
+import org.springframework.stereotype.Component;
+
+import at.gv.egiz.eaaf.core.api.idp.auth.data.IIdentityLink;
+import at.gv.egiz.eaaf.core.api.idp.process.ExecutionContext;
+import at.gv.egiz.eaaf.core.exceptions.TaskExecutionException;
+import at.gv.egiz.eaaf.core.impl.idp.auth.modules.AbstractAuthServletTask;
+import at.gv.egiz.eaaf.core.impl.utils.TransactionIDUtils;
+import at.gv.egiz.eaaf.modules.pvp2.sp.impl.utils.AssertionAttributeExtractor;
+import at.gv.egovernment.moa.id.advancedlogging.MOAIDEventConstants;
+import at.gv.egovernment.moa.id.auth.data.AuthenticationSessionWrapper;
+import at.gv.egovernment.moa.id.auth.modules.sl20_auth.Constants;
+import at.gv.egovernment.moa.id.auth.modules.sl20_auth.sl20.SL20Constants;
+import at.gv.egovernment.moa.id.auth.modules.sl20_auth.sl20.verifier.QualifiedeIDVerifier;
+import at.gv.egovernment.moa.id.auth.parser.IdentityLinkAssertionParser;
+import at.gv.egovernment.moa.id.commons.api.AuthConfiguration;
+import at.gv.egovernment.moa.id.commons.api.IOAAuthParameters;
+import at.gv.egovernment.moa.id.commons.api.data.IVerifiyXMLSignatureResponse;
+import at.gv.egovernment.moa.id.commons.api.exceptions.MOAIDException;
+import at.gv.egovernment.moa.util.Base64Utils;
+import at.gv.egovernment.moa.util.DateTimeUtils;
+import at.gv.egovernment.moaspss.logging.Logger;
+
+
+@Component("VerifyQualifiedeIDTask")
+public class VerifyQualifiedeIDTask extends AbstractAuthServletTask {
+
+ @Override
+ public void execute(ExecutionContext executionContext, HttpServletRequest request, HttpServletResponse response)
+ throws TaskExecutionException {
+
+ Logger.debug("Verify qualified eID data from SL20 response .... ");
+ try {
+ //check if there was an error
+ TaskExecutionException sl20Error = pendingReq.getGenericData(
+ Constants.PENDING_REQ_STORAGE_PREFIX + SL20Constants.SL20_COMMAND_IDENTIFIER_ERROR,
+ TaskExecutionException.class);
+ if (sl20Error != null) {
+ Logger.info("Found SL2.0 error after redirect ... ");
+ throw sl20Error;
+
+ }
+
+ //get data from pending request
+ String sl20ReqId = pendingReq.getGenericData(
+ Constants.PENDING_REQ_STORAGE_PREFIX + SL20Constants.SL20_REQID,
+ String.class);
+ String idlB64 = pendingReq.getGenericData(
+ Constants.PENDING_REQ_STORAGE_PREFIX + SL20Constants.SL20_COMMAND_PARAM_EID_RESULT_IDL,
+ String.class);
+ String authBlockB64 = pendingReq.getGenericData(
+ Constants.PENDING_REQ_STORAGE_PREFIX + SL20Constants.SL20_COMMAND_PARAM_EID_RESULT_AUTHBLOCK,
+ String.class);
+ String ccsURL = pendingReq.getGenericData(
+ Constants.PENDING_REQ_STORAGE_PREFIX + SL20Constants.SL20_COMMAND_PARAM_EID_RESULT_CCSURL,
+ String.class);
+ String LoA = pendingReq.getGenericData(
+ Constants.PENDING_REQ_STORAGE_PREFIX + SL20Constants.SL20_COMMAND_PARAM_EID_RESULT_LOA,
+ String.class);
+
+ //parse eID data
+ IIdentityLink idl = new IdentityLinkAssertionParser(new ByteArrayInputStream(Base64Utils.decode(idlB64, false))).parseIdentityLink();
+ IVerifiyXMLSignatureResponse authBlockVerificationResult = null;
+ try {
+ Assertion authBlock = QualifiedeIDVerifier.parseAuthBlockToSaml2Assertion(authBlockB64);
+ AssertionAttributeExtractor authBlockExtractor = new AssertionAttributeExtractor(authBlock);
+
+
+ //validate eID data
+ QualifiedeIDVerifier.verifyIdentityLink(idl,
+ pendingReq.getServiceProviderConfiguration(IOAAuthParameters.class),
+ (AuthConfiguration) authConfig);
+
+ authBlockVerificationResult = QualifiedeIDVerifier.verifyAuthBlock(
+ authBlockB64,
+ pendingReq.getServiceProviderConfiguration(IOAAuthParameters.class),
+ (AuthConfiguration) authConfig);
+
+ QualifiedeIDVerifier.checkConsistencyOfeIDData(sl20ReqId, idl, authBlockExtractor, authBlockVerificationResult);
+
+ //TODO: add LoA verification
+
+ } catch (MOAIDException e) {
+ if (authConfig.getBasicMOAIDConfigurationBoolean(Constants.CONFIG_PROP_DISABLE_EID_VALIDATION, false)) {
+ Logger.warn("SL20 eID data validation IS DISABLED!!");
+ Logger.warn("SL20 eID data IS NOT VALID!!! Reason: " + e.getMessage(), e);
+
+ } else
+ throw e;
+
+ }
+
+ revisionsLogger.logEvent(pendingReq, MOAIDEventConstants.AUTHPROCESS_IDL_VALIDATED);
+ revisionsLogger.logEvent(pendingReq, MOAIDEventConstants.AUTHPROCESS_AUTHBLOCK_VALIDATED);
+
+
+
+ //add into session
+ AuthenticationSessionWrapper moasession = new AuthenticationSessionWrapper(pendingReq.genericFullDataStorage());
+ moasession.setIdentityLink(idl);
+ moasession.setBkuURL(ccsURL);
+ //TODO: from AuthBlock
+ if (authBlockVerificationResult != null)
+ moasession.setIssueInstant(DateTimeUtils.buildDateTimeUTC(authBlockVerificationResult.getSigningDateTime()));
+ else
+ moasession.setIssueInstant(DateTimeUtils.buildDateTimeUTC(Calendar.getInstance()));
+
+ moasession.setQAALevel(LoA);
+
+ //store pending request
+ requestStoreage.storePendingRequest(pendingReq);
+
+ } catch (MOAIDException e) {
+ Logger.warn("ERROR:", e);
+ throw new TaskExecutionException(pendingReq, "SL2.0 Authentication FAILED. Msg: " + e.getMessage(), e);
+
+ } catch (Exception e) {
+ Logger.warn("ERROR:", e);
+ Logger.warn("SL2.0 Authentication FAILED with a generic error.", e);
+ throw new TaskExecutionException(pendingReq, e.getMessage(), e);
+
+ } finally {
+ TransactionIDUtils.removeTransactionId();
+ TransactionIDUtils.removeSessionId();
+
+ }
+ }
+}
diff --git a/id/server/modules/moa-id-module-sl20_authentication/src/main/resources/moaid_sl20_auth.beans.xml b/id/server/modules/moa-id-module-sl20_authentication/src/main/resources/moaid_sl20_auth.beans.xml
index 37551b3f5..a9c9bac8e 100644
--- a/id/server/modules/moa-id-module-sl20_authentication/src/main/resources/moaid_sl20_auth.beans.xml
+++ b/id/server/modules/moa-id-module-sl20_authentication/src/main/resources/moaid_sl20_auth.beans.xml
@@ -29,5 +29,9 @@
<bean id="ReceiveQualeIDResponseTask"
class="at.gv.egovernment.moa.id.auth.modules.sl20_auth.tasks.ReceiveQualeIDTask"
scope="prototype"/>
+
+ <bean id="VerifyQualifiedeIDTask"
+ class="at.gv.egovernment.moa.id.auth.modules.sl20_auth.tasks.VerifyQualifiedeIDTask"
+ scope="prototype"/>
</beans> \ No newline at end of file
diff --git a/id/server/modules/moa-id-module-sl20_authentication/src/main/resources/sl20.Authentication.process.xml b/id/server/modules/moa-id-module-sl20_authentication/src/main/resources/sl20.Authentication.process.xml
index bcd74f84c..673144b06 100644
--- a/id/server/modules/moa-id-module-sl20_authentication/src/main/resources/sl20.Authentication.process.xml
+++ b/id/server/modules/moa-id-module-sl20_authentication/src/main/resources/sl20.Authentication.process.xml
@@ -3,17 +3,19 @@
<pd:Task id="createQualifiedeIDRequest" class="CreateQualeIDRequestTask" />
<pd:Task id="receiveQualifiedeID" class="ReceiveQualeIDResponseTask" async="true"/>
-
- <!-- <pd:Task id="finalizeAuthentication" class="FinalizeAuthenticationTask" /> -->
+ <pd:Task id="verifyQualifiedeIDTask" class="VerifyQualifiedeIDTask" async="true"/>
+ <pd:Task id="userRestrictionTask" class="UserRestrictionTask" />
+ <pd:Task id="finalizeAuthentication" class="FinalizeAuthenticationTask" />
<pd:StartEvent id="start" />
<pd:Transition from="start" to="createQualifiedeIDRequest" />
- <pd:Transition from="createQualifiedeIDRequest" to="receiveQualifiedeID" />
- <pd:Transition from="receiveQualifiedeID" to="end" />
-
- <!-- It's only required if we can not use the finalize redirect on SL20 redirect command -->
- <!-- <pd:Transition from="receiveQualifiedeID" to="finalizeAuthentication" />
- <pd:Transition from="finalizeAuthentication" to="end" /> -->
+ <pd:Transition from="createQualifiedeIDRequest" to="receiveQualifiedeID" />
+ <pd:Transition from="receiveQualifiedeID" to="verifyQualifiedeIDTask" />
+ <pd:Transition from="verifyQualifiedeIDTask" to="userRestrictionTask" />
+ <pd:Transition from="userRestrictionTask" to="finalizeAuthentication" />
+ <pd:Transition from="finalizeAuthentication" to="end" />
+
+
<pd:EndEvent id="end" />