aboutsummaryrefslogtreecommitdiff
path: root/id/server/modules/moa-id-module-sl20_authentication/src/main/java/at/gv/egovernment/moa/id/auth/modules/sl20_auth
diff options
context:
space:
mode:
Diffstat (limited to 'id/server/modules/moa-id-module-sl20_authentication/src/main/java/at/gv/egovernment/moa/id/auth/modules/sl20_auth')
-rw-r--r--id/server/modules/moa-id-module-sl20_authentication/src/main/java/at/gv/egovernment/moa/id/auth/modules/sl20_auth/Constants.java55
-rw-r--r--id/server/modules/moa-id-module-sl20_authentication/src/main/java/at/gv/egovernment/moa/id/auth/modules/sl20_auth/SL20AuthenticationModulImpl.java127
-rw-r--r--id/server/modules/moa-id-module-sl20_authentication/src/main/java/at/gv/egovernment/moa/id/auth/modules/sl20_auth/SL20AuthenticationSpringResourceProvider.java28
-rw-r--r--id/server/modules/moa-id-module-sl20_authentication/src/main/java/at/gv/egovernment/moa/id/auth/modules/sl20_auth/SL20SignalServlet.java61
-rw-r--r--id/server/modules/moa-id-module-sl20_authentication/src/main/java/at/gv/egovernment/moa/id/auth/modules/sl20_auth/data/VerificationResult.java39
-rw-r--r--id/server/modules/moa-id-module-sl20_authentication/src/main/java/at/gv/egovernment/moa/id/auth/modules/sl20_auth/exceptions/SL20Exception.java19
-rw-r--r--id/server/modules/moa-id-module-sl20_authentication/src/main/java/at/gv/egovernment/moa/id/auth/modules/sl20_auth/exceptions/SL20SecurityException.java20
-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/exceptions/SLCommandoBuildException.java17
-rw-r--r--id/server/modules/moa-id-module-sl20_authentication/src/main/java/at/gv/egovernment/moa/id/auth/modules/sl20_auth/exceptions/SLCommandoParserException.java17
-rw-r--r--id/server/modules/moa-id-module-sl20_authentication/src/main/java/at/gv/egovernment/moa/id/auth/modules/sl20_auth/sl20/IJOSETools.java49
-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.java359
-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.java232
-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.java45
-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.java617
-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.java350
-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.java243
-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.java323
-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
20 files changed, 2974 insertions, 0 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
new file mode 100644
index 000000000..f474461bf
--- /dev/null
+++ b/id/server/modules/moa-id-module-sl20_authentication/src/main/java/at/gv/egovernment/moa/id/auth/modules/sl20_auth/Constants.java
@@ -0,0 +1,55 @@
+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_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";
+ public static final String CONFIG_PROP_SECURITY_KEYSTORE_KEY_SIGN_PASSWORD = CONFIG_PROP_PREFIX + ".security.sign.password";
+ public static final String CONFIG_PROP_SECURITY_KEYSTORE_KEY_ENCRYPTION_ALIAS = CONFIG_PROP_PREFIX + ".security.encryption.alias";;
+ public static final String CONFIG_PROP_SECURITY_KEYSTORE_KEY_ENCRYPTION_PASSWORD = CONFIG_PROP_PREFIX + ".security.encryption.password";
+
+ 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_";
+
+ /**
+ * Only dummy data for development!!!!!!
+ */
+ public static final String DUMMY_SIGNING_CERT =
+ "MIIC9zCCAd8CBFretWcwDQYJKoZIhvcNAQEOBQAwQDELMAkGA1UEBhMCQVQxDTAL\n" +
+ "BgNVBAoMBEVHSVoxIjAgBgNVBAMMGW93biBkdW1teSBtZXRhZGF0YSBzaWduZXIw\n" +
+ "HhcNMTgwNDI0MDQ0MTExWhcNMjEwMTE3MDQ0MTExWjBAMQswCQYDVQQGEwJBVDEN\n" +
+ "MAsGA1UECgwERUdJWjEiMCAGA1UEAwwZb3duIGR1bW15IG1ldGFkYXRhIHNpZ25l\n" +
+ "cjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAJvN3l1pjzlnmoW5trHH\n" +
+ "Rb1s60QtGNp2v1nfMg1R6h7SzygtmO869v5bqrVBBVGmujslr7W8cZ2DLmJoQx1N\n" +
+ "WwhccjXTHpNPw0B70qHGch2uRNkqkizSOlwth0Ll2DJtzxTolbajYdg+xppXScUq\n" +
+ "WNlNZndauPSnB2CESgNkaUou4x4YVSDInugAtLvdLx8rf2YcuidI6UIXxeSZr3VO\n" +
+ "Z12YtddzcJ+lwh7OX8B0UvLsdYjKjefjEudyuNBmVwLv4K2LsFhSqgE1CAzk3oCb\n" +
+ "V2A84klaWVPiXoBiOucyouvX781WVp1aCBp0QA8gpJH7/2wRsdPQ90tjMzM7dcgY\n" +
+ "LDkCAwEAATANBgkqhkiG9w0BAQ4FAAOCAQEAQuYRQcCNLDYU1ItliYz9f28+KDyU\n" +
+ "8WjF3NDZrlJbGSKQ4n7wkBfxdK3zprmpHadWDB+aZaPt/+voE2FduzPiLUDlpazN\n" +
+ "60JJ5/YHZ3q9MZvdoNg6rjkpioWatoj/smUkT6oUWL/gp8tH12fOd2oJygBqXMve\n" +
+ "3y3qVCghnjRaMYuXcScTZcjH9yebkTLygirtw34oGVb7t+HwbtcN65fUIBly6Rcl\n" +
+ "8NV3pwOKhXFKDAqXUpvhebL4+tWOqPdqfIfGaE6rELfTf3icGY3CQCzDz5Gp0Ptc\n" +
+ "TfQqm64xnhtAruXNJXWg2ptg+GuQgWnJUgQ8wLNMxw9XdeEwlQo5dL6xmg==";
+
+ public static final String DUMMY_SIGNING_CERT_FINGERPRINT = "IwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAJvN3l1pjzlnmoW";
+
+}
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
new file mode 100644
index 000000000..9c2d47ca7
--- /dev/null
+++ b/id/server/modules/moa-id-module-sl20_authentication/src/main/java/at/gv/egovernment/moa/id/auth/modules/sl20_auth/SL20AuthenticationModulImpl.java
@@ -0,0 +1,127 @@
+/*
+ * Copyright 2014 Federal Chancellery Austria
+ * MOA-ID has been developed in a cooperation between BRZ, the Federal
+ * Chancellery Austria - ICT staff unit, and Graz University of Technology.
+ *
+ * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by
+ * the European Commission - subsequent versions of the EUPL (the "Licence");
+ * You may not use this work except in compliance with the Licence.
+ * You may obtain a copy of the Licence at:
+ * http://www.osor.eu/eupl/
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the Licence is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the Licence for the specific language governing permissions and
+ * limitations under the Licence.
+ *
+ * This product combines work with different licenses. See the "NOTICE" text
+ * file for details on the various modules and licenses.
+ * The "NOTICE" text file is part of the distribution. Any derivative works
+ * that you distribute must include a readable copy of the "NOTICE" text file.
+ */
+package at.gv.egovernment.moa.id.auth.modules.sl20_auth;
+
+import java.util.Arrays;
+import java.util.List;
+
+import javax.annotation.PostConstruct;
+
+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 {
+ 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;
+
+ @Override
+ public int getPriority() {
+ return priority;
+ }
+
+ /**
+ * Sets the priority of this module. Default value is {@code 0}.
+ * @param priority The priority.
+ */
+ public void setPriority(int priority) {
+ this.priority = priority;
+ }
+
+ @PostConstruct
+ protected void initalSL20Authentication() {
+ //parameter to whiteList
+ authManager.addHeaderNameToWhiteList(SL20Constants.HTTP_HEADER_SL20_CLIENT_TYPE);
+ authManager.addHeaderNameToWhiteList(SL20Constants.HTTP_HEADER_SL20_VDA_TYPE);
+
+ }
+
+
+ /* (non-Javadoc)
+ * @see at.gv.egovernment.moa.id.auth.modules.AuthModule#selectProcess(at.gv.egovernment.moa.id.process.api.ExecutionContext)
+ */
+ @Override
+ public String selectProcess(ExecutionContext context) {
+ 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("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)
+ * @see at.gv.egovernment.moa.id.auth.modules.AuthModule#getProcessDefinitions()
+ */
+ @Override
+ public String[] getProcessDefinitions() {
+ return new String[] { "classpath:sl20.Authentication.process.xml" };
+ }
+
+}
diff --git a/id/server/modules/moa-id-module-sl20_authentication/src/main/java/at/gv/egovernment/moa/id/auth/modules/sl20_auth/SL20AuthenticationSpringResourceProvider.java b/id/server/modules/moa-id-module-sl20_authentication/src/main/java/at/gv/egovernment/moa/id/auth/modules/sl20_auth/SL20AuthenticationSpringResourceProvider.java
new file mode 100644
index 000000000..2658a363d
--- /dev/null
+++ b/id/server/modules/moa-id-module-sl20_authentication/src/main/java/at/gv/egovernment/moa/id/auth/modules/sl20_auth/SL20AuthenticationSpringResourceProvider.java
@@ -0,0 +1,28 @@
+package at.gv.egovernment.moa.id.auth.modules.sl20_auth;
+
+import org.springframework.core.io.ClassPathResource;
+import org.springframework.core.io.Resource;
+
+import at.gv.egiz.components.spring.api.SpringResourceProvider;
+
+public class SL20AuthenticationSpringResourceProvider implements SpringResourceProvider {
+
+ @Override
+ public String getName() {
+ return "MOA-ID Security-Layer 2.0 Authentication SpringResourceProvider";
+ }
+
+ @Override
+ public String[] getPackagesToScan() {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ public Resource[] getResourcesToLoad() {
+ ClassPathResource sl20AuthConfig = new ClassPathResource("/moaid_sl20_auth.beans.xml", SL20AuthenticationSpringResourceProvider.class);
+
+ return new Resource[] {sl20AuthConfig};
+ }
+
+}
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
new file mode 100644
index 000000000..87e9e933d
--- /dev/null
+++ b/id/server/modules/moa-id-module-sl20_authentication/src/main/java/at/gv/egovernment/moa/id/auth/modules/sl20_auth/SL20SignalServlet.java
@@ -0,0 +1,61 @@
+/*
+ * Copyright 2014 Federal Chancellery Austria
+ * MOA-ID has been developed in a cooperation between BRZ, the Federal
+ * Chancellery Austria - ICT staff unit, and Graz University of Technology.
+ *
+ * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by
+ * the European Commission - subsequent versions of the EUPL (the "Licence");
+ * You may not use this work except in compliance with the Licence.
+ * You may obtain a copy of the Licence at:
+ * http://www.osor.eu/eupl/
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the Licence is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the Licence for the specific language governing permissions and
+ * limitations under the Licence.
+ *
+ * This product combines work with different licenses. See the "NOTICE" text
+ * file for details on the various modules and licenses.
+ * The "NOTICE" text file is part of the distribution. Any derivative works
+ * that you distribute must include a readable copy of the "NOTICE" text file.
+ */
+package at.gv.egovernment.moa.id.auth.modules.sl20_auth;
+
+import java.io.IOException;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.springframework.stereotype.Controller;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestMethod;
+
+import at.gv.egiz.eaaf.core.impl.idp.controller.AbstractProcessEngineSignalController;
+import at.gv.egovernment.moa.logging.Logger;
+
+/**
+ * @author tlenz
+ *
+ */
+@Controller
+public class SL20SignalServlet extends AbstractProcessEngineSignalController {
+
+ public SL20SignalServlet() {
+ super();
+ Logger.debug("Registering servlet " + getClass().getName() +
+ " with mappings '"+ Constants.HTTP_ENDPOINT_DATAURL +
+ " and " + Constants.HTTP_ENDPOINT_RESUME +
+ "'.");
+
+ }
+
+ @RequestMapping(value = { Constants.HTTP_ENDPOINT_DATAURL,
+ Constants.HTTP_ENDPOINT_RESUME
+ },
+ method = {RequestMethod.POST, RequestMethod.GET})
+ public void performCitizenCardAuthentication(HttpServletRequest req, HttpServletResponse resp) throws IOException {
+ signalProcessManagement(req, resp);
+ }
+
+}
diff --git a/id/server/modules/moa-id-module-sl20_authentication/src/main/java/at/gv/egovernment/moa/id/auth/modules/sl20_auth/data/VerificationResult.java b/id/server/modules/moa-id-module-sl20_authentication/src/main/java/at/gv/egovernment/moa/id/auth/modules/sl20_auth/data/VerificationResult.java
new file mode 100644
index 000000000..2a24096f9
--- /dev/null
+++ b/id/server/modules/moa-id-module-sl20_authentication/src/main/java/at/gv/egovernment/moa/id/auth/modules/sl20_auth/data/VerificationResult.java
@@ -0,0 +1,39 @@
+package at.gv.egovernment.moa.id.auth.modules.sl20_auth.data;
+
+import java.security.cert.X509Certificate;
+import java.util.List;
+
+import com.google.gson.JsonObject;
+
+public class VerificationResult {
+
+ private Boolean validSigned = null;
+ private List<X509Certificate> certs = null;
+ private JsonObject payload = null;
+
+ public VerificationResult(JsonObject payload) {
+ this.payload = payload;
+
+ }
+
+ public VerificationResult(JsonObject string, List<X509Certificate> certs, boolean wasValidSigned) {
+ this.payload = string;
+ this.certs = certs;
+ this.validSigned = wasValidSigned;
+
+ }
+
+ public Boolean isValidSigned() {
+ return validSigned;
+ }
+ public List<X509Certificate> getCertChain() {
+ return certs;
+ }
+ public JsonObject getPayload() {
+ return payload;
+ }
+
+
+
+
+}
diff --git a/id/server/modules/moa-id-module-sl20_authentication/src/main/java/at/gv/egovernment/moa/id/auth/modules/sl20_auth/exceptions/SL20Exception.java b/id/server/modules/moa-id-module-sl20_authentication/src/main/java/at/gv/egovernment/moa/id/auth/modules/sl20_auth/exceptions/SL20Exception.java
new file mode 100644
index 000000000..898bd7097
--- /dev/null
+++ b/id/server/modules/moa-id-module-sl20_authentication/src/main/java/at/gv/egovernment/moa/id/auth/modules/sl20_auth/exceptions/SL20Exception.java
@@ -0,0 +1,19 @@
+package at.gv.egovernment.moa.id.auth.modules.sl20_auth.exceptions;
+
+import at.gv.egovernment.moa.id.commons.api.exceptions.MOAIDException;
+
+public class SL20Exception extends MOAIDException {
+
+ private static final long serialVersionUID = 1L;
+
+ public SL20Exception(String messageId, Object[] parameters) {
+ super(messageId, parameters);
+
+ }
+
+ public SL20Exception(String messageId, Object[] parameters, Throwable wrapped) {
+ super(messageId, parameters, wrapped);
+
+ }
+
+}
diff --git a/id/server/modules/moa-id-module-sl20_authentication/src/main/java/at/gv/egovernment/moa/id/auth/modules/sl20_auth/exceptions/SL20SecurityException.java b/id/server/modules/moa-id-module-sl20_authentication/src/main/java/at/gv/egovernment/moa/id/auth/modules/sl20_auth/exceptions/SL20SecurityException.java
new file mode 100644
index 000000000..3bea12cb1
--- /dev/null
+++ b/id/server/modules/moa-id-module-sl20_authentication/src/main/java/at/gv/egovernment/moa/id/auth/modules/sl20_auth/exceptions/SL20SecurityException.java
@@ -0,0 +1,20 @@
+package at.gv.egovernment.moa.id.auth.modules.sl20_auth.exceptions;
+
+public class SL20SecurityException extends SL20Exception {
+
+ private static final long serialVersionUID = 3281385988027147449L;
+
+ public SL20SecurityException(Object[] parameters) {
+ super("sl20.05", parameters);
+ }
+
+ public SL20SecurityException(String parameter) {
+ super("sl20.05", new Object[] {parameter});
+ }
+
+ public SL20SecurityException(Object[] parameters, Throwable wrapped) {
+ super("sl20.05", parameters, wrapped);
+
+ }
+
+}
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/exceptions/SLCommandoBuildException.java b/id/server/modules/moa-id-module-sl20_authentication/src/main/java/at/gv/egovernment/moa/id/auth/modules/sl20_auth/exceptions/SLCommandoBuildException.java
new file mode 100644
index 000000000..35cf728f6
--- /dev/null
+++ b/id/server/modules/moa-id-module-sl20_authentication/src/main/java/at/gv/egovernment/moa/id/auth/modules/sl20_auth/exceptions/SLCommandoBuildException.java
@@ -0,0 +1,17 @@
+package at.gv.egovernment.moa.id.auth.modules.sl20_auth.exceptions;
+
+public class SLCommandoBuildException extends SL20Exception {
+
+ private static final long serialVersionUID = 1L;
+
+
+ public SLCommandoBuildException(String msg) {
+ super("sl20.01", new Object[]{msg});
+
+ }
+
+ public SLCommandoBuildException(String msg, Throwable e) {
+ super("sl20.01", new Object[]{msg}, e);
+
+ }
+}
diff --git a/id/server/modules/moa-id-module-sl20_authentication/src/main/java/at/gv/egovernment/moa/id/auth/modules/sl20_auth/exceptions/SLCommandoParserException.java b/id/server/modules/moa-id-module-sl20_authentication/src/main/java/at/gv/egovernment/moa/id/auth/modules/sl20_auth/exceptions/SLCommandoParserException.java
new file mode 100644
index 000000000..f36e8ad82
--- /dev/null
+++ b/id/server/modules/moa-id-module-sl20_authentication/src/main/java/at/gv/egovernment/moa/id/auth/modules/sl20_auth/exceptions/SLCommandoParserException.java
@@ -0,0 +1,17 @@
+package at.gv.egovernment.moa.id.auth.modules.sl20_auth.exceptions;
+
+public class SLCommandoParserException extends SL20Exception {
+
+ private static final long serialVersionUID = 1L;
+
+
+ public SLCommandoParserException(String msg) {
+ super("sl20.02", new Object[]{msg});
+
+ }
+
+ public SLCommandoParserException(String msg, Throwable e) {
+ super("sl20.02", new Object[]{msg}, 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/IJOSETools.java b/id/server/modules/moa-id-module-sl20_authentication/src/main/java/at/gv/egovernment/moa/id/auth/modules/sl20_auth/sl20/IJOSETools.java
new file mode 100644
index 000000000..6fd1c3c4d
--- /dev/null
+++ b/id/server/modules/moa-id-module-sl20_authentication/src/main/java/at/gv/egovernment/moa/id/auth/modules/sl20_auth/sl20/IJOSETools.java
@@ -0,0 +1,49 @@
+package at.gv.egovernment.moa.id.auth.modules.sl20_auth.sl20;
+
+import java.security.cert.X509Certificate;
+
+import com.google.gson.JsonElement;
+
+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.SL20SecurityException;
+import at.gv.egovernment.moa.id.auth.modules.sl20_auth.exceptions.SLCommandoBuildException;
+import at.gv.egovernment.moa.id.auth.modules.sl20_auth.exceptions.SLCommandoParserException;
+
+public interface IJOSETools {
+
+ /**
+ * Create a JWS signature
+ *
+ * @param payLoad Payload to sign
+ * @throws SLCommandoBuildException
+ */
+ public String createSignature(String payLoad) throws SLCommandoBuildException;
+
+ /**
+ * Validates a JWS signature
+ *
+ * @param serializedContent
+ * @return
+ * @throws SLCommandoParserException
+ * @throws SL20Exception
+ */
+ public VerificationResult validateSignature(String serializedContent) throws SL20Exception;
+
+ /**
+ * Get the encryption certificate for SL2.0 End-to-End encryption
+ *
+ * @return
+ */
+ public X509Certificate getEncryptionCertificate();
+
+ /**
+ * Decrypt a serialized JWE token
+ *
+ * @param compactSerialization Serialized JWE token
+ * @return decrypted payload
+ * @throws SL20Exception
+ */
+ public JsonElement decryptPayload(String compactSerialization) throws SL20Exception;
+
+}
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
new file mode 100644
index 000000000..42783468d
--- /dev/null
+++ b/id/server/modules/moa-id-module-sl20_authentication/src/main/java/at/gv/egovernment/moa/id/auth/modules/sl20_auth/sl20/JsonSecurityUtils.java
@@ -0,0 +1,359 @@
+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;
+
+import org.jose4j.jwa.AlgorithmConstraints;
+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;
+
+import com.google.gson.JsonElement;
+import com.google.gson.JsonParser;
+import com.google.gson.JsonSyntaxException;
+
+import at.gv.egiz.eaaf.core.impl.utils.FileUtils;
+import at.gv.egiz.eaaf.core.impl.utils.KeyStoreUtils;
+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.SL20SecurityException;
+import at.gv.egovernment.moa.id.auth.modules.sl20_auth.exceptions.SLCommandoBuildException;
+import at.gv.egovernment.moa.id.auth.modules.sl20_auth.exceptions.SLCommandoParserException;
+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{
+
+ @Autowired(required=true) AuthConfiguration authConfig;
+ private Key signPrivKey = null;
+ private X509Certificate[] signCertChain = null;
+
+ 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 ... ");
+ try {
+ KeyStore keyStore = KeyStoreUtils.loadKeyStore(getKeyStoreFilePath(),
+ getKeyStorePassword());
+
+ //load signing key
+ signPrivKey = keyStore.getKey(getSigningKeyAlias(), getSigningKeyPassword().toCharArray());
+ Certificate[] certChainSigning = keyStore.getCertificateChain(getSigningKeyAlias());
+ signCertChain = new X509Certificate[certChainSigning.length];
+ for (int i=0; i<certChainSigning.length; i++) {
+ if (certChainSigning[i] instanceof X509Certificate) {
+ signCertChain[i] = (X509Certificate)certChainSigning[i];
+ } else
+ Logger.warn("NO X509 certificate for signing: " + certChainSigning[i].getType());
+
+ }
+
+ //load encryption key
+ try {
+ encPrivKey = keyStore.getKey(getEncryptionKeyAlias(), getEncryptionKeyPassword().toCharArray());
+ if (encPrivKey != null) {
+ Certificate[] certChainEncryption = keyStore.getCertificateChain(getEncryptionKeyAlias());
+ encCertChain = new X509Certificate[certChainEncryption.length];
+ for (int i=0; i<certChainEncryption.length; i++) {
+ if (certChainEncryption[i] instanceof X509Certificate) {
+ encCertChain[i] = (X509Certificate)certChainEncryption[i];
+ } else
+ Logger.warn("NO X509 certificate for encryption: " + certChainEncryption[i].getType());
+ }
+ } else
+ Logger.info("No encryption key for SL2.0 found. End-to-End encryption is not used.");
+
+ } catch (Exception e) {
+ Logger.warn("No encryption key for SL2.0 found. End-to-End encryption is not used. Reason: " + e.getMessage(), e);
+
+ }
+
+ //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());
+ throw new SL20Exception("sl20.03", new Object[]{"Can NOT open private key for signing"});
+
+ }
+
+ if (signCertChain == null || signCertChain.length == 0) {
+ Logger.info("NO certificate for SL2.0 signing. KeyStore=" + getKeyStoreFilePath());
+ throw new SL20Exception("sl20.03", new Object[]{"NO certificate for SL2.0 signing"});
+
+ }
+
+ Logger.info("SL2.0 authentication security constrains initialized.");
+
+ } catch ( Exception e) {
+ Logger.error("SL2.0 security constrains initialization FAILED.", e);
+
+ }
+
+ }
+
+
+ @Override
+ public String createSignature(String payLoad) throws SLCommandoBuildException {
+ try {
+ JsonWebSignature jws = new JsonWebSignature();
+
+ //set payload
+ jws.setPayload(payLoad);
+
+ //set basic header
+ jws.setContentTypeHeaderValue(SL20Constants.SL20_CONTENTTYPE_SIGNED_COMMAND);
+
+ //set signing information
+ jws.setAlgorithmHeaderValue(AlgorithmIdentifiers.RSA_USING_SHA256);
+ jws.setKey(signPrivKey);
+
+ //TODO:
+ jws.setCertificateChainHeaderValue(signCertChain);
+ jws.setX509CertSha256ThumbprintHeaderValue(signCertChain[0]);
+
+ return jws.getCompactSerialization();
+
+ } catch (JoseException e) {
+ Logger.warn("Can NOT sign SL2.0 command.", e);
+ throw new SLCommandoBuildException("Can NOT sign SL2.0 command.", e);
+
+ }
+
+ }
+
+ @Override
+ public VerificationResult validateSignature(String serializedContent) throws SL20Exception {
+ try {
+ JsonWebSignature jws = new JsonWebSignature();
+ //set payload
+ jws.setCompactSerialization(serializedContent);
+
+ //set security constrains
+ jws.setAlgorithmConstraints(new AlgorithmConstraints(ConstraintType.WHITELIST,
+ 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();
+ String x5t256 = jws.getX509CertSha256ThumbprintHeaderValue();
+ if (x5cCerts != null) {
+ Logger.debug("Found x509 certificate in JOSE header ... ");
+ Logger.trace("Sorting received X509 certificates ... ");
+ 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(selectedKey);
+
+ //validate signature
+ boolean valid = jws.verifySignature();
+ if (!valid) {
+ Logger.info("JWS signature invalide. Stopping authentication process ...");
+ Logger.debug("Received JWS msg: " + serializedContent);
+ throw new SL20SecurityException("JWS signature invalide.");
+
+ }
+
+
+ //load payLoad
+ Logger.debug("SL2.0 commando signature validation sucessfull");
+ JsonElement sl20Req = new JsonParser().parse(jws.getPayload());
+
+ return new VerificationResult(sl20Req.getAsJsonObject(), null, valid) ;
+
+ } catch (JoseException e) {
+ Logger.warn("SL2.0 commando signature validation FAILED", e);
+ throw new SL20SecurityException(new Object[]{e.getMessage()}, e);
+
+ }
+
+ }
+
+
+ @Override
+ public JsonElement decryptPayload(String compactSerialization) throws SL20Exception {
+ try {
+ JsonWebEncryption receiverJwe = new JsonWebEncryption();
+
+ //set security constrains
+ receiverJwe.setAlgorithmConstraints(
+ new AlgorithmConstraints(ConstraintType.WHITELIST,
+ SL20Constants.SL20_ALGORITHM_WHITELIST_KEYENCRYPTION.toArray(new String[SL20Constants.SL20_ALGORITHM_WHITELIST_KEYENCRYPTION.size()])));
+ receiverJwe.setContentEncryptionAlgorithmConstraints(
+ new AlgorithmConstraints(ConstraintType.WHITELIST,
+ SL20Constants.SL20_ALGORITHM_WHITELIST_ENCRYPTION.toArray(new String[SL20Constants.SL20_ALGORITHM_WHITELIST_ENCRYPTION.size()])));
+
+ //set payload
+ receiverJwe.setCompactSerialization(compactSerialization);
+
+
+ //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);
+
+ 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) {
+ Logger.warn("SL2.0 result decryption FAILED", e);
+ throw new SL20SecurityException(new Object[]{e.getMessage()}, e);
+
+ } catch ( JsonSyntaxException e) {
+ Logger.warn("Decrypted SL2.0 result is NOT a valid JSON.", e);
+ throw new SLCommandoParserException("Decrypted SL2.0 result is NOT a valid JSON.", e);
+
+ }
+
+ }
+
+
+
+ @Override
+ public X509Certificate getEncryptionCertificate() {
+ //TODO: maybe update after SL2.0 update on encryption certificate parts
+ if (encCertChain !=null && encCertChain.length > 0)
+ return encCertChain[0];
+ else
+ return null;
+ }
+
+ private String getKeyStoreFilePath() throws ConfigurationException {
+ return FileUtils.makeAbsoluteURL(
+ authConfig.getBasicConfiguration(Constants.CONFIG_PROP_SECURITY_KEYSTORE_PATH),
+ authConfig.getRootConfigFileDir());
+ }
+
+ private String getKeyStorePassword() {
+ return authConfig.getBasicConfiguration(Constants.CONFIG_PROP_SECURITY_KEYSTORE_PASSWORD).trim();
+
+ }
+
+ private String getSigningKeyAlias() {
+ return authConfig.getBasicConfiguration(
+ Constants.CONFIG_PROP_SECURITY_KEYSTORE_KEY_SIGN_ALIAS).trim();
+ }
+
+ private String getSigningKeyPassword() {
+ return authConfig.getBasicConfiguration(
+ Constants.CONFIG_PROP_SECURITY_KEYSTORE_KEY_SIGN_PASSWORD).trim();
+ }
+
+ private String getEncryptionKeyAlias() {
+ return authConfig.getBasicConfiguration(
+ Constants.CONFIG_PROP_SECURITY_KEYSTORE_KEY_ENCRYPTION_ALIAS).trim();
+ }
+
+ private String getEncryptionKeyPassword() {
+ return authConfig.getBasicConfiguration(
+ Constants.CONFIG_PROP_SECURITY_KEYSTORE_KEY_ENCRYPTION_PASSWORD).trim();
+ }
+
+}
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
new file mode 100644
index 000000000..645b043ce
--- /dev/null
+++ b/id/server/modules/moa-id-module-sl20_authentication/src/main/java/at/gv/egovernment/moa/id/auth/modules/sl20_auth/sl20/SL20Constants.java
@@ -0,0 +1,232 @@
+package at.gv.egovernment.moa.id.auth.modules.sl20_auth.sl20;
+
+import java.util.Arrays;
+import java.util.List;
+
+import org.jose4j.jwe.ContentEncryptionAlgorithmIdentifiers;
+import org.jose4j.jwe.KeyManagementAlgorithmIdentifiers;
+import org.jose4j.jws.AlgorithmIdentifiers;
+
+public class SL20Constants {
+ 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";
+
+
+ //*******************************************************************************************
+ //JSON signing and encryption headers
+ public static final String JSON_ALGORITHM = "alg";
+ public static final String JSON_CONTENTTYPE = "cty";
+ public static final String JSON_X509_CERTIFICATE = "x5c";
+ public static final String JSON_X509_FINGERPRINT = "x5t#S256";
+ public static final String JSON_ENCRYPTION_PAYLOAD = "enc";
+
+ public static final String JSON_ALGORITHM_SIGNING_RS256 = AlgorithmIdentifiers.RSA_USING_SHA256;
+ public static final String JSON_ALGORITHM_SIGNING_RS512 = AlgorithmIdentifiers.RSA_USING_SHA512;
+ public static final String JSON_ALGORITHM_SIGNING_ES256 = AlgorithmIdentifiers.ECDSA_USING_P256_CURVE_AND_SHA256;
+ public static final String JSON_ALGORITHM_SIGNING_ES512 = AlgorithmIdentifiers.ECDSA_USING_P521_CURVE_AND_SHA512;
+ public static final String JSON_ALGORITHM_SIGNING_PS256 = AlgorithmIdentifiers.RSA_PSS_USING_SHA256;
+ public static final String JSON_ALGORITHM_SIGNING_PS512 = AlgorithmIdentifiers.RSA_PSS_USING_SHA512;
+
+ public static final List<String> SL20_ALGORITHM_WHITELIST_SIGNING = Arrays.asList(
+ JSON_ALGORITHM_SIGNING_RS256,
+ JSON_ALGORITHM_SIGNING_RS512,
+ JSON_ALGORITHM_SIGNING_ES256,
+ JSON_ALGORITHM_SIGNING_ES512,
+ JSON_ALGORITHM_SIGNING_PS256,
+ JSON_ALGORITHM_SIGNING_PS512
+ );
+
+ public static final String JSON_ALGORITHM_ENC_KEY_RSAOAEP = KeyManagementAlgorithmIdentifiers.RSA_OAEP;
+ public static final String JSON_ALGORITHM_ENC_KEY_RSAOAEP256 = KeyManagementAlgorithmIdentifiers.RSA_OAEP_256;
+
+ public static final List<String> SL20_ALGORITHM_WHITELIST_KEYENCRYPTION = Arrays.asList(
+ JSON_ALGORITHM_ENC_KEY_RSAOAEP,
+ JSON_ALGORITHM_ENC_KEY_RSAOAEP256
+ );
+
+ public static final String JSON_ALGORITHM_ENC_PAYLOAD_A128CBCHS256 = ContentEncryptionAlgorithmIdentifiers.AES_128_CBC_HMAC_SHA_256;
+ public static final String JSON_ALGORITHM_ENC_PAYLOAD_A256CBCHS512 = ContentEncryptionAlgorithmIdentifiers.AES_256_CBC_HMAC_SHA_512;
+ public static final String JSON_ALGORITHM_ENC_PAYLOAD_A128GCM = ContentEncryptionAlgorithmIdentifiers.AES_128_GCM;
+ public static final String JSON_ALGORITHM_ENC_PAYLOAD_A256GCM = ContentEncryptionAlgorithmIdentifiers.AES_256_GCM;
+
+ public static final List<String> SL20_ALGORITHM_WHITELIST_ENCRYPTION = Arrays.asList(
+ JSON_ALGORITHM_ENC_PAYLOAD_A128CBCHS256,
+ JSON_ALGORITHM_ENC_PAYLOAD_A256CBCHS512,
+ JSON_ALGORITHM_ENC_PAYLOAD_A128GCM,
+ JSON_ALGORITHM_ENC_PAYLOAD_A256GCM
+ );
+
+
+ //*********************************************************************************************
+ //Object identifier for generic transport container
+ public static final String SL20_CONTENTTYPE_SIGNED_COMMAND ="application/sl2.0;command";
+ public static final String SL20_CONTENTTYPE_ENCRYPTED_RESULT ="application/sl2.0;result";
+
+ public static final String SL20_VERSION = "v";
+ public static final String SL20_REQID = "reqID";
+ public static final String SL20_RESPID = "respID";
+ public static final String SL20_INRESPTO = "inResponseTo";
+ public static final String SL20_TRANSACTIONID = "transactionID";
+ public static final String SL20_PAYLOAD = "payload";
+ public static final String SL20_SIGNEDPAYLOAD = "signedPayload";
+
+ //Generic Object identifier for commands
+ public static final String SL20_COMMAND_CONTAINER_NAME = "name";
+ public static final String SL20_COMMAND_CONTAINER_PARAMS = "params";
+ public static final String SL20_COMMAND_CONTAINER_RESULT = "result";
+ public static final String SL20_COMMAND_CONTAINER_ENCRYPTEDRESULT = "encryptedResult";
+
+ //COMMAND Object identifier
+ public static final String SL20_COMMAND_IDENTIFIER_REDIRECT = "redirect";
+ 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_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";
+
+ public static final String SL20_COMMAND_IDENTIFIER_AUTH_IDANDPASSWORD = "idAndPassword";
+ public static final String SL20_COMMAND_IDENTIFIER_AUTH_JWSTOKENFACTOR = "jwsTokenAuth";
+ public static final String SL20_COMMAND_IDENTIFIER_AUTH_QRCODEFACTOR = "qrCodeFactor";
+
+ //*****COMMAND parameter identifier******
+ //general Identifier
+ public static final String SL20_COMMAND_PARAM_GENERAL_REQPARAMETER_VALUE = "value";
+ 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";
+ public static final String SL20_COMMAND_PARAM_GENERAL_REDIRECT_COMMAND = "command";
+ public static final String SL20_COMMAND_PARAM_GENERAL_REDIRECT_SIGNEDCOMMAND = "signedCommand";
+ public static final String SL20_COMMAND_PARAM_GENERAL_REDIRECT_IPCREDIRECT = "IPCRedirect";
+
+ //Call command
+ public static final String SL20_COMMAND_PARAM_GENERAL_CALL_URL = SL20_COMMAND_PARAM_GENERAL_REDIRECT_URL;
+ public static final String SL20_COMMAND_PARAM_GENERAL_CALL_METHOD = "method";
+ public static final String SL20_COMMAND_PARAM_GENERAL_CALL_METHOD_GET = "get";
+ public static final String SL20_COMMAND_PARAM_GENERAL_CALL_METHOD_POST = "post";
+ public static final String SL20_COMMAND_PARAM_GENERAL_CALL_INCLUDETRANSACTIONID = "includeTransactionID";
+ public static final String SL20_COMMAND_PARAM_GENERAL_CALL_REQPARAMETER = "reqParams";
+
+ //error command
+ public static final String SL20_COMMAND_PARAM_GENERAL_RESPONSE_ERRORCODE = "errorCode";
+ public static final String SL20_COMMAND_PARAM_GENERAL_RESPONSE_ERRORMESSAGE = "errorMessage";
+
+ //qualified eID command
+ public static final String SL20_COMMAND_PARAM_EID_AUTHBLOCKID = "authBlockTemplateID";
+ 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-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;
+
+
+ //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";
+ public static final String SL20_COMMAND_PARAM_BINDING_CREATE_SN = "SN";
+ public static final String SL20_COMMAND_PARAM_BINDING_CREATE_KEYLENGTH = "keyLength";
+ public static final String SL20_COMMAND_PARAM_BINDING_CREATE_KEYALG = "keyAlg";
+ public static final String SL20_COMMAND_PARAM_BINDING_CREATE_POLICIES = "policies";
+ public static final String SL20_COMMAND_PARAM_BINDING_CREATE_DATAURL = SL20_COMMAND_PARAM_GENERAL_DATAURL;
+ public static final String SL20_COMMAND_PARAM_BINDING_CREATE_X5CVDATRUST = "x5cVdaTrust";
+ public static final String SL20_COMMAND_PARAM_BINDING_CREATE_REQUESTUSERPASSWORD = "reqUserPassword";
+ public static final String SL20_COMMAND_PARAM_BINDING_CREATE_X5CENC = SL20_COMMAND_PARAM_GENERAL_RESPONSEENCRYPTIONCERTIFICATE;
+
+ public static final String SL20_COMMAND_PARAM_BINDING_CREATE_KEYALG_RSA = "RSA";
+ public static final String SL20_COMMAND_PARAM_BINDING_CREATE_KEYALG_SECPR256R1 = "secp256r1";
+
+ public static final String SL20_COMMAND_PARAM_BINDING_CREATE_POLICIES_LIFETIME = "lifeTime";
+ public static final String SL20_COMMAND_PARAM_BINDING_CREATE_POLICIES_USESECUREELEMENT = "useSecureElement";
+ public static final String SL20_COMMAND_PARAM_BINDING_CREATE_POLICIES_KEYTIMEOUT = "keyTimeout";
+ public static final String SL20_COMMAND_PARAM_BINDING_CREATE_POLICIES_NEEDUSERAUTH = "needUserAuth";
+
+ public static final String SL20_COMMAND_PARAM_BINDING_CREATE_RESULT_APPID = "appID";
+ public static final String SL20_COMMAND_PARAM_BINDING_CREATE_RESULT_CSR = "csr";
+ public static final String SL20_COMMAND_PARAM_BINDING_CREATE_RESULT_KEYATTESTATIONZERTIFICATE = "attCert";
+ public static final String SL20_COMMAND_PARAM_BINDING_CREATE_RESULT_USERPASSWORD = "encodedPass";
+
+
+ //store binding certificate command
+ public static final String SL20_COMMAND_PARAM_BINDING_STORE_CERTIFICATE = "x5c";
+ public static final String SL20_COMMAND_PARAM_BINDING_STORE_DATAURL = SL20_COMMAND_PARAM_GENERAL_DATAURL;
+ public static final String SL20_COMMAND_PARAM_BINDING_STORE_RESULT_SUCESS = "success";
+ public static final String SL20_COMMAND_PARAM_BINDING_STORE_RESULT_SUCESS_VALUE = "OK";
+
+ // Username and password authentication
+ public static final String SL20_COMMAND_PARAM_AUTH_IDANDPASSWORD_KEYALG = "keyAlg";
+ public static final String SL20_COMMAND_PARAM_AUTH_IDANDPASSWORD_KEYALG_VALUE_PLAIN = "plain";
+ public static final String SL20_COMMAND_PARAM_AUTH_IDANDPASSWORD_KEYALG_VALUE_PBKDF2 = "PBKDF2";
+ public static final String SL20_COMMAND_PARAM_AUTH_IDANDPASSWORD_DATAURL = SL20_COMMAND_PARAM_GENERAL_DATAURL;
+ public static final String SL20_COMMAND_PARAM_AUTH_IDANDPASSWORD_X5CENC = SL20_COMMAND_PARAM_GENERAL_RESPONSEENCRYPTIONCERTIFICATE;
+ public static final String SL20_COMMAND_PARAM_AUTH_IDANDPASSWORD_RESULT_KONTOID = SL20_COMMAND_PARAM_BINDING_CREATE_KONTOID;
+ public static final String SL20_COMMAND_PARAM_AUTH_IDANDPASSWORD_RESULT_USERPASSWORD = SL20_COMMAND_PARAM_BINDING_CREATE_RESULT_USERPASSWORD;
+
+ //JWS Token authentication
+ public static final String SL20_COMMAND_PARAM_AUTH_JWSTOKEN_NONCE = "nonce";
+ public static final String SL20_COMMAND_PARAM_AUTH_JWSTOKEN_DISPLAYDATA = "displayData";
+ public static final String SL20_COMMAND_PARAM_AUTH_JWSTOKEN_DISPLAYURL = "displayUrl";
+ public static final String SL20_COMMAND_PARAM_AUTH_JWSTOKEN_DATAURL = SL20_COMMAND_PARAM_GENERAL_DATAURL;
+ public static final String SL20_COMMAND_PARAM_AUTH_JWSTOKEN_RESULT_NONCE = SL20_COMMAND_PARAM_AUTH_JWSTOKEN_NONCE;
+
+ //QR-Code authentication
+ public static final String SL20_COMMAND_PARAM_AUTH_QRCODE_QRCODE = "qrCode";
+ public static final String SL20_COMMAND_PARAM_AUTH_QRCODE_DATAURL = SL20_COMMAND_PARAM_GENERAL_DATAURL;
+
+}
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
new file mode 100644
index 000000000..169cb8e73
--- /dev/null
+++ b/id/server/modules/moa-id-module-sl20_authentication/src/main/java/at/gv/egovernment/moa/id/auth/modules/sl20_auth/sl20/SL20HttpBindingUtils.java
@@ -0,0 +1,45 @@
+package at.gv.egovernment.moa.id.auth.modules.sl20_auth.sl20;
+
+import java.io.IOException;
+import java.io.StringWriter;
+import java.net.URISyntaxException;
+
+import javax.servlet.http.HttpServletRequest;
+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;
+
+import at.gv.egovernment.moaspss.logging.Logger;
+
+public class SL20HttpBindingUtils {
+
+ public static void writeIntoResponse(HttpServletRequest request, HttpServletResponse response, JsonObject sl20Forward, String redirectURL) throws IOException, URISyntaxException {
+ //forward SL2.0 command
+ 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 ... ");
+ StringWriter writer = new StringWriter();
+ writer.write(sl20Forward.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);
+
+ } else {
+ Logger.debug("Client request containts is no native client ... ");
+ URIBuilder clientRedirectURI = new URIBuilder(redirectURL);
+ 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
new file mode 100644
index 000000000..d5dec1fe1
--- /dev/null
+++ b/id/server/modules/moa-id-module-sl20_authentication/src/main/java/at/gv/egovernment/moa/id/auth/modules/sl20_auth/sl20/SL20JSONBuilderUtils.java
@@ -0,0 +1,617 @@
+package at.gv.egovernment.moa.id.auth.modules.sl20_auth.sl20;
+
+import java.security.cert.CertificateEncodingException;
+import java.security.cert.X509Certificate;
+import java.util.Arrays;
+import java.util.Base64;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+
+import com.google.gson.JsonArray;
+import com.google.gson.JsonElement;
+import com.google.gson.JsonObject;
+
+import at.gv.egovernment.moa.id.auth.modules.sl20_auth.Constants;
+import at.gv.egovernment.moa.id.auth.modules.sl20_auth.exceptions.SLCommandoBuildException;
+
+public class SL20JSONBuilderUtils {
+
+ /**
+ * Create command request
+ * @param name
+ * @param params
+ * @throws SLCommandoBuildException
+ * @return
+ */
+ public static JsonObject createCommand(String name, JsonElement params) throws SLCommandoBuildException {
+ JsonObject command = new JsonObject();
+ addSingleStringElement(command, SL20Constants.SL20_COMMAND_CONTAINER_NAME, name, true);
+ addSingleJSONElement(command, SL20Constants.SL20_COMMAND_CONTAINER_PARAMS, params, true);
+ return command;
+
+ }
+
+ /**
+ * Create signed command request
+ *
+ * @param name
+ * @param params
+ * @param signer
+ * @return
+ * @throws SLCommandoBuildException
+ */
+ public static String createSignedCommand(String name, JsonElement params, IJOSETools signer) throws SLCommandoBuildException {
+ JsonObject command = new JsonObject();
+ addSingleStringElement(command, SL20Constants.SL20_COMMAND_CONTAINER_NAME, name, true);
+ addSingleJSONElement(command, SL20Constants.SL20_COMMAND_CONTAINER_PARAMS, params, true);
+ return signer.createSignature(command.toString());
+
+ }
+
+
+ /**
+ * Create encrypted command result
+ *
+ * @param result
+ * @param encrypter
+ * @return
+ * @throws SLCommandoBuildException
+ */
+ public static String createEncryptedCommandoResult(JsonObject result, JsonSecurityUtils encrypter) throws SLCommandoBuildException {
+ //TODO: add real implementation
+ //create header and footer
+ String dummyHeader = createJsonEncryptionHeader(encrypter).toString();
+ String payLoad = result.toString();
+ String dummyFooter = createJsonSignedFooter(encrypter);
+
+ return Base64.getUrlEncoder().encodeToString(dummyHeader.getBytes()) + "."
+ + Base64.getUrlEncoder().encodeToString(payLoad.getBytes()) + "."
+ + Base64.getUrlEncoder().encodeToString(dummyFooter.getBytes());
+
+ }
+
+
+ /**
+ * Create command result
+ *
+ * @param name
+ * @param result
+ * @param encryptedResult
+ * @throws SLCommandoBuildException
+ * @return
+ */
+ public static JsonObject createCommandResponse(String name, JsonElement result, String encryptedResult) throws SLCommandoBuildException {
+ JsonObject command = new JsonObject();
+ addSingleStringElement(command, SL20Constants.SL20_COMMAND_CONTAINER_NAME, name, true);
+ addOnlyOnceOfTwo(command,
+ SL20Constants.SL20_COMMAND_CONTAINER_RESULT, SL20Constants.SL20_COMMAND_CONTAINER_ENCRYPTEDRESULT,
+ result, encryptedResult);
+ return command;
+
+ }
+
+ /**
+ * Create command result
+ *
+ * @param name
+ * @param result
+ * @param encryptedResult
+ * @throws SLCommandoBuildException
+ * @return
+ */
+ public static String createSignedCommandResponse(String name, JsonElement result, String encryptedResult, JsonSecurityUtils signer) throws SLCommandoBuildException {
+ JsonObject command = new JsonObject();
+ addSingleStringElement(command, SL20Constants.SL20_COMMAND_CONTAINER_NAME, name, true);
+ addOnlyOnceOfTwo(command,
+ SL20Constants.SL20_COMMAND_CONTAINER_RESULT, SL20Constants.SL20_COMMAND_CONTAINER_ENCRYPTEDRESULT,
+ result, encryptedResult);
+ String encodedCommand = command.toString();
+
+ //TODO: add real implementation
+ //create header and footer
+ String dummyHeader = createJsonSignedHeader(signer).toString();
+ String dummyFooter = createJsonSignedFooter(signer);
+
+ return Base64.getUrlEncoder().encodeToString(dummyHeader.getBytes()) + "."
+ + Base64.getUrlEncoder().encodeToString(encodedCommand.getBytes()) + "."
+ + Base64.getUrlEncoder().encodeToString(dummyFooter.getBytes());
+
+ }
+
+ /**
+ * Create parameters for Redirect command
+ *
+ * @param url
+ * @param command
+ * @param signedCommand
+ * @param ipcRedirect
+ * @return
+ * @throws SLCommandoBuildException
+ */
+ public static JsonObject createRedirectCommandParameters(String url, JsonElement command, JsonElement signedCommand, Boolean ipcRedirect) throws SLCommandoBuildException{
+ JsonObject redirectReqParams = new JsonObject();
+ addOnlyOnceOfTwo(redirectReqParams,
+ SL20Constants.SL20_COMMAND_PARAM_GENERAL_REDIRECT_COMMAND, SL20Constants.SL20_COMMAND_PARAM_GENERAL_REDIRECT_SIGNEDCOMMAND,
+ command, signedCommand);
+ addSingleStringElement(redirectReqParams, SL20Constants.SL20_COMMAND_PARAM_GENERAL_REDIRECT_URL, url, false);
+ addSingleBooleanElement(redirectReqParams, SL20Constants.SL20_COMMAND_PARAM_GENERAL_REDIRECT_IPCREDIRECT, ipcRedirect, false);
+ return redirectReqParams;
+
+ }
+
+ /**
+ * Create parameters for Call command
+ *
+ * @param url
+ * @param method
+ * @param includeTransactionId
+ * @param reqParameters
+ * @return
+ * @throws SLCommandoBuildException
+ */
+ public static JsonObject createCallCommandParameters(String url, String method, Boolean includeTransactionId, Map<String, String> reqParameters) throws SLCommandoBuildException {
+ JsonObject callReqParams = new JsonObject();
+ addSingleStringElement(callReqParams, SL20Constants.SL20_COMMAND_PARAM_GENERAL_CALL_URL, url, true);
+ addSingleStringElement(callReqParams, SL20Constants.SL20_COMMAND_PARAM_GENERAL_CALL_METHOD, method, true);
+ addSingleBooleanElement(callReqParams, SL20Constants.SL20_COMMAND_PARAM_GENERAL_CALL_INCLUDETRANSACTIONID, includeTransactionId, false);
+ addArrayOfStringElements(callReqParams, SL20Constants.SL20_COMMAND_PARAM_GENERAL_CALL_REQPARAMETER, reqParameters);
+ return callReqParams;
+
+ }
+
+ /**
+ * Create result for Error command
+ *
+ * @param errorCode
+ * @param errorMsg
+ * @return
+ * @throws SLCommandoBuildException
+ */
+ public static JsonObject createErrorCommandResult(String errorCode, String errorMsg) throws SLCommandoBuildException {
+ JsonObject result = new JsonObject();
+ addSingleStringElement(result, SL20Constants.SL20_COMMAND_PARAM_GENERAL_RESPONSE_ERRORCODE, errorCode, true);
+ addSingleStringElement(result, SL20Constants.SL20_COMMAND_PARAM_GENERAL_RESPONSE_ERRORMESSAGE, errorMsg, true);
+ return result;
+
+ }
+
+
+ /**
+ * Create parameters for qualifiedeID command
+ *
+ * @param authBlockId
+ * @param dataUrl
+ * @param additionalReqParameters
+ * @param x5cEnc
+ * @return
+ * @throws CertificateEncodingException
+ * @throws SLCommandoBuildException
+ */
+ public static JsonObject createQualifiedeIDCommandParameters(String authBlockId, String dataUrl,
+ Map<String, String> additionalReqParameters, X509Certificate x5cEnc) throws CertificateEncodingException, SLCommandoBuildException {
+ JsonObject params = new JsonObject();
+ addSingleStringElement(params, SL20Constants.SL20_COMMAND_PARAM_EID_AUTHBLOCKID, authBlockId, true);
+ addSingleStringElement(params, SL20Constants.SL20_COMMAND_PARAM_EID_DATAURL, dataUrl, true);
+ addArrayOfStringElements(params, SL20Constants.SL20_COMMAND_PARAM_EID_ATTRIBUTES, additionalReqParameters);
+ addSingleCertificateElement(params, SL20Constants.SL20_COMMAND_PARAM_EID_X5CENC, x5cEnc, false);
+ return params;
+
+ }
+
+ /**
+ * Create result for qualifiedeID command
+ *
+ * @param idl
+ * @param authBlock
+ * @param ccsURL
+ * @param LoA
+ * @return
+ * @throws SLCommandoBuildException
+ */
+ public static JsonObject createQualifiedeIDCommandResult(byte[] idl, byte[] authBlock, String ccsURL, String LoA) throws SLCommandoBuildException {
+ JsonObject result = new JsonObject();
+ addSingleByteElement(result, SL20Constants.SL20_COMMAND_PARAM_EID_RESULT_IDL, idl, true);
+ addSingleByteElement(result, SL20Constants.SL20_COMMAND_PARAM_EID_RESULT_AUTHBLOCK, authBlock, true);
+ addSingleStringElement(result, SL20Constants.SL20_COMMAND_PARAM_EID_RESULT_CCSURL, ccsURL, true);
+ addSingleStringElement(result, SL20Constants.SL20_COMMAND_PARAM_EID_RESULT_LOA, LoA, true);
+ return result;
+
+ }
+
+
+ /**
+ * Create Binding-Key command parameters
+ *
+ * @param kontoId
+ * @param subjectName
+ * @param keySize
+ * @param keyAlg
+ * @param policies
+ * @param dataUrl
+ * @param x5cVdaTrust
+ * @param reqUserPassword
+ * @param x5cEnc
+ * @return
+ * @throws SLCommandoBuildException
+ * @throws CertificateEncodingException
+ */
+ public static JsonObject createBindingKeyCommandParams(String kontoId, String subjectName, int keySize, String keyAlg,
+ Map<String, String> policies, String dataUrl, X509Certificate x5cVdaTrust, Boolean reqUserPassword, X509Certificate x5cEnc) throws SLCommandoBuildException, CertificateEncodingException {
+ JsonObject params = new JsonObject();
+ addSingleStringElement(params, SL20Constants.SL20_COMMAND_PARAM_BINDING_CREATE_KONTOID, kontoId, true);
+ addSingleStringElement(params, SL20Constants.SL20_COMMAND_PARAM_BINDING_CREATE_SN, subjectName, true);
+ addSingleNumberElement(params, SL20Constants.SL20_COMMAND_PARAM_BINDING_CREATE_KEYLENGTH, keySize, true);
+ addSingleStringElement(params, SL20Constants.SL20_COMMAND_PARAM_BINDING_CREATE_KEYALG, keyAlg, true);
+ addArrayOfStringElements(params, SL20Constants.SL20_COMMAND_PARAM_BINDING_CREATE_POLICIES, policies);
+ addSingleStringElement(params, SL20Constants.SL20_COMMAND_PARAM_BINDING_CREATE_DATAURL, dataUrl, true);
+ addSingleCertificateElement(params, SL20Constants.SL20_COMMAND_PARAM_BINDING_CREATE_X5CVDATRUST, x5cVdaTrust, false);
+ addSingleBooleanElement(params, SL20Constants.SL20_COMMAND_PARAM_BINDING_CREATE_REQUESTUSERPASSWORD, reqUserPassword, false);
+ addSingleCertificateElement(params, SL20Constants.SL20_COMMAND_PARAM_BINDING_CREATE_X5CENC, x5cEnc, false);
+ return params;
+
+ }
+
+ /**
+ * Create Binding-Key command result
+ *
+ * @param appId
+ * @param csr
+ * @param attCert
+ * @param password
+ * @return
+ * @throws SLCommandoBuildException
+ * @throws CertificateEncodingException
+ */
+ public static JsonObject createBindingKeyCommandResult(String appId, byte[] csr, X509Certificate attCert, byte[] password) throws SLCommandoBuildException, CertificateEncodingException {
+ JsonObject result = new JsonObject();
+ addSingleStringElement(result, SL20Constants.SL20_COMMAND_PARAM_BINDING_CREATE_RESULT_APPID, appId, true);
+ addSingleByteElement(result, SL20Constants.SL20_COMMAND_PARAM_BINDING_CREATE_RESULT_CSR, csr, true);
+ addSingleCertificateElement(result, SL20Constants.SL20_COMMAND_PARAM_BINDING_CREATE_RESULT_KEYATTESTATIONZERTIFICATE, attCert, false);
+ addSingleByteElement(result, SL20Constants.SL20_COMMAND_PARAM_BINDING_CREATE_RESULT_USERPASSWORD, password, false);
+ return result;
+
+ }
+
+ /**
+ * Create Store Binding-Certificate command parameters
+ *
+ * @param cert
+ * @param dataUrl
+ * @return
+ * @throws CertificateEncodingException
+ * @throws SLCommandoBuildException
+ */
+ public static JsonObject createStoreBindingCertCommandParams(X509Certificate cert, String dataUrl) throws CertificateEncodingException, SLCommandoBuildException {
+ JsonObject params = new JsonObject();
+ addSingleCertificateElement(params, SL20Constants.SL20_COMMAND_PARAM_BINDING_STORE_CERTIFICATE, cert, true);
+ addSingleStringElement(params, SL20Constants.SL20_COMMAND_PARAM_BINDING_STORE_DATAURL, dataUrl, true);
+ return params;
+
+ }
+
+ /**
+ * Create Store Binding-Certificate command result
+ *
+ * @return
+ * @throws SLCommandoBuildException
+ */
+ public static JsonObject createStoreBindingCertCommandSuccessResult() throws SLCommandoBuildException {
+ JsonObject result = new JsonObject();
+ addSingleStringElement(result, SL20Constants.SL20_COMMAND_PARAM_BINDING_STORE_RESULT_SUCESS,
+ SL20Constants.SL20_COMMAND_PARAM_BINDING_STORE_RESULT_SUCESS_VALUE, true);
+ return result;
+
+ }
+
+
+ /**
+ * Create idAndPassword command parameters
+ *
+ * @param keyAlg
+ * @param dataUrl
+ * @param x5cEnc
+ * @return
+ * @throws SLCommandoBuildException
+ * @throws CertificateEncodingException
+ */
+ public static JsonObject createIdAndPasswordCommandParameters(String keyAlg, String dataUrl, X509Certificate x5cEnc) throws SLCommandoBuildException, CertificateEncodingException {
+ JsonObject params = new JsonObject();
+ addSingleStringElement(params, SL20Constants.SL20_COMMAND_PARAM_AUTH_IDANDPASSWORD_KEYALG, keyAlg, true);
+ addSingleStringElement(params, SL20Constants.SL20_COMMAND_PARAM_AUTH_IDANDPASSWORD_DATAURL, dataUrl, true);
+ addSingleCertificateElement(params, SL20Constants.SL20_COMMAND_PARAM_AUTH_IDANDPASSWORD_X5CENC, x5cEnc, false);
+ return params;
+
+ }
+
+ /**
+ * Create idAndPassword command result
+ *
+ * @param kontoId
+ * @param password
+ * @return
+ * @throws SLCommandoBuildException
+ */
+ public static JsonObject createIdAndPasswordCommandResult(String kontoId, byte[] password) throws SLCommandoBuildException {
+ JsonObject result = new JsonObject();
+ addSingleStringElement(result, SL20Constants.SL20_COMMAND_PARAM_AUTH_IDANDPASSWORD_RESULT_KONTOID, kontoId, true);
+ addSingleByteElement(result, SL20Constants.SL20_COMMAND_PARAM_AUTH_IDANDPASSWORD_RESULT_USERPASSWORD, password, true);
+ return result;
+
+ }
+
+ /**
+ * Create JWS Token Authentication command
+ *
+ * @param nonce
+ * @param dataUrl
+ * @param displayData
+ * @param displayUrl
+ * @return
+ * @throws SLCommandoBuildException
+ */
+ public static JsonObject createJwsTokenAuthCommandParams(String nonce, String dataUrl, List<String> displayData, List<String> displayUrl) throws SLCommandoBuildException {
+ JsonObject params = new JsonObject();
+ addSingleStringElement(params, SL20Constants.SL20_COMMAND_PARAM_AUTH_JWSTOKEN_NONCE, nonce, true);
+ addSingleStringElement(params, SL20Constants.SL20_COMMAND_PARAM_AUTH_JWSTOKEN_DATAURL, dataUrl, true);
+ addArrayOfStrings(params, SL20Constants.SL20_COMMAND_PARAM_AUTH_JWSTOKEN_DISPLAYDATA, displayData);
+ addArrayOfStrings(params, SL20Constants.SL20_COMMAND_PARAM_AUTH_JWSTOKEN_DISPLAYURL, displayUrl);
+ return params;
+
+ }
+
+ /**
+ * Create JWS Token Authentication command result
+ *
+ * @param nonce
+ * @return
+ * @throws SLCommandoBuildException
+ */
+ public static JsonObject createJwsTokenAuthCommandResult(String nonce) throws SLCommandoBuildException {
+ JsonObject result = new JsonObject();
+ addSingleStringElement(result, SL20Constants.SL20_COMMAND_PARAM_AUTH_JWSTOKEN_RESULT_NONCE, nonce, true);
+ return result;
+
+ }
+
+
+ /**
+ * Create Generic Request Container
+ *
+ * @param reqId
+ * @param transactionId
+ * @param payLoad
+ * @param signedPayload
+ * @return
+ * @throws SLCommandoBuildException
+ */
+ public static JsonObject createGenericRequest(String reqId, String transactionId, JsonElement payLoad, String signedPayload) throws SLCommandoBuildException {
+ JsonObject req = new JsonObject();
+ 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,
+ payLoad, signedPayload);
+ return req;
+
+ }
+
+ /**
+ * Create Generic Response Container
+ *
+ * @param respId
+ * @param inResponseTo
+ * @param transactionId
+ * @param payLoad
+ * @param signedPayload
+ * @return
+ * @throws SLCommandoBuildException
+ */
+ public static final JsonObject createGenericResponse(String respId, String inResponseTo, String transactionId,
+ JsonElement payLoad, String signedPayload) throws SLCommandoBuildException {
+
+ JsonObject req = new JsonObject();
+ 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);
+ addOnlyOnceOfTwo(req, SL20Constants.SL20_PAYLOAD, SL20Constants.SL20_SIGNEDPAYLOAD,
+ payLoad, signedPayload);
+ return req;
+
+ }
+
+ /**
+ * Add one element of two possible elements <br>
+ * This method adds either the first element or the second element to parent JSON, but never both.
+ *
+ * @param parent Parent JSON element
+ * @param firstKeyId first element Id
+ * @param secondKeyId second element Id
+ * @param first first element
+ * @param second second element
+ * @throws SLCommandoBuildException
+ */
+ public static void addOnlyOnceOfTwo(JsonObject parent, String firstKeyId, String secondKeyId, JsonElement first, String second) throws SLCommandoBuildException {
+ if (first == null && (second == null || second.isEmpty()))
+ throw new SLCommandoBuildException(firstKeyId + " and " + secondKeyId + " is NULL");
+
+ else if (first != null && second != null)
+ throw new SLCommandoBuildException(firstKeyId + " and " + secondKeyId + " can not SET TWICE");
+
+ else if (first != null)
+ parent.add(firstKeyId, first);
+
+ else if (second != null && !second.isEmpty())
+ parent.addProperty(secondKeyId, second);
+
+ else
+ throw new SLCommandoBuildException("Internal build error");
+ }
+
+
+
+ //TODO!!!!
+ private static JsonObject createJsonSignedHeader(JsonSecurityUtils signer) throws SLCommandoBuildException {
+ JsonObject header = new JsonObject();
+ addSingleStringElement(header, SL20Constants.JSON_ALGORITHM, SL20Constants.JSON_ALGORITHM_SIGNING_RS256, true);
+ addSingleStringElement(header, SL20Constants.JSON_CONTENTTYPE, SL20Constants.SL20_CONTENTTYPE_SIGNED_COMMAND, true);
+ addArrayOfStrings(header, SL20Constants.JSON_X509_CERTIFICATE, Arrays.asList(Constants.DUMMY_SIGNING_CERT));
+
+ return header;
+ }
+
+ //TODO!!!!
+ private static JsonObject createJsonEncryptionHeader(JsonSecurityUtils signer) throws SLCommandoBuildException {
+ JsonObject header = new JsonObject();
+ addSingleStringElement(header, SL20Constants.JSON_ALGORITHM, SL20Constants.JSON_ALGORITHM_ENC_KEY_RSAOAEP, true);
+ addSingleStringElement(header, SL20Constants.JSON_ENCRYPTION_PAYLOAD, SL20Constants.JSON_ALGORITHM_ENC_PAYLOAD_A128CBCHS256, true);
+ addSingleStringElement(header, SL20Constants.JSON_CONTENTTYPE, SL20Constants.SL20_CONTENTTYPE_ENCRYPTED_RESULT, true);
+ addSingleStringElement(header, SL20Constants.JSON_X509_FINGERPRINT, Constants.DUMMY_SIGNING_CERT_FINGERPRINT, true);
+
+ return header;
+ }
+
+ //TODO!!!!
+ private static String createJsonSignedFooter(JsonSecurityUtils signer) {
+ return "cC4hiUPoj9Eetdgtv3hF80EGrhuB__dzERat0XF9g2VtQgr9PJbu3XOiZj5RZmh7\n" +
+ " AAuHIm4Bh-0Qc_lF5YKt_O8W2Fp5jujGbds9uJdbF9CUAr7t1dnZcAcQjbKBYNX4\n" +
+ " BAynRFdiuB--f_nZLgrnbyTyWzO75vRK5h6xBArLIARNPvkSjtQBMHlb1L07Qe7K\n" +
+ " 0GarZRmB_eSN9383LcOLn6_dO--xi12jzDwusC-eOkHWEsqtFZESc6BfI7noOPqv\n" +
+ " hJ1phCnvWh6IeYI2w9QOYEUipUTI8np6LbgGY9Fs98rqVt5AXLIhWkWywlVmtVrB\n" +
+ " p0igcN_IoypGlUPQGe77Rw";
+ }
+
+
+
+ private static void addArrayOfStrings(JsonObject parent, String keyId, List<String> values) throws SLCommandoBuildException {
+ validateParentAndKey(parent, keyId);
+ if (values != null) {
+ JsonArray callReqParamsArray = new JsonArray();
+ parent.add(keyId, callReqParamsArray );
+ for(String el : values)
+ callReqParamsArray.add(el);
+
+ }
+ }
+
+
+ private static void addArrayOfStringElements(JsonObject parent, String keyId, Map<String, String> keyValuePairs) throws SLCommandoBuildException {
+ validateParentAndKey(parent, keyId);
+ if (keyValuePairs != null) {
+ JsonArray callReqParamsArray = new JsonArray();
+ parent.add(keyId, callReqParamsArray );
+
+ for(Entry<String, String> el : keyValuePairs.entrySet()) {
+ JsonObject callReqParams = new JsonObject();
+ //callReqParams.addProperty(SL20Constants.SL20_COMMAND_PARAM_GENERAL_REQPARAMETER_KEY, el.getKey());
+ //callReqParams.addProperty(SL20Constants.SL20_COMMAND_PARAM_GENERAL_REQPARAMETER_VALUE, el.getValue());
+ callReqParams.addProperty(el.getKey(), el.getValue());
+ callReqParamsArray.add(callReqParams);
+
+ }
+ }
+ }
+
+ private static void addSingleCertificateElement(JsonObject parent, String keyId, X509Certificate cert, boolean isRequired) throws CertificateEncodingException, SLCommandoBuildException {
+ if (cert != null)
+ addSingleByteElement(parent, keyId, cert.getEncoded(), isRequired);
+
+ else if (isRequired)
+ throw new SLCommandoBuildException(keyId + " is marked as REQUIRED");
+
+ }
+
+
+
+ private static void addSingleByteElement(JsonObject parent, String keyId, byte[] value, boolean isRequired) throws SLCommandoBuildException {
+ validateParentAndKey(parent, keyId);
+
+ if (isRequired && value == null)
+ throw new SLCommandoBuildException(keyId + " has NULL value");
+
+ else if (value != null)
+ parent.addProperty(keyId, Base64.getEncoder().encodeToString(value));
+
+ }
+
+ private static void addSingleBooleanElement(JsonObject parent, String keyId, Boolean value, boolean isRequired) throws SLCommandoBuildException {
+ validateParentAndKey(parent, keyId);
+
+ if (isRequired && value == null)
+ throw new SLCommandoBuildException(keyId + " has a NULL value");
+
+ else if (value != null)
+ parent.addProperty(keyId, value);
+
+ }
+
+ private static void addSingleNumberElement(JsonObject parent, String keyId, Integer value, boolean isRequired) throws SLCommandoBuildException {
+ validateParentAndKey(parent, keyId);
+
+ if (isRequired && value == null)
+ throw new SLCommandoBuildException(keyId + " has a NULL value");
+
+ else if (value != null)
+ parent.addProperty(keyId, value);;
+
+ }
+
+ private static void addSingleStringElement(JsonObject parent, String keyId, String value, boolean isRequired) throws SLCommandoBuildException {
+ validateParentAndKey(parent, keyId);
+
+ if (isRequired && (value == null || value.isEmpty()))
+ throw new SLCommandoBuildException(keyId + " has an empty value");
+
+ else if (value != null && !value.isEmpty())
+ parent.addProperty(keyId, value);
+
+ }
+
+ 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);
+
+ if (isRequired && element == null)
+ throw new SLCommandoBuildException("No commando name included");
+
+ else if (element != null)
+ parent.add(keyId, element);
+
+ }
+
+ private static void addOnlyOnceOfTwo(JsonObject parent, String firstKeyId, String secondKeyId, JsonElement first, JsonElement second) throws SLCommandoBuildException {
+ if (first == null && second == null)
+ throw new SLCommandoBuildException(firstKeyId + " and " + secondKeyId + " is NULL");
+
+ else if (first != null && second != null)
+ throw new SLCommandoBuildException(firstKeyId + " and " + secondKeyId + " can not SET TWICE");
+
+ else if (first != null)
+ parent.add(firstKeyId, first);
+
+ else if (second != null)
+ parent.add(secondKeyId, second);
+
+ else
+ throw new SLCommandoBuildException("Internal build error");
+ }
+
+ private static void validateParentAndKey(JsonObject parent, String keyId) throws SLCommandoBuildException {
+ if (parent == null)
+ throw new SLCommandoBuildException("NO parent JSON element");
+
+ if (keyId == null || keyId.isEmpty())
+ throw new SLCommandoBuildException("NO JSON element identifier");
+ }
+}
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
new file mode 100644
index 000000000..759d9c838
--- /dev/null
+++ b/id/server/modules/moa-id-module-sl20_authentication/src/main/java/at/gv/egovernment/moa/id/auth/modules/sl20_auth/sl20/SL20JSONExtractorUtils.java
@@ -0,0 +1,350 @@
+package at.gv.egovernment.moa.id.auth.modules.sl20_auth.sl20;
+
+import java.io.InputStreamReader;
+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;
+import com.google.gson.JsonParser;
+
+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;
+
+public class SL20JSONExtractorUtils {
+ private static final Logger log = Logger.getLogger(SL20JSONExtractorUtils.class);
+
+ /**
+ * Extract String value from JSON
+ *
+ * @param input
+ * @param keyID
+ * @param isRequired
+ * @return
+ * @throws SLCommandoParserException
+ */
+ public static String getStringValue(JsonObject input, String keyID, boolean isRequired) throws SLCommandoParserException {
+ try {
+ JsonElement internal = getAndCheck(input, keyID, isRequired);
+
+ if (internal != null)
+ return internal.getAsString();
+ else
+ return null;
+
+ } catch (SLCommandoParserException e) {
+ throw e;
+
+ } catch (Exception e) {
+ throw new SLCommandoParserException("Can not extract String value with keyId: " + keyID, e);
+
+ }
+ }
+
+ /**
+ * Extract Boolean value from JSON
+ *
+ * @param input
+ * @param keyID
+ * @param isRequired
+ * @return
+ * @throws SLCommandoParserException
+ */
+ public static boolean getBooleanValue(JsonObject input, String keyID, boolean isRequired, boolean defaultValue) throws SLCommandoParserException {
+ try {
+ JsonElement internal = getAndCheck(input, keyID, isRequired);
+
+ if (internal != null)
+ return internal.getAsBoolean();
+ else
+ return defaultValue;
+
+ } catch (SLCommandoParserException e) {
+ throw e;
+
+ } catch (Exception e) {
+ throw new SLCommandoParserException("Can not extract Boolean value with keyId: " + keyID, e);
+
+ }
+ }
+
+ /**
+ * Extract JSONObject value from JSON
+ *
+ * @param input
+ * @param keyID
+ * @param isRequired
+ * @return
+ * @throws SLCommandoParserException
+ */
+ public static JsonObject getJSONObjectValue(JsonObject input, String keyID, boolean isRequired) throws SLCommandoParserException {
+ try {
+ JsonElement internal = getAndCheck(input, keyID, isRequired);
+
+ if (internal != null)
+ return internal.getAsJsonObject();
+ else
+ return null;
+
+ } catch (SLCommandoParserException e) {
+ throw e;
+
+ } catch (Exception e) {
+ throw new SLCommandoParserException("Can not extract Boolean value with keyId: " + keyID, e);
+
+ }
+ }
+
+ /**
+ * Extract a List of String elements from a JSON element
+ *
+ * @param input
+ * @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 (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);
+ JsonElement encryptedResult = command.get(SL20Constants.SL20_COMMAND_CONTAINER_ENCRYPTEDRESULT);
+
+ if (result == null && encryptedResult == null)
+ throw new SLCommandoParserException("NO result OR encryptedResult FOUND.");
+
+ else if (encryptedResult == null && mustBeEncrypted)
+ throw new SLCommandoParserException("result MUST be signed.");
+
+ else if (encryptedResult != null && encryptedResult.isJsonPrimitive()) {
+ 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");
+
+ //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;
+
+ } else
+ throw new SLCommandoParserException("Internal build error");
+
+
+ }
+
+ /**
+ * Extract payLoad from generic transport container
+ *
+ * @param container
+ * @param joseTools
+ * @return
+ * @throws SLCommandoParserException
+ */
+ public static VerificationResult extractSL20PayLoad(JsonObject container, IJOSETools joseTools, boolean mustBeSigned) throws SL20Exception {
+
+ JsonElement sl20Payload = container.get(SL20Constants.SL20_PAYLOAD);
+ JsonElement sl20SignedPayload = container.get(SL20Constants.SL20_SIGNEDPAYLOAD);
+
+ if (mustBeSigned && joseTools == null)
+ throw new SLCommandoParserException("'joseTools' MUST be set if 'mustBeSigned' is 'true'");
+
+ if (sl20Payload == null && sl20SignedPayload == null)
+ throw new SLCommandoParserException("NO payLoad OR signedPayload FOUND.");
+
+ 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)
+ return new VerificationResult(sl20Payload.getAsJsonObject());
+
+ else
+ throw new SLCommandoParserException("Internal build error");
+
+
+ }
+
+
+ /**
+ * Extract generic transport container from httpResponse
+ *
+ * @param httpResp
+ * @return
+ * @throws SLCommandoParserException
+ */
+ public static JsonObject getSL20ContainerFromResponse(HttpResponse httpResp) throws SLCommandoParserException {
+ try {
+ JsonObject sl20Resp = null;
+ if (httpResp.getStatusLine().getStatusCode() == 307) {
+ Header[] locationHeader = httpResp.getHeaders("Location");
+ if (locationHeader == null)
+ 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(Base64Url.encode((sl20RespString.getBytes()))).getAsJsonObject();
+
+ } else if (httpResp.getStatusLine().getStatusCode() == 200) {
+ 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) {
+ throw new SLCommandoParserException("SL20 response parsing FAILED! Reason: " + e.getMessage(), e);
+
+ }
+ }
+
+ 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);
+
+ if (internal == null && isRequired)
+ throw new SLCommandoParserException("REQUIRED Element with keyId: " + keyID + " does not exist");
+
+ return internal;
+
+ }
+}
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
new file mode 100644
index 000000000..3408cf538
--- /dev/null
+++ b/id/server/modules/moa-id-module-sl20_authentication/src/main/java/at/gv/egovernment/moa/id/auth/modules/sl20_auth/tasks/CreateQualeIDRequestTask.java
@@ -0,0 +1,243 @@
+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 javax.net.ssl.SSLSocketFactory;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.apache.http.HttpResponse;
+import org.apache.http.NameValuePair;
+import org.apache.http.client.entity.UrlEncodedFormEntity;
+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;
+
+import com.google.gson.JsonObject;
+
+import at.gv.egiz.eaaf.core.api.idp.ISPConfiguration;
+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;
+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;
+import at.gv.egovernment.moaspss.logging.Logger;
+
+@Component("CreateQualeIDRequestTask")
+public class CreateQualeIDRequestTask extends AbstractAuthServletTask {
+
+ @Autowired(required=true) private IJOSETools joseTools;
+ @Autowired private AuthConfiguration moaAuthConfig;
+
+ @Override
+ public void execute(ExecutionContext executionContext, HttpServletRequest request, HttpServletResponse response)
+ 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 = extractVDAURLForSpecificOA(oaConfig, executionContext);
+ if (MiscUtil.isEmpty(vdaQualeIDUrl)) {
+ 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)) {
+ Logger.error("NO AuthBlock Template identifier for qualified eID (" + Constants.CONFIG_PROP_VDA_AUTHBLOCK_ID + ")");
+ throw new SL20Exception("sl20.03", new Object[]{"NO AuthBlock Template identifier for qualified eID"});
+
+ }
+
+ //build DataURL for qualified eID response
+ String dataURL = new DataURLBuilder().buildDataURL(
+ pendingReq.getAuthURL(), Constants.HTTP_ENDPOINT_DATAURL, pendingReq.getPendingRequestId());
+
+ //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_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,
+ encCert
+ );
+
+ //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);
+
+ //open http client
+ SSLSocketFactory sslFactory = SSLUtils.getSSLSocketFactory(
+ moaAuthConfig,
+ vdaQualeIDUrl);
+ CloseableHttpClient httpClient = HttpClientWithProxySupport.getHttpClient(
+ sslFactory,
+ moaAuthConfig.getBasicMOAIDConfigurationBoolean(AuthConfiguration.PROP_KEY_OVS_SSL_HOSTNAME_VALIDATION, true));
+
+ //build http POST request
+ HttpPost httpReq = new HttpPost(new URIBuilder(vdaQualeIDUrl).build());
+ List<NameValuePair> parameters = new ArrayList<NameValuePair>();;
+ 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);
+
+ //parse response
+ Logger.info("Receive response from VDA ... ");
+ JsonObject sl20Resp = SL20JSONExtractorUtils.getSL20ContainerFromResponse(httpResp);
+ VerificationResult respPayloadContainer = SL20JSONExtractorUtils.extractSL20PayLoad(sl20Resp, null, false);
+
+ if (respPayloadContainer.isValidSigned() == null) {
+ Logger.debug("Receive unsigned payLoad from VDA");
+
+ }
+
+ JsonObject respPayload = respPayloadContainer.getPayload();
+ if (respPayload.get(SL20Constants.SL20_COMMAND_CONTAINER_NAME).getAsString()
+ .equals(SL20Constants.SL20_COMMAND_IDENTIFIER_REDIRECT)) {
+ Logger.debug("Find 'redirect' command in VDA response ... ");
+ JsonObject params = SL20JSONExtractorUtils.getJSONObjectValue(respPayload, SL20Constants.SL20_COMMAND_CONTAINER_PARAMS, true);
+ String redirectURL = SL20JSONExtractorUtils.getStringValue(params, SL20Constants.SL20_COMMAND_PARAM_GENERAL_REDIRECT_URL, true);
+ JsonObject command = SL20JSONExtractorUtils.getJSONObjectValue(params, SL20Constants.SL20_COMMAND_PARAM_GENERAL_REDIRECT_COMMAND, false);
+ String signedCommand = SL20JSONExtractorUtils.getStringValue(params, SL20Constants.SL20_COMMAND_PARAM_GENERAL_REDIRECT_SIGNEDCOMMAND, false);
+
+ //create forward SL2.0 command
+ JsonObject sl20Forward = sl20Resp.deepCopy().getAsJsonObject();
+ SL20JSONBuilderUtils.addOnlyOnceOfTwo(sl20Forward,
+ SL20Constants.SL20_PAYLOAD, SL20Constants.SL20_SIGNEDPAYLOAD,
+ command, signedCommand);
+
+ //store pending request
+ pendingReq.setRawDataToTransaction(Constants.PENDING_REQ_STORAGE_PREFIX + SL20Constants.SL20_REQID,
+ qualeIDReqId);
+ requestStoreage.storePendingRequest(pendingReq);
+
+ //forward SL2.0 command
+ //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()");
+ }
+
+
+ } catch (MOAIDException e) {
+ throw new TaskExecutionException(pendingReq, "SL2.0 Authentication FAILED. Msg: " + e.getMessage(), e);
+
+ } catch (Exception e) {
+ Logger.warn("SL2.0 Authentication FAILED with a generic error.", e);
+ throw new TaskExecutionException(pendingReq, e.getMessage(), e);
+
+ } finally {
+ TransactionIDUtils.removeTransactionId();
+ TransactionIDUtils.removeSessionId();
+
+ }
+
+ }
+
+ 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
new file mode 100644
index 000000000..fc386b796
--- /dev/null
+++ b/id/server/modules/moa-id-module-sl20_authentication/src/main/java/at/gv/egovernment/moa/id/auth/modules/sl20_auth/tasks/ReceiveQualeIDTask.java
@@ -0,0 +1,323 @@
+package at.gv.egovernment.moa.id.auth.modules.sl20_auth.tasks;
+
+import java.io.IOException;
+import java.io.StringWriter;
+import java.security.cert.X509Certificate;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.UUID;
+
+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;
+
+import com.google.gson.JsonElement;
+import com.google.gson.JsonObject;
+import com.google.gson.JsonParser;
+import com.google.gson.JsonSyntaxException;
+
+import at.gv.egiz.eaaf.core.api.data.EAAFConstants;
+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.StreamUtils;
+import at.gv.egiz.eaaf.core.impl.utils.TransactionIDUtils;
+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.SL20SecurityException;
+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.SL20JSONBuilderUtils;
+import at.gv.egovernment.moa.id.auth.modules.sl20_auth.sl20.SL20JSONExtractorUtils;
+import at.gv.egovernment.moa.id.commons.api.exceptions.MOAIDException;
+import at.gv.egovernment.moa.util.MiscUtil;
+import at.gv.egovernment.moaspss.logging.Logger;
+
+
+@Component("ReceiveQualeIDTask")
+public class ReceiveQualeIDTask extends AbstractAuthServletTask {
+
+ @Autowired(required=true) private IJOSETools joseTools;
+
+ @Override
+ public void execute(ExecutionContext executionContext, HttpServletRequest request, HttpServletResponse response)
+ throws TaskExecutionException {
+ String sl20Result = null;
+
+ try {
+ 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
+ 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);
+
+ }
+
+ //validate reqId with inResponseTo
+ String sl20ReqId = pendingReq.getRawData(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,
+ authConfig.getBasicMOAIDConfigurationBoolean(Constants.CONFIG_PROP_FORCE_EID_SIGNED_RESULT, true));
+
+ 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();
+
+ //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 .... ");
+
+ 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.setRawDataToTransaction(
+ Constants.PENDING_REQ_STORAGE_PREFIX + SL20Constants.SL20_COMMAND_PARAM_EID_RESULT_IDL,
+ idlB64);
+ pendingReq.setRawDataToTransaction(
+ Constants.PENDING_REQ_STORAGE_PREFIX + SL20Constants.SL20_COMMAND_PARAM_EID_RESULT_AUTHBLOCK,
+ authBlockB64);
+ pendingReq.setRawDataToTransaction(
+ Constants.PENDING_REQ_STORAGE_PREFIX + SL20Constants.SL20_COMMAND_PARAM_EID_RESULT_CCSURL,
+ ccsURL);
+ pendingReq.setRawDataToTransaction(
+ 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.setRawDataToTransaction(
+ 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.setRawDataToTransaction(
+ Constants.PENDING_REQ_STORAGE_PREFIX + SL20Constants.SL20_COMMAND_IDENTIFIER_ERROR,
+ new TaskExecutionException(pendingReq, e.getMessage(), e));
+
+ } finally {
+ //store pending request
+ 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());
+ JsonObject callReqParams = SL20JSONBuilderUtils.createCallCommandParameters(
+ new DataURLBuilder().buildDataURL(pendingReq.getAuthURL(), Constants.HTTP_ENDPOINT_RESUME, null),
+ SL20Constants.SL20_COMMAND_PARAM_GENERAL_CALL_METHOD_GET,
+ false,
+ reqParameters);
+ JsonObject callCommand = SL20JSONBuilderUtils.createCommand(SL20Constants.SL20_COMMAND_IDENTIFIER_CALL, callReqParams);
+
+ //build first redirect command for app
+ JsonObject redirectOneParams = SL20JSONBuilderUtils.createRedirectCommandParameters(
+ generateICPRedirectURLForDebugging(),
+ callCommand, null, true);
+ JsonObject redirectOneCommand = SL20JSONBuilderUtils.createCommand(SL20Constants.SL20_COMMAND_IDENTIFIER_REDIRECT, redirectOneParams);
+
+ //build second redirect command for IDP
+ JsonObject redirectTwoParams = SL20JSONBuilderUtils.createRedirectCommandParameters(
+ new DataURLBuilder().buildDataURL(pendingReq.getAuthURL(), Constants.HTTP_ENDPOINT_RESUME, null),
+ redirectOneCommand, null, true);
+ JsonObject redirectTwoCommand = SL20JSONBuilderUtils.createCommand(SL20Constants.SL20_COMMAND_IDENTIFIER_REDIRECT, redirectTwoParams);
+
+ //build generic SL2.0 response container
+ String transactionId = SL20JSONExtractorUtils.getStringValue(sl20ReqObj, SL20Constants.SL20_TRANSACTIONID, false);
+ JsonObject respContainer = SL20JSONBuilderUtils.createGenericRequest(
+ UUID.randomUUID().toString(),
+ transactionId,
+ 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)
+ || 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");
+ response.setStatus(HttpServletResponse.SC_OK);
+ response.setContentLength(content.length);
+ response.setContentType(ContentType.APPLICATION_JSON.toString());
+ response.getOutputStream().write(content);
+
+
+ } else {
+ Logger.info("SL2.0 DataURL communication needs http header: '" + SL20Constants.HTTP_HEADER_SL20_CLIENT_TYPE + "'");
+ throw new SL20Exception("sl20.06",
+ new Object[] {"SL2.0 DataURL communication needs http header: '" + SL20Constants.HTTP_HEADER_SL20_CLIENT_TYPE + "'"});
+
+ }
+ }
+
+ /**
+ * 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());
+
+ }
+
+ return ipcRedirectURLConfig;
+ }
+
+ 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..6811d1016
--- /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.getRawData(
+ 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.getRawData(
+ Constants.PENDING_REQ_STORAGE_PREFIX + SL20Constants.SL20_REQID,
+ String.class);
+ String idlB64 = pendingReq.getRawData(
+ Constants.PENDING_REQ_STORAGE_PREFIX + SL20Constants.SL20_COMMAND_PARAM_EID_RESULT_IDL,
+ String.class);
+ String authBlockB64 = pendingReq.getRawData(
+ Constants.PENDING_REQ_STORAGE_PREFIX + SL20Constants.SL20_COMMAND_PARAM_EID_RESULT_AUTHBLOCK,
+ String.class);
+ String ccsURL = pendingReq.getRawData(
+ Constants.PENDING_REQ_STORAGE_PREFIX + SL20Constants.SL20_COMMAND_PARAM_EID_RESULT_CCSURL,
+ String.class);
+ String LoA = pendingReq.getRawData(
+ 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 = pendingReq.getSessionData(AuthenticationSessionWrapper.class);
+ 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();
+
+ }
+ }
+}