From 9f0fa316c8f7adeb3529cb4c3b2c553f085f7d95 Mon Sep 17 00:00:00 2001
From: Thomas <>
Date: Tue, 15 Jun 2021 12:14:51 +0200
Subject: add ZMR client, to some re-factoring, and a lot of bug-fixing
---
.../specific/modules/auth/eidas/v2/Constants.java | 64 ++-
.../auth/eidas/v2/clients/AbstractSoapClient.java | 197 +++++++
.../auth/eidas/v2/clients/szr/SzrClient.java | 469 ++++++++++++++++
.../auth/eidas/v2/clients/szr/SzrService.java | 164 ++++++
.../auth/eidas/v2/clients/zmr/IZmrClient.java | 89 +++
.../auth/eidas/v2/clients/zmr/ZmrSoapClient.java | 560 +++++++++++++++++++
.../eidas/v2/dao/MergedRegisterSearchResult.java | 75 ---
.../modules/auth/eidas/v2/dao/RegisterResult.java | 67 +--
.../modules/auth/eidas/v2/dao/SimpleEidasData.java | 28 +-
.../eidas/v2/dao/SimpleMobileSignatureData.java | 4 +-
.../auth/eidas/v2/ernp/DummyErnpClient.java | 9 +-
.../modules/auth/eidas/v2/ernp/IErnpClient.java | 4 +-
.../v2/exception/InvalidUserInputException.java | 5 +-
.../v2/exception/ManualFixNecessaryException.java | 10 +-
.../auth/eidas/v2/exception/WorkflowException.java | 65 ++-
.../v2/exception/ZmrCommunicationException.java | 38 ++
.../eidas/v2/handler/AbstractEidProcessor.java | 17 +-
.../CountrySpecificDetailSearchProcessor.java | 15 +-
.../handler/DeSpecificDetailSearchProcessor.java | 41 +-
.../handler/ItSpecificDetailSearchProcessor.java | 30 +-
.../eidas/v2/service/RegisterSearchService.java | 328 ++++++++---
.../modules/auth/eidas/v2/szr/SzrClient.java | 601 ---------------------
.../modules/auth/eidas/v2/szr/SzrService.java | 164 ------
.../eidas/v2/tasks/CreateIdentityLinkTask.java | 57 +-
.../eidas/v2/tasks/CreateNewErnpEntryTask.java | 25 +-
.../auth/eidas/v2/tasks/InitialSearchTask.java | 229 ++++----
.../ReceiveAustrianResidenceGuiResponseTask.java | 104 ++--
.../ReceiveMobilePhoneSignatureResponseTask.java | 159 +++---
.../ReceiveOtherLoginMethodGuiResponseTask.java | 30 +-
.../auth/eidas/v2/utils/EidasResponseUtils.java | 46 +-
.../auth/eidas/v2/utils/MatchingTaskUtils.java | 88 +++
.../modules/auth/eidas/v2/utils/VersionHolder.java | 40 ++
.../modules/auth/eidas/v2/zmr/DummyZmrClient.java | 50 +-
.../modules/auth/eidas/v2/zmr/IZmrClient.java | 48 --
34 files changed, 2516 insertions(+), 1404 deletions(-)
create mode 100644 eidas_modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/clients/AbstractSoapClient.java
create mode 100644 eidas_modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/clients/szr/SzrClient.java
create mode 100644 eidas_modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/clients/szr/SzrService.java
create mode 100644 eidas_modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/clients/zmr/IZmrClient.java
create mode 100644 eidas_modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/clients/zmr/ZmrSoapClient.java
delete mode 100644 eidas_modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/dao/MergedRegisterSearchResult.java
create mode 100644 eidas_modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/exception/ZmrCommunicationException.java
delete mode 100644 eidas_modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/szr/SzrClient.java
delete mode 100644 eidas_modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/szr/SzrService.java
create mode 100644 eidas_modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/utils/MatchingTaskUtils.java
create mode 100644 eidas_modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/utils/VersionHolder.java
delete mode 100644 eidas_modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/zmr/IZmrClient.java
(limited to 'eidas_modules/authmodule-eIDAS-v2/src/main/java')
diff --git a/eidas_modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/Constants.java b/eidas_modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/Constants.java
index 3a267d29..3e20a132 100644
--- a/eidas_modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/Constants.java
+++ b/eidas_modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/Constants.java
@@ -27,6 +27,9 @@ import at.gv.egiz.eaaf.core.api.data.EaafConstants;
public class Constants {
+ //TODO: should we make it configurable?
+ public static final String MATCHING_INTERNAL_BPK_TARGET = EaafConstants.URN_PREFIX_CDID + "ZP";
+
public static final String ERRORCODE_00 = "module.eidasauth.00";
public static final String DATA_REQUESTERID = "req_requesterId";
@@ -91,6 +94,42 @@ public class Constants {
public static final String FORWARD_METHOD_POST = "POST";
public static final String FORWARD_METHOD_GET = "GET";
+ // ZMR Client configuration properties
+ public static final String CONIG_PROPS_EIDAS_ZMRCLIENT = CONIG_PROPS_EIDAS_PREFIX + ".zmrclient";
+ public static final String CONIG_PROPS_EIDAS_ZMRCLIENT_ENDPOINT = CONIG_PROPS_EIDAS_ZMRCLIENT
+ + ".endpoint";
+ public static final String CONIG_PROPS_EIDAS_ZMRCLIENT_DEBUG_TRACEMESSAGES = CONIG_PROPS_EIDAS_ZMRCLIENT
+ + ".debug.logfullmessages";
+ public static final String CONIG_PROPS_EIDAS_ZMRCLIENT_TIMEOUT_CONNECTION = CONIG_PROPS_EIDAS_ZMRCLIENT
+ + ".timeout.connection";
+ public static final String CONIG_PROPS_EIDAS_ZMRCLIENT_TIMEOUT_RESPONSE = CONIG_PROPS_EIDAS_ZMRCLIENT
+ + ".timeout.response";
+ public static final String CONIG_PROPS_EIDAS_ZMRCLIENT_SSL_KEYSTORE_PATH = CONIG_PROPS_EIDAS_ZMRCLIENT
+ + ".ssl.keyStore.path";
+ public static final String CONIG_PROPS_EIDAS_ZMRCLIENT_SSL_KEYSTORE_PASSWORD = CONIG_PROPS_EIDAS_ZMRCLIENT
+ + ".ssl.keyStore.password";
+ public static final String CONIG_PROPS_EIDAS_ZMRCLIENT_SSL_KEYSTORE_TYPE = CONIG_PROPS_EIDAS_ZMRCLIENT
+ + ".ssl.keyStore.type";
+ public static final String CONIG_PROPS_EIDAS_ZMRCLIENT_SSL_KEYSTORE_NAME = CONIG_PROPS_EIDAS_ZMRCLIENT
+ + ".ssl.keyStore.name";
+ public static final String CONIG_PROPS_EIDAS_ZMRCLIENT_SSL_KEYS_ALIAS = CONIG_PROPS_EIDAS_ZMRCLIENT
+ + ".ssl.key.alias";
+ public static final String CONIG_PROPS_EIDAS_ZMRCLIENT_SSL_KEY_PASSWORD = CONIG_PROPS_EIDAS_ZMRCLIENT
+ + ".ssl.key.password";
+ public static final String CONIG_PROPS_EIDAS_ZMRCLIENT_SSL_TRUSTSTORE_PATH = CONIG_PROPS_EIDAS_ZMRCLIENT
+ + ".ssl.trustStore.path";
+ public static final String CONIG_PROPS_EIDAS_ZMRCLIENT_SSL_TRUSTSTORE_PASSWORD = CONIG_PROPS_EIDAS_ZMRCLIENT
+ + ".ssl.trustStore.password";
+ public static final String CONIG_PROPS_EIDAS_ZMRCLIENT_SSL_TRUSTSTORE_TYPE = CONIG_PROPS_EIDAS_ZMRCLIENT
+ + ".ssl.trustStore.type";
+ public static final String CONIG_PROPS_EIDAS_ZMRCLIENT_SSL_TRUSTSTORE_NAME = CONIG_PROPS_EIDAS_ZMRCLIENT
+ + ".ssl.trustStore.name";
+
+ public static final String CONIG_PROPS_EIDAS_ZMRCLIENT_REQ_ORGANIZATION_NR = CONIG_PROPS_EIDAS_ZMRCLIENT
+ + ".req.organisation.behoerdennr";
+
+
+ // SZR Client configuration properties
public static final String CONIG_PROPS_EIDAS_SZRCLIENT = CONIG_PROPS_EIDAS_PREFIX + ".szrclient";
public static final String CONIG_PROPS_EIDAS_SZRCLIENT_USETESTSERVICE = CONIG_PROPS_EIDAS_SZRCLIENT
+ ".useTestService";
@@ -112,11 +151,23 @@ public class Constants {
+ ".ssl.keyStore.path";
public static final String CONIG_PROPS_EIDAS_SZRCLIENT_SSL_KEYSTORE_PASSWORD = CONIG_PROPS_EIDAS_SZRCLIENT
+ ".ssl.keyStore.password";
+ public static final String CONIG_PROPS_EIDAS_SZRCLIENT_SSL_KEYSTORE_TYPE = CONIG_PROPS_EIDAS_SZRCLIENT
+ + ".ssl.keyStore.type";
+ public static final String CONIG_PROPS_EIDAS_SZRCLIENT_SSL_KEYSTORE_NAME = CONIG_PROPS_EIDAS_SZRCLIENT
+ + ".ssl.keyStore.name";
+ public static final String CONIG_PROPS_EIDAS_SZRCLIENT_SSL_KEYS_ALIAS = CONIG_PROPS_EIDAS_SZRCLIENT
+ + ".ssl.key.alias";
+ public static final String CONIG_PROPS_EIDAS_SZRCLIENT_SSL_KEY_PASSWORD = CONIG_PROPS_EIDAS_SZRCLIENT
+ + ".ssl.key.password";
public static final String CONIG_PROPS_EIDAS_SZRCLIENT_SSL_TRUSTSTORE_PATH = CONIG_PROPS_EIDAS_SZRCLIENT
+ ".ssl.trustStore.path";
public static final String CONIG_PROPS_EIDAS_SZRCLIENT_SSL_TRUSTSTORE_PASSWORD = CONIG_PROPS_EIDAS_SZRCLIENT
+ ".ssl.trustStore.password";
-
+ public static final String CONIG_PROPS_EIDAS_SZRCLIENT_SSL_TRUSTSTORE_TYPE = CONIG_PROPS_EIDAS_SZRCLIENT
+ + ".ssl.trustStore.type";
+ public static final String CONIG_PROPS_EIDAS_SZRCLIENT_SSL_TRUSTSTORE_NAME = CONIG_PROPS_EIDAS_SZRCLIENT
+ + ".ssl.trustStore.name";
+
public static final String CONIG_PROPS_EIDAS_SZRCLIENT_PARAMS_EDOCUMENTTYPE = CONIG_PROPS_EIDAS_SZRCLIENT
+ ".params.documenttype";
public static final String CONIG_PROPS_EIDAS_SZRCLIENT_PARAMS_VKZ = CONIG_PROPS_EIDAS_SZRCLIENT
@@ -153,7 +204,7 @@ public class Constants {
// eIDAS request parameters
public static final String eIDAS_REQ_NAMEID_FORMAT = "urn:oasis:names:tc:SAML:2.0:nameid-format:persistent";
- // eIDAS attribute names
+ // eIDAS attribute names
public static final String eIDAS_ATTR_PERSONALIDENTIFIER = "PersonIdentifier";
public static final String eIDAS_ATTR_DATEOFBIRTH = "DateOfBirth";
public static final String eIDAS_ATTR_CURRENTGIVENNAME = "FirstName";
@@ -166,6 +217,15 @@ public class Constants {
public static final String eIDAS_ATTR_LEGALPERSONIDENTIFIER = "LegalPersonIdentifier";
public static final String eIDAS_ATTR_LEGALNAME = "LegalName";
+
+ //eIDAS attribute URN
+ public static final String eIDAS_ATTRURN_PREFIX = "http://eidas.europa.eu/attributes/";
+ public static final String eIDAS_ATTRURN_PREFIX_NATURAL = eIDAS_ATTRURN_PREFIX + "naturalperson/";
+
+ public static final String eIDAS_ATTRURN_PERSONALIDENTIFIER =
+ eIDAS_ATTRURN_PREFIX_NATURAL + eIDAS_ATTR_PERSONALIDENTIFIER;
+
+
public static final String eIDAS_REQ_PARAM_SECTOR_PUBLIC = "public";
public static final String eIDAS_REQ_PARAM_SECTOR_PRIVATE = "private";
diff --git a/eidas_modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/clients/AbstractSoapClient.java b/eidas_modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/clients/AbstractSoapClient.java
new file mode 100644
index 00000000..bfdf3991
--- /dev/null
+++ b/eidas_modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/clients/AbstractSoapClient.java
@@ -0,0 +1,197 @@
+package at.asitplus.eidas.specific.modules.auth.eidas.v2.clients;
+
+import java.security.KeyManagementException;
+import java.security.KeyStore;
+import java.security.NoSuchAlgorithmException;
+import java.security.Provider;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+
+import javax.net.ssl.SSLContext;
+import javax.xml.ws.BindingProvider;
+import javax.xml.ws.handler.Handler;
+
+import org.apache.commons.lang3.StringUtils;
+import org.apache.cxf.configuration.jsse.TLSClientParameters;
+import org.apache.cxf.endpoint.Client;
+import org.apache.cxf.frontend.ClientProxy;
+import org.apache.cxf.jaxws.DispatchImpl;
+import org.apache.cxf.transport.http.HTTPConduit;
+import org.apache.cxf.transports.http.configuration.HTTPClientPolicy;
+import org.apache.http.ssl.SSLContextBuilder;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.lang.Nullable;
+
+import at.asitplus.eidas.specific.modules.auth.eidas.v2.utils.LoggingHandler;
+import at.gv.egiz.eaaf.core.api.idp.IConfiguration;
+import at.gv.egiz.eaaf.core.exceptions.EaafConfigurationException;
+import at.gv.egiz.eaaf.core.exceptions.EaafException;
+import at.gv.egiz.eaaf.core.impl.credential.EaafKeyStoreFactory;
+import at.gv.egiz.eaaf.core.impl.credential.KeyStoreConfiguration;
+import at.gv.egiz.eaaf.core.impl.credential.KeyStoreConfiguration.KeyStoreType;
+import at.gv.egiz.eaaf.core.impl.data.Pair;
+import at.gv.egiz.eaaf.core.impl.http.HttpUtils;
+import lombok.Builder;
+import lombok.Getter;
+import lombok.extern.slf4j.Slf4j;
+
+@Slf4j
+public class AbstractSoapClient {
+
+ @Autowired
+ protected IConfiguration basicConfig;
+ @Autowired
+ EaafKeyStoreFactory keyStoreFactory;
+
+ @Builder
+ @Getter
+ public static class HttpClientConfig {
+
+ private final String clientName;
+
+ private final String clientUrl;
+ private final String clientType;
+
+ private final String connectionTimeout;
+ private final String responseTimeout;
+
+ private final KeyStoreConfiguration keyStoreConfig;
+ private final String keyAlias;
+ private final String keyPassword;
+
+ private final KeyStoreConfiguration trustStoreConfig;
+
+ @Builder.Default
+ private final boolean trustAll = false;
+
+ }
+
+ /**
+ * Build a validated KeyStore Configuration-Object from configuration keys.
+ *
+ * @param keyStoreTypeKey Configuration key for type
+ * @param keyStorePathKey Configuration key for path
+ * @param keyStorePasswordKey Configuration key for password
+ * @param keyStoreNameKey Configuration key for name
+ * @param friendlyName Friendlyname for logging and errorhandling
+ * @return Valid KeyStore configuration or null
if no type was
+ * defined
+ * @throws EaafConfigurationException In case of validation error
+ */
+ @Nullable
+ protected KeyStoreConfiguration buildKeyStoreConfiguration(String keyStoreTypeKey, String keyStorePathKey,
+ String keyStorePasswordKey, String keyStoreNameKey, String friendlyName)
+ throws EaafConfigurationException {
+ if (StringUtils.isNotEmpty(basicConfig.getBasicConfiguration(keyStoreTypeKey))) {
+ final KeyStoreConfiguration config = new KeyStoreConfiguration();
+ config.setFriendlyName(friendlyName);
+ config.setKeyStoreType(basicConfig.getBasicConfiguration(keyStoreTypeKey, KeyStoreType.PKCS12.name()));
+ config.setKeyStoreName(basicConfig.getBasicConfiguration(keyStoreNameKey));
+ config.setSoftKeyStoreFilePath(basicConfig.getBasicConfiguration(keyStorePathKey));
+ config.setSoftKeyStorePassword(basicConfig.getBasicConfiguration(keyStorePasswordKey));
+
+ // validate keystore configuration
+ config.validate();
+
+ return config;
+
+ } else {
+ return null;
+
+ }
+
+ }
+
+ protected void injectHttpClient(Object raw, HttpClientConfig config) {
+ // extract client from implementation
+ Client client;
+ if (raw instanceof DispatchImpl>) {
+ client = ((DispatchImpl>) raw).getClient();
+ } else if (raw instanceof Client) {
+ client = ClientProxy.getClient(raw);
+ } else {
+ throw new RuntimeException("SOAP Client for SZR connection is of UNSUPPORTED type: " + raw.getClass()
+ .getName());
+ }
+
+ // set basic connection policies
+ final HTTPConduit http = (HTTPConduit) client.getConduit();
+
+ // set timeout policy
+ final HTTPClientPolicy httpClientPolicy = new HTTPClientPolicy();
+ httpClientPolicy.setConnectionTimeout(Integer.parseInt(config.getConnectionTimeout()) * 1000L);
+ httpClientPolicy.setReceiveTimeout(Integer.parseInt(config.getResponseTimeout()) * 1000L);
+ http.setClient(httpClientPolicy);
+
+ // inject SSL context in case of https
+ if (config.getClientUrl().toLowerCase().startsWith("https")) {
+ try {
+ log.debug("Adding SSLContext to client: " + config.getClientType() + " ... ");
+
+ final TLSClientParameters tlsParams = new TLSClientParameters();
+ if (config.getKeyStoreConfig() != null) {
+ final SSLContext sslContext = HttpUtils.buildSslContextWithSslClientAuthentication(
+ keyStoreFactory.buildNewKeyStore(config.getKeyStoreConfig()),
+ config.getKeyAlias(),
+ config.getKeyPassword(),
+ loadTrustStore(config.getTrustStoreConfig(), config.getClientName()),
+ config.isTrustAll(),
+ config.getClientName());
+ tlsParams.setSSLSocketFactory(sslContext.getSocketFactory());
+
+ } else {
+ log.debug(
+ "No KeyStore for SSL Client Auth. found. Initializing SSLContext for: {} without authentication ... ",
+ config.getClientName());
+ tlsParams.setSSLSocketFactory(SSLContextBuilder.create().build().getSocketFactory());
+
+ }
+
+ http.setTlsClientParameters(tlsParams);
+ log.info("SSLContext initialized for client: " + config.getClientType());
+
+ } catch (EaafException | KeyManagementException | NoSuchAlgorithmException e) {
+ log.error("SSLContext initialization FAILED.", e);
+ throw new RuntimeException("SSLContext initialization FAILED.", e);
+
+ }
+ }
+ }
+
+ private Pair loadTrustStore(KeyStoreConfiguration trustStoreConfig, String friendlyName)
+ throws EaafException {
+ if (trustStoreConfig != null) {
+ log.info("Build custom SSL truststore for: {}", friendlyName);
+ return keyStoreFactory.buildNewKeyStore(trustStoreConfig);
+
+ } else {
+ log.info("Use default SSL truststore for: {}", friendlyName);
+ return null;
+
+ }
+
+ }
+
+ protected void injectBindingProvider(BindingProvider bindingProvider, String clientType, String szrUrl,
+ boolean enableTraceLogging) {
+ final Map requestContext = bindingProvider.getRequestContext();
+ requestContext.put(BindingProvider.ENDPOINT_ADDRESS_PROPERTY, szrUrl);
+
+ log.trace("Adding JAX-WS request/response trace handler to client: " + clientType);
+ List handlerList = bindingProvider.getBinding().getHandlerChain();
+ if (handlerList == null) {
+ handlerList = new ArrayList<>();
+ bindingProvider.getBinding().setHandlerChain(handlerList);
+
+ }
+
+ // add logging handler to trace messages if required
+ if (enableTraceLogging) {
+ final LoggingHandler loggingHandler = new LoggingHandler();
+ handlerList.add(loggingHandler);
+
+ }
+ bindingProvider.getBinding().setHandlerChain(handlerList);
+ }
+}
diff --git a/eidas_modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/clients/szr/SzrClient.java b/eidas_modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/clients/szr/SzrClient.java
new file mode 100644
index 00000000..2230f30a
--- /dev/null
+++ b/eidas_modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/clients/szr/SzrClient.java
@@ -0,0 +1,469 @@
+/*
+ * Copyright 2018 A-SIT Plus GmbH
+ * AT-specific eIDAS Connector has been developed in a cooperation between EGIZ,
+ * A-SIT Plus GmbH, A-SIT, and Graz University of Technology.
+ *
+ * Licensed under the EUPL, Version 1.2 or - as soon they will be approved by
+ * the European Commission - subsequent versions of the EUPL (the "License");
+ * You may not use this work except in compliance with the License.
+ * You may obtain a copy of the License at:
+ * https://joinup.ec.europa.eu/news/understanding-eupl-v12
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * 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.asitplus.eidas.specific.modules.auth.eidas.v2.clients.szr;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.net.URL;
+import java.nio.charset.StandardCharsets;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import javax.annotation.PostConstruct;
+import javax.xml.XMLConstants;
+import javax.xml.bind.JAXBContext;
+import javax.xml.bind.Marshaller;
+import javax.xml.namespace.QName;
+import javax.xml.transform.Source;
+import javax.xml.transform.Transformer;
+import javax.xml.transform.TransformerException;
+import javax.xml.transform.TransformerFactory;
+import javax.xml.transform.stream.StreamResult;
+import javax.xml.transform.stream.StreamSource;
+import javax.xml.ws.BindingProvider;
+import javax.xml.ws.Dispatch;
+
+import org.apache.commons.lang3.StringUtils;
+import org.apache.xpath.XPathAPI;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.stereotype.Service;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.ObjectMapper;
+
+import at.asitplus.eidas.specific.modules.auth.eidas.v2.Constants;
+import at.asitplus.eidas.specific.modules.auth.eidas.v2.clients.AbstractSoapClient;
+import at.asitplus.eidas.specific.modules.auth.eidas.v2.clients.AbstractSoapClient.HttpClientConfig.HttpClientConfigBuilder;
+import at.asitplus.eidas.specific.modules.auth.eidas.v2.dao.SimpleEidasData;
+import at.asitplus.eidas.specific.modules.auth.eidas.v2.exception.SzrCommunicationException;
+import at.gv.e_government.reference.namespace.persondata._20020228.AlternativeNameType;
+import at.gv.e_government.reference.namespace.persondata._20020228.PersonNameType;
+import at.gv.e_government.reference.namespace.persondata._20020228.PhysicalPersonType;
+import at.gv.egiz.eaaf.core.api.data.PvpAttributeDefinitions;
+import at.gv.egiz.eaaf.core.api.data.XmlNamespaceConstants;
+import at.gv.egiz.eaaf.core.exceptions.EaafConfigurationException;
+import at.gv.egiz.eaaf.core.impl.utils.DomUtils;
+import szrservices.GetBPK;
+import szrservices.GetBPKResponse;
+import szrservices.GetIdentityLinkEidas;
+import szrservices.GetIdentityLinkEidasResponse;
+import szrservices.IdentityLinkType;
+import szrservices.JwsHeaderParam;
+import szrservices.ObjectFactory;
+import szrservices.PersonInfoType;
+import szrservices.SZR;
+import szrservices.SZRException_Exception;
+import szrservices.SignContent;
+import szrservices.SignContentEntry;
+import szrservices.SignContentResponseType;
+import szrservices.TravelDocumentType;
+
+
+@Service("SZRClientForeIDAS")
+public class SzrClient extends AbstractSoapClient {
+ private static final Logger log = LoggerFactory.getLogger(SzrClient.class);
+
+ private static final String CLIENT_DEFAULT = "DefaultClient";
+ private static final String CLIENT_RAW = "RawClient";
+
+ private static final String ATTR_NAME_VSZ = "urn:eidgvat:attributes.vsz.value";
+ private static final String ATTR_NAME_PUBKEYS = "urn:eidgvat:attributes.user.pubkeys";
+ private static final String ATTR_NAME_STATUS = "urn:eidgvat:attributes.eid.status";
+ private static final String KEY_BC_BIND = "bcBindReq";
+ private static final String JOSE_HEADER_USERCERTPINNING_TYPE = "urn:at.gv.eid:bindtype";
+ private static final String JOSE_HEADER_USERCERTPINNING_EIDASBIND = "urn:at.gv.eid:eidasBind";
+ public static final String ATTR_NAME_MDS = "urn:eidgvat:mds";
+
+ // client for anything, without identitylink
+ private SZR szr = null;
+
+ // RAW client is needed for identitylink
+ private Dispatch dispatch = null;
+
+ final ObjectMapper mapper = new ObjectMapper();
+
+ /**
+ * Get IdentityLink of a person.
+ *
+ *
+ * @param eidData minimum dataset of person
+ * @return IdentityLink
+ * @throws SzrCommunicationException In case of a SZR error
+ */
+ public IdentityLinkType getIdentityLinkInRawMode(SimpleEidasData eidData)
+ throws SzrCommunicationException {
+ try {
+ final GetIdentityLinkEidas getIdl = new GetIdentityLinkEidas();
+ getIdl.setPersonInfo(generateSzrRequest(eidData));
+
+ final JAXBContext jaxbContext = JAXBContext.newInstance(ObjectFactory.class);
+ final Marshaller jaxbMarshaller = jaxbContext.createMarshaller();
+
+ final ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
+ jaxbMarshaller.marshal(getIdl, outputStream);
+ outputStream.flush();
+
+ final Source source = new StreamSource(new ByteArrayInputStream(outputStream.toByteArray()));
+ outputStream.close();
+
+ log.trace("Requesting SZR ... ");
+ final Source response = dispatch.invoke(source);
+ log.trace("Receive RAW response from SZR");
+
+ final byte[] szrResponse = sourceToByteArray(response);
+ final GetIdentityLinkEidasResponse jaxbElement = (GetIdentityLinkEidasResponse) jaxbContext
+ .createUnmarshaller().unmarshal(new ByteArrayInputStream(szrResponse));
+
+ // build response
+ log.trace(new String(szrResponse, StandardCharsets.UTF_8));
+
+ // ok, we have success
+ final Document doc = DomUtils.parseDocument(
+ new ByteArrayInputStream(szrResponse),
+ true,
+ XmlNamespaceConstants.ALL_SCHEMA_LOCATIONS + " " + Constants.SZR_SCHEMA_LOCATIONS,
+ null, null);
+ final String xpathExpression = "//saml:Assertion";
+ final Element nsNode = doc.createElementNS("urn:oasis:names:tc:SAML:1.0:assertion", "saml:NSNode");
+
+ log.trace("Selecting signed doc " + xpathExpression);
+ final Element documentNode = (Element) XPathAPI.selectSingleNode(doc,
+ xpathExpression, nsNode);
+ log.trace("Signed document: " + DomUtils.serializeNode(documentNode));
+
+ final IdentityLinkType idl = new IdentityLinkType();
+ idl.setAssertion(documentNode);
+ idl.setPersonInfo(jaxbElement.getGetIdentityLinkReturn().getPersonInfo());
+
+ return idl;
+
+ } catch (final Exception e) {
+ log.warn("SZR communication FAILED. Reason: " + e.getMessage(), e);
+ throw new SzrCommunicationException("ernb.02", new Object[]{e.getMessage()}, e);
+
+ }
+
+ }
+
+ /**
+ * Get bPK of person.
+ *
+ *
+ * @param eidData Minimum dataset of person
+ * @param target requested bPK target
+ * @param vkz Verfahrenskennzeichen
+ * @return bPK for this person
+ * @throws SzrCommunicationException In case of a SZR error
+ */
+ public List getBpk(SimpleEidasData eidData, String target, String vkz)
+ throws SzrCommunicationException {
+ try {
+ final GetBPK parameters = new GetBPK();
+ parameters.setPersonInfo(generateSzrRequest(eidData));
+ parameters.getBereichsKennung().add(target);
+ parameters.setVKZ(vkz);
+ final GetBPKResponse result = this.szr.getBPK(parameters);
+
+ return result.getGetBPKReturn();
+
+ } catch (final SZRException_Exception e) {
+ log.warn("SZR communication FAILED. Reason: " + e.getMessage(), e);
+ throw new SzrCommunicationException("ernb.02", new Object[]{e.getMessage()}, e);
+
+ }
+
+ }
+
+ /**
+ * Creates a new ERnP entry.
+ * TODO Is this correct? Ask BMI.
+ *
+ * @param eidasData Minimum dataset of person
+ * @return encrypted baseId
+ * @throws SzrCommunicationException In case of a SZR error
+ */
+ public String createNewErnpEntry(final SimpleEidasData eidasData) throws SzrCommunicationException {
+ final String resp;
+ try {
+ resp = this.szr.getStammzahlEncrypted(generateSzrRequest(eidasData), true);
+ } catch (SZRException_Exception e) {
+ throw new SzrCommunicationException("ernb.02", new Object[]{e.getMessage()}, e);
+ }
+ if (StringUtils.isEmpty(resp)) {
+ throw new SzrCommunicationException("ernb.01", new Object[]{"Stammzahl response empty"}); // TODO error handling
+ }
+ return resp;
+ }
+
+ /**
+ * Request a encrypted baseId from SZR.
+ *
+ * Note: Previously, this method did create a new ERnP entry, if it did not exist. This is
+ * not the case any more. See {@link #createNewErnpEntry(SimpleEidasData)} for that functionality.
+ *
+ * @param eidData Minimum dataset of person
+ * @return encrypted baseId
+ * @throws SzrCommunicationException In case of a SZR error
+ */
+ public String getEncryptedStammzahl(final SimpleEidasData eidData)
+ throws SzrCommunicationException {
+ final String resp;
+ try {
+ resp = this.szr.getStammzahlEncrypted(generateSzrRequest(eidData), false);
+ } catch (SZRException_Exception e) {
+ throw new SzrCommunicationException("ernb.02", new Object[]{e.getMessage()}, e);
+ }
+
+ if (StringUtils.isEmpty(resp)) {
+ throw new SzrCommunicationException("ernb.01", new Object[]{"Stammzahl response empty"}); // TODO error handling
+ }
+
+ return resp;
+
+ }
+
+ /**
+ * Sign an eidasBind data-structure that combines vsz with user's pubKey and E-ID status.
+ *
+ * @param vsz encrypted baseId
+ * @param bindingPubKey binding PublicKey as PKCS1# (ASN.1) container
+ * @param eidStatus Status of the E-ID
+ * @param eidData eID information that was used for ERnP registration
+ * @return bPK for this person
+ * @throws SzrCommunicationException In case of a SZR error
+ */
+ public String getEidasBind(final String vsz, final String bindingPubKey, final String eidStatus,
+ SimpleEidasData eidData)throws SzrCommunicationException {
+
+ final Map eidsaBindMap = new HashMap<>();
+ eidsaBindMap.put(ATTR_NAME_VSZ, vsz);
+ eidsaBindMap.put(ATTR_NAME_STATUS, eidStatus);
+ eidsaBindMap.put(ATTR_NAME_PUBKEYS, Collections.singletonList(bindingPubKey));
+ eidsaBindMap.put(PvpAttributeDefinitions.EID_ISSUING_NATION_NAME, eidData.getCitizenCountryCode());
+ injectMdsIfAvailableAndActive(eidsaBindMap, eidData);
+
+ try {
+ final String serializedEidasBind = mapper.writeValueAsString(eidsaBindMap);
+ final SignContent req = new SignContent();
+ final SignContentEntry eidasBindInfo = new SignContentEntry();
+ eidasBindInfo.setKey(KEY_BC_BIND);
+ eidasBindInfo.setValue(serializedEidasBind);
+ req.getIn().add(eidasBindInfo);
+ req.setAppendCert(false);
+ final JwsHeaderParam eidasBindJoseHeader = new JwsHeaderParam();
+ eidasBindJoseHeader.setKey(JOSE_HEADER_USERCERTPINNING_TYPE);
+ eidasBindJoseHeader.setValue(JOSE_HEADER_USERCERTPINNING_EIDASBIND);
+ req.getJWSHeaderParam().add(eidasBindJoseHeader);
+
+ log.trace("Requesting SZR to sign bcBind datastructure ... ");
+ final SignContentResponseType resp = szr.signContent(req.isAppendCert(), req.getJWSHeaderParam(), req.getIn());
+ log.trace("Receive SZR response on bcBind siging operation ");
+
+ if (resp == null || resp.getOut() == null
+ || resp.getOut().isEmpty()
+ || StringUtils.isEmpty(resp.getOut().get(0).getValue())) {
+ throw new SzrCommunicationException("ernb.01", new Object[]{"BcBind response empty"});
+ }
+
+ return resp.getOut().get(0).getValue();
+
+ } catch (final JsonProcessingException | SZRException_Exception e) {
+ log.warn("Requesting bcBind by using SZR FAILED.", e);
+ throw new SzrCommunicationException("ernb.02",
+ new Object[]{e.getMessage()}, e);
+ }
+ }
+
+ private PersonInfoType generateSzrRequest(SimpleEidasData eidData) {
+ log.debug("Starting connecting SZR Gateway");
+ final PersonInfoType personInfo = new PersonInfoType();
+ final PersonNameType personName = new PersonNameType();
+ final PhysicalPersonType naturalPerson = new PhysicalPersonType();
+ final TravelDocumentType eDocument = new TravelDocumentType();
+
+ naturalPerson.setName(personName);
+ personInfo.setPerson(naturalPerson);
+ personInfo.setTravelDocument(eDocument);
+
+ // person information
+ personName.setFamilyName(eidData.getFamilyName());
+ personName.setGivenName(eidData.getGivenName());
+ naturalPerson.setDateOfBirth(eidData.getDateOfBirth());
+ eDocument.setIssuingCountry(eidData.getCitizenCountryCode());
+ eDocument.setDocumentNumber(eidData.getPseudonym());
+
+ // eID document information
+ String documentType = basicConfig
+ .getBasicConfiguration(Constants.CONIG_PROPS_EIDAS_SZRCLIENT_PARAMS_EDOCUMENTTYPE,
+ Constants.SZR_CONSTANTS_DEFAULT_DOCUMENT_TYPE);
+ eDocument.setDocumentType(documentType);
+
+ // set PlaceOfBirth if available
+ if (eidData.getPlaceOfBirth() != null) {
+ log.trace("Find 'PlaceOfBirth' attribute: " + eidData.getPlaceOfBirth());
+ boolean setPlaceOfBirth = basicConfig
+ .getBasicConfigurationBoolean(Constants.CONIG_PROPS_EIDAS_SZRCLIENT_PARAMS_SETPLACEOFBIRTHIFAVAILABLE, true);
+ if (setPlaceOfBirth) {
+ naturalPerson.setPlaceOfBirth(eidData.getPlaceOfBirth());
+ log.trace("Adding 'PlaceOfBirth' to ERnB request ... ");
+ }
+ }
+
+ // set BirthName if available
+ if (eidData.getBirthName() != null) {
+ log.trace("Find 'BirthName' attribute: " + eidData.getBirthName());
+ boolean setBirthName = basicConfig
+ .getBasicConfigurationBoolean(Constants.CONIG_PROPS_EIDAS_SZRCLIENT_PARAMS_SETBIRTHNAMEIFAVAILABLE, true);
+ if (setBirthName) {
+ final AlternativeNameType alternativeName = new AlternativeNameType();
+ naturalPerson.setAlternativeName(alternativeName);
+ alternativeName.setFamilyName(eidData.getBirthName());
+ log.trace("Adding 'BirthName' to ERnB request ... ");
+ }
+ }
+
+ return personInfo;
+ }
+
+ @PostConstruct
+ private void initialize() throws EaafConfigurationException {
+ log.info("Starting SZR-Client initialization .... ");
+ final URL url = SzrClient.class.getResource("/wsdl/szr_client/SZR_v4.0.wsdl");
+
+ final boolean useTestSzr = basicConfig.getBasicConfigurationBoolean(
+ Constants.CONIG_PROPS_EIDAS_SZRCLIENT_USETESTSERVICE,
+ true);
+
+ SzrService szrService;
+ QName qname;
+ String szrUrl;
+ if (useTestSzr) {
+ log.debug("Initializing SZR test environment configuration.");
+ qname = SzrService.SZRTestumgebung;
+ szrService = new SzrService(url, new QName("urn:SZRServices", "SZRService"));
+ szr = szrService.getSzrTestumgebung();
+ szrUrl = basicConfig.getBasicConfiguration(Constants.CONIG_PROPS_EIDAS_SZRCLIENT_ENDPOINT_TEST);
+
+ } else {
+ log.debug("Initializing SZR productive configuration.");
+ qname = SzrService.SZRProduktionsumgebung;
+ szrService = new SzrService(url, new QName("urn:SZRServices", "SZRService"));
+ szr = szrService.getSzrProduktionsumgebung();
+ szrUrl = basicConfig.getBasicConfiguration(Constants.CONIG_PROPS_EIDAS_SZRCLIENT_ENDPOINT_PROD);
+
+ }
+
+ // create raw client;
+ dispatch = szrService.createDispatch(qname, Source.class, javax.xml.ws.Service.Mode.PAYLOAD);
+
+ if (StringUtils.isEmpty(szrUrl)) {
+ log.error("No SZR service-URL found. SZR-Client initalisiation failed.");
+ throw new RuntimeException("No SZR service URL found. SZR-Client initalisiation failed.");
+
+ }
+
+ // check if Clients can be initialized
+ if (szr == null) {
+ log.error("SZR " + CLIENT_DEFAULT + " is 'NULL'. Something goes wrong");
+ throw new RuntimeException("SZR " + CLIENT_DEFAULT + " is 'NULL'. Something goes wrong");
+
+ }
+ if (dispatch == null) {
+ log.error("SZR " + CLIENT_RAW + " is 'NULL'. Something goes wrong");
+ throw new RuntimeException("SZR " + CLIENT_RAW + " is 'NULL'. Something goes wrong");
+
+ }
+
+ // inject handler
+ log.info("Use SZR service-URL: " + szrUrl);
+ injectBindingProvider((BindingProvider) szr, CLIENT_DEFAULT, szrUrl,
+ basicConfig.getBasicConfigurationBoolean(Constants.CONIG_PROPS_EIDAS_SZRCLIENT_DEBUG_TRACEMESSAGES, false));
+ injectBindingProvider(dispatch, CLIENT_RAW, szrUrl,
+ basicConfig.getBasicConfigurationBoolean(Constants.CONIG_PROPS_EIDAS_SZRCLIENT_DEBUG_TRACEMESSAGES, false));
+
+ // inject http parameters and SSL context
+ log.debug("Inject HTTP client settings ... ");
+ HttpClientConfigBuilder httpClientBuilder = HttpClientConfig.builder()
+ .clientName("SZR Client")
+ .clientUrl(szrUrl)
+ .connectionTimeout(basicConfig.getBasicConfiguration(
+ Constants.CONIG_PROPS_EIDAS_SZRCLIENT_TIMEOUT_CONNECTION,
+ Constants.HTTP_CLIENT_DEFAULT_TIMEOUT_CONNECTION))
+ .responseTimeout(basicConfig.getBasicConfiguration(
+ Constants.CONIG_PROPS_EIDAS_SZRCLIENT_TIMEOUT_RESPONSE,
+ Constants.HTTP_CLIENT_DEFAULT_TIMEOUT_RESPONSE))
+ .keyStoreConfig(buildKeyStoreConfiguration(
+ Constants.CONIG_PROPS_EIDAS_SZRCLIENT_SSL_KEYSTORE_TYPE,
+ Constants.CONIG_PROPS_EIDAS_SZRCLIENT_SSL_KEYSTORE_PATH,
+ Constants.CONIG_PROPS_EIDAS_SZRCLIENT_SSL_KEYSTORE_PASSWORD,
+ Constants.CONIG_PROPS_EIDAS_SZRCLIENT_SSL_KEYSTORE_NAME,
+ "SZR SSL Client-Authentication KeyStore"))
+ .keyAlias(basicConfig.getBasicConfiguration(Constants.CONIG_PROPS_EIDAS_SZRCLIENT_SSL_KEYS_ALIAS))
+ .keyPassword(basicConfig.getBasicConfiguration(Constants.CONIG_PROPS_EIDAS_SZRCLIENT_SSL_KEY_PASSWORD))
+ .trustAll(false)
+ .trustStoreConfig(buildKeyStoreConfiguration(
+ Constants.CONIG_PROPS_EIDAS_SZRCLIENT_SSL_TRUSTSTORE_TYPE,
+ Constants.CONIG_PROPS_EIDAS_SZRCLIENT_SSL_TRUSTSTORE_PATH,
+ Constants.CONIG_PROPS_EIDAS_SZRCLIENT_SSL_TRUSTSTORE_PASSWORD,
+ Constants.CONIG_PROPS_EIDAS_SZRCLIENT_SSL_TRUSTSTORE_NAME,
+ "SZR SSL Client-Authentication KeyStore"));
+
+ injectHttpClient(szr, httpClientBuilder.clientType(CLIENT_DEFAULT).build());
+ injectHttpClient(dispatch, httpClientBuilder.clientType(CLIENT_RAW).build());
+
+ log.info("SZR-Client initialization successfull");
+ }
+
+ private void injectMdsIfAvailableAndActive(Map eidsaBindMap, SimpleEidasData eidData) {
+ if (basicConfig.getBasicConfigurationBoolean(
+ Constants.CONIG_PROPS_EIDAS_SZRCLIENT_SET_MDS_TO_EIDASBIND, false)) {
+ log.info("Injecting MDS into eidasBind ... ");
+ final Map mds = new HashMap<>();
+ mds.put(PvpAttributeDefinitions.PRINCIPAL_NAME_NAME, eidData.getFamilyName());
+ mds.put(PvpAttributeDefinitions.GIVEN_NAME_NAME, eidData.getGivenName());
+ mds.put(PvpAttributeDefinitions.BIRTHDATE_NAME, eidData.getDateOfBirth());
+ eidsaBindMap.put(ATTR_NAME_MDS, mds);
+
+ }
+ }
+
+ private byte[] sourceToByteArray(Source result) throws TransformerException {
+ final TransformerFactory factory = TransformerFactory.newInstance();
+ factory.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true);
+ final Transformer transformer = factory.newTransformer();
+ transformer.setOutputProperty("omit-xml-declaration", "yes");
+ transformer.setOutputProperty("method", "xml");
+ final ByteArrayOutputStream out = new ByteArrayOutputStream();
+ final StreamResult streamResult = new StreamResult();
+ streamResult.setOutputStream(out);
+ transformer.transform(result, streamResult);
+ return out.toByteArray();
+ }
+
+}
diff --git a/eidas_modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/clients/szr/SzrService.java b/eidas_modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/clients/szr/SzrService.java
new file mode 100644
index 00000000..590f88a4
--- /dev/null
+++ b/eidas_modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/clients/szr/SzrService.java
@@ -0,0 +1,164 @@
+/*
+ * Copyright 2018 A-SIT Plus GmbH
+ * AT-specific eIDAS Connector has been developed in a cooperation between EGIZ,
+ * A-SIT Plus GmbH, A-SIT, and Graz University of Technology.
+ *
+ * Licensed under the EUPL, Version 1.2 or - as soon they will be approved by
+ * the European Commission - subsequent versions of the EUPL (the "License");
+ * You may not use this work except in compliance with the License.
+ * You may obtain a copy of the License at:
+ * https://joinup.ec.europa.eu/news/understanding-eupl-v12
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * 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.asitplus.eidas.specific.modules.auth.eidas.v2.clients.szr;
+
+import java.net.URL;
+
+import javax.xml.namespace.QName;
+import javax.xml.ws.Service;
+import javax.xml.ws.WebEndpoint;
+import javax.xml.ws.WebServiceClient;
+import javax.xml.ws.WebServiceFeature;
+
+import szrservices.SZR;
+
+/**
+ * This class was generated by Apache CXF 3.1.16 2018-07-10T09:36:01.466+02:00
+ * Generated source version: 3.1.16
+ *
+ */
+@WebServiceClient(name = "SZRService",
+ wsdlLocation = "./src/main/resources/szr_client/SZR-1.WSDL",
+ targetNamespace = "urn:SZRServices")
+public class SzrService extends Service {
+
+ public static final URL WSDL_LOCATION;
+
+ public static final QName SERVICE = new QName("urn:SZRServices", "SZRService");
+ public static final QName SZRProduktionsumgebung = new QName("urn:SZRServices", "SZRProduktionsumgebung");
+ public static final QName SZRTestumgebung = new QName("urn:SZRServices", "SZRTestumgebung");
+ public static final QName SZRBusinesspartnerTestumgebung = new QName("urn:SZRServices",
+ "SZRBusinesspartnerTestumgebung");
+
+ static {
+ URL url = SzrService.class.getResource("./src/main/resources/wsdl/szr_client/SZR-1.WSDL");
+ if (url == null) {
+ url = SzrService.class.getClassLoader().getResource("/szr_client/SZR-1.WSDL");
+ }
+ if (url == null) {
+ java.util.logging.Logger.getLogger(SzrService.class.getName())
+ .log(java.util.logging.Level.INFO,
+ "Can not initialize the default wsdl from {0}", "/szr_client/SZR-1.WSDL");
+ }
+ WSDL_LOCATION = url;
+
+ }
+
+ public SzrService(URL wsdlLocation) {
+ super(wsdlLocation, SERVICE);
+ }
+
+ public SzrService(URL wsdlLocation, QName serviceName) {
+ super(wsdlLocation, serviceName);
+ }
+
+ public SzrService() {
+ super(WSDL_LOCATION, SERVICE);
+ }
+
+ public SzrService(WebServiceFeature... features) {
+ super(WSDL_LOCATION, SERVICE, features);
+ }
+
+ public SzrService(URL wsdlLocation, WebServiceFeature... features) {
+ super(wsdlLocation, SERVICE, features);
+ }
+
+ public SzrService(URL wsdlLocation, QName serviceName, WebServiceFeature... features) {
+ super(wsdlLocation, serviceName, features);
+ }
+
+ /**
+ * Get SZR Web-Service.
+ *
+ * @return returns SZR
+ */
+ @WebEndpoint(name = "SZRProduktionsumgebung")
+ public SZR getSzrProduktionsumgebung() {
+ return super.getPort(SZRProduktionsumgebung, SZR.class);
+ }
+
+ /**
+ * Get SZR Web-Service.
+ *
+ * @param features A list of {@link javax.xml.ws.WebServiceFeature} to configure
+ * on the proxy. Supported features not in the
+ * features
parameter will have their default
+ * values.
+ * @return returns SZR
+ */
+ @WebEndpoint(name = "SZRProduktionsumgebung")
+ public SZR getSzrProduktionsumgebung(WebServiceFeature... features) {
+ return super.getPort(SZRProduktionsumgebung, SZR.class, features);
+ }
+
+ /**
+ *Get SZR Web-Service.
+ *
+ * @return returns SZR
+ */
+ @WebEndpoint(name = "SZRTestumgebung")
+ public SZR getSzrTestumgebung() {
+ return super.getPort(SZRTestumgebung, SZR.class);
+ }
+
+ /**
+ * Get SZR Web-Service.
+ *
+ * @param features A list of {@link javax.xml.ws.WebServiceFeature} to configure
+ * on the proxy. Supported features not in the
+ * features
parameter will have their default
+ * values.
+ * @return returns SZR
+ */
+ @WebEndpoint(name = "SZRTestumgebung")
+ public SZR getSzrTestumgebung(WebServiceFeature... features) {
+ return super.getPort(SZRTestumgebung, SZR.class, features);
+ }
+
+ /**
+ * Get SZR Web-Service.
+ *
+ * @return returns SZR
+ */
+ @WebEndpoint(name = "SZRBusinesspartnerTestumgebung")
+ public SZR getSzrBusinesspartnerTestumgebung() {
+ return super.getPort(SZRBusinesspartnerTestumgebung, SZR.class);
+ }
+
+ /**
+ * Get SZR Web-Service.
+ *
+ * @param features A list of {@link javax.xml.ws.WebServiceFeature} to configure
+ * on the proxy. Supported features not in the
+ * features
parameter will have their default
+ * values.
+ * @return returns SZR
+ */
+ @WebEndpoint(name = "SZRBusinesspartnerTestumgebung")
+ public SZR getSzrBusinesspartnerTestumgebung(WebServiceFeature... features) {
+ return super.getPort(SZRBusinesspartnerTestumgebung, SZR.class, features);
+ }
+
+}
diff --git a/eidas_modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/clients/zmr/IZmrClient.java b/eidas_modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/clients/zmr/IZmrClient.java
new file mode 100644
index 00000000..18bcbacc
--- /dev/null
+++ b/eidas_modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/clients/zmr/IZmrClient.java
@@ -0,0 +1,89 @@
+/*
+ * Copyright 2020 A-SIT Plus GmbH
+ * AT-specific eIDAS Connector has been developed in a cooperation between EGIZ,
+ * A-SIT Plus GmbH, A-SIT, and Graz University of Technology.
+ *
+ * Licensed under the EUPL, Version 1.2 or - as soon they will be approved by
+ * the European Commission - subsequent versions of the EUPL (the "License");
+ * You may not use this work except in compliance with the License.
+ * You may obtain a copy of the License at:
+ * https://joinup.ec.europa.eu/news/understanding-eupl-v12
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * 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.asitplus.eidas.specific.modules.auth.eidas.v2.clients.zmr;
+
+import java.math.BigInteger;
+
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+
+import at.asitplus.eidas.specific.modules.auth.eidas.v2.clients.zmr.ZmrSoapClient.ZmrRegisterResult;
+import at.asitplus.eidas.specific.modules.auth.eidas.v2.dao.RegisterResult;
+import at.asitplus.eidas.specific.modules.auth.eidas.v2.dao.SimpleEidasData;
+import at.asitplus.eidas.specific.modules.auth.eidas.v2.exception.EidasSAuthenticationException;
+import at.gv.bmi.namespace.zmr_su.zmr._20040201.PersonSuchenRequest;
+
+public interface IZmrClient {
+
+ /**
+ * Search person based on eIDAS personal identifier.
+ *
+ * @param zmrProzessId ProcessId from ZMR or null
if no processId exists
+ * @param personIdentifier Full eIDAS personal identifier with prefix
+ * @return Search result but never null
+ * @throws EidasSAuthenticationException In case of a communication error
+ */
+ @Nonnull
+ ZmrRegisterResult searchWithPersonIdentifier(@Nullable BigInteger zmrProzessId, @Nonnull String personIdentifier)
+ throws EidasSAuthenticationException;
+
+ /**
+ * Search person based on eIDSA MDS information.
+ *
+ * @param zmrProzessId ProcessId from ZMR or null
if no processId exists
+ * @param givenName eIDAS given name
+ * @param familyName eIDAS principle name
+ * @param dateOfBirth eIDAS date-of-birth
+ * @param citizenCountryCode CountryCode of the eIDAS proxy-service
+ * @return Search result but never null
+ * @throws EidasSAuthenticationException In case of a communication error
+ */
+ @Nonnull
+ ZmrRegisterResult searchWithMds(@Nullable BigInteger zmrProzessId, @Nonnull String givenName,
+ @Nonnull String familyName, @Nonnull String dateOfBirth, @Nonnull String citizenCountryCode)
+ throws EidasSAuthenticationException;
+
+ /**
+ * Search person based on country-specific natural person set.
+ *
+ * @param zmrProzessId ProcessId from ZMR or null
if no processId exists
+ * @param personSearchDao Specific set of natural person informations.
+ * @param citizenCountryCode CountryCode of the eIDAS proxy-service
+ * @return Search result but never null
+ * @throws EidasSAuthenticationException In case of a communication error
+ */
+ @Nonnull
+ ZmrRegisterResult searchCountrySpecific(@Nullable BigInteger zmrProzessId,
+ @Nonnull PersonSuchenRequest personSearchDao, @Nonnull String citizenCountryCode)
+ throws EidasSAuthenticationException;
+
+
+ void update(@Nullable BigInteger zmrProzessId, RegisterResult registerResult, SimpleEidasData eidData);
+
+ ZmrRegisterResult searchWithBpkZp(@Nullable BigInteger zmrProzessId, String bpkzp);
+
+ ZmrRegisterResult searchWithResidenceData(@Nullable BigInteger zmrProzessId, String givenName, String familyName,
+ String dateOfBirth, String zipcode, String city, String street);
+
+}
diff --git a/eidas_modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/clients/zmr/ZmrSoapClient.java b/eidas_modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/clients/zmr/ZmrSoapClient.java
new file mode 100644
index 00000000..014d202b
--- /dev/null
+++ b/eidas_modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/clients/zmr/ZmrSoapClient.java
@@ -0,0 +1,560 @@
+package at.asitplus.eidas.specific.modules.auth.eidas.v2.clients.zmr;
+
+import java.math.BigInteger;
+import java.net.URL;
+import java.text.MessageFormat;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+import java.util.Objects;
+import java.util.stream.Collectors;
+
+import javax.annotation.Nonnull;
+import javax.annotation.PostConstruct;
+import javax.xml.ws.BindingProvider;
+
+import org.apache.commons.lang3.StringUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.lang.NonNull;
+import org.springframework.lang.Nullable;
+
+import at.asitplus.eidas.specific.modules.auth.eidas.v2.Constants;
+import at.asitplus.eidas.specific.modules.auth.eidas.v2.clients.AbstractSoapClient;
+import at.asitplus.eidas.specific.modules.auth.eidas.v2.dao.RegisterResult;
+import at.asitplus.eidas.specific.modules.auth.eidas.v2.dao.SimpleEidasData;
+import at.asitplus.eidas.specific.modules.auth.eidas.v2.exception.EidasSAuthenticationException;
+import at.asitplus.eidas.specific.modules.auth.eidas.v2.exception.ZmrCommunicationException;
+import at.asitplus.eidas.specific.modules.auth.eidas.v2.utils.EidasResponseUtils;
+import at.asitplus.eidas.specific.modules.auth.eidas.v2.utils.VersionHolder;
+import at.gv.bmi.namespace.zmr_su.base._20040201.ClientInfoType;
+import at.gv.bmi.namespace.zmr_su.base._20040201.Organisation;
+import at.gv.bmi.namespace.zmr_su.base._20040201.RequestType;
+import at.gv.bmi.namespace.zmr_su.base._20040201.ResponseType;
+import at.gv.bmi.namespace.zmr_su.base._20040201.WorkflowInfoClient;
+import at.gv.bmi.namespace.zmr_su.base._20040201.WorkflowInfoServer;
+import at.gv.bmi.namespace.zmr_su.base._20040201_.Service;
+import at.gv.bmi.namespace.zmr_su.base._20040201_.ServiceFault;
+import at.gv.bmi.namespace.zmr_su.base._20040201_.ServicePort;
+import at.gv.bmi.namespace.zmr_su.zmr._20040201.EidasSuchdatenType;
+import at.gv.bmi.namespace.zmr_su.zmr._20040201.ErgebniskriterienType;
+import at.gv.bmi.namespace.zmr_su.zmr._20040201.NatuerlichePersonErgebnisType;
+import at.gv.bmi.namespace.zmr_su.zmr._20040201.PersonErgebnisSatzType;
+import at.gv.bmi.namespace.zmr_su.zmr._20040201.PersonErgebnisType;
+import at.gv.bmi.namespace.zmr_su.zmr._20040201.PersonSuchenRequest;
+import at.gv.bmi.namespace.zmr_su.zmr._20040201.PersonSuchenResponse;
+import at.gv.bmi.namespace.zmr_su.zmr._20040201.PersonensucheInfoType;
+import at.gv.bmi.namespace.zmr_su.zmr._20040201.SuchkriterienType;
+import at.gv.e_government.reference.namespace.persondata.de._20040201.NatuerlichePersonTyp;
+import at.gv.e_government.reference.namespace.persondata.de._20040201.PersonenNameTyp;
+import at.gv.egiz.eaaf.core.exceptions.EaafAuthenticationException;
+import at.gv.egiz.eaaf.core.exceptions.EaafConfigurationException;
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+import lombok.extern.slf4j.Slf4j;
+
+/**
+ * ZMR client implementation for eIDAS matching operations.
+ *
+ * @author tlenz
+ *
+ */
+@Slf4j
+public class ZmrSoapClient extends AbstractSoapClient implements IZmrClient {
+
+ private static final String ERROR_MATCHING_00 = "module.eidasauth.matching.00";
+ private static final String ERROR_MATCHING_01 = "module.eidasauth.matching.01";
+ private static final String ERROR_MATCHING_02 = "module.eidasauth.matching.02";
+ private static final String ERROR_MATCHING_99 = "module.eidasauth.matching.99";
+
+ private static final String LOGMSG_MISSING_CONFIG = "Missing configuration with key: {0}";
+
+ private static final String LOGMSG_ZMR_ERROR =
+ "Receive an error from ZMR during '{}' operation with msg: {}";
+ private static final String LOGMSG_ZMR_RESP_PROCESS =
+ "Proces ZMR response during '{}' operation failes with msg: {}";
+
+ private static final String LOGMSG_ZMR_SOAP_ERROR =
+ "ZMR anwser for transaction: {} with code: {} and message: {}";
+
+ private static final String PROCESS_GENERAL = "eIDAS_Matching";
+ private static final String PROCESS_SEARCH_PERSONAL_IDENTIFIER =
+ "Searching " + Constants.eIDAS_ATTR_PERSONALIDENTIFIER;
+ private static final String PROCESS_SEARCH_MDS_ONLY = "Searching with MDS only";
+ private static final String PROCESS_SEARCH_COUNTRY_SPECIFIC = "Searching {} specific";
+
+ private static final String CLIENT_INFO = "eIDAS MS-Connector v{0}";
+ private static final String CLIENT_DEFAULT = "ZMR Client";
+
+
+ @Autowired VersionHolder versionHolder;
+
+ private ServicePort zmrClient;
+
+
+ @AllArgsConstructor
+ @Getter
+ public static class ZmrRegisterResult {
+ private final List personResult;
+ private final BigInteger processId;
+
+ }
+
+ @Override
+ public ZmrRegisterResult searchWithPersonIdentifier(BigInteger zmrProzessId, String personIdentifier)
+ throws EidasSAuthenticationException {
+
+ try {
+ // build search request
+ final RequestType req = new RequestType();
+
+ // set eIDAS person information
+ final PersonSuchenRequest searchPersonReq = new PersonSuchenRequest();
+ req.setPersonSuchenRequest(searchPersonReq);
+ final EidasSuchdatenType eidasInfos = new EidasSuchdatenType();
+ searchPersonReq.setEidasSuchdaten(eidasInfos);
+ eidasInfos.setEidasArt(Constants.eIDAS_ATTRURN_PERSONALIDENTIFIER);
+ eidasInfos.setEidasNummer(personIdentifier);
+
+ // set work-flow client information
+ req.setWorkflowInfoClient(generateWorkFlowInfos(PROCESS_SEARCH_PERSONAL_IDENTIFIER, null));
+ req.setClientInfo(generateClientInfos());
+
+ // set additionl search parameters
+ searchPersonReq.setPersonensucheInfo(generateSearchCriteria(false, true, false));
+
+ // request ZMR
+ log.trace("Requesting ZMR for '{}' operation", PROCESS_SEARCH_PERSONAL_IDENTIFIER);
+ final ResponseType resp = zmrClient.service(req, null);
+
+ // parse ZMR response
+ return processZmrResponse(resp, EidasResponseUtils.parseEidasPersonalIdentifier(personIdentifier)
+ .getFirst(),
+ true, PROCESS_SEARCH_PERSONAL_IDENTIFIER);
+
+ } catch (final ServiceFault e) {
+ final String errorMsg = extractReasonFromError(e);
+ log.warn(LOGMSG_ZMR_ERROR, PROCESS_SEARCH_PERSONAL_IDENTIFIER, errorMsg);
+ throw new ZmrCommunicationException(ERROR_MATCHING_01, new Object[] { errorMsg }, e);
+
+ } catch (final EaafAuthenticationException e) {
+ log.warn(LOGMSG_ZMR_RESP_PROCESS, PROCESS_SEARCH_PERSONAL_IDENTIFIER, e.getMessage());
+ throw new EidasSAuthenticationException(ERROR_MATCHING_99, new Object[] { e.getMessage() }, e);
+
+ }
+ }
+
+ @Override
+ public ZmrRegisterResult searchWithMds(BigInteger zmrProzessId, String givenName, String familyName,
+ String dateOfBirth, String citizenCountryCode) throws EidasSAuthenticationException {
+ try {
+ // build search request
+ final RequestType req = new RequestType();
+
+ // set eIDAS person information
+ final PersonSuchenRequest searchPersonReq = new PersonSuchenRequest();
+ req.setPersonSuchenRequest(searchPersonReq);
+
+ final NatuerlichePersonTyp searchNatPerson = new NatuerlichePersonTyp();
+ searchPersonReq.setNatuerlichePerson(searchNatPerson);
+ final PersonenNameTyp searchNatPersonName = new PersonenNameTyp();
+ searchNatPerson.setPersonenName(searchNatPersonName);
+
+ searchNatPersonName.setFamilienname(familyName);
+ searchNatPersonName.setVorname(givenName);
+ searchNatPerson.setGeburtsdatum(dateOfBirth);
+
+ // set work-flow client information
+ req.setWorkflowInfoClient(generateWorkFlowInfos(PROCESS_SEARCH_MDS_ONLY, zmrProzessId));
+ req.setClientInfo(generateClientInfos());
+
+ // set additionl search parameters
+ searchPersonReq.setPersonensucheInfo(generateSearchCriteria(false, true, false));
+
+ // request ZMR
+ log.trace("Requesting ZMR for '{}' operation", PROCESS_SEARCH_MDS_ONLY);
+ final ResponseType resp = zmrClient.service(req, null);
+
+ // parse ZMR response
+ return processZmrResponse(resp, citizenCountryCode, false, PROCESS_SEARCH_MDS_ONLY);
+
+ } catch (final ServiceFault e) {
+ final String errorMsg = extractReasonFromError(e);
+ log.warn(LOGMSG_ZMR_ERROR, PROCESS_SEARCH_MDS_ONLY, errorMsg);
+ throw new ZmrCommunicationException(ERROR_MATCHING_01, new Object[] { errorMsg }, e);
+
+ } catch (final EaafAuthenticationException e) {
+ log.warn(LOGMSG_ZMR_RESP_PROCESS, PROCESS_SEARCH_MDS_ONLY, e.getMessage());
+ throw new EidasSAuthenticationException(ERROR_MATCHING_99, new Object[] { e.getMessage() }, e);
+
+ }
+
+ }
+
+ @Override
+ public ZmrRegisterResult searchCountrySpecific(BigInteger zmrProzessId, PersonSuchenRequest personSearchDao,
+ String citizenCountryCode)
+ throws EidasSAuthenticationException {
+ final String friendlyMsg = MessageFormat.format(PROCESS_SEARCH_COUNTRY_SPECIFIC, citizenCountryCode);
+
+ try {
+ // build search request
+ final RequestType req = new RequestType();
+
+ // set eIDAS person information
+ req.setPersonSuchenRequest(personSearchDao);
+
+ // set work-flow client information
+ req.setWorkflowInfoClient(generateWorkFlowInfos(friendlyMsg, zmrProzessId));
+ req.setClientInfo(generateClientInfos());
+
+ // set additionl search parameters
+ personSearchDao.setPersonensucheInfo(generateSearchCriteria(false, true, false));
+
+ // request ZMR
+ log.trace("Requesting ZMR for '{}' operation", friendlyMsg);
+ final ResponseType resp = zmrClient.service(req, null);
+
+ // parse ZMR response
+ return processZmrResponse(resp, citizenCountryCode, true,
+ friendlyMsg);
+
+ } catch (final ServiceFault e) {
+ final String errorMsg = extractReasonFromError(e);
+ log.warn(LOGMSG_ZMR_ERROR, friendlyMsg, errorMsg);
+ throw new ZmrCommunicationException(ERROR_MATCHING_01, new Object[] { errorMsg }, e);
+
+ } catch (final EaafAuthenticationException e) {
+ log.warn(LOGMSG_ZMR_RESP_PROCESS, friendlyMsg, e.getMessage());
+ throw new EidasSAuthenticationException(ERROR_MATCHING_99, new Object[] { e.getMessage() }, e);
+
+ }
+ }
+
+ @Override
+ public void update(BigInteger zmrProzessId, RegisterResult registerResult, SimpleEidasData eidData) {
+ // TODO Auto-generated method stub
+
+ }
+
+ @Override
+ public ZmrRegisterResult searchWithBpkZp(BigInteger zmrProzessId, String bpkzp) {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ public ZmrRegisterResult searchWithResidenceData(BigInteger zmrProzessId, String givenName, String familyName,
+ String dateOfBirth, String zipcode, String city, String street) {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ @PostConstruct
+ private void initialize() throws EaafConfigurationException {
+ // set-up the ZMR client
+ initializeTechnicalZmrClient();
+
+ // validate additional ZMR communication parameters
+ valdiateAdditionalConfigParameters();
+
+ }
+
+ private void initializeTechnicalZmrClient() throws EaafConfigurationException {
+ log.info("Starting ZMR-Client initialization .... ");
+ final URL url = ZmrSoapClient.class.getResource("/wsdl/zmr_client/wsdl/Service.wsdl");
+ final Service zmrService = new Service(url);
+ zmrClient = zmrService.getService();
+
+ final String zmrServiceUrl = basicConfig.getBasicConfiguration(
+ Constants.CONIG_PROPS_EIDAS_ZMRCLIENT_ENDPOINT);
+ if (StringUtils.isEmpty(zmrServiceUrl)) {
+ log.error("No ZMR service-URL found. ZMR-Client initalisiation failed.");
+ throw new RuntimeException("No ZMR service URL found. ZMR-Client initalisiation failed.");
+
+ }
+
+ // inject handler
+ log.info("Use ZMR service-URL: " + zmrServiceUrl);
+ injectBindingProvider((BindingProvider) zmrClient, CLIENT_DEFAULT, zmrServiceUrl,
+ basicConfig.getBasicConfigurationBoolean(Constants.CONIG_PROPS_EIDAS_ZMRCLIENT_DEBUG_TRACEMESSAGES,
+ false));
+
+ // inject http parameters and SSL context
+ log.debug("Inject HTTP client settings ... ");
+ injectHttpClient(zmrClient, HttpClientConfig.builder()
+ .clientName(CLIENT_DEFAULT)
+ .clientType(CLIENT_DEFAULT)
+ .clientUrl(zmrServiceUrl)
+ .connectionTimeout(basicConfig.getBasicConfiguration(
+ Constants.CONIG_PROPS_EIDAS_ZMRCLIENT_TIMEOUT_CONNECTION,
+ Constants.HTTP_CLIENT_DEFAULT_TIMEOUT_CONNECTION))
+ .responseTimeout(basicConfig.getBasicConfiguration(
+ Constants.CONIG_PROPS_EIDAS_ZMRCLIENT_TIMEOUT_RESPONSE,
+ Constants.HTTP_CLIENT_DEFAULT_TIMEOUT_RESPONSE))
+ .keyStoreConfig(buildKeyStoreConfiguration(
+ Constants.CONIG_PROPS_EIDAS_ZMRCLIENT_SSL_KEYSTORE_TYPE,
+ Constants.CONIG_PROPS_EIDAS_ZMRCLIENT_SSL_KEYSTORE_PATH,
+ Constants.CONIG_PROPS_EIDAS_ZMRCLIENT_SSL_KEYSTORE_PASSWORD,
+ Constants.CONIG_PROPS_EIDAS_ZMRCLIENT_SSL_KEYSTORE_NAME,
+ "ZMR SSL Client-Authentication KeyStore"))
+ .keyAlias(basicConfig.getBasicConfiguration(Constants.CONIG_PROPS_EIDAS_ZMRCLIENT_SSL_KEYS_ALIAS))
+ .keyPassword(basicConfig.getBasicConfiguration(
+ Constants.CONIG_PROPS_EIDAS_ZMRCLIENT_SSL_KEY_PASSWORD))
+ .trustAll(false)
+ .trustStoreConfig(buildKeyStoreConfiguration(
+ Constants.CONIG_PROPS_EIDAS_ZMRCLIENT_SSL_TRUSTSTORE_TYPE,
+ Constants.CONIG_PROPS_EIDAS_ZMRCLIENT_SSL_TRUSTSTORE_PATH,
+ Constants.CONIG_PROPS_EIDAS_ZMRCLIENT_SSL_TRUSTSTORE_PASSWORD,
+ Constants.CONIG_PROPS_EIDAS_ZMRCLIENT_SSL_TRUSTSTORE_NAME,
+ "ZMR SSL Client-Authentication TrustStore"))
+ .build());
+
+ }
+
+ private void valdiateAdditionalConfigParameters() {
+ checkConfigurationValue(Constants.CONIG_PROPS_EIDAS_ZMRCLIENT_REQ_ORGANIZATION_NR);
+
+ }
+
+ private void checkConfigurationValue(String key) {
+ if (StringUtils.isEmpty(basicConfig.getBasicConfiguration(key))) {
+ throw new RuntimeException(MessageFormat.format(LOGMSG_MISSING_CONFIG, key));
+
+ }
+ }
+
+ @Nonnull
+ private WorkflowInfoClient generateWorkFlowInfos(@Nonnull String subStepName,
+ @Nullable BigInteger prozessInstanzId) {
+ final WorkflowInfoClient infos = new WorkflowInfoClient();
+ infos.setProzessName(PROCESS_GENERAL);
+ infos.setVorgangName(subStepName);
+
+ //set processId that we received from ZMR before, if already available
+ if (prozessInstanzId != null) {
+ infos.setProzessInstanzID(prozessInstanzId);
+
+ }
+
+ return infos;
+
+ }
+
+ @Nonnull
+ private PersonensucheInfoType generateSearchCriteria(boolean searchInErnp,
+ boolean searchInZmrHistory, boolean includeHistoryResults) {
+ final PersonensucheInfoType personSearchInfo = new PersonensucheInfoType();
+ final SuchkriterienType searchCriteria = new SuchkriterienType();
+ final ErgebniskriterienType resultCriteria = new ErgebniskriterienType();
+ personSearchInfo.setSuchkriterien(searchCriteria);
+ personSearchInfo.setErgebniskriterien(resultCriteria);
+
+ // TODO: are these flags valid?
+ searchCriteria.setInclusivERnP(searchInErnp);
+ searchCriteria.setInclusivHistorie(searchInZmrHistory);
+
+ // TODO: check 'processSearchPersonResponse' if we change this to 'true'
+ resultCriteria.setInclusivHistorie(includeHistoryResults);
+
+ return personSearchInfo;
+
+ }
+
+ @Nonnull
+ private ClientInfoType generateClientInfos() {
+ final ClientInfoType clientInfo = new ClientInfoType();
+ final Organisation clientOrganisation = new Organisation();
+ clientInfo.setOrganisation(clientOrganisation);
+
+ // set client information
+ clientInfo.setClient(MessageFormat.format(CLIENT_INFO, versionHolder.getVersion()));
+
+ // set Behoerdennummer as organization identifier
+ clientOrganisation.setBehoerdenNr(basicConfig.getBasicConfiguration(
+ Constants.CONIG_PROPS_EIDAS_ZMRCLIENT_REQ_ORGANIZATION_NR));
+
+ return clientInfo;
+ }
+
+ @Nonnull
+ private String extractReasonFromError(ServiceFault e) {
+ if (e.getFaultInfo() != null) {
+ return MessageFormat.format(LOGMSG_ZMR_SOAP_ERROR,
+ e.getFaultInfo().getServerTransaktionNr(),
+ e.getFaultInfo().getErrorCode(),
+ e.getFaultInfo().getErrorMessage());
+
+ } else {
+ log.error("ZMR response without error code", e);
+ return e.getMessage();
+
+ }
+ }
+
+ @Nonnull
+ private ZmrRegisterResult processZmrResponse(@Nonnull ResponseType resp,
+ @Nonnull String citizenCountryCode,
+ boolean forceSinglePersonMatch, @Nonnull String processStepFiendlyname)
+ throws EaafAuthenticationException {
+ final PersonSuchenResponse searchPersonResp = resp.getPersonSuchenResponse();
+ if (searchPersonResp.getPersonensuchergebnis() == null
+ || searchPersonResp.getPersonensuchergebnis().getPersonErgebnisSatz().isEmpty()) {
+ log.debug("ZMR result contains NO 'Personensuchergebnis' or 'PersonErgebnisSatz' is empty");
+ return new ZmrRegisterResult(Collections.emptyList(), extractZmrProcessId(resp.getWorkflowInfoServer()));
+
+ } else {
+ // TODO: what we to with ERnP results?
+ log.debug("Get #{} person results from '{}' operation",
+ searchPersonResp.getPersonensuchergebnis().getGefundeneSaetze(), processStepFiendlyname);
+
+ if (forceSinglePersonMatch) {
+ return new ZmrRegisterResult(processSearchPersonResponseSingleResult(
+ searchPersonResp.getPersonensuchergebnis().getPersonErgebnisSatz(), citizenCountryCode),
+ extractZmrProcessId(resp.getWorkflowInfoServer()));
+
+ } else {
+ return new ZmrRegisterResult(processSearchPersonResponse(
+ searchPersonResp.getPersonensuchergebnis().getPersonErgebnisSatz(), citizenCountryCode),
+ extractZmrProcessId(resp.getWorkflowInfoServer()));
+
+ }
+ }
+ }
+
+ private BigInteger extractZmrProcessId(WorkflowInfoServer workflowInfoServer) {
+ return workflowInfoServer != null ? workflowInfoServer.getProzessInstanzID() : null;
+
+ }
+
+ @Nonnull
+ private List processSearchPersonResponse(
+ @Nonnull List personErgebnisSatz,
+ @Nonnull String citizenCountryCode) throws EaafAuthenticationException {
+
+ return personErgebnisSatz.stream()
+ .map(el -> {
+ try {
+ return processPersonResult(el, citizenCountryCode);
+
+ } catch (final EaafAuthenticationException e) {
+ log.warn("Skip ZMR person result by reason: {}", e.getMessage(), e);
+ return null;
+
+ }
+ })
+ .filter(Objects::nonNull)
+ .collect(Collectors.toList());
+
+ }
+
+ @NonNull
+ private List processSearchPersonResponseSingleResult(
+ @Nonnull List personErgebnisSatz,
+ @Nonnull String citizenCountryCode) throws EaafAuthenticationException {
+ if (personErgebnisSatz.size() > 1) {
+ log.error("Find more than on person with eIDAS personalIdentifier.");
+ throw new EaafAuthenticationException(ERROR_MATCHING_00, null);
+
+ } else {
+ return Arrays.asList(processPersonResult(personErgebnisSatz.get(0), citizenCountryCode));
+
+ }
+ }
+
+ @Nonnull
+ private RegisterResult processPersonResult(
+ @Nonnull PersonErgebnisSatzType personEl, @Nonnull String citizenCountryCode)
+ throws EaafAuthenticationException {
+ // TODO: maybe check on 'null' if ERnP data is also allowed
+ log.debug("Find #{} data sets in person information",
+ personEl.getPersonendaten().getPersonErgebnis().size());
+
+ if (personEl.getPersonendaten().getPersonErgebnis().size() > 1) {
+ log.error("Find more than on person with eIDAS personalIdentifier.");
+ throw new EaafAuthenticationException(ERROR_MATCHING_02, null);
+
+ } else {
+ return mapZmrResponseToRegisterResult(
+ personEl.getPersonendaten().getPersonErgebnis().get(0), citizenCountryCode);
+
+ }
+
+ }
+
+ @Nonnull
+ private RegisterResult mapZmrResponseToRegisterResult(@Nonnull PersonErgebnisType person,
+ @Nonnull String citizenCountryCode) {
+ // TODO: kann ich bei historischen daten davon ausgehen dass die Reihenfolge der
+ // Ergebnisse von aktuell --> alt ist?
+
+ // build result
+ return RegisterResult.builder()
+ .pseudonym(selectAllEidasDocument(person, citizenCountryCode,
+ Constants.eIDAS_ATTRURN_PERSONALIDENTIFIER))
+ .familyName(person.getNatuerlichePerson().getPersonenName().getFamilienname())
+ .givenName(person.getNatuerlichePerson().getPersonenName().getVorname())
+ .dateOfBirth(person.getNatuerlichePerson().getGeburtsdatum())
+ .bpk(extractBpkZp(person.getNatuerlichePerson()))
+ .placeOfBirth(selectSingleEidasDocument(person, citizenCountryCode,
+ Constants.eIDAS_ATTRURN_PERSONALIDENTIFIER))
+ .birthName(selectSingleEidasDocument(person, citizenCountryCode,
+ Constants.eIDAS_ATTRURN_PERSONALIDENTIFIER))
+ .build();
+
+ }
+
+ private String extractBpkZp(NatuerlichePersonErgebnisType natuerlichePerson) {
+ String bpk = natuerlichePerson.getIdentification().stream()
+ .filter(el -> Constants.MATCHING_INTERNAL_BPK_TARGET.equals(el.getType()))
+ .findFirst()
+ .map(el -> el.getValue())
+ .orElse(null);
+ if (StringUtils.isEmpty(bpk)) {
+ log.warn("ZMR response contains no 'bPK' for target: 'ZP'");
+
+ }
+ return bpk;
+
+ }
+
+ /**
+ * Get all eIDAS document with the specified country code and document type.
+ *
+ * @param person Person information from ZMR
+ * @param citizenCountryCode Country code of the eIDAS attribute
+ * @param eidasAttrurnPersonalidentifier eIDAS attribute identifier
+ * @return {@link List} of eIDAS attribute values or an empty list if's not
+ * found
+ */
+ @NonNull
+ private List selectAllEidasDocument(PersonErgebnisType person, String citizenCountryCode,
+ String eidasAttrurnPersonalidentifier) {
+ return person.getEidasIdentitaet().stream()
+ .filter(el -> eidasAttrurnPersonalidentifier.equals(el.getEidasArt())
+ && el.getStaatscode3().equals(citizenCountryCode))
+ .map(el -> el.getDokumentNummer())
+ .collect(Collectors.toList());
+
+ }
+
+ /**
+ * Get the first eIDAS document with the specified country code and document
+ * type.
+ *
+ * @param person Person information from ZMR
+ * @param citizenCountryCode Country code of the eIDAS attribute
+ * @param eidasAttrurnPersonalidentifier eIDAS attribute identifier
+ * @return Value of this eIDAS attribute or null
if's not found
+ */
+ @Nullable
+ private String selectSingleEidasDocument(PersonErgebnisType person, String citizenCountryCode,
+ String eidasAttrurnPersonalidentifier) {
+ return person.getEidasIdentitaet().stream()
+ .filter(el -> eidasAttrurnPersonalidentifier.equals(el.getEidasArt())
+ && el.getStaatscode3().equals(citizenCountryCode))
+ .findFirst()
+ .map(el -> el.getDokumentNummer())
+ .orElse(null);
+
+ }
+}
diff --git a/eidas_modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/dao/MergedRegisterSearchResult.java b/eidas_modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/dao/MergedRegisterSearchResult.java
deleted file mode 100644
index 0c977016..00000000
--- a/eidas_modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/dao/MergedRegisterSearchResult.java
+++ /dev/null
@@ -1,75 +0,0 @@
-/*
- * Copyright 2020 A-SIT Plus GmbH
- * AT-specific eIDAS Connector has been developed in a cooperation between EGIZ,
- * A-SIT Plus GmbH, A-SIT, and Graz University of Technology.
- *
- * Licensed under the EUPL, Version 1.2 or - as soon they will be approved by
- * the European Commission - subsequent versions of the EUPL (the "License");
- * You may not use this work except in compliance with the License.
- * You may obtain a copy of the License at:
- * https://joinup.ec.europa.eu/news/understanding-eupl-v12
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" basis,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- * 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.asitplus.eidas.specific.modules.auth.eidas.v2.dao;
-
-import at.asitplus.eidas.specific.modules.auth.eidas.v2.exception.WorkflowException;
-import lombok.Data;
-
-import java.util.List;
-
-@Data
-public class MergedRegisterSearchResult {
-
- private final List resultsZmr;
- private final List resultsErnp;
-
- public MergedRegisterSearchResult(List resultsZmr, List resultsErnp) {
- this.resultsZmr = resultsZmr;
- this.resultsErnp = resultsErnp;
- }
-
- public int getResultCount() {
- return resultsZmr.size() + resultsErnp.size();
- }
-
- /**
- * Verifies that there is only one match and returns the bpk.
- *
- * @return bpk bpk of the match
- * @throws WorkflowException if multiple results have been found
- */
- public String getBpk() throws WorkflowException {
- if (getResultCount() != 1) {
- throw new WorkflowException("getResultCount() != 1");
- }
- return getResult().getBpk();
- }
-
- /**
- * Returns the results, if there is exactly one, throws exception otherwise.
- *
- * @return The result
- * @throws WorkflowException Results does not contain exactly one result
- */
- public RegisterResult getResult() throws WorkflowException {
- if (getResultCount() != 1) {
- throw new WorkflowException("getResultCount() != 1");
- }
- if (resultsZmr.size() == 1) {
- return resultsZmr.get(0);
- } else {
- return resultsErnp.get(0);
- }
- }
-}
diff --git a/eidas_modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/dao/RegisterResult.java b/eidas_modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/dao/RegisterResult.java
index 369a4e31..4959d72f 100644
--- a/eidas_modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/dao/RegisterResult.java
+++ b/eidas_modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/dao/RegisterResult.java
@@ -23,70 +23,29 @@
package at.asitplus.eidas.specific.modules.auth.eidas.v2.dao;
+import java.util.List;
+
import at.gv.e_government.reference.namespace.persondata._20020228.PostalAddressType;
-import lombok.Data;
+import lombok.Builder;
+import lombok.Getter;
-@Data
+@Builder
+@Getter
public class RegisterResult {
// MDS
- private final String pseudonym;
+ private final List pseudonym;
private final String givenName;
private final String familyName;
private final String dateOfBirth;
// additional attributes
- private final String placeOfBirth;
- private final String birthName;
- private final String taxNumber;
- private final PostalAddressType address;
-
- private final String bpk;
+ private String placeOfBirth;
+ private String birthName;
+ private String taxNumber;
+ private PostalAddressType address;
- /**
- * Register search result.
- *
- * @param bpk The bpk
- * @param pseudonym The pseudonym
- * @param givenName The givenName
- * @param familyName The familyName
- * @param dateOfBirth The dateOfBirth
- */
- public RegisterResult(String bpk, String pseudonym, String givenName, String familyName, String dateOfBirth) {
- this.bpk = bpk;
- this.pseudonym = pseudonym;
- this.givenName = givenName;
- this.familyName = familyName;
- this.dateOfBirth = dateOfBirth;
- this.placeOfBirth = null;
- this.birthName = null;
- this.taxNumber = null;
- this.address = null;
- }
+ private String bpk;
- /**
- * Register search result.
- *
- * @param bpk The bpk
- * @param pseudonym The pseudonym
- * @param givenName The givenName
- * @param familyName The familyName
- * @param dateOfBirth The dateOfBirth
- * @param placeOfBirth The placeOfBirth
- * @param birthName The birthName
- * @param taxNumber The taxNumber
- * @param address The address
- */
- public RegisterResult(String bpk, String pseudonym, String givenName, String familyName, String dateOfBirth,
- String placeOfBirth, String birthName, String taxNumber, PostalAddressType address) {
- this.bpk = bpk;
- this.pseudonym = pseudonym;
- this.givenName = givenName;
- this.familyName = familyName;
- this.dateOfBirth = dateOfBirth;
- this.placeOfBirth = placeOfBirth;
- this.birthName = birthName;
- this.taxNumber = taxNumber;
- this.address = address;
- }
+
}
diff --git a/eidas_modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/dao/SimpleEidasData.java b/eidas_modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/dao/SimpleEidasData.java
index ecf5007a..ab84a45f 100644
--- a/eidas_modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/dao/SimpleEidasData.java
+++ b/eidas_modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/dao/SimpleEidasData.java
@@ -23,20 +23,32 @@
package at.asitplus.eidas.specific.modules.auth.eidas.v2.dao;
+import org.apache.commons.lang3.builder.EqualsBuilder;
+
import at.asitplus.eidas.specific.modules.auth.eidas.v2.exception.WorkflowException;
+import at.asitplus.eidas.specific.modules.auth.eidas.v2.service.RegisterSearchService.RegisterSearchResult;
import at.gv.e_government.reference.namespace.persondata._20020228.PostalAddressType;
import lombok.Builder;
import lombok.Data;
-import org.apache.commons.lang3.builder.EqualsBuilder;
@Data
@Builder
public class SimpleEidasData {
+ /**
+ * Full eIDAS personal identifier with prefix.
+ */
private final String personalIdentifier;
+
+ /**
+ * Citizen country-code from eIDAS personal-identifier.
+ */
private final String citizenCountryCode;
// MDS
+ /**
+ * eIDAS personal identifier without prefix.
+ */
private final String pseudonym;
private final String givenName;
private final String familyName;
@@ -55,16 +67,24 @@ public class SimpleEidasData {
* @return true or false depending of the data matches
* @throws WorkflowException if multiple results have been found
*/
- public boolean equalsRegisterData(MergedRegisterSearchResult result) throws WorkflowException {
+ public boolean equalsRegisterData(RegisterSearchResult result) throws WorkflowException {
+ /*TODO: maybe this is check is not valid, because only the minimum data-set (personalIdentifer, givenName,
+ * familyName, dateOfBirth) has to be always available. Any other attributes are optional.
+ * This check will always evaluate to false if register has more information as current eIDAS process!!!
+ */
+
return new EqualsBuilder()
- .append(result.getResult().getPseudonym(), pseudonym)
.append(result.getResult().getGivenName(), givenName)
.append(result.getResult().getFamilyName(), familyName)
.append(result.getResult().getDateOfBirth(), dateOfBirth)
.append(result.getResult().getPlaceOfBirth(), placeOfBirth)
.append(result.getResult().getBirthName(), birthName)
.append(result.getResult().getTaxNumber(), taxNumber)
- .isEquals();
+ .isEquals() && result.getResult().getPseudonym().stream()
+ .filter(el -> el.equals(pseudonym))
+ .findFirst()
+ .isPresent();
+
}
}
diff --git a/eidas_modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/dao/SimpleMobileSignatureData.java b/eidas_modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/dao/SimpleMobileSignatureData.java
index 4a27e60e..92e727ea 100644
--- a/eidas_modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/dao/SimpleMobileSignatureData.java
+++ b/eidas_modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/dao/SimpleMobileSignatureData.java
@@ -23,15 +23,15 @@
package at.asitplus.eidas.specific.modules.auth.eidas.v2.dao;
+import org.apache.commons.lang3.builder.EqualsBuilder;
+
import lombok.Builder;
import lombok.Data;
-import org.apache.commons.lang3.builder.EqualsBuilder;
@Data
@Builder
public class SimpleMobileSignatureData {
- private final String citizenCountryCode;
private final String bpk;
private final String givenName;
private final String familyName;
diff --git a/eidas_modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/ernp/DummyErnpClient.java b/eidas_modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/ernp/DummyErnpClient.java
index 3536b0dc..065b17a2 100644
--- a/eidas_modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/ernp/DummyErnpClient.java
+++ b/eidas_modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/ernp/DummyErnpClient.java
@@ -23,13 +23,14 @@
package at.asitplus.eidas.specific.modules.auth.eidas.v2.ernp;
-import at.asitplus.eidas.specific.modules.auth.eidas.v2.dao.RegisterResult;
-import at.asitplus.eidas.specific.modules.auth.eidas.v2.dao.SimpleEidasData;
-import org.springframework.stereotype.Service;
-
import java.util.Collections;
import java.util.List;
+import org.springframework.stereotype.Service;
+
+import at.asitplus.eidas.specific.modules.auth.eidas.v2.dao.RegisterResult;
+import at.asitplus.eidas.specific.modules.auth.eidas.v2.dao.SimpleEidasData;
+
@Service("ErnbClientForeIDAS")
public class DummyErnpClient implements IErnpClient {
diff --git a/eidas_modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/ernp/IErnpClient.java b/eidas_modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/ernp/IErnpClient.java
index 218a9f41..b3b0c033 100644
--- a/eidas_modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/ernp/IErnpClient.java
+++ b/eidas_modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/ernp/IErnpClient.java
@@ -23,11 +23,11 @@
package at.asitplus.eidas.specific.modules.auth.eidas.v2.ernp;
+import java.util.List;
+
import at.asitplus.eidas.specific.modules.auth.eidas.v2.dao.RegisterResult;
import at.asitplus.eidas.specific.modules.auth.eidas.v2.dao.SimpleEidasData;
-import java.util.List;
-
public interface IErnpClient {
List searchWithPersonIdentifier(String personIdentifier);
diff --git a/eidas_modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/exception/InvalidUserInputException.java b/eidas_modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/exception/InvalidUserInputException.java
index f28d8afa..c7df56d0 100644
--- a/eidas_modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/exception/InvalidUserInputException.java
+++ b/eidas_modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/exception/InvalidUserInputException.java
@@ -26,8 +26,9 @@ package at.asitplus.eidas.specific.modules.auth.eidas.v2.exception;
public class InvalidUserInputException extends EidasSAuthenticationException {
private static final long serialVersionUID = 1L;
- public InvalidUserInputException() {
- super("eidas.10", null);
+ public InvalidUserInputException(String errorCode) {
+ super(errorCode, null);
+
}
}
diff --git a/eidas_modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/exception/ManualFixNecessaryException.java b/eidas_modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/exception/ManualFixNecessaryException.java
index 2fecaa6b..cf69bd2c 100644
--- a/eidas_modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/exception/ManualFixNecessaryException.java
+++ b/eidas_modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/exception/ManualFixNecessaryException.java
@@ -28,11 +28,17 @@ import at.asitplus.eidas.specific.modules.auth.eidas.v2.dao.SimpleEidasData;
public class ManualFixNecessaryException extends EidasSAuthenticationException {
private static final long serialVersionUID = 1L;
+ //TODO: should we pass some infos?
public ManualFixNecessaryException(String personIdentifier) {
- super("eidas.09", new Object[] { personIdentifier });
+ super("module.eidasauth.matching.04", new Object[] { personIdentifier });
}
public ManualFixNecessaryException(SimpleEidasData eidData) {
- super("eidas.09", new Object[] { eidData.getPseudonym() });//TODO what info to pass???
+ super("module.eidasauth.matching.04", new Object[] { eidData.getPseudonym() });
}
+
+ public ManualFixNecessaryException(SimpleEidasData eidData, Throwable e) {
+ super("module.eidasauth.matching.04", new Object[] { eidData.getPseudonym() }, e);
+ }
+
}
diff --git a/eidas_modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/exception/WorkflowException.java b/eidas_modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/exception/WorkflowException.java
index b6f3309b..795b4386 100644
--- a/eidas_modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/exception/WorkflowException.java
+++ b/eidas_modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/exception/WorkflowException.java
@@ -23,11 +23,72 @@
package at.asitplus.eidas.specific.modules.auth.eidas.v2.exception;
+import lombok.Getter;
+
+@Getter
public class WorkflowException extends EidasSAuthenticationException {
private static final long serialVersionUID = 1L;
- public WorkflowException(String data) {
- super("eidas.08", new Object[]{data});
+ private String processStepName;
+ private String errorReason;
+ private boolean requiresManualFix = false;
+
+ /**
+ * In case of a error during matching work-flow.
+ *
+ * @param processStep Matching step identifier
+ * @param errorReason Reason for this error
+ */
+ public WorkflowException(String processStep, String errorReason) {
+ super("module.eidasauth.matching.03", new Object[]{processStep, errorReason});
+ this.processStepName = processStep;
+ this.errorReason = errorReason;
+
}
+ /**
+ * In case of a error during matching work-flow.
+ *
+ * @param processStep Matching step identifier
+ * @param errorReason Reason for this error
+ * @param e Catched exception
+ */
+ public WorkflowException(String processStep, String errorReason, Throwable e) {
+ super("module.eidasauth.matching.03", new Object[]{processStep, errorReason}, e);
+ this.processStepName = processStep;
+ this.errorReason = errorReason;
+
+ }
+
+ /**
+ * In case of a error during matching work-flow.
+ *
+ * @param processStep Matching step identifier
+ * @param errorReason Reason for this error
+ * @param needsManualFix Mark this work-flow as manually fixable
+ */
+ public WorkflowException(String processStep, String errorReason, boolean needsManualFix) {
+ super("module.eidasauth.matching.03", new Object[]{processStep, errorReason});
+ this.processStepName = processStep;
+ this.errorReason = errorReason;
+ this.requiresManualFix = needsManualFix;
+
+ }
+
+ /**
+ * In case of a error during matching work-flow.
+ *
+ * @param processStep Matching step identifier
+ * @param errorReason Reason for this error
+ * @param needsManualFix Mark this work-flow as manually fixable
+ * @param e Catched exception
+ */
+ public WorkflowException(String processStep, String errorReason, boolean needsManualFix, Throwable e) {
+ super("module.eidasauth.matching.03", new Object[]{processStep, errorReason}, e);
+ this.processStepName = processStep;
+ this.errorReason = errorReason;
+ this.requiresManualFix = needsManualFix;
+
+ }
+
}
diff --git a/eidas_modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/exception/ZmrCommunicationException.java b/eidas_modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/exception/ZmrCommunicationException.java
new file mode 100644
index 00000000..a6978458
--- /dev/null
+++ b/eidas_modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/exception/ZmrCommunicationException.java
@@ -0,0 +1,38 @@
+/*
+ * Copyright 2018 A-SIT Plus GmbH
+ * AT-specific eIDAS Connector has been developed in a cooperation between EGIZ,
+ * A-SIT Plus GmbH, A-SIT, and Graz University of Technology.
+ *
+ * Licensed under the EUPL, Version 1.2 or - as soon they will be approved by
+ * the European Commission - subsequent versions of the EUPL (the "License");
+ * You may not use this work except in compliance with the License.
+ * You may obtain a copy of the License at:
+ * https://joinup.ec.europa.eu/news/understanding-eupl-v12
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * 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.asitplus.eidas.specific.modules.auth.eidas.v2.exception;
+
+public class ZmrCommunicationException extends EidasSAuthenticationException {
+
+ private static final long serialVersionUID = 1L;
+
+ public ZmrCommunicationException(String internalMsgId, Object[] params) {
+ super(internalMsgId, params);
+ }
+
+ public ZmrCommunicationException(String internalMsgId, Object[] params, Throwable e) {
+ super(internalMsgId, params, e);
+ }
+
+}
diff --git a/eidas_modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/handler/AbstractEidProcessor.java b/eidas_modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/handler/AbstractEidProcessor.java
index 05254fe2..1050f8d9 100644
--- a/eidas_modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/handler/AbstractEidProcessor.java
+++ b/eidas_modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/handler/AbstractEidProcessor.java
@@ -24,11 +24,13 @@
package at.asitplus.eidas.specific.modules.auth.eidas.v2.handler;
+import static at.asitplus.eidas.specific.modules.auth.eidas.v2.utils.EidasResponseUtils.processCountryCode;
+import static at.asitplus.eidas.specific.modules.auth.eidas.v2.utils.EidasResponseUtils.processDateOfBirthToString;
+
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
-import at.asitplus.eidas.specific.modules.auth.eidas.v2.dao.SimpleEidasData;
import org.apache.commons.lang3.StringUtils;
import org.joda.time.DateTime;
import org.slf4j.Logger;
@@ -37,7 +39,9 @@ import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.lang.NonNull;
import com.google.common.collect.ImmutableSortedSet;
+
import at.asitplus.eidas.specific.modules.auth.eidas.v2.Constants;
+import at.asitplus.eidas.specific.modules.auth.eidas.v2.dao.SimpleEidasData;
import at.asitplus.eidas.specific.modules.auth.eidas.v2.exception.EidPostProcessingException;
import at.asitplus.eidas.specific.modules.auth.eidas.v2.exception.EidasAttributeException;
import at.asitplus.eidas.specific.modules.auth.eidas.v2.service.EidasAttributeRegistry;
@@ -47,15 +51,11 @@ import at.gv.egiz.eaaf.core.api.IRequest;
import at.gv.egiz.eaaf.core.api.data.EaafConstants;
import at.gv.egiz.eaaf.core.api.idp.IConfigurationWithSP;
import at.gv.egiz.eaaf.core.api.idp.ISpConfiguration;
-
import eu.eidas.auth.commons.attribute.AttributeDefinition;
import eu.eidas.auth.commons.attribute.ImmutableAttributeMap;
import eu.eidas.auth.commons.light.impl.LightRequest.Builder;
import eu.eidas.auth.commons.protocol.eidas.SpType;
-import static at.asitplus.eidas.specific.modules.auth.eidas.v2.utils.EidasResponseUtils.processCountryCode;
-import static at.asitplus.eidas.specific.modules.auth.eidas.v2.utils.EidasResponseUtils.processDateOfBirthToString;
-
public abstract class AbstractEidProcessor implements INationalEidProcessor {
private static final Logger log = LoggerFactory.getLogger(AbstractEidProcessor.class);
@@ -77,19 +77,26 @@ public abstract class AbstractEidProcessor implements INationalEidProcessor {
public final SimpleEidasData postProcess(Map eidasAttrMap) throws EidPostProcessingException,
EidasAttributeException {
SimpleEidasData.SimpleEidasDataBuilder builder = SimpleEidasData.builder()
+ .personalIdentifier(EidasResponseUtils.processPersonalIdentifier(
+ eidasAttrMap.get(Constants.eIDAS_ATTR_PERSONALIDENTIFIER)))
+
// MDS attributes
.citizenCountryCode(processCountryCode(eidasAttrMap.get(Constants.eIDAS_ATTR_PERSONALIDENTIFIER)))
.pseudonym(processPseudonym(eidasAttrMap.get(Constants.eIDAS_ATTR_PERSONALIDENTIFIER)))
.familyName(processFamilyName(eidasAttrMap.get(Constants.eIDAS_ATTR_CURRENTFAMILYNAME)))
.givenName(processGivenName(eidasAttrMap.get(Constants.eIDAS_ATTR_CURRENTGIVENNAME)))
.dateOfBirth(processDateOfBirthToString(eidasAttrMap.get(Constants.eIDAS_ATTR_DATEOFBIRTH)))
+
// additional attributes
.placeOfBirth(processPlaceOfBirth(eidasAttrMap.get(Constants.eIDAS_ATTR_PLACEOFBIRTH)))
.birthName(processBirthName(eidasAttrMap.get(Constants.eIDAS_ATTR_BIRTHNAME)))
.address(processAddress(eidasAttrMap.get(Constants.eIDAS_ATTR_CURRENTADDRESS)));
+
if (eidasAttrMap.containsKey(Constants.eIDAS_ATTR_TAXREFERENCE)) {
builder.taxNumber(EidasResponseUtils.processTaxReference(eidasAttrMap.get(Constants.eIDAS_ATTR_TAXREFERENCE)));
+
}
+
return builder.build();
}
diff --git a/eidas_modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/handler/CountrySpecificDetailSearchProcessor.java b/eidas_modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/handler/CountrySpecificDetailSearchProcessor.java
index 6e8f7fce..c2a62f5c 100644
--- a/eidas_modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/handler/CountrySpecificDetailSearchProcessor.java
+++ b/eidas_modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/handler/CountrySpecificDetailSearchProcessor.java
@@ -23,8 +23,10 @@
package at.asitplus.eidas.specific.modules.auth.eidas.v2.handler;
-import at.asitplus.eidas.specific.modules.auth.eidas.v2.dao.MergedRegisterSearchResult;
+import javax.annotation.Nonnull;
+
import at.asitplus.eidas.specific.modules.auth.eidas.v2.dao.SimpleEidasData;
+import at.gv.bmi.namespace.zmr_su.zmr._20040201.PersonSuchenRequest;
public interface CountrySpecificDetailSearchProcessor {
@@ -37,11 +39,18 @@ public interface CountrySpecificDetailSearchProcessor {
* Check if this postProcessor is sensitive for a specific country.
*
* @param countryCode of the eID data that should be processed
- * @param eidData eID data
+ * @param eidData eID information from eIDAS Proxy-Service
* @return true if this implementation can handle the country, otherwise false
*/
boolean canHandle(String countryCode, SimpleEidasData eidData);
- MergedRegisterSearchResult search(SimpleEidasData eidData);
+ /**
+ * Builds a country-specific search person request for ZMR.
+ *
+ * @param eidData eID information from eIDAS Proxy-Service
+ * @return {@link PersonSuchenRequest} but never null
+ */
+ @Nonnull
+ PersonSuchenRequest generateSearchRequest(SimpleEidasData eidData);
}
diff --git a/eidas_modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/handler/DeSpecificDetailSearchProcessor.java b/eidas_modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/handler/DeSpecificDetailSearchProcessor.java
index 904c41a1..802fde14 100644
--- a/eidas_modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/handler/DeSpecificDetailSearchProcessor.java
+++ b/eidas_modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/handler/DeSpecificDetailSearchProcessor.java
@@ -23,40 +23,39 @@
package at.asitplus.eidas.specific.modules.auth.eidas.v2.handler;
+import org.apache.commons.lang3.StringUtils;
+
import at.asitplus.eidas.specific.modules.auth.eidas.v2.Constants;
-import at.asitplus.eidas.specific.modules.auth.eidas.v2.dao.MergedRegisterSearchResult;
import at.asitplus.eidas.specific.modules.auth.eidas.v2.dao.SimpleEidasData;
-import at.asitplus.eidas.specific.modules.auth.eidas.v2.service.RegisterSearchService;
+import at.gv.bmi.namespace.zmr_su.zmr._20040201.EidasSuchdatenType;
+import at.gv.bmi.namespace.zmr_su.zmr._20040201.PersonSuchenRequest;
public class DeSpecificDetailSearchProcessor implements CountrySpecificDetailSearchProcessor {
- private final RegisterSearchService registerSearchService;
-
- public DeSpecificDetailSearchProcessor(RegisterSearchService registerSearchService) {
- this.registerSearchService = registerSearchService;
- }
-
@Override
public String getName() {
- return this.getClass().getName();
+ return this.getClass().getSimpleName();
}
@Override
public boolean canHandle(String countryCode, SimpleEidasData eidData) {
- if (!countryCode.equalsIgnoreCase(Constants.COUNTRY_CODE_DE)) {
- return false;
- }
- if (eidData.getBirthName() == null || eidData.getBirthName().isEmpty()) {
- return false;
- }
- if (eidData.getPlaceOfBirth() == null || eidData.getPlaceOfBirth().isEmpty()) {
- return false;
- }
- return true;
+ return countryCode.equalsIgnoreCase(Constants.COUNTRY_CODE_DE)
+ && StringUtils.isNotEmpty(eidData.getBirthName())
+ && StringUtils.isNotEmpty(eidData.getPlaceOfBirth());
+
}
@Override
- public MergedRegisterSearchResult search(SimpleEidasData eidData) {
- return registerSearchService.searchDeSpecific(eidData);
+ public PersonSuchenRequest generateSearchRequest(SimpleEidasData eidData) {
+
+ PersonSuchenRequest req = new PersonSuchenRequest();
+ EidasSuchdatenType eidasInfos = new EidasSuchdatenType();
+ req.setEidasSuchdaten(eidasInfos);
+
+
+ //TODO: how we can search for more than one eIDAS attribute as a Set
+
+
+ return req;
}
}
diff --git a/eidas_modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/handler/ItSpecificDetailSearchProcessor.java b/eidas_modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/handler/ItSpecificDetailSearchProcessor.java
index 7e74a85c..b49c355d 100644
--- a/eidas_modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/handler/ItSpecificDetailSearchProcessor.java
+++ b/eidas_modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/handler/ItSpecificDetailSearchProcessor.java
@@ -23,37 +23,31 @@
package at.asitplus.eidas.specific.modules.auth.eidas.v2.handler;
+import org.apache.commons.lang3.StringUtils;
+
import at.asitplus.eidas.specific.modules.auth.eidas.v2.Constants;
-import at.asitplus.eidas.specific.modules.auth.eidas.v2.dao.MergedRegisterSearchResult;
import at.asitplus.eidas.specific.modules.auth.eidas.v2.dao.SimpleEidasData;
-import at.asitplus.eidas.specific.modules.auth.eidas.v2.service.RegisterSearchService;
+import at.gv.bmi.namespace.zmr_su.zmr._20040201.PersonSuchenRequest;
public class ItSpecificDetailSearchProcessor implements CountrySpecificDetailSearchProcessor {
- private final RegisterSearchService registerSearchService;
-
- public ItSpecificDetailSearchProcessor(RegisterSearchService registerSearchService) {
- this.registerSearchService = registerSearchService;
- }
-
@Override
public String getName() {
- return this.getClass().getName();
+ return this.getClass().getSimpleName();
}
@Override
public boolean canHandle(String countryCode, SimpleEidasData eidData) {
- if (!countryCode.equalsIgnoreCase(Constants.COUNTRY_CODE_IT)) {
- return false;
- }
- if (eidData.getTaxNumber() == null || eidData.getTaxNumber().isEmpty()) {
- return false;
- }
- return true;
+ return countryCode.equalsIgnoreCase(Constants.COUNTRY_CODE_IT)
+ && StringUtils.isNotEmpty(eidData.getTaxNumber());
+
}
@Override
- public MergedRegisterSearchResult search(SimpleEidasData eidData) {
- return registerSearchService.searchItSpecific(eidData);
+ public PersonSuchenRequest generateSearchRequest(SimpleEidasData eidData) {
+
+ //TODO: add IT specific search request if TaxNumber attribute is defined by IT
+ return new PersonSuchenRequest();
+
}
}
diff --git a/eidas_modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/service/RegisterSearchService.java b/eidas_modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/service/RegisterSearchService.java
index 6b524e36..166ffafb 100644
--- a/eidas_modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/service/RegisterSearchService.java
+++ b/eidas_modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/service/RegisterSearchService.java
@@ -1,18 +1,28 @@
package at.asitplus.eidas.specific.modules.auth.eidas.v2.service;
-import at.asitplus.eidas.specific.modules.auth.eidas.v2.dao.MergedRegisterSearchResult;
+import java.math.BigInteger;
+import java.util.Collections;
+import java.util.List;
+
+import javax.annotation.Nonnull;
+
+import org.jetbrains.annotations.Nullable;
+import org.springframework.stereotype.Service;
+
+import at.asitplus.eidas.specific.modules.auth.eidas.v2.clients.zmr.IZmrClient;
+import at.asitplus.eidas.specific.modules.auth.eidas.v2.clients.zmr.ZmrSoapClient.ZmrRegisterResult;
import at.asitplus.eidas.specific.modules.auth.eidas.v2.dao.RegisterResult;
import at.asitplus.eidas.specific.modules.auth.eidas.v2.dao.SimpleEidasData;
import at.asitplus.eidas.specific.modules.auth.eidas.v2.ernp.IErnpClient;
+import at.asitplus.eidas.specific.modules.auth.eidas.v2.exception.EidasSAuthenticationException;
import at.asitplus.eidas.specific.modules.auth.eidas.v2.exception.WorkflowException;
-import at.asitplus.eidas.specific.modules.auth.eidas.v2.zmr.IZmrClient;
-import at.gv.egiz.eaaf.core.api.IRequest;
-import at.gv.egiz.eaaf.core.exceptions.TaskExecutionException;
+import at.asitplus.eidas.specific.modules.auth.eidas.v2.exception.ZmrCommunicationException;
+import at.asitplus.eidas.specific.modules.auth.eidas.v2.handler.CountrySpecificDetailSearchProcessor;
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+import lombok.RequiredArgsConstructor;
+import lombok.Setter;
import lombok.extern.slf4j.Slf4j;
-import org.springframework.stereotype.Service;
-
-import java.util.Collections;
-import java.util.List;
@Slf4j
@Service("registerSearchService")
@@ -21,99 +31,277 @@ public class RegisterSearchService {
private final IZmrClient zmrClient;
private final IErnpClient ernpClient;
- public RegisterSearchService(IZmrClient zmrClient, IErnpClient ernpClient) {
+ private final List handlers;
+
+ /**
+ * Service that combines ZMR and ERnP register search operations.
+ *
+ * @param handlers Available country-specific search processors
+ * @param zmrClient ZMR client
+ * @param ernpClient ERnP client
+ */
+ public RegisterSearchService(List handlers, IZmrClient zmrClient,
+ IErnpClient ernpClient) {
this.zmrClient = zmrClient;
this.ernpClient = ernpClient;
+ this.handlers = handlers;
+ log.info("Init with #{} search services for country-specific details", handlers.size());
+
}
/**
- * Automatic process to fix the register entries.
+ * Search with Person Identifier (eIDAS Pseudonym) in ZMR and ERnP.
*
- * @param initialSearchResult Result of initial register search
- * @param specificSearchResult Result of last register search
- * @param eidasData Received eidas data
- * @param pendingReq Pending request
- * @return The bpk
- * @throws TaskExecutionException if an error occurs during the register update
+ * @param eidasData Received eIDAS data
+ * @throws WorkflowException In case of a register interaction error
*/
- public String step7aKittProcess(MergedRegisterSearchResult initialSearchResult,
- MergedRegisterSearchResult specificSearchResult,
- SimpleEidasData eidasData,
- IRequest pendingReq) throws TaskExecutionException {
- log.trace("Starting step7aKittProcess");
- // TODO verify with which data this method gets called
+ @Nonnull
+ public RegisterSearchResult searchWithPersonIdentifier(SimpleEidasData eidasData)
+ throws WorkflowException {
try {
- if (initialSearchResult.getResultCount() != 0) {
- throw new WorkflowException("initialSearchResult.getResultCount() != 0");
- }
- if (specificSearchResult.getResultCount() != 1) {
- throw new WorkflowException("specificSearchResult.getResultCount() != 1");
- }
- if (specificSearchResult.getResultsZmr().size() == 1) {
- zmrClient.update(specificSearchResult.getResultsZmr().get(0), eidasData);
- }
- if (specificSearchResult.getResultsErnp().size() == 1) {
- ernpClient.update(specificSearchResult.getResultsErnp().get(0), eidasData);
- }
- return specificSearchResult.getBpk();
- } catch (WorkflowException e) {
- throw new TaskExecutionException(pendingReq, "Step7a failed.", e);
+ final ZmrRegisterResult resultsZmr = zmrClient.searchWithPersonIdentifier(
+ null, eidasData.getPersonalIdentifier());
+ final List resultsErnp = ernpClient.searchWithPersonIdentifier(
+ eidasData.getPersonalIdentifier());
+
+ return new RegisterSearchResult(new RegisterOperationStatus(resultsZmr.getProcessId()),
+ resultsZmr.getPersonResult(), resultsErnp);
+
+ } catch (final EidasSAuthenticationException e) {
+ throw new WorkflowException("searchWithPersonalIdentifier", e.getMessage(),
+ !(e instanceof ZmrCommunicationException), e);
+
}
}
/**
* Search with MDS (Given Name, Family Name, Date of Birth) in ZMR and ERnP.
+ *
+ * @param operationStatus Current register-operation status that contains processing informations
+ * @param eidasData Received eIDAS data
+ * @throws WorkflowException In case of a register interaction error
*/
- public MergedRegisterSearchResult searchWithMds(SimpleEidasData eidasData) {
- List resultsZmr =
- zmrClient.searchWithMds(eidasData.getGivenName(), eidasData.getFamilyName(), eidasData.getDateOfBirth());
- List resultsErnp =
- ernpClient.searchWithMds(eidasData.getGivenName(), eidasData.getFamilyName(), eidasData.getDateOfBirth());
- return new MergedRegisterSearchResult(resultsZmr, resultsErnp);
+ @Nonnull
+ public RegisterSearchResult searchWithMds(RegisterOperationStatus operationStatus, SimpleEidasData eidasData)
+ throws WorkflowException {
+ try {
+ final ZmrRegisterResult resultsZmr =
+ zmrClient.searchWithMds(operationStatus.getZmrProcessId(), eidasData.getGivenName(),
+ eidasData.getFamilyName(), eidasData.getDateOfBirth(), eidasData.getCitizenCountryCode());
+
+ final List resultsErnp =
+ ernpClient.searchWithMds(eidasData.getGivenName(), eidasData.getFamilyName(), eidasData
+ .getDateOfBirth());
+
+ return new RegisterSearchResult(new RegisterOperationStatus(resultsZmr.getProcessId()),
+ resultsZmr.getPersonResult(), resultsErnp);
+
+ } catch (final EidasSAuthenticationException e) {
+ throw new WorkflowException("searchWithMDSOnly", e.getMessage(),
+ !(e instanceof ZmrCommunicationException), e);
+
+ }
}
/**
- * Search with Person Identifier (eIDAS Pseudonym) in ZMR and ERnP.
+ * Search with country-specific parameters based on information from available
+ * {@link CountrySpecificDetailSearchProcessor} implementations.
+ *
+ * @param operationStatus Current register-operation status that contains processing informations
+ * @param eidasData Receive eIDAS eID information
+ * @return Results from ZMR or ERnP search
+ * @throws WorkflowException In case of a register interaction error
*/
- public MergedRegisterSearchResult searchWithPersonIdentifier(SimpleEidasData eidasData) {
- List resultsZmr = zmrClient.searchWithPersonIdentifier(eidasData.getPseudonym());
- List resultsErnp = ernpClient.searchWithPersonIdentifier(eidasData.getPseudonym());
- return new MergedRegisterSearchResult(resultsZmr, resultsErnp);
+ @Nonnull
+ public RegisterSearchResult searchWithCountrySpecifics(RegisterOperationStatus operationStatus,
+ SimpleEidasData eidasData) throws WorkflowException {
+ try {
+ @Nullable
+ final CountrySpecificDetailSearchProcessor ccSpecificProcessor = findSpecificProcessor(eidasData);
+ if (ccSpecificProcessor != null) {
+ log.debug("Selecting country-specific search processor: {}", ccSpecificProcessor.getName());
+ final ZmrRegisterResult resultsZmr =
+ zmrClient.searchCountrySpecific(operationStatus.getZmrProcessId(),
+ ccSpecificProcessor.generateSearchRequest(eidasData),
+ eidasData.getCitizenCountryCode());
+
+ // TODO: add search procesfor for ERnP searching
+ return new RegisterSearchResult(operationStatus, resultsZmr.getPersonResult(), Collections.emptyList());
+
+ } else {
+ return new RegisterSearchResult(operationStatus, Collections.emptyList(), Collections.emptyList());
+
+ }
+
+ } catch (final EidasSAuthenticationException e) {
+ throw new WorkflowException("searchWithCountrySpecifics", e.getMessage(),
+ !(e instanceof ZmrCommunicationException), e);
+
+ }
}
/**
- * Search with Tax Number in ZMR and ERnP.
+ * Search with BPK-ZP in BMR and ERnP.
*/
- public MergedRegisterSearchResult searchItSpecific(SimpleEidasData eidasData) {
- List resultsZmr = zmrClient.searchItSpecific(eidasData.getTaxNumber());
- List resultsErnb = ernpClient.searchItSpecific(eidasData.getTaxNumber());
- return new MergedRegisterSearchResult(resultsZmr, resultsErnb);
+ public RegisterSearchResult searchWithBpkZp(RegisterOperationStatus operationStatus, String bpkZp) {
+ final ZmrRegisterResult resultsZmr = zmrClient.searchWithBpkZp(
+ operationStatus.getZmrProcessId(), bpkZp);
+ final List resultsErnp = ernpClient.searchWithBpkZp(bpkZp);
+ return new RegisterSearchResult(operationStatus, resultsZmr.getPersonResult(), resultsErnp);
+
}
/**
- * Search with Given Name, Family Name, Date of Birth, Place of Birth and Birth Name in ZMR and ERnP.
+ * Search with residence infos.
+ *
+ * @param operationStatus Current register-operation status that contains processing informations
+ * @param zipcode Provided Zipcode
+ * @param city Provided City
+ * @param street Provided street
+ * @return Results from ZMR or ERnP search
*/
- public MergedRegisterSearchResult searchDeSpecific(SimpleEidasData eidasData) {
- List resultsZmr =
- zmrClient.searchDeSpecific(eidasData.getGivenName(), eidasData.getFamilyName(), eidasData.getDateOfBirth(),
- eidasData.getPlaceOfBirth(), eidasData.getBirthName());
- List resultsErnb =
- ernpClient.searchDeSpecific(eidasData.getGivenName(), eidasData.getFamilyName(), eidasData.getDateOfBirth(),
- eidasData.getPlaceOfBirth(), eidasData.getBirthName());
- return new MergedRegisterSearchResult(resultsZmr, resultsErnb);
+ public RegisterSearchResult searchWithResidence(RegisterOperationStatus operationStatus, SimpleEidasData eidasData,
+ String zipcode, String city, String street) {
+ final ZmrRegisterResult resultsZmr = zmrClient.searchWithResidenceData(
+ operationStatus.getZmrProcessId(), eidasData.getGivenName(), eidasData.getFamilyName(),
+ eidasData.getDateOfBirth(), zipcode, city, street);
+ return new RegisterSearchResult(operationStatus, resultsZmr.getPersonResult(), Collections.emptyList());
+
}
/**
- * Search with BPK-ZP in BMR and ERnP.
+ * Automatic process to fix the register entries.
+ *
+ * @param specificSearchResult Result of last register search
+ * @param eidasData Received eidas data
+ */
+ public void step7aKittProcess(RegisterSearchResult specificSearchResult,
+ SimpleEidasData eidasData) throws WorkflowException {
+ log.trace("Starting step7aKittProcess");
+ // TODO verify with which data this method gets called
+ if (specificSearchResult.getResultCount() != 1) {
+ throw new WorkflowException("step7aKittProcess", "getResultCount() != 1");
+
+ }
+
+ if (specificSearchResult.getResultsZmr().size() == 1) {
+ zmrClient.update(specificSearchResult.getOperationStatus().getZmrProcessId(),
+
+ specificSearchResult.getResultsZmr().get(0), eidasData);
+ }
+
+ if (specificSearchResult.getResultsErnp().size() == 1) {
+ ernpClient.update(specificSearchResult.getResultsErnp().get(0), eidasData);
+
+ }
+
+ }
+
+ @Nullable
+ private CountrySpecificDetailSearchProcessor findSpecificProcessor(SimpleEidasData eidasData) {
+ final String citizenCountry = eidasData.getCitizenCountryCode();
+ for (final CountrySpecificDetailSearchProcessor processor : handlers) {
+ if (processor.canHandle(citizenCountry, eidasData)) {
+ log.debug("Found suitable search handler for {} by using: {}", citizenCountry, processor.getName());
+ return processor;
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Register releated information that are needed for any request.
+ *
+ * @author tlenz
+ *
*/
- public MergedRegisterSearchResult searchWithBpkZp(String bpkZp) {
- List resultsZmr = zmrClient.searchWithBpkZp(bpkZp);
- List resultsErnp = ernpClient.searchWithBpkZp(bpkZp);
- return new MergedRegisterSearchResult(resultsZmr, resultsErnp);
+ @AllArgsConstructor
+ @Getter
+ public static class RegisterOperationStatus {
+
+ /**
+ * ZMR internal processId that is required for any further request in the same process.
+ */
+ private BigInteger zmrProcessId;
+
+
}
+
+ /**
+ * Response container for {@link RegisterSearchService}.
+ *
+ * @author tlenz
+ *
+ */
+ @Getter
+ @RequiredArgsConstructor
+ public static class RegisterSearchResult {
+
+ /**
+ * Mark the register result finished.
+ */
+ @Setter
+ private boolean matchingFinished = false;
+
+ /**
+ * Operation status for this result.
+ */
+ private final RegisterOperationStatus operationStatus;
+
+ /**
+ * Current ZMR search result.
+ */
+ private final List resultsZmr;
+
+ /**
+ * Current ERnP search result.
+ */
+ private final List resultsErnp;
+
+
+ /**
+ * Get sum of ZMR and ERnP results.
+ *
+ * @return number of results
+ */
+ public int getResultCount() {
+ return resultsZmr.size() + resultsErnp.size();
+ }
+
+ /**
+ * Verifies that there is only one match and returns the bpk.
+ *
+ * @return bpk bpk of the match
+ * @throws WorkflowException if multiple results have been found or matching is not marked as finished
+ */
+ public String getBpk() throws WorkflowException {
+ if (getResultCount() != 1 || !matchingFinished) {
+ throw new WorkflowException("readRegisterResults",
+ matchingFinished ? "getResultCount() != 1" : "matching prozess not finished yet");
+
+ }
+ return getResult().getBpk();
+ }
- public MergedRegisterSearchResult searchWithResidence(String zipcode, String city, String street) {
- List resultsZmr = zmrClient.searchWithResidenceData(zipcode, city, street);
- return new MergedRegisterSearchResult(resultsZmr, Collections.emptyList());
+ /**
+ * Returns the results, if there is exactly one, throws exception otherwise.
+ *
+ * @return The result
+ * @throws WorkflowException Results does not contain exactly one result
+ */
+ public RegisterResult getResult() throws WorkflowException {
+ if (getResultCount() != 1) {
+ throw new WorkflowException("readRegisterResults", "getResultCount() != 1");
+ }
+ if (resultsZmr.size() == 1) {
+ return resultsZmr.get(0);
+
+ } else {
+ return resultsErnp.get(0);
+
+ }
+ }
+
}
+
}
diff --git a/eidas_modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/szr/SzrClient.java b/eidas_modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/szr/SzrClient.java
deleted file mode 100644
index 2d612f0c..00000000
--- a/eidas_modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/szr/SzrClient.java
+++ /dev/null
@@ -1,601 +0,0 @@
-/*
- * Copyright 2018 A-SIT Plus GmbH
- * AT-specific eIDAS Connector has been developed in a cooperation between EGIZ,
- * A-SIT Plus GmbH, A-SIT, and Graz University of Technology.
- *
- * Licensed under the EUPL, Version 1.2 or - as soon they will be approved by
- * the European Commission - subsequent versions of the EUPL (the "License");
- * You may not use this work except in compliance with the License.
- * You may obtain a copy of the License at:
- * https://joinup.ec.europa.eu/news/understanding-eupl-v12
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" basis,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- * 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.asitplus.eidas.specific.modules.auth.eidas.v2.szr;
-
-import java.io.ByteArrayInputStream;
-import java.io.ByteArrayOutputStream;
-import java.io.IOException;
-import java.net.URL;
-import java.nio.charset.StandardCharsets;
-import java.security.KeyManagementException;
-import java.security.KeyStore;
-import java.security.KeyStoreException;
-import java.security.NoSuchAlgorithmException;
-import java.security.SecureRandom;
-import java.security.UnrecoverableKeyException;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-
-import javax.annotation.PostConstruct;
-import javax.net.ssl.KeyManager;
-import javax.net.ssl.KeyManagerFactory;
-import javax.net.ssl.SSLContext;
-import javax.net.ssl.TrustManager;
-import javax.net.ssl.TrustManagerFactory;
-import javax.xml.XMLConstants;
-import javax.xml.bind.JAXBContext;
-import javax.xml.bind.Marshaller;
-import javax.xml.namespace.QName;
-import javax.xml.transform.Source;
-import javax.xml.transform.Transformer;
-import javax.xml.transform.TransformerException;
-import javax.xml.transform.TransformerFactory;
-import javax.xml.transform.stream.StreamResult;
-import javax.xml.transform.stream.StreamSource;
-import javax.xml.ws.BindingProvider;
-import javax.xml.ws.Dispatch;
-import javax.xml.ws.handler.Handler;
-
-import at.asitplus.eidas.specific.modules.auth.eidas.v2.dao.SimpleEidasData;
-import at.gv.e_government.reference.namespace.persondata._20020228.AlternativeNameType;
-import at.gv.e_government.reference.namespace.persondata._20020228.PersonNameType;
-import at.gv.e_government.reference.namespace.persondata._20020228.PhysicalPersonType;
-import org.apache.commons.lang3.StringUtils;
-import org.apache.cxf.configuration.jsse.TLSClientParameters;
-import org.apache.cxf.endpoint.Client;
-import org.apache.cxf.frontend.ClientProxy;
-import org.apache.cxf.jaxws.DispatchImpl;
-import org.apache.cxf.transport.http.HTTPConduit;
-import org.apache.cxf.transports.http.configuration.HTTPClientPolicy;
-import org.apache.xpath.XPathAPI;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.stereotype.Service;
-import org.w3c.dom.Document;
-import org.w3c.dom.Element;
-
-import com.fasterxml.jackson.core.JsonProcessingException;
-import com.fasterxml.jackson.databind.ObjectMapper;
-
-import at.asitplus.eidas.specific.modules.auth.eidas.v2.Constants;
-import at.asitplus.eidas.specific.modules.auth.eidas.v2.exception.SzrCommunicationException;
-import at.asitplus.eidas.specific.modules.auth.eidas.v2.utils.LoggingHandler;
-import at.gv.egiz.eaaf.core.api.data.PvpAttributeDefinitions;
-import at.gv.egiz.eaaf.core.api.data.XmlNamespaceConstants;
-import at.gv.egiz.eaaf.core.api.idp.IConfiguration;
-import at.gv.egiz.eaaf.core.impl.utils.DomUtils;
-import at.gv.egiz.eaaf.core.impl.utils.FileUtils;
-import at.gv.egiz.eaaf.core.impl.utils.KeyStoreUtils;
-import szrservices.GetBPK;
-import szrservices.GetBPKResponse;
-import szrservices.GetIdentityLinkEidas;
-import szrservices.GetIdentityLinkEidasResponse;
-import szrservices.IdentityLinkType;
-import szrservices.JwsHeaderParam;
-import szrservices.ObjectFactory;
-import szrservices.PersonInfoType;
-import szrservices.SZR;
-import szrservices.SZRException_Exception;
-import szrservices.SignContent;
-import szrservices.SignContentEntry;
-import szrservices.SignContentResponseType;
-import szrservices.TravelDocumentType;
-
-
-@Service("SZRClientForeIDAS")
-public class SzrClient {
- private static final Logger log = LoggerFactory.getLogger(SzrClient.class);
-
- private static final String CLIENT_DEFAULT = "DefaultClient";
- private static final String CLIENT_RAW = "RawClient";
-
- private static final String ATTR_NAME_VSZ = "urn:eidgvat:attributes.vsz.value";
- private static final String ATTR_NAME_PUBKEYS = "urn:eidgvat:attributes.user.pubkeys";
- private static final String ATTR_NAME_STATUS = "urn:eidgvat:attributes.eid.status";
- private static final String KEY_BC_BIND = "bcBindReq";
- private static final String JOSE_HEADER_USERCERTPINNING_TYPE = "urn:at.gv.eid:bindtype";
- private static final String JOSE_HEADER_USERCERTPINNING_EIDASBIND = "urn:at.gv.eid:eidasBind";
- public static final String ATTR_NAME_MDS = "urn:eidgvat:mds";
-
- @SuppressWarnings("SpringJavaInjectionPointsAutowiringInspection")
- @Autowired
- private IConfiguration basicConfig;
-
- // client for anything, without identitylink
- private SZR szr = null;
-
- // RAW client is needed for identitylink
- private Dispatch dispatch = null;
-
- final ObjectMapper mapper = new ObjectMapper();
-
- /**
- * Get IdentityLink of a person.
- *
- *
- * @param eidData minimum dataset of person
- * @return IdentityLink
- * @throws SzrCommunicationException In case of a SZR error
- */
- public IdentityLinkType getIdentityLinkInRawMode(SimpleEidasData eidData)
- throws SzrCommunicationException {
- try {
- final GetIdentityLinkEidas getIdl = new GetIdentityLinkEidas();
- getIdl.setPersonInfo(generateSzrRequest(eidData));
-
- final JAXBContext jaxbContext = JAXBContext.newInstance(ObjectFactory.class);
- final Marshaller jaxbMarshaller = jaxbContext.createMarshaller();
-
- final ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
- jaxbMarshaller.marshal(getIdl, outputStream);
- outputStream.flush();
-
- final Source source = new StreamSource(new ByteArrayInputStream(outputStream.toByteArray()));
- outputStream.close();
-
- log.trace("Requesting SZR ... ");
- final Source response = dispatch.invoke(source);
- log.trace("Receive RAW response from SZR");
-
- final byte[] szrResponse = sourceToByteArray(response);
- final GetIdentityLinkEidasResponse jaxbElement = (GetIdentityLinkEidasResponse) jaxbContext
- .createUnmarshaller().unmarshal(new ByteArrayInputStream(szrResponse));
-
- // build response
- log.trace(new String(szrResponse, StandardCharsets.UTF_8));
-
- // ok, we have success
- final Document doc = DomUtils.parseDocument(
- new ByteArrayInputStream(szrResponse),
- true,
- XmlNamespaceConstants.ALL_SCHEMA_LOCATIONS + " " + Constants.SZR_SCHEMA_LOCATIONS,
- null, null);
- final String xpathExpression = "//saml:Assertion";
- final Element nsNode = doc.createElementNS("urn:oasis:names:tc:SAML:1.0:assertion", "saml:NSNode");
-
- log.trace("Selecting signed doc " + xpathExpression);
- final Element documentNode = (Element) XPathAPI.selectSingleNode(doc,
- xpathExpression, nsNode);
- log.trace("Signed document: " + DomUtils.serializeNode(documentNode));
-
- final IdentityLinkType idl = new IdentityLinkType();
- idl.setAssertion(documentNode);
- idl.setPersonInfo(jaxbElement.getGetIdentityLinkReturn().getPersonInfo());
-
- return idl;
-
- } catch (final Exception e) {
- log.warn("SZR communication FAILED. Reason: " + e.getMessage(), e);
- throw new SzrCommunicationException("ernb.02", new Object[]{e.getMessage()}, e);
-
- }
-
- }
-
- /**
- * Get bPK of person.
- *
- *
- * @param eidData Minimum dataset of person
- * @param target requested bPK target
- * @param vkz Verfahrenskennzeichen
- * @return bPK for this person
- * @throws SzrCommunicationException In case of a SZR error
- */
- public List getBpk(SimpleEidasData eidData, String target, String vkz)
- throws SzrCommunicationException {
- try {
- final GetBPK parameters = new GetBPK();
- parameters.setPersonInfo(generateSzrRequest(eidData));
- parameters.getBereichsKennung().add(target);
- parameters.setVKZ(vkz);
- final GetBPKResponse result = this.szr.getBPK(parameters);
-
- return result.getGetBPKReturn();
-
- } catch (final SZRException_Exception e) {
- log.warn("SZR communication FAILED. Reason: " + e.getMessage(), e);
- throw new SzrCommunicationException("ernb.02", new Object[]{e.getMessage()}, e);
-
- }
-
- }
-
- /**
- * Creates a new ERnP entry.
- * TODO Is this correct? Ask BMI.
- *
- * @param eidasData Minimum dataset of person
- * @return encrypted baseId
- * @throws SzrCommunicationException In case of a SZR error
- */
- public String createNewErnpEntry(final SimpleEidasData eidasData) throws SzrCommunicationException {
- final String resp;
- try {
- resp = this.szr.getStammzahlEncrypted(generateSzrRequest(eidasData), true);
- } catch (SZRException_Exception e) {
- throw new SzrCommunicationException("ernb.02", new Object[]{e.getMessage()}, e);
- }
- if (StringUtils.isEmpty(resp)) {
- throw new SzrCommunicationException("ernb.01", new Object[]{"Stammzahl response empty"}); // TODO error handling
- }
- return resp;
- }
-
- /**
- * Request a encrypted baseId from SZR.
- *
- * Note: Previously, this method did create a new ERnP entry, if it did not exist. This is
- * not the case any more. See {@link #createNewErnpEntry(SimpleEidasData)} for that functionality.
- *
- * @param eidData Minimum dataset of person
- * @return encrypted baseId
- * @throws SzrCommunicationException In case of a SZR error
- */
- public String getEncryptedStammzahl(final SimpleEidasData eidData)
- throws SzrCommunicationException {
- final String resp;
- try {
- resp = this.szr.getStammzahlEncrypted(generateSzrRequest(eidData), false);
- } catch (SZRException_Exception e) {
- throw new SzrCommunicationException("ernb.02", new Object[]{e.getMessage()}, e);
- }
-
- if (StringUtils.isEmpty(resp)) {
- throw new SzrCommunicationException("ernb.01", new Object[]{"Stammzahl response empty"}); // TODO error handling
- }
-
- return resp;
-
- }
-
- /**
- * Sign an eidasBind data-structure that combines vsz with user's pubKey and E-ID status.
- *
- * @param vsz encrypted baseId
- * @param bindingPubKey binding PublicKey as PKCS1# (ASN.1) container
- * @param eidStatus Status of the E-ID
- * @param eidData eID information that was used for ERnP registration
- * @return bPK for this person
- * @throws SzrCommunicationException In case of a SZR error
- */
- public String getEidasBind(final String vsz, final String bindingPubKey, final String eidStatus,
- SimpleEidasData eidData)throws SzrCommunicationException {
-
- final Map eidsaBindMap = new HashMap<>();
- eidsaBindMap.put(ATTR_NAME_VSZ, vsz);
- eidsaBindMap.put(ATTR_NAME_STATUS, eidStatus);
- eidsaBindMap.put(ATTR_NAME_PUBKEYS, Collections.singletonList(bindingPubKey));
- eidsaBindMap.put(PvpAttributeDefinitions.EID_ISSUING_NATION_NAME, eidData.getCitizenCountryCode());
- injectMdsIfAvailableAndActive(eidsaBindMap, eidData);
-
- try {
- final String serializedEidasBind = mapper.writeValueAsString(eidsaBindMap);
- final SignContent req = new SignContent();
- final SignContentEntry eidasBindInfo = new SignContentEntry();
- eidasBindInfo.setKey(KEY_BC_BIND);
- eidasBindInfo.setValue(serializedEidasBind);
- req.getIn().add(eidasBindInfo);
- req.setAppendCert(false);
- final JwsHeaderParam eidasBindJoseHeader = new JwsHeaderParam();
- eidasBindJoseHeader.setKey(JOSE_HEADER_USERCERTPINNING_TYPE);
- eidasBindJoseHeader.setValue(JOSE_HEADER_USERCERTPINNING_EIDASBIND);
- req.getJWSHeaderParam().add(eidasBindJoseHeader);
-
- log.trace("Requesting SZR to sign bcBind datastructure ... ");
- final SignContentResponseType resp = szr.signContent(req.isAppendCert(), req.getJWSHeaderParam(), req.getIn());
- log.trace("Receive SZR response on bcBind siging operation ");
-
- if (resp == null || resp.getOut() == null
- || resp.getOut().isEmpty()
- || StringUtils.isEmpty(resp.getOut().get(0).getValue())) {
- throw new SzrCommunicationException("ernb.01", new Object[]{"BcBind response empty"});
- }
-
- return resp.getOut().get(0).getValue();
-
- } catch (final JsonProcessingException | SZRException_Exception e) {
- log.warn("Requesting bcBind by using SZR FAILED.", e);
- throw new SzrCommunicationException("ernb.02",
- new Object[]{e.getMessage()}, e);
- }
- }
-
- private PersonInfoType generateSzrRequest(SimpleEidasData eidData) {
- log.debug("Starting connecting SZR Gateway");
- final PersonInfoType personInfo = new PersonInfoType();
- final PersonNameType personName = new PersonNameType();
- final PhysicalPersonType naturalPerson = new PhysicalPersonType();
- final TravelDocumentType eDocument = new TravelDocumentType();
-
- naturalPerson.setName(personName);
- personInfo.setPerson(naturalPerson);
- personInfo.setTravelDocument(eDocument);
-
- // person information
- personName.setFamilyName(eidData.getFamilyName());
- personName.setGivenName(eidData.getGivenName());
- naturalPerson.setDateOfBirth(eidData.getDateOfBirth());
- eDocument.setIssuingCountry(eidData.getCitizenCountryCode());
- eDocument.setDocumentNumber(eidData.getPseudonym());
-
- // eID document information
- String documentType = basicConfig
- .getBasicConfiguration(Constants.CONIG_PROPS_EIDAS_SZRCLIENT_PARAMS_EDOCUMENTTYPE,
- Constants.SZR_CONSTANTS_DEFAULT_DOCUMENT_TYPE);
- eDocument.setDocumentType(documentType);
-
- // set PlaceOfBirth if available
- if (eidData.getPlaceOfBirth() != null) {
- log.trace("Find 'PlaceOfBirth' attribute: " + eidData.getPlaceOfBirth());
- boolean setPlaceOfBirth = basicConfig
- .getBasicConfigurationBoolean(Constants.CONIG_PROPS_EIDAS_SZRCLIENT_PARAMS_SETPLACEOFBIRTHIFAVAILABLE, true);
- if (setPlaceOfBirth) {
- naturalPerson.setPlaceOfBirth(eidData.getPlaceOfBirth());
- log.trace("Adding 'PlaceOfBirth' to ERnB request ... ");
- }
- }
-
- // set BirthName if available
- if (eidData.getBirthName() != null) {
- log.trace("Find 'BirthName' attribute: " + eidData.getBirthName());
- boolean setBirthName = basicConfig
- .getBasicConfigurationBoolean(Constants.CONIG_PROPS_EIDAS_SZRCLIENT_PARAMS_SETBIRTHNAMEIFAVAILABLE, true);
- if (setBirthName) {
- final AlternativeNameType alternativeName = new AlternativeNameType();
- naturalPerson.setAlternativeName(alternativeName);
- alternativeName.setFamilyName(eidData.getBirthName());
- log.trace("Adding 'BirthName' to ERnB request ... ");
- }
- }
-
- return personInfo;
- }
-
- @PostConstruct
- private void initialize() {
- log.info("Starting SZR-Client initialization .... ");
- final URL url = SzrClient.class.getResource("/szr_client/SZR_v4.0.wsdl");
-
- final boolean useTestSzr = basicConfig.getBasicConfigurationBoolean(
- Constants.CONIG_PROPS_EIDAS_SZRCLIENT_USETESTSERVICE,
- true);
-
- SzrService szrService;
- QName qname;
- String szrUrl;
- if (useTestSzr) {
- log.debug("Initializing SZR test environment configuration.");
- qname = SzrService.SZRTestumgebung;
- szrService = new SzrService(url, new QName("urn:SZRServices", "SZRService"));
- szr = szrService.getSzrTestumgebung();
- szrUrl = basicConfig.getBasicConfiguration(Constants.CONIG_PROPS_EIDAS_SZRCLIENT_ENDPOINT_TEST);
-
- } else {
- log.debug("Initializing SZR productive configuration.");
- qname = SzrService.SZRProduktionsumgebung;
- szrService = new SzrService(url, new QName("urn:SZRServices", "SZRService"));
- szr = szrService.getSzrProduktionsumgebung();
- szrUrl = basicConfig.getBasicConfiguration(Constants.CONIG_PROPS_EIDAS_SZRCLIENT_ENDPOINT_PROD);
-
- }
-
- // create raw client;
- dispatch = szrService.createDispatch(qname, Source.class, javax.xml.ws.Service.Mode.PAYLOAD);
-
- if (StringUtils.isEmpty(szrUrl)) {
- log.error("No SZR service-URL found. SZR-Client initalisiation failed.");
- throw new RuntimeException("No SZR service URL found. SZR-Client initalisiation failed.");
-
- }
-
- // check if Clients can be initialized
- if (szr == null) {
- log.error("SZR " + CLIENT_DEFAULT + " is 'NULL'. Something goes wrong");
- throw new RuntimeException("SZR " + CLIENT_DEFAULT + " is 'NULL'. Something goes wrong");
-
- }
- if (dispatch == null) {
- log.error("SZR " + CLIENT_RAW + " is 'NULL'. Something goes wrong");
- throw new RuntimeException("SZR " + CLIENT_RAW + " is 'NULL'. Something goes wrong");
-
- }
-
- // inject handler
- log.info("Use SZR service-URL: " + szrUrl);
- injectBindingProvider((BindingProvider) szr, CLIENT_DEFAULT, szrUrl);
- injectBindingProvider(dispatch, CLIENT_RAW, szrUrl);
-
- // inject http parameters and SSL context
- log.debug("Inject HTTP client settings ... ");
- injectHttpClient(szr, CLIENT_DEFAULT, szrUrl);
- injectHttpClient(dispatch, CLIENT_RAW, szrUrl);
-
- log.info("SZR-Client initialization successfull");
- }
-
- private void injectHttpClient(Object raw, String clientType, String szrUrl) {
- // extract client from implementation
- Client client;
- if (raw instanceof DispatchImpl>) {
- client = ((DispatchImpl>) raw).getClient();
- } else if (raw instanceof Client) {
- client = ClientProxy.getClient(raw);
- } else {
- throw new RuntimeException("SOAP Client for SZR connection is of UNSUPPORTED type: " + raw.getClass()
- .getName());
- }
-
- // set basic connection policies
- final HTTPConduit http = (HTTPConduit) client.getConduit();
-
- // set timeout policy
- final HTTPClientPolicy httpClientPolicy = new HTTPClientPolicy();
- String connectionTimeout = basicConfig.getBasicConfiguration(
- Constants.CONIG_PROPS_EIDAS_SZRCLIENT_TIMEOUT_CONNECTION, Constants.HTTP_CLIENT_DEFAULT_TIMEOUT_CONNECTION);
- httpClientPolicy.setConnectionTimeout(Integer.parseInt(connectionTimeout) * 1000L);
- String responseTimeout = basicConfig.getBasicConfiguration(
- Constants.CONIG_PROPS_EIDAS_SZRCLIENT_TIMEOUT_RESPONSE, Constants.HTTP_CLIENT_DEFAULT_TIMEOUT_RESPONSE);
- httpClientPolicy.setReceiveTimeout(Integer.parseInt(responseTimeout) * 1000L);
- http.setClient(httpClientPolicy);
-
- // inject SSL context in case of https
- if (szrUrl.toLowerCase().startsWith("https")) {
- log.debug("Adding SSLContext to client: " + clientType + " ... ");
- final TLSClientParameters tlsParams = new TLSClientParameters();
- tlsParams.setSSLSocketFactory(createSslContext(clientType).getSocketFactory());
- http.setTlsClientParameters(tlsParams);
- log.info("SSLContext initialized for client: " + clientType);
-
- }
-
- }
-
- private void injectBindingProvider(BindingProvider bindingProvider, String clientType, String szrUrl) {
- final Map requestContext = bindingProvider.getRequestContext();
- requestContext.put(BindingProvider.ENDPOINT_ADDRESS_PROPERTY, szrUrl);
-
- log.trace("Adding JAX-WS request/response trace handler to client: " + clientType);
- List handlerList = bindingProvider.getBinding().getHandlerChain();
- if (handlerList == null) {
- handlerList = new ArrayList<>();
- bindingProvider.getBinding().setHandlerChain(handlerList);
-
- }
-
- // add logging handler to trace messages if required
- if (basicConfig.getBasicConfigurationBoolean(
- Constants.CONIG_PROPS_EIDAS_SZRCLIENT_DEBUG_TRACEMESSAGES,
- false)) {
- final LoggingHandler loggingHandler = new LoggingHandler();
- handlerList.add(loggingHandler);
-
- }
- bindingProvider.getBinding().setHandlerChain(handlerList);
- }
-
- private SSLContext createSslContext(String clientType) {
- try {
- final SSLContext context = SSLContext.getInstance("TLS");
-
- // initialize key-mangager for SSL client-authentication
- KeyManager[] keyManager = null;
- final String keyStorePath = basicConfig.getBasicConfiguration(
- Constants.CONIG_PROPS_EIDAS_SZRCLIENT_SSL_KEYSTORE_PATH);
- final String keyStorePassword = basicConfig.getBasicConfiguration(
- Constants.CONIG_PROPS_EIDAS_SZRCLIENT_SSL_KEYSTORE_PASSWORD);
- if (StringUtils.isNotEmpty(keyStorePath)) {
- log.trace("Find keyStore path: " + keyStorePath + " Injecting SSL client certificate ... ");
- try {
- final KeyStore keyStore = KeyStoreUtils.loadKeyStore(
- FileUtils.makeAbsoluteUrl(keyStorePath, basicConfig.getConfigurationRootDirectory()),
- keyStorePassword);
-
- final KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509");
- kmf.init(keyStore, keyStorePassword.toCharArray());
- keyManager = kmf.getKeyManagers();
- log.debug("SSL client certificate injected to client: " + clientType);
-
- } catch (KeyStoreException | IOException | UnrecoverableKeyException e) {
- log.error("Can NOT load SSL client certificate from path: " + keyStorePath);
- throw new RuntimeException("Can NOT load SSL client certificate from path: " + keyStorePath, e);
-
- }
- } else {
- log.debug(
- "No KeyStore for SSL Client Auth. found. Initializing SSLContext without authentication ... ");
-
- }
-
- // initialize SSL TrustStore
- TrustManager[] trustManager = null;
- final String trustStorePath = basicConfig.getBasicConfiguration(
- Constants.CONIG_PROPS_EIDAS_SZRCLIENT_SSL_TRUSTSTORE_PATH);
- final String trustStorePassword = basicConfig.getBasicConfiguration(
- Constants.CONIG_PROPS_EIDAS_SZRCLIENT_SSL_TRUSTSTORE_PASSWORD);
- if (StringUtils.isNotEmpty(trustStorePath)) {
- log.trace("Find trustStore path: " + trustStorePath + " Injecting SSL TrustStore ... ");
- try {
- final KeyStore trustStore = KeyStoreUtils.loadKeyStore(
- FileUtils.makeAbsoluteUrl(trustStorePath, basicConfig.getConfigurationRootDirectory()),
- trustStorePassword);
-
- final TrustManagerFactory tmf = TrustManagerFactory.getInstance("SunX509");
- tmf.init(trustStore);
- trustManager = tmf.getTrustManagers();
- log.debug("SSL TrustStore injected to client: " + clientType);
-
- } catch (KeyStoreException | IOException e) {
- log.error("Can NOT open SSL TrustStore from path: " + trustStorePath);
- throw new RuntimeException("Can NOT open SSL TrustStore from path: " + trustStorePath, e);
-
- }
-
- } else {
- log.debug("No custom SSL TrustStore found. Initializing SSLContext with JVM default truststore ... ");
-
- }
-
- context.init(keyManager, trustManager, new SecureRandom());
- return context;
-
- } catch (NoSuchAlgorithmException | KeyManagementException e) {
- log.error("SSLContext initialization FAILED.", e);
- throw new RuntimeException("SSLContext initialization FAILED.", e);
-
- }
-
- }
-
- private void injectMdsIfAvailableAndActive(Map eidsaBindMap, SimpleEidasData eidData) {
- if (basicConfig.getBasicConfigurationBoolean(
- Constants.CONIG_PROPS_EIDAS_SZRCLIENT_SET_MDS_TO_EIDASBIND, false)) {
- log.info("Injecting MDS into eidasBind ... ");
- final Map mds = new HashMap<>();
- mds.put(PvpAttributeDefinitions.PRINCIPAL_NAME_NAME, eidData.getFamilyName());
- mds.put(PvpAttributeDefinitions.GIVEN_NAME_NAME, eidData.getGivenName());
- mds.put(PvpAttributeDefinitions.BIRTHDATE_NAME, eidData.getDateOfBirth());
- eidsaBindMap.put(ATTR_NAME_MDS, mds);
-
- }
- }
-
- private byte[] sourceToByteArray(Source result) throws TransformerException {
- final TransformerFactory factory = TransformerFactory.newInstance();
- factory.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true);
- final Transformer transformer = factory.newTransformer();
- transformer.setOutputProperty("omit-xml-declaration", "yes");
- transformer.setOutputProperty("method", "xml");
- final ByteArrayOutputStream out = new ByteArrayOutputStream();
- final StreamResult streamResult = new StreamResult();
- streamResult.setOutputStream(out);
- transformer.transform(result, streamResult);
- return out.toByteArray();
- }
-
-}
diff --git a/eidas_modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/szr/SzrService.java b/eidas_modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/szr/SzrService.java
deleted file mode 100644
index dde868b1..00000000
--- a/eidas_modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/szr/SzrService.java
+++ /dev/null
@@ -1,164 +0,0 @@
-/*
- * Copyright 2018 A-SIT Plus GmbH
- * AT-specific eIDAS Connector has been developed in a cooperation between EGIZ,
- * A-SIT Plus GmbH, A-SIT, and Graz University of Technology.
- *
- * Licensed under the EUPL, Version 1.2 or - as soon they will be approved by
- * the European Commission - subsequent versions of the EUPL (the "License");
- * You may not use this work except in compliance with the License.
- * You may obtain a copy of the License at:
- * https://joinup.ec.europa.eu/news/understanding-eupl-v12
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" basis,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- * 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.asitplus.eidas.specific.modules.auth.eidas.v2.szr;
-
-import java.net.URL;
-
-import javax.xml.namespace.QName;
-import javax.xml.ws.Service;
-import javax.xml.ws.WebEndpoint;
-import javax.xml.ws.WebServiceClient;
-import javax.xml.ws.WebServiceFeature;
-
-import szrservices.SZR;
-
-/**
- * This class was generated by Apache CXF 3.1.16 2018-07-10T09:36:01.466+02:00
- * Generated source version: 3.1.16
- *
- */
-@WebServiceClient(name = "SZRService",
- wsdlLocation = "./src/main/resources/szr_client/SZR-1.WSDL",
- targetNamespace = "urn:SZRServices")
-public class SzrService extends Service {
-
- public static final URL WSDL_LOCATION;
-
- public static final QName SERVICE = new QName("urn:SZRServices", "SZRService");
- public static final QName SZRProduktionsumgebung = new QName("urn:SZRServices", "SZRProduktionsumgebung");
- public static final QName SZRTestumgebung = new QName("urn:SZRServices", "SZRTestumgebung");
- public static final QName SZRBusinesspartnerTestumgebung = new QName("urn:SZRServices",
- "SZRBusinesspartnerTestumgebung");
-
- static {
- URL url = SzrService.class.getResource("./src/main/resources/szr_client/SZR-1.WSDL");
- if (url == null) {
- url = SzrService.class.getClassLoader().getResource("/szr_client/SZR-1.WSDL");
- }
- if (url == null) {
- java.util.logging.Logger.getLogger(SzrService.class.getName())
- .log(java.util.logging.Level.INFO,
- "Can not initialize the default wsdl from {0}", "/szr_client/SZR-1.WSDL");
- }
- WSDL_LOCATION = url;
-
- }
-
- public SzrService(URL wsdlLocation) {
- super(wsdlLocation, SERVICE);
- }
-
- public SzrService(URL wsdlLocation, QName serviceName) {
- super(wsdlLocation, serviceName);
- }
-
- public SzrService() {
- super(WSDL_LOCATION, SERVICE);
- }
-
- public SzrService(WebServiceFeature... features) {
- super(WSDL_LOCATION, SERVICE, features);
- }
-
- public SzrService(URL wsdlLocation, WebServiceFeature... features) {
- super(wsdlLocation, SERVICE, features);
- }
-
- public SzrService(URL wsdlLocation, QName serviceName, WebServiceFeature... features) {
- super(wsdlLocation, serviceName, features);
- }
-
- /**
- * Get SZR Web-Service.
- *
- * @return returns SZR
- */
- @WebEndpoint(name = "SZRProduktionsumgebung")
- public SZR getSzrProduktionsumgebung() {
- return super.getPort(SZRProduktionsumgebung, SZR.class);
- }
-
- /**
- * Get SZR Web-Service.
- *
- * @param features A list of {@link javax.xml.ws.WebServiceFeature} to configure
- * on the proxy. Supported features not in the
- * features
parameter will have their default
- * values.
- * @return returns SZR
- */
- @WebEndpoint(name = "SZRProduktionsumgebung")
- public SZR getSzrProduktionsumgebung(WebServiceFeature... features) {
- return super.getPort(SZRProduktionsumgebung, SZR.class, features);
- }
-
- /**
- *Get SZR Web-Service.
- *
- * @return returns SZR
- */
- @WebEndpoint(name = "SZRTestumgebung")
- public SZR getSzrTestumgebung() {
- return super.getPort(SZRTestumgebung, SZR.class);
- }
-
- /**
- * Get SZR Web-Service.
- *
- * @param features A list of {@link javax.xml.ws.WebServiceFeature} to configure
- * on the proxy. Supported features not in the
- * features
parameter will have their default
- * values.
- * @return returns SZR
- */
- @WebEndpoint(name = "SZRTestumgebung")
- public SZR getSzrTestumgebung(WebServiceFeature... features) {
- return super.getPort(SZRTestumgebung, SZR.class, features);
- }
-
- /**
- * Get SZR Web-Service.
- *
- * @return returns SZR
- */
- @WebEndpoint(name = "SZRBusinesspartnerTestumgebung")
- public SZR getSzrBusinesspartnerTestumgebung() {
- return super.getPort(SZRBusinesspartnerTestumgebung, SZR.class);
- }
-
- /**
- * Get SZR Web-Service.
- *
- * @param features A list of {@link javax.xml.ws.WebServiceFeature} to configure
- * on the proxy. Supported features not in the
- * features
parameter will have their default
- * values.
- * @return returns SZR
- */
- @WebEndpoint(name = "SZRBusinesspartnerTestumgebung")
- public SZR getSzrBusinesspartnerTestumgebung(WebServiceFeature... features) {
- return super.getPort(SZRBusinesspartnerTestumgebung, SZR.class, features);
- }
-
-}
diff --git a/eidas_modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/tasks/CreateIdentityLinkTask.java b/eidas_modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/tasks/CreateIdentityLinkTask.java
index 97769cc2..41bf4409 100644
--- a/eidas_modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/tasks/CreateIdentityLinkTask.java
+++ b/eidas_modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/tasks/CreateIdentityLinkTask.java
@@ -23,15 +23,40 @@
package at.asitplus.eidas.specific.modules.auth.eidas.v2.tasks;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import javax.xml.parsers.ParserConfigurationException;
+
+import org.apache.commons.lang3.StringUtils;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+import org.joda.time.DateTime;
+import org.jose4j.lang.JoseException;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+import org.w3c.dom.Element;
+import org.w3c.dom.Node;
+import org.xml.sax.SAXException;
+
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.ImmutableSet;
+
import at.asitplus.eidas.specific.connector.MsConnectorEventCodes;
import at.asitplus.eidas.specific.connector.MsEidasNodeConstants;
import at.asitplus.eidas.specific.modules.auth.eidas.v2.Constants;
+import at.asitplus.eidas.specific.modules.auth.eidas.v2.clients.szr.SzrClient;
import at.asitplus.eidas.specific.modules.auth.eidas.v2.dao.SimpleEidasData;
import at.asitplus.eidas.specific.modules.auth.eidas.v2.exception.EidasAttributeException;
import at.asitplus.eidas.specific.modules.auth.eidas.v2.exception.SzrCommunicationException;
import at.asitplus.eidas.specific.modules.auth.eidas.v2.service.AuthBlockSigningService;
import at.asitplus.eidas.specific.modules.auth.eidas.v2.service.ICcSpecificEidProcessingService;
-import at.asitplus.eidas.specific.modules.auth.eidas.v2.szr.SzrClient;
import at.asitplus.eidas.specific.modules.auth.eidas.v2.utils.EidasResponseUtils;
import at.gv.egiz.eaaf.core.api.data.EaafConstants;
import at.gv.egiz.eaaf.core.api.data.PvpAttributeDefinitions;
@@ -48,36 +73,14 @@ import at.gv.egiz.eaaf.core.impl.idp.auth.data.SimpleIdentityLinkAssertionParser
import at.gv.egiz.eaaf.core.impl.idp.auth.modules.AbstractAuthServletTask;
import at.gv.egiz.eaaf.core.impl.utils.DomUtils;
import at.gv.egiz.eaaf.core.impl.utils.XPathUtils;
-import com.fasterxml.jackson.core.JsonProcessingException;
-import com.google.common.collect.ImmutableMap;
-import com.google.common.collect.ImmutableSet;
import eu.eidas.auth.commons.attribute.AttributeDefinition;
import eu.eidas.auth.commons.attribute.AttributeValue;
import eu.eidas.auth.commons.light.ILightResponse;
import eu.eidas.auth.commons.protocol.eidas.impl.PostalAddress;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
-import org.apache.commons.lang3.StringUtils;
-import org.jetbrains.annotations.NotNull;
-import org.jetbrains.annotations.Nullable;
-import org.joda.time.DateTime;
-import org.jose4j.lang.JoseException;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.stereotype.Component;
-import org.w3c.dom.Element;
-import org.w3c.dom.Node;
-import org.xml.sax.SAXException;
import szrservices.IdentityLinkType;
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
-import javax.xml.parsers.ParserConfigurationException;
-import java.io.IOException;
-import java.io.InputStream;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-
/**
* Task that creates the IdentityLink for an eIDAS authenticated person.
* Input:
@@ -127,10 +130,14 @@ public class CreateIdentityLinkTask extends AbstractAuthServletTask {
public void execute(ExecutionContext executionContext, HttpServletRequest request, HttpServletResponse response)
throws TaskExecutionException {
try {
+
+ /*TODO: needs refactoring because we has to be operate on national identifiers
+ * because matching and insert ERnP was already done!!
+ */
final ILightResponse eidasResponse = getAuthProcessDataWrapper()
.getGenericDataFromSession(Constants.DATA_FULL_EIDAS_RESPONSE, ILightResponse.class);
final Map eidasAttributes = convertEidasAttrToSimpleMap(
- eidasResponse.getAttributes().getAttributeMap());
+ eidasResponse.getAttributes().getAttributeMap());
final SimpleEidasData eidData = eidPostProcessor.postProcess(eidasAttributes);
//final SimpleEidasData eidData =
// getAuthProcessDataWrapper().getGenericDataFromSession(Constants.DATA_SIMPLE_EIDAS, SimpleEidasData.class);
@@ -192,7 +199,7 @@ public class CreateIdentityLinkTask extends AbstractAuthServletTask {
private void executeEidMode(SimpleEidasData eidData, String personalIdentifier)
throws JsonProcessingException, EaafException, JoseException {
- // get encrypted baseId
+ // get encrypted baseId
String vsz = szrClient.getEncryptedStammzahl(eidData);
//write revision-Log entry and extended infos personal-identifier mapping
diff --git a/eidas_modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/tasks/CreateNewErnpEntryTask.java b/eidas_modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/tasks/CreateNewErnpEntryTask.java
index 025f3475..69b127d8 100644
--- a/eidas_modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/tasks/CreateNewErnpEntryTask.java
+++ b/eidas_modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/tasks/CreateNewErnpEntryTask.java
@@ -23,18 +23,19 @@
package at.asitplus.eidas.specific.modules.auth.eidas.v2.tasks;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.springframework.stereotype.Component;
+
import at.asitplus.eidas.specific.modules.auth.eidas.v2.Constants;
+import at.asitplus.eidas.specific.modules.auth.eidas.v2.clients.szr.SzrClient;
import at.asitplus.eidas.specific.modules.auth.eidas.v2.dao.SimpleEidasData;
-import at.asitplus.eidas.specific.modules.auth.eidas.v2.szr.SzrClient;
+import at.asitplus.eidas.specific.modules.auth.eidas.v2.utils.MatchingTaskUtils;
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.data.AuthProcessDataWrapper;
import at.gv.egiz.eaaf.core.impl.idp.auth.modules.AbstractAuthServletTask;
import lombok.extern.slf4j.Slf4j;
-import org.springframework.stereotype.Component;
-
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
/**
* Task that searches ERnP and ZMR before adding person to SZR.
@@ -69,9 +70,11 @@ public class CreateNewErnpEntryTask extends AbstractAuthServletTask {
public void execute(ExecutionContext executionContext, HttpServletRequest request, HttpServletResponse response)
throws TaskExecutionException {
try {
- SimpleEidasData simpleEidasData = getInitialEidasData();
+ SimpleEidasData simpleEidasData = MatchingTaskUtils.getInitialEidasData(pendingReq);
+
// TODO When to do eidPostProcessor.postProcess on the eidas attributes?
String vsz = szrClient.createNewErnpEntry(simpleEidasData);
+
// TODO what to do with the VSZ now
log.info("VSZ: {}", vsz);
} catch (final Exception e) {
@@ -80,12 +83,4 @@ public class CreateNewErnpEntryTask extends AbstractAuthServletTask {
}
}
- private SimpleEidasData getInitialEidasData() {
- return getAuthProcessDataWrapper().getGenericDataFromSession(Constants.DATA_SIMPLE_EIDAS, SimpleEidasData.class);
- }
-
- private AuthProcessDataWrapper getAuthProcessDataWrapper() {
- return pendingReq.getSessionData(AuthProcessDataWrapper.class);
- }
-
}
diff --git a/eidas_modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/tasks/InitialSearchTask.java b/eidas_modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/tasks/InitialSearchTask.java
index a6e0bca8..1563d6df 100644
--- a/eidas_modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/tasks/InitialSearchTask.java
+++ b/eidas_modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/tasks/InitialSearchTask.java
@@ -23,43 +23,44 @@
package at.asitplus.eidas.specific.modules.auth.eidas.v2.tasks;
+import static at.asitplus.eidas.specific.modules.auth.eidas.v2.Constants.TRANSITION_TO_CREATE_NEW_ERNP_ENTRY_TASK;
+import static at.asitplus.eidas.specific.modules.auth.eidas.v2.Constants.TRANSITION_TO_GENERATE_OTHER_LOGIN_METHOD_GUI_TASK;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.apache.commons.lang3.StringUtils;
+import org.jetbrains.annotations.NotNull;
+import org.joda.time.DateTime;
+import org.springframework.stereotype.Component;
+
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.ImmutableSet;
+
import at.asitplus.eidas.specific.modules.auth.eidas.v2.Constants;
-import at.asitplus.eidas.specific.modules.auth.eidas.v2.dao.MergedRegisterSearchResult;
import at.asitplus.eidas.specific.modules.auth.eidas.v2.dao.SimpleEidasData;
import at.asitplus.eidas.specific.modules.auth.eidas.v2.exception.EidPostProcessingException;
import at.asitplus.eidas.specific.modules.auth.eidas.v2.exception.EidasAttributeException;
-import at.asitplus.eidas.specific.modules.auth.eidas.v2.exception.ManualFixNecessaryException;
import at.asitplus.eidas.specific.modules.auth.eidas.v2.exception.WorkflowException;
-import at.asitplus.eidas.specific.modules.auth.eidas.v2.handler.CountrySpecificDetailSearchProcessor;
import at.asitplus.eidas.specific.modules.auth.eidas.v2.service.ICcSpecificEidProcessingService;
import at.asitplus.eidas.specific.modules.auth.eidas.v2.service.RegisterSearchService;
+import at.asitplus.eidas.specific.modules.auth.eidas.v2.service.RegisterSearchService.RegisterOperationStatus;
+import at.asitplus.eidas.specific.modules.auth.eidas.v2.service.RegisterSearchService.RegisterSearchResult;
import at.asitplus.eidas.specific.modules.auth.eidas.v2.utils.EidasResponseUtils;
+import at.asitplus.eidas.specific.modules.auth.eidas.v2.utils.MatchingTaskUtils;
import at.gv.egiz.eaaf.core.api.idp.process.ExecutionContext;
import at.gv.egiz.eaaf.core.exceptions.EaafStorageException;
import at.gv.egiz.eaaf.core.exceptions.TaskExecutionException;
-import at.gv.egiz.eaaf.core.impl.idp.auth.data.AuthProcessDataWrapper;
import at.gv.egiz.eaaf.core.impl.idp.auth.modules.AbstractAuthServletTask;
-import com.google.common.collect.ImmutableMap;
-import com.google.common.collect.ImmutableSet;
import eu.eidas.auth.commons.attribute.AttributeDefinition;
import eu.eidas.auth.commons.attribute.AttributeValue;
import eu.eidas.auth.commons.light.ILightResponse;
import eu.eidas.auth.commons.protocol.eidas.impl.PostalAddress;
import lombok.extern.slf4j.Slf4j;
-import org.apache.commons.lang3.StringUtils;
-import org.jetbrains.annotations.NotNull;
-import org.jetbrains.annotations.Nullable;
-import org.joda.time.DateTime;
-import org.springframework.stereotype.Component;
-
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-
-import static at.asitplus.eidas.specific.modules.auth.eidas.v2.Constants.TRANSITION_TO_CREATE_NEW_ERNP_ENTRY_TASK;
-import static at.asitplus.eidas.specific.modules.auth.eidas.v2.Constants.TRANSITION_TO_GENERATE_OTHER_LOGIN_METHOD_GUI_TASK;
/**
* Task that searches registers (ERnP and ZMR) before adding person to SZR.
@@ -91,23 +92,19 @@ import static at.asitplus.eidas.specific.modules.auth.eidas.v2.Constants.TRANSIT
@SuppressWarnings("PMD.TooManyStaticImports")
public class InitialSearchTask extends AbstractAuthServletTask {
- private final List handlers;
private final RegisterSearchService registerSearchService;
private final ICcSpecificEidProcessingService eidPostProcessor;
/**
* Constructor.
- * @param handlers List of countrySpecificSearchProcessors
* @param registerSearchService Service for register search access
* @param eidPostProcessor Country-Specific post processing of attributes
*/
- public InitialSearchTask(List handlers,
- RegisterSearchService registerSearchService,
+ public InitialSearchTask(RegisterSearchService registerSearchService,
ICcSpecificEidProcessingService eidPostProcessor) {
this.registerSearchService = registerSearchService;
- this.handlers = handlers;
this.eidPostProcessor = eidPostProcessor;
- log.info("Init with {} country specific detail search services", handlers.size());
+
}
@Override
@@ -115,126 +112,124 @@ public class InitialSearchTask extends AbstractAuthServletTask {
throws TaskExecutionException {
try {
final SimpleEidasData eidasData = convertEidasAttrToSimpleData();
- storeInitialEidasData(eidasData);
+ MatchingTaskUtils.storeInitialEidasData(pendingReq, eidasData);
step2RegisterSearchWithPersonIdentifier(executionContext, eidasData);
+
+ } catch (WorkflowException e) {
+ throw new TaskExecutionException(pendingReq, "Initial search failed", e);
+
} catch (final Exception e) {
log.error("Initial search failed", e);
- throw new TaskExecutionException(pendingReq, "Initial search failed", e);
+ throw new TaskExecutionException(pendingReq, "Initial search failed with a generic error", e);
+
}
}
private void step2RegisterSearchWithPersonIdentifier(
- ExecutionContext executionContext, SimpleEidasData eidasData)
- throws TaskExecutionException, EaafStorageException, ManualFixNecessaryException {
- log.trace("Starting step2RegisterSearchWithPersonIdentifier");
- MergedRegisterSearchResult initialSearchResult = registerSearchService.searchWithPersonIdentifier(eidasData);
- storeInitialRegisterResult(initialSearchResult);
- int resultCount = initialSearchResult.getResultCount();
- if (resultCount == 0) {
- step5CountrySpecificSearchCheck(executionContext, initialSearchResult, eidasData);
- } else if (resultCount == 1) {
- step3CheckRegisterUpdateNecessary(initialSearchResult, eidasData);
- } else {
- throw new ManualFixNecessaryException(eidasData);
- }
- }
-
- private void step3CheckRegisterUpdateNecessary(
- MergedRegisterSearchResult initialSearchResult, SimpleEidasData eidasData)
- throws ManualFixNecessaryException {
- log.trace("Starting step3CheckRegisterUpdateNecessary");
- try {
- if (eidasData.equalsRegisterData(initialSearchResult)) {
- storeMatchingBpk(initialSearchResult.getBpk());
+ ExecutionContext executionContext, SimpleEidasData eidasData) throws WorkflowException, EaafStorageException {
+ try {
+ log.trace("Starting step2RegisterSearchWithPersonIdentifier");
+ RegisterSearchResult initialSearchResult = registerSearchService.searchWithPersonIdentifier(eidasData);
+ int resultCount = initialSearchResult.getResultCount();
+ if (resultCount == 0) {
+ step6CountrySpecificSearch(executionContext, initialSearchResult.getOperationStatus(), eidasData);
+
+ } else if (resultCount == 1) {
+ // find person by PersonalIdentifier --> finalize first matching task
+ initialSearchResult.setMatchingFinished(true);
+ foundMatchFinializeTask(initialSearchResult, eidasData);
+
} else {
- // TODO Update "initialSearchResult" in register with "eidasData" from login not possible for now
- log.info("Update in Register");
- storeMatchingBpk(initialSearchResult.getBpk());
+ throw new WorkflowException("step2RegisterSearchWithPersonIdentifier",
+ "More than one entry with unique personal-identifier", true);
+
}
- } catch (WorkflowException | EaafStorageException e) {
- throw new ManualFixNecessaryException(eidasData);
+
+ } catch (WorkflowException e) {
+ //TODO: what we do in case of a workflow error and manual matching are necessary??
+
+ log.warn("Workflow error during matching step: {}. Reason: {}", e.getProcessStepName(), e.getErrorReason());
+ throw e;
+
}
}
-
- private void step5CountrySpecificSearchCheck(
- ExecutionContext executionContext, MergedRegisterSearchResult initialSearchResult, SimpleEidasData eidasData)
- throws TaskExecutionException, ManualFixNecessaryException, EaafStorageException {
- log.trace("Starting step5CheckAndPerformCountrySpecificSearchIfPossible");
- CountrySpecificDetailSearchProcessor specificHandler = findSpecificProcessor(eidasData);
- if (specificHandler != null) {
- step6CountrySpecificSearch(executionContext, specificHandler, initialSearchResult, eidasData);
+
+ private void step6CountrySpecificSearch(
+ ExecutionContext executionContext, RegisterOperationStatus registerOperationStatus, SimpleEidasData eidasData)
+ throws EaafStorageException, WorkflowException {
+
+ log.trace("Starting 'step6CountrySpecificSearch' ... ");
+ RegisterSearchResult countrySpecificResult = registerSearchService.searchWithCountrySpecifics(
+ registerOperationStatus, eidasData);
+ if (countrySpecificResult.getResultCount() == 0) {
+ log.trace("'step6CountrySpecificSearch' ends with no result. Forward to next matching step ... ");
+ step8RegisterSearchWithMds(executionContext, countrySpecificResult.getOperationStatus(), eidasData);
+
+ } else if (countrySpecificResult.getResultCount() == 1) {
+ log.trace("'step6CountrySpecificSearch' finds a person. Forward to 'step7aKittProcess' step ... ");
+ registerSearchService.step7aKittProcess(countrySpecificResult, eidasData);
+
+ // find person by country-specific information --> finalize first matching task
+ countrySpecificResult.setMatchingFinished(true);
+ foundMatchFinializeTask(countrySpecificResult, eidasData);
+
} else {
- step8RegisterSearchWithMds(executionContext, eidasData);
- }
+ throw new WorkflowException("step6CountrySpecificSearch",
+ "More than one entry with unique country-specific informations", true);
+
+ }
}
- @Nullable
- private CountrySpecificDetailSearchProcessor findSpecificProcessor(SimpleEidasData eidasData) {
- final String citizenCountry = eidasData.getCitizenCountryCode();
- for (final CountrySpecificDetailSearchProcessor processor : handlers) {
- if (processor.canHandle(citizenCountry, eidasData)) {
- log.debug("Found suitable search handler for {} by using: {}", citizenCountry, processor.getName());
- return processor;
- }
- }
- return null;
- }
-
- private void step6CountrySpecificSearch(ExecutionContext executionContext,
- CountrySpecificDetailSearchProcessor processor,
- MergedRegisterSearchResult initialSearchResult,
- SimpleEidasData eidasData)
- throws TaskExecutionException, ManualFixNecessaryException, EaafStorageException {
- log.trace("Starting step6CountrySpecificSearch");
- MergedRegisterSearchResult countrySearchResult = processor.search(eidasData);
- int resultCount = countrySearchResult.getResultCount();
- if (resultCount == 0) {
- step8RegisterSearchWithMds(executionContext, eidasData);
- } else if (resultCount == 1) {
- String bpk = registerSearchService
- .step7aKittProcess(initialSearchResult, countrySearchResult, eidasData, pendingReq);
- storeMatchingBpk(bpk);
- } else {
- throw new ManualFixNecessaryException(eidasData);
- }
- }
-
- private void step8RegisterSearchWithMds(ExecutionContext executionContext, SimpleEidasData eidasData)
- throws EaafStorageException {
+ private void step8RegisterSearchWithMds(ExecutionContext executionContext,
+ RegisterOperationStatus registerOperationStatus, SimpleEidasData eidasData)
+ throws EaafStorageException, WorkflowException {
log.trace("Starting step8RegisterSearchWithMds");
- MergedRegisterSearchResult registerData = registerSearchService.searchWithMds(eidasData);
+ RegisterSearchResult registerData = registerSearchService.searchWithMds(registerOperationStatus, eidasData);
+
if (registerData.getResultCount() == 0) {
+ log.debug("Matching step: 'step8RegisterSearchWithMds' has no result. Forward to create new ERnP entry ... ");
executionContext.put(TRANSITION_TO_CREATE_NEW_ERNP_ENTRY_TASK, true);
+
} else {
- storeFurtherRegisterResults(registerData);
+ log.debug("Matching step: 'step8RegisterSearchWithMds' has #{} results. "
+ + "Forward to GUI based matching steps ... ", registerData.getResultCount());
+
+ MatchingTaskUtils.storeInitialRegisterResult(pendingReq, registerData);
executionContext.put(TRANSITION_TO_GENERATE_OTHER_LOGIN_METHOD_GUI_TASK, true);
+
}
}
- private void storeInitialRegisterResult(MergedRegisterSearchResult registerData) throws EaafStorageException {
- getAuthProcessDataWrapper().setGenericDataToSession(Constants.DATA_INITIAL_REGISTER_RESULT, registerData);
- }
-
- private void storeFurtherRegisterResults(MergedRegisterSearchResult registerData) throws EaafStorageException {
- getAuthProcessDataWrapper().setGenericDataToSession(Constants.DATA_FURTHER_REGISTER_RESULT, registerData);
- }
- private void storeInitialEidasData(SimpleEidasData eidasData) throws EaafStorageException {
- getAuthProcessDataWrapper().setGenericDataToSession(Constants.DATA_SIMPLE_EIDAS, eidasData);
- }
- private void storeMatchingBpk(String bpk) throws EaafStorageException {
- getAuthProcessDataWrapper().setGenericDataToSession(Constants.DATA_RESULT_MATCHING_BPK, bpk);
+ private void foundMatchFinializeTask(RegisterSearchResult searchResult, SimpleEidasData eidasData)
+ throws WorkflowException, EaafStorageException {
+ // check if register update is required
+ step3CheckRegisterUpdateNecessary(searchResult, eidasData);
+
+ // store search result
+ MatchingTaskUtils.storeInitialRegisterResult(pendingReq, searchResult);
+
}
-
- private AuthProcessDataWrapper getAuthProcessDataWrapper() {
- return pendingReq.getSessionData(AuthProcessDataWrapper.class);
+
+ private void step3CheckRegisterUpdateNecessary(RegisterSearchResult initialSearchResult,
+ SimpleEidasData eidasData) throws WorkflowException {
+ log.trace("Starting step3CheckRegisterUpdateNecessary");
+ if (!eidasData.equalsRegisterData(initialSearchResult)) {
+ // TODO Update "initialSearchResult" in register with "eidasData" from login not possible for now
+ log.info("Skipping update-register-information step, because it's not supported yet");
+
+ } else {
+ log.debug("Register information match to eIDAS information. No update requird");
+
+ }
+
}
-
+
@NotNull
private SimpleEidasData convertEidasAttrToSimpleData()
throws EidasAttributeException, EidPostProcessingException {
- final ILightResponse eidasResponse = getAuthProcessDataWrapper()
+ final ILightResponse eidasResponse = MatchingTaskUtils.getAuthProcessDataWrapper(pendingReq)
.getGenericDataFromSession(Constants.DATA_FULL_EIDAS_RESPONSE, ILightResponse.class);
Map simpleMap = convertEidasAttrToSimpleMap(eidasResponse.getAttributes().getAttributeMap());
return eidPostProcessor.postProcess(simpleMap);
diff --git a/eidas_modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/tasks/ReceiveAustrianResidenceGuiResponseTask.java b/eidas_modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/tasks/ReceiveAustrianResidenceGuiResponseTask.java
index 3b7f361c..b18104fa 100644
--- a/eidas_modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/tasks/ReceiveAustrianResidenceGuiResponseTask.java
+++ b/eidas_modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/tasks/ReceiveAustrianResidenceGuiResponseTask.java
@@ -23,29 +23,31 @@
package at.asitplus.eidas.specific.modules.auth.eidas.v2.tasks;
+import java.util.Enumeration;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.apache.commons.lang.StringEscapeUtils;
+import org.jetbrains.annotations.NotNull;
+import org.springframework.stereotype.Component;
+
import at.asitplus.eidas.specific.modules.auth.eidas.v2.Constants;
-import at.asitplus.eidas.specific.modules.auth.eidas.v2.dao.MergedRegisterSearchResult;
import at.asitplus.eidas.specific.modules.auth.eidas.v2.dao.SimpleEidasData;
import at.asitplus.eidas.specific.modules.auth.eidas.v2.exception.InvalidUserInputException;
import at.asitplus.eidas.specific.modules.auth.eidas.v2.exception.ManualFixNecessaryException;
import at.asitplus.eidas.specific.modules.auth.eidas.v2.exception.WorkflowException;
import at.asitplus.eidas.specific.modules.auth.eidas.v2.service.RegisterSearchService;
+import at.asitplus.eidas.specific.modules.auth.eidas.v2.service.RegisterSearchService.RegisterSearchResult;
+import at.asitplus.eidas.specific.modules.auth.eidas.v2.utils.MatchingTaskUtils;
import at.gv.egiz.eaaf.core.api.idp.process.ExecutionContext;
import at.gv.egiz.eaaf.core.exceptions.EaafStorageException;
import at.gv.egiz.eaaf.core.exceptions.TaskExecutionException;
-import at.gv.egiz.eaaf.core.impl.idp.auth.data.AuthProcessDataWrapper;
import at.gv.egiz.eaaf.core.impl.idp.auth.modules.AbstractAuthServletTask;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.extern.slf4j.Slf4j;
-import org.apache.commons.lang.StringEscapeUtils;
-import org.jetbrains.annotations.NotNull;
-import org.springframework.stereotype.Component;
-
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
-import java.util.Enumeration;
/**
@@ -69,6 +71,7 @@ import java.util.Enumeration;
*
* @author amarsalek
* @author ckollmann
+ * @author tlenz
*/
@Slf4j
@Component("ReceiveAustrianResidenceGuiResponseTask")
@@ -98,72 +101,88 @@ public class ReceiveAustrianResidenceGuiResponseTask extends AbstractAuthServlet
public void execute(ExecutionContext executionContext, HttpServletRequest request, HttpServletResponse response)
throws TaskExecutionException {
log.trace("Starting ReceiveAustrianResidenceGuiResponseTask");
- UserInput input = parseHtmlInput(request);
+
+ UserInput input = parseHtmlInput(request);
if (!input.isFormerResidenceAvailable()) {
moveToNextTask(executionContext);
return;
+
}
+
+ //TODO: Here, we need an error handling an can not stop full process if form input was invalid
+ //TODO: check minimum form elements
+ /*TODO: maybe we can switch to custom controller and use WebMVC form-binding feature.
+ * Binding element can be add as attribute to this request
+ */
if (input.getStreet().isEmpty() || input.getCity().isEmpty() || input.getZipcode().isEmpty()) {
// HTML form should ensure that mandatory fields are set => this should never happen
- throw new TaskExecutionException(pendingReq, "Invalid user input", new InvalidUserInputException());
+ throw new TaskExecutionException(pendingReq, "Invalid user input",
+ new InvalidUserInputException("module.eidasauth.matching.06"));
+
}
- // TODO Also search with MDS? But MDS Search has already happened?
+
+
+
try {
- SimpleEidasData eidasData = getInitialEidasData();
- MergedRegisterSearchResult residencyResult = registerSearchService
- .searchWithResidence(input.zipcode, input.city, input.street);
+ SimpleEidasData eidasData = MatchingTaskUtils.getInitialEidasData(pendingReq);
+ RegisterSearchResult initialSearchResult = MatchingTaskUtils.getInitialRegisterResult(pendingReq);
+
+ RegisterSearchResult residencyResult =
+ registerSearchService.searchWithResidence(initialSearchResult.getOperationStatus(),
+ eidasData, input.zipcode, input.city, input.street);
if (residencyResult.getResultCount() == 0) {
+ //TODO: her we should add a GUI step of result is zero to inform user an forward process by click
moveToNextTask(executionContext);
+
} else if (residencyResult.getResultCount() == 1) {
compareSearchResultWithInitialData(executionContext, residencyResult, eidasData);
+
} else {
+ /*TODO: align with form generation task and to better error handling in case of more-than-one result.
+ * Maybe the user has to provide more information.
+ */
throw new TaskExecutionException(pendingReq,
"Manual Fix necessary", new ManualFixNecessaryException(eidasData));
+
}
+
} catch (EaafStorageException e) {
log.error("Search with residency data failed", e);
throw new TaskExecutionException(pendingReq, "Search with residency data failed", e);
+
}
}
- private void compareSearchResultWithInitialData(ExecutionContext executionContext,
- MergedRegisterSearchResult residencyResult, SimpleEidasData eidasData)
+ private void compareSearchResultWithInitialData(ExecutionContext executionContext,
+ RegisterSearchResult residencyResult, SimpleEidasData eidasData)
throws TaskExecutionException, EaafStorageException {
- try {
- MergedRegisterSearchResult initialSearchResult = getInitialRegisterResult();
- // TODO search "residencyResult" in "initialSearchResult"!?
+ try {
+ /*TODO: check 'equalsRegisterData' because this method maybe this method evaluate to an invalid result.
+ * See TODO in methods body
+ */
if (eidasData.equalsRegisterData(residencyResult)) {
- String bpk = registerSearchService
- .step7aKittProcess(initialSearchResult, residencyResult, eidasData, pendingReq);
- storeMatchingBpk(bpk);
+ // update register information
+ registerSearchService.step7aKittProcess(residencyResult, eidasData);
+
+ // store search result to re-used in CreateIdentityLink step, because there we need bPK and MDS
+ residencyResult.setMatchingFinished(true);
+ MatchingTaskUtils.storeInitialRegisterResult(pendingReq, residencyResult);
+
} else {
moveToNextTask(executionContext);
+
}
+
} catch (WorkflowException e) {
throw new TaskExecutionException(pendingReq, "Search failed", new ManualFixNecessaryException(eidasData));
+
}
}
- private SimpleEidasData getInitialEidasData() {
- return getAuthProcessDataWrapper().getGenericDataFromSession(Constants.DATA_SIMPLE_EIDAS, SimpleEidasData.class);
- }
-
- private MergedRegisterSearchResult getInitialRegisterResult() {
- return getAuthProcessDataWrapper().getGenericDataFromSession(Constants.DATA_INITIAL_REGISTER_RESULT,
- MergedRegisterSearchResult.class);
- }
-
- private void storeMatchingBpk(String bpk) throws EaafStorageException {
- getAuthProcessDataWrapper().setGenericDataToSession(Constants.DATA_RESULT_MATCHING_BPK, bpk);
- }
-
- private AuthProcessDataWrapper getAuthProcessDataWrapper() {
- return pendingReq.getSessionData(AuthProcessDataWrapper.class);
- }
-
private void moveToNextTask(ExecutionContext executionContext) {
// Later on, this should transition to Step 20
executionContext.put(Constants.TRANSITION_TO_CREATE_NEW_ERNP_ENTRY_TASK, true);
+
}
private @NotNull UserInput parseHtmlInput(HttpServletRequest request) {
@@ -174,15 +193,20 @@ public class ReceiveAustrianResidenceGuiResponseTask extends AbstractAuthServlet
String escaped = StringEscapeUtils.escapeHtml(request.getParameter(paramName));
if (PARAM_FORMER_RESIDENCE_AVAILABLE.equalsIgnoreCase(paramName)) {
result.setFormerResidenceAvailable(Boolean.parseBoolean(escaped));
+
} else if (PARAM_STREET.equalsIgnoreCase(paramName)) {
result.setStreet(escaped);
+
} else if (PARAM_CITY.equalsIgnoreCase(paramName)) {
result.setCity(escaped);
+
} else if (PARAM_ZIPCODE.equalsIgnoreCase(paramName)) {
result.setZipcode(escaped);
+
}
}
return result;
+
}
}
diff --git a/eidas_modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/tasks/ReceiveMobilePhoneSignatureResponseTask.java b/eidas_modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/tasks/ReceiveMobilePhoneSignatureResponseTask.java
index a6ff345d..fd469f49 100644
--- a/eidas_modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/tasks/ReceiveMobilePhoneSignatureResponseTask.java
+++ b/eidas_modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/tasks/ReceiveMobilePhoneSignatureResponseTask.java
@@ -23,24 +23,45 @@
package at.asitplus.eidas.specific.modules.auth.eidas.v2.tasks;
+import static at.asitplus.eidas.specific.modules.auth.eidas.v2.idaustriaclient.IdAustriaClientAuthConstants.MODULE_NAME_FOR_LOGGING;
+
+import java.io.IOException;
+import java.util.List;
+import java.util.Set;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import javax.xml.transform.TransformerException;
+
+import org.apache.commons.lang3.StringUtils;
+import org.jetbrains.annotations.NotNull;
+import org.opensaml.core.xml.io.MarshallingException;
+import org.opensaml.messaging.decoder.MessageDecodingException;
+import org.opensaml.saml.saml2.core.Response;
+import org.opensaml.saml.saml2.core.StatusCode;
+import org.opensaml.saml.saml2.metadata.IDPSSODescriptor;
+import org.springframework.stereotype.Component;
+
import at.asitplus.eidas.specific.modules.auth.eidas.v2.Constants;
-import at.asitplus.eidas.specific.modules.auth.eidas.v2.dao.MergedRegisterSearchResult;
+import at.asitplus.eidas.specific.modules.auth.eidas.v2.dao.RegisterResult;
import at.asitplus.eidas.specific.modules.auth.eidas.v2.dao.SimpleEidasData;
import at.asitplus.eidas.specific.modules.auth.eidas.v2.dao.SimpleMobileSignatureData;
import at.asitplus.eidas.specific.modules.auth.eidas.v2.exception.InvalidUserInputException;
-import at.asitplus.eidas.specific.modules.auth.eidas.v2.exception.ManualFixNecessaryException;
+import at.asitplus.eidas.specific.modules.auth.eidas.v2.exception.WorkflowException;
import at.asitplus.eidas.specific.modules.auth.eidas.v2.idaustriaclient.IdAustriaClientAuthConstants;
import at.asitplus.eidas.specific.modules.auth.eidas.v2.idaustriaclient.IdAustriaClientAuthEventConstants;
import at.asitplus.eidas.specific.modules.auth.eidas.v2.idaustriaclient.provider.IdAustriaClientAuthCredentialProvider;
import at.asitplus.eidas.specific.modules.auth.eidas.v2.idaustriaclient.provider.IdAustriaClientAuthMetadataProvider;
import at.asitplus.eidas.specific.modules.auth.eidas.v2.service.RegisterSearchService;
+import at.asitplus.eidas.specific.modules.auth.eidas.v2.service.RegisterSearchService.RegisterSearchResult;
+import at.asitplus.eidas.specific.modules.auth.eidas.v2.utils.MatchingTaskUtils;
import at.gv.egiz.eaaf.core.api.data.PvpAttributeDefinitions;
import at.gv.egiz.eaaf.core.api.idp.process.ExecutionContext;
import at.gv.egiz.eaaf.core.exceptions.EaafBuilderException;
-import at.gv.egiz.eaaf.core.exceptions.EaafStorageException;
import at.gv.egiz.eaaf.core.exceptions.TaskExecutionException;
import at.gv.egiz.eaaf.core.impl.data.Pair;
-import at.gv.egiz.eaaf.core.impl.idp.auth.data.AuthProcessDataWrapper;
import at.gv.egiz.eaaf.core.impl.idp.auth.modules.AbstractAuthServletTask;
import at.gv.egiz.eaaf.modules.pvp2.api.binding.IDecoder;
import at.gv.egiz.eaaf.modules.pvp2.exception.CredentialsNotAvailableException;
@@ -58,23 +79,6 @@ import at.gv.egiz.eaaf.modules.pvp2.sp.exception.AssertionValidationExeption;
import at.gv.egiz.eaaf.modules.pvp2.sp.exception.AuthnResponseValidationException;
import at.gv.egiz.eaaf.modules.pvp2.sp.impl.utils.AssertionAttributeExtractor;
import lombok.extern.slf4j.Slf4j;
-import org.apache.commons.lang3.StringUtils;
-import org.jetbrains.annotations.NotNull;
-import org.opensaml.core.xml.io.MarshallingException;
-import org.opensaml.messaging.decoder.MessageDecodingException;
-import org.opensaml.saml.saml2.core.Response;
-import org.opensaml.saml.saml2.core.StatusCode;
-import org.opensaml.saml.saml2.metadata.IDPSSODescriptor;
-import org.springframework.stereotype.Component;
-
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
-import javax.xml.transform.TransformerException;
-import java.io.IOException;
-import java.util.List;
-import java.util.Set;
-
-import static at.asitplus.eidas.specific.modules.auth.eidas.v2.idaustriaclient.IdAustriaClientAuthConstants.MODULE_NAME_FOR_LOGGING;
/**
* Task that receives the SAML2 response from ID Austria system.
@@ -144,95 +148,84 @@ public class ReceiveMobilePhoneSignatureResponseTask extends AbstractAuthServlet
InboundMessage inboundMessage = decodeAndVerifyMessage(request, response, decoder, comparator);
Pair processedMsg = validateAssertion((PvpSProfileResponse) inboundMessage);
if (processedMsg.getSecond()) {
- stopProcessFromUserDecision(executionContext, request, response);
+ // forward to next matching step in case of ID Autria authentication was stopped by user
+ executionContext.put(Constants.TRANSITION_TO_GENERATE_GUI_QUERY_AUSTRIAN_RESIDENCE_TASK, true);
return;
+
}
+ // validate SAML2 response
validateEntityId(inboundMessage);
+ log.info("Receive a valid assertion from IDP " + inboundMessage.getEntityID());
+
+ // load already existing information from session
+ SimpleEidasData eidasData = MatchingTaskUtils.getInitialEidasData(pendingReq);
+ RegisterSearchResult initialSearchResult = MatchingTaskUtils.getInitialRegisterResult(pendingReq);
+
+ // extract user information from ID Austria authentication
AssertionAttributeExtractor extractor = new AssertionAttributeExtractor(processedMsg.getFirst().getResponse());
-
- /*
- * SAML2 response ist bereits vollständig validiert und die Attribute können aus dem
- * ausgelesen werden.
- * Die AttributeNamen sind entsprechend PVP Spezifikation, z.B. PvpAttributeDefinitions.GIVEN_NAME_NAME
- *
- * ---------------------------------------------------------------------------------------------
- *
- * TODO: ab hier müssen wir wohl was anpassen
- *
- */
-
- MergedRegisterSearchResult initialSearchResult = getInitialRegisterResult();
- SimpleEidasData eidasData = getInitialEidasData();
- String bpkZp = extractBpkZp(extractor, eidasData);
-
- // TODO Hier ist wohl keine Register-Suche notwendig, denn das ergibt sicher einen Treffer
- // TODO Soll: In den Ergebnissen aus Step8 matchen! Über BPK matchen, und dann schauen, ob zumindest
- // Geburtsdatum passt
- MergedRegisterSearchResult registerResult = registerSearchService.searchWithBpkZp(bpkZp);
- if (registerResult.getResultCount() == 0) {
- executionContext.put(Constants.TRANSITION_TO_GENERATE_GUI_QUERY_AUSTRIAN_RESIDENCE_TASK, true);
- return;
- } else if (registerResult.getResultCount() == 1) {
- String bpk = registerSearchService
- .step7aKittProcess(initialSearchResult, registerResult, eidasData, pendingReq);
- storeMatchingBpk(bpk);
- return;
- } else if (registerResult.getResultCount() > 1) {
- throw new ManualFixNecessaryException(eidasData);
+ SimpleMobileSignatureData simpleMobileSignatureData = getAuthDataFromInterfederation(extractor);
+
+ // check if MDS from ID Austria authentication matchs to eIDAS authentication
+ if (!simpleMobileSignatureData.equalsSimpleEidasData(eidasData)) {
+ // user has cheated!?
+ throw new InvalidUserInputException("module.eidasauth.matching.05");
+
}
-
- // set NeedConsent to false, because user gives consent during authentication
- pendingReq.setNeedUserConsent(false);
- log.info("Receive a valid assertion from IDP " + inboundMessage.getEntityID());
+
+ // search entry in initial search result from steps before and build new RegisterSearchResult
+ RegisterSearchResult registerResult = new RegisterSearchResult(initialSearchResult.getOperationStatus(),
+ extractEntriesByBpk(initialSearchResult.getResultsZmr().stream(), simpleMobileSignatureData.getBpk()),
+ extractEntriesByBpk(initialSearchResult.getResultsErnp().stream(), simpleMobileSignatureData.getBpk()));
+
+ if (registerResult.getResultCount() != 1) {
+ throw new WorkflowException("matchWithIDAustriaAuthentication",
+ "Suspect state detected. MDS matches to eIDAS authentication "
+ + "but register search-result with MDS contains #" + registerResult.getResultCount()
+ + " entry with bPK from ID Austria authentication", false);
+
+ } else {
+ // perform kit operation
+ registerSearchService.step7aKittProcess(registerResult, eidasData);
+
+ // store search result to re-used in CreateIdentityLink step, because there we need bPK and MDS
+ registerResult.setMatchingFinished(true);
+ MatchingTaskUtils.storeInitialRegisterResult(pendingReq, registerResult);
+
+ }
+
} catch (final AuthnResponseValidationException e) {
throw new TaskExecutionException(pendingReq, ERROR_MSG_03, e);
+
} catch (MessageDecodingException | SecurityException | SamlSigningException e) {
//final String samlRequest = request.getParameter("SAMLRequest");
//log.debug("Receive INVALID PVP Response from 'ms-specific eIDAS node': {}",
// samlRequest, null, e);
throw new TaskExecutionException(pendingReq, ERROR_MSG_00,
new AuthnResponseValidationException(ERROR_PVP_11, new Object[]{MODULE_NAME_FOR_LOGGING}, e));
+
} catch (IOException | MarshallingException | TransformerException e) {
log.debug("Processing PVP response from 'ms-specific eIDAS node' FAILED.", e);
throw new TaskExecutionException(pendingReq, ERROR_MSG_01,
new AuthnResponseValidationException(ERROR_PVP_12, new Object[]{MODULE_NAME_FOR_LOGGING, e.getMessage()}, e));
+
} catch (final CredentialsNotAvailableException e) {
log.debug("PVP response decryption FAILED. No credential found.", e);
throw new TaskExecutionException(pendingReq, ERROR_MSG_02,
new AuthnResponseValidationException(ERROR_PVP_10, new Object[]{MODULE_NAME_FOR_LOGGING}, e));
+
} catch (final Exception e) {
// todo catch ManualFixNecessaryException in any other way?
log.debug("PVP response validation FAILED. Msg:" + e.getMessage(), e);
throw new TaskExecutionException(pendingReq, ERROR_MSG_03,
new AuthnResponseValidationException(ERROR_PVP_12, new Object[]{MODULE_NAME_FOR_LOGGING, e.getMessage()}, e));
+
}
}
- private String extractBpkZp(AssertionAttributeExtractor extractor,
- SimpleEidasData eidasData) throws EaafBuilderException, InvalidUserInputException {
- SimpleMobileSignatureData simpleMobileSignatureData = getAuthDataFromInterfederation(extractor);
- if (!simpleMobileSignatureData.equalsSimpleEidasData(eidasData)) {
- throw new InvalidUserInputException(); // user has cheated!?
- }
- return simpleMobileSignatureData.getBpk();
- }
+ private List extractEntriesByBpk(Stream stream, String bpk) {
+ return stream.filter(el -> bpk.equals(el.getBpk())).collect(Collectors.toList());
- private SimpleEidasData getInitialEidasData() {
- return getAuthProcessDataWrapper().getGenericDataFromSession(Constants.DATA_SIMPLE_EIDAS, SimpleEidasData.class);
- }
-
- private MergedRegisterSearchResult getInitialRegisterResult() {
- return getAuthProcessDataWrapper().getGenericDataFromSession(Constants.DATA_INITIAL_REGISTER_RESULT,
- MergedRegisterSearchResult.class);
- }
-
- private void storeMatchingBpk(String bpk) throws EaafStorageException {
- getAuthProcessDataWrapper().setGenericDataToSession(Constants.DATA_RESULT_MATCHING_BPK, bpk);
- }
-
- private AuthProcessDataWrapper getAuthProcessDataWrapper() {
- return pendingReq.getSessionData(AuthProcessDataWrapper.class);
}
@NotNull
@@ -359,13 +352,15 @@ public class ReceiveMobilePhoneSignatureResponseTask extends AbstractAuthServlet
}
if (PvpAttributeDefinitions.BIRTHDATE_NAME.equals(attrName)) {
builder.dateOfBirth(extractor.getSingleAttributeValue(attrName));
- }
+ }
if (PvpAttributeDefinitions.EID_CITIZEN_EIDAS_QAA_LEVEL_NAME.equals(attrName)) {
- getAuthProcessDataWrapper().setQaaLevel(extractor.getSingleAttributeValue(attrName));
+ MatchingTaskUtils.getAuthProcessDataWrapper(pendingReq).setQaaLevel(
+ extractor.getSingleAttributeValue(attrName));
}
}
- getAuthProcessDataWrapper().setIssueInstant(extractor.getAssertionIssuingDate());
+ MatchingTaskUtils.getAuthProcessDataWrapper(pendingReq).setIssueInstant(extractor.getAssertionIssuingDate());
return builder.build();
+
}
diff --git a/eidas_modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/tasks/ReceiveOtherLoginMethodGuiResponseTask.java b/eidas_modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/tasks/ReceiveOtherLoginMethodGuiResponseTask.java
index e139b280..59a6886a 100644
--- a/eidas_modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/tasks/ReceiveOtherLoginMethodGuiResponseTask.java
+++ b/eidas_modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/tasks/ReceiveOtherLoginMethodGuiResponseTask.java
@@ -23,6 +23,14 @@
package at.asitplus.eidas.specific.modules.auth.eidas.v2.tasks;
+import java.util.Enumeration;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.apache.commons.lang.StringEscapeUtils;
+import org.springframework.stereotype.Component;
+
import at.asitplus.eidas.specific.modules.auth.eidas.v2.Constants;
import at.asitplus.eidas.specific.modules.auth.eidas.v2.dao.SelectedLoginMethod;
import at.asitplus.eidas.specific.modules.auth.eidas.v2.exception.InvalidUserInputException;
@@ -30,12 +38,6 @@ 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 lombok.extern.slf4j.Slf4j;
-import org.apache.commons.lang.StringEscapeUtils;
-import org.springframework.stereotype.Component;
-
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
-import java.util.Enumeration;
/**
* Handles user's selection from {@link GenerateOtherLoginMethodGuiTask}.
@@ -69,13 +71,16 @@ public class ReceiveOtherLoginMethodGuiResponseTask extends AbstractAuthServletT
SelectedLoginMethod selection = SelectedLoginMethod.valueOf(extractUserSelection(request));
executionContext.put(Constants.REQ_SELECTED_LOGIN_METHOD_PARAMETER, selection);
transitionToNextTask(executionContext, selection);
+
} catch (final IllegalArgumentException e) {
log.error("Parsing selected login method FAILED.", e);
throw new TaskExecutionException(pendingReq, "Parsing selected login method FAILED.",
- new InvalidUserInputException());
+ new InvalidUserInputException("module.eidasauth.matching.98"));
+
} catch (final Exception e) {
log.error("Parsing selected login method FAILED.", e);
throw new TaskExecutionException(pendingReq, "Parsing selected login method FAILED.", e);
+
}
}
@@ -85,9 +90,12 @@ public class ReceiveOtherLoginMethodGuiResponseTask extends AbstractAuthServletT
String paramName = paramNames.nextElement();
if (Constants.REQ_SELECTED_LOGIN_METHOD_PARAMETER.equalsIgnoreCase(paramName)) {
return StringEscapeUtils.escapeHtml(request.getParameter(paramName));
+
}
}
- throw new InvalidUserInputException();
+
+ throw new InvalidUserInputException("module.eidasauth.matching.98");
+
}
private void transitionToNextTask(ExecutionContext executionContext, SelectedLoginMethod selection)
@@ -96,14 +104,18 @@ public class ReceiveOtherLoginMethodGuiResponseTask extends AbstractAuthServletT
case EIDAS_LOGIN:
executionContext.put(Constants.TRANSITION_TO_GENERATE_EIDAS_LOGIN, true);
return;
+
case MOBILE_PHONE_SIGNATURE_LOGIN:
executionContext.put(Constants.TRANSITION_TO_GENERATE_MOBILE_PHONE_SIGNATURE_REQUEST_TASK, true);
return;
+
case NO_OTHER_LOGIN:
executionContext.put(Constants.TRANSITION_TO_GENERATE_GUI_QUERY_AUSTRIAN_RESIDENCE_TASK, true);
return;
+
default:
- throw new InvalidUserInputException();
+ throw new InvalidUserInputException("module.eidasauth.matching.98");
+
}
}
diff --git a/eidas_modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/utils/EidasResponseUtils.java b/eidas_modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/utils/EidasResponseUtils.java
index 3023bc0a..6b541135 100644
--- a/eidas_modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/utils/EidasResponseUtils.java
+++ b/eidas_modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/utils/EidasResponseUtils.java
@@ -23,30 +23,33 @@
package at.asitplus.eidas.specific.modules.auth.eidas.v2.utils;
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import javax.annotation.Nullable;
+
+import org.apache.commons.lang3.StringUtils;
+import org.joda.time.DateTime;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableSet;
+
import at.asitplus.eidas.specific.modules.auth.eidas.v2.Constants;
import at.asitplus.eidas.specific.modules.auth.eidas.v2.exception.EidasAttributeException;
import at.gv.e_government.reference.namespace.persondata._20020228.PostalAddressType;
import at.gv.egiz.eaaf.core.impl.data.Triple;
-import com.google.common.collect.ImmutableList;
-import com.google.common.collect.ImmutableSet;
import eu.eidas.auth.commons.attribute.AttributeDefinition;
import eu.eidas.auth.commons.attribute.AttributeValue;
import eu.eidas.auth.commons.attribute.AttributeValueMarshaller;
import eu.eidas.auth.commons.attribute.AttributeValueMarshallingException;
import eu.eidas.auth.commons.attribute.AttributeValueTransliterator;
import eu.eidas.auth.commons.protocol.eidas.impl.PostalAddress;
-import org.apache.commons.lang3.StringUtils;
-import org.joda.time.DateTime;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import javax.annotation.Nullable;
-import java.text.ParseException;
-import java.text.SimpleDateFormat;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
public class EidasResponseUtils {
private static final Logger log = LoggerFactory.getLogger(EidasResponseUtils.class);
@@ -323,6 +326,21 @@ public class EidasResponseUtils {
return (String) familyNameObj;
}
+ /**
+ * Post-Process the eIDAS personal identifier attribute.
+ *
+ * @param personalIdentifierObj eIDAS personal identifier attribute-information
+ * @return formated user's full personal identifier
+ * @throws EidasAttributeException if NO attribute is available
+ */
+ public static String processPersonalIdentifier(Object personalIdentifierObj) throws EidasAttributeException {
+ if (!(personalIdentifierObj instanceof String)) {
+ throw new EidasAttributeException(Constants.eIDAS_ATTR_PERSONALIDENTIFIER);
+ }
+ return (String) personalIdentifierObj;
+ }
+
+
/**
* Post-Process the eIDAS pseudonym to ERnB unique identifier.
*
diff --git a/eidas_modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/utils/MatchingTaskUtils.java b/eidas_modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/utils/MatchingTaskUtils.java
new file mode 100644
index 00000000..5625a30d
--- /dev/null
+++ b/eidas_modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/utils/MatchingTaskUtils.java
@@ -0,0 +1,88 @@
+package at.asitplus.eidas.specific.modules.auth.eidas.v2.utils;
+
+import javax.annotation.Nullable;
+
+import org.springframework.lang.NonNull;
+
+import at.asitplus.eidas.specific.modules.auth.eidas.v2.Constants;
+import at.asitplus.eidas.specific.modules.auth.eidas.v2.dao.SimpleEidasData;
+import at.asitplus.eidas.specific.modules.auth.eidas.v2.service.RegisterSearchService.RegisterSearchResult;
+import at.gv.egiz.eaaf.core.api.IRequest;
+import at.gv.egiz.eaaf.core.exceptions.EaafStorageException;
+import at.gv.egiz.eaaf.core.impl.idp.auth.data.AuthProcessDataWrapper;
+
+public class MatchingTaskUtils {
+
+ /**
+ * Get eIDAS log-in information from session.
+ *
+ * @param pendingReq Current pendingRequest
+ * @return eIDAS infos or null
if not exist
+ */
+ @Nullable
+ public static SimpleEidasData getInitialEidasData(IRequest pendingReq) {
+ return getAuthProcessDataWrapper(pendingReq).getGenericDataFromSession(
+ Constants.DATA_SIMPLE_EIDAS, SimpleEidasData.class);
+
+ }
+
+ /**
+ * Set eIDAS log-in information to session.
+ *
+ * @param pendingReq Current pendingRequest
+ * @param eidasData infos from eIDAS Proxy-Service
+ * @throws EaafStorageException In case of data can not be add into session
+ */
+ @Nullable
+ public static void storeInitialEidasData(IRequest pendingReq, SimpleEidasData eidasData)
+ throws EaafStorageException {
+ getAuthProcessDataWrapper(pendingReq).setGenericDataToSession(Constants.DATA_SIMPLE_EIDAS, eidasData);
+
+ }
+
+ /**
+ * Get Matching result from session.
+ *
+ * @param pendingReq Current pendingRequest
+ * @return Matching result or null
if not exist
+ */
+ @Nullable
+ public static RegisterSearchResult getInitialRegisterResult(IRequest pendingReq) {
+ return getAuthProcessDataWrapper(pendingReq).getGenericDataFromSession(Constants.DATA_INITIAL_REGISTER_RESULT,
+ RegisterSearchResult.class);
+
+ }
+
+ /**
+ * Store matching result into session.
+ *
+ * @param pendingReq Current pendingRequest
+ * @param registerData Matching result information
+ * @throws EaafStorageException In case of data can not be add into session
+ */
+ @Nullable
+ public static void storeInitialRegisterResult(IRequest pendingReq, RegisterSearchResult registerData)
+ throws EaafStorageException {
+ getAuthProcessDataWrapper(pendingReq).setGenericDataToSession(
+ Constants.DATA_INITIAL_REGISTER_RESULT, registerData);
+
+ }
+
+ /**
+ * Get holder for authentication information for the current process.
+ *
+ * @param pendingReq Current pendingRequest
+ * @return {@link AuthProcessDataWrapper}
+ */
+ @NonNull
+ public static AuthProcessDataWrapper getAuthProcessDataWrapper(IRequest pendingReq) {
+ return pendingReq.getSessionData(AuthProcessDataWrapper.class);
+
+ }
+
+ private MatchingTaskUtils() {
+ //hide constructor in case of class contains only static methods
+
+ }
+
+}
diff --git a/eidas_modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/utils/VersionHolder.java b/eidas_modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/utils/VersionHolder.java
new file mode 100644
index 00000000..dbe88d33
--- /dev/null
+++ b/eidas_modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/utils/VersionHolder.java
@@ -0,0 +1,40 @@
+package at.asitplus.eidas.specific.modules.auth.eidas.v2.utils;
+
+import java.util.Optional;
+
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+import org.springframework.context.ApplicationContext;
+
+/**
+ * SpringBoot based implementation of an application-version holder.
+ *
+ * @author tlenz
+ *
+ */
+public class VersionHolder {
+
+ private final String version;
+
+ /**
+ * Build up a holder that contains the current version of this application.
+ *
+ * @param context SprintBoot context
+ */
+ public VersionHolder(ApplicationContext context) {
+ version = context.getBeansWithAnnotation(SpringBootApplication.class).entrySet().stream()
+ .findFirst()
+ .flatMap(es -> Optional.ofNullable(es.getValue().getClass().getPackage().getImplementationVersion()))
+ .orElse("unknown");
+
+ }
+
+ /**
+ * Get version of this application.
+ *
+ * @return version
+ */
+ public String getVersion() {
+ return version;
+
+ }
+}
diff --git a/eidas_modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/zmr/DummyZmrClient.java b/eidas_modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/zmr/DummyZmrClient.java
index 80e61451..30a801a4 100644
--- a/eidas_modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/zmr/DummyZmrClient.java
+++ b/eidas_modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/zmr/DummyZmrClient.java
@@ -23,55 +23,59 @@
package at.asitplus.eidas.specific.modules.auth.eidas.v2.zmr;
-import at.asitplus.eidas.specific.modules.auth.eidas.v2.dao.RegisterResult;
-import at.asitplus.eidas.specific.modules.auth.eidas.v2.dao.SimpleEidasData;
+import java.math.BigInteger;
+import java.util.Collections;
+
import org.springframework.stereotype.Service;
-import java.util.Collections;
-import java.util.List;
+import at.asitplus.eidas.specific.modules.auth.eidas.v2.clients.zmr.IZmrClient;
+import at.asitplus.eidas.specific.modules.auth.eidas.v2.clients.zmr.ZmrSoapClient.ZmrRegisterResult;
+import at.asitplus.eidas.specific.modules.auth.eidas.v2.dao.RegisterResult;
+import at.asitplus.eidas.specific.modules.auth.eidas.v2.dao.SimpleEidasData;
+import at.asitplus.eidas.specific.modules.auth.eidas.v2.exception.EidasSAuthenticationException;
+import at.gv.bmi.namespace.zmr_su.zmr._20040201.PersonSuchenRequest;
@Service("ZmrClientForeIDAS")
public class DummyZmrClient implements IZmrClient {
@Override
- public List searchWithPersonIdentifier(String personIdentifier) {
- return Collections.emptyList();
+ public ZmrRegisterResult searchWithPersonIdentifier(BigInteger zmrProzessId, String personIdentifier) {
+ return new ZmrRegisterResult(Collections.emptyList(), null);
+
}
@Override
- public List searchWithMds(String givenName, String familyName, String dateOfBirth) {
+ public ZmrRegisterResult searchWithMds(BigInteger zmrProzessId, String givenName, String familyName,
+ String dateOfBirth, String countryCode) {
//TODO will I only receive matches where all three values match perfectly?
- return Collections.emptyList();
+ return new ZmrRegisterResult(Collections.emptyList(), null);
+
}
@Override
- public List searchDeSpecific(String givenName, String familyName, String dateOfBirth,
- String birthPlace, String birthName) {
- //TODO
- return Collections.emptyList();
- }
-
- @Override
- public List searchItSpecific(String taxNumber) {
- //TODO
- return Collections.emptyList();
+ public ZmrRegisterResult searchCountrySpecific(BigInteger zmrProzessId, PersonSuchenRequest personSearchDao,
+ String citizenCountryCode) throws EidasSAuthenticationException {
+ return new ZmrRegisterResult(Collections.emptyList(), null);
+
}
@Override
- public void update(RegisterResult registerResult, SimpleEidasData eidData) {
+ public void update(BigInteger zmrProzessId, RegisterResult registerResult, SimpleEidasData eidData) {
//TODO
}
@Override
- public List searchWithBpkZp(String bpkzp) {
+ public ZmrRegisterResult searchWithBpkZp(BigInteger zmrProzessId, String bpkzp) {
//TODO
- return Collections.emptyList();
+ return new ZmrRegisterResult(Collections.emptyList(), null);
}
@Override
- public List searchWithResidenceData(String zipcode, String city, String street) {
+ public ZmrRegisterResult searchWithResidenceData(BigInteger zmrProzessId, String givenName, String familyName,
+ String dateOfBirth, String zipcode, String city, String street) {
// TODO
- return Collections.emptyList();
+ return new ZmrRegisterResult(Collections.emptyList(), null);
}
+
}
diff --git a/eidas_modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/zmr/IZmrClient.java b/eidas_modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/zmr/IZmrClient.java
deleted file mode 100644
index 5ca69d3d..00000000
--- a/eidas_modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/zmr/IZmrClient.java
+++ /dev/null
@@ -1,48 +0,0 @@
-/*
- * Copyright 2020 A-SIT Plus GmbH
- * AT-specific eIDAS Connector has been developed in a cooperation between EGIZ,
- * A-SIT Plus GmbH, A-SIT, and Graz University of Technology.
- *
- * Licensed under the EUPL, Version 1.2 or - as soon they will be approved by
- * the European Commission - subsequent versions of the EUPL (the "License");
- * You may not use this work except in compliance with the License.
- * You may obtain a copy of the License at:
- * https://joinup.ec.europa.eu/news/understanding-eupl-v12
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" basis,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- * 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.asitplus.eidas.specific.modules.auth.eidas.v2.zmr;
-
-import at.asitplus.eidas.specific.modules.auth.eidas.v2.dao.RegisterResult;
-import at.asitplus.eidas.specific.modules.auth.eidas.v2.dao.SimpleEidasData;
-
-import java.util.List;
-
-public interface IZmrClient {
-
- List searchWithPersonIdentifier(String personIdentifier);
-
- List searchWithMds(String givenName, String familyName, String dateOfBirth);
-
- List searchDeSpecific(String givenName, String familyName, String dateOfBirth,
- String birthPlace, String birthName);
-
- List searchItSpecific(String taxNumber);
-
- void update(RegisterResult registerResult, SimpleEidasData eidData);
-
- List searchWithBpkZp(String bpkzp);
-
- List searchWithResidenceData(String zipcode, String city, String street);
-
-}
--
cgit v1.2.3