diff options
author | Thomas Lenz <tlenz@iaik.tugraz.at> | 2018-07-16 18:34:17 +0200 |
---|---|---|
committer | Thomas Lenz <tlenz@iaik.tugraz.at> | 2018-07-16 18:34:17 +0200 |
commit | 43b57a3c903669fc9de36c46e99773bac97a2102 (patch) | |
tree | 1e5cd74c040f79709d0265acb134bb50085848e3 /id/server/modules/moa-id-module-sl20_authentication/src/main/java/at/gv/egovernment/moa/id | |
parent | 05d5c29bb3be38d40484f9c5bb5fdbdc131cba9f (diff) | |
parent | 4ae32fabc822b3c8ed51d380969f7db682d1bfae (diff) | |
download | moa-id-spss-43b57a3c903669fc9de36c46e99773bac97a2102.tar.gz moa-id-spss-43b57a3c903669fc9de36c46e99773bac97a2102.tar.bz2 moa-id-spss-43b57a3c903669fc9de36c46e99773bac97a2102.zip |
Merge branch 'huge_refactoring' into development_preview
# Conflicts:
# id/server/doc/handbook/config/config.html
# id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/config/auth/OAAuthParameterDecorator.java
# id/server/modules/moa-id-modul-citizencard_authentication/src/main/java/at/gv/egovernment/moa/id/auth/AuthenticationServer.java
# id/server/modules/moa-id-modul-citizencard_authentication/src/main/java/at/gv/egovernment/moa/id/auth/modules/internal/tasks/VerifyAuthenticationBlockTask.java
# id/server/modules/moa-id-modul-citizencard_authentication/src/main/java/at/gv/egovernment/moa/id/auth/validator/CreateXMLSignatureResponseValidator.java
Diffstat (limited to 'id/server/modules/moa-id-module-sl20_authentication/src/main/java/at/gv/egovernment/moa/id')
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(); + + } + } +} |