From 6d09f43225ba2e0f6d7b0583f843c858a1015807 Mon Sep 17 00:00:00 2001
From: Thomas Lenz <thomas.lenz@egiz.gv.at>
Date: Thu, 26 Jul 2018 10:30:14 +0200
Subject: namespace refactoring

---
 .../modules/authmodule_eIDASv2/Constants.java      | 110 ++++++
 .../eIDASAuthenticationModulImpl.java              |  53 +++
 .../eIDASAuthenticationSpringResourceProvider.java |  30 ++
 .../authmodule_eIDASv2/eIDASSignalServlet.java     | 131 +++++++
 .../exception/SZRCommunicationException.java       |  15 +
 .../exception/eIDASAttributeException.java         |  15 +
 .../exception/eIDASAuthenticationException.java    |  20 ++
 .../exception/eIDASValidationException.java        |  14 +
 .../service/eIDASAttributeRegistry.java            | 115 +++++++
 .../modules/authmodule_eIDASv2/szr/SZRClient.java  | 372 ++++++++++++++++++++
 .../modules/authmodule_eIDASv2/szr/SZRService.java | 139 ++++++++
 .../tasks/CreateIdentityLinkTask.java              | 380 +++++++++++++++++++++
 .../tasks/GenerateAuthnRequestTask.java            | 306 +++++++++++++++++
 .../tasks/ReceiveAuthnResponseTask.java            |  97 ++++++
 .../authmodule_eIDASv2/utils/LoggingHandler.java   |  52 +++
 .../utils/eIDASResponseUtils.java                  |  98 ++++++
 .../validator/eIDASResponseValidator.java          | 135 ++++++++
 17 files changed, 2082 insertions(+)
 create mode 100644 eidas_modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/authmodule_eIDASv2/Constants.java
 create mode 100644 eidas_modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/authmodule_eIDASv2/eIDASAuthenticationModulImpl.java
 create mode 100644 eidas_modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/authmodule_eIDASv2/eIDASAuthenticationSpringResourceProvider.java
 create mode 100644 eidas_modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/authmodule_eIDASv2/eIDASSignalServlet.java
 create mode 100644 eidas_modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/authmodule_eIDASv2/exception/SZRCommunicationException.java
 create mode 100644 eidas_modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/authmodule_eIDASv2/exception/eIDASAttributeException.java
 create mode 100644 eidas_modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/authmodule_eIDASv2/exception/eIDASAuthenticationException.java
 create mode 100644 eidas_modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/authmodule_eIDASv2/exception/eIDASValidationException.java
 create mode 100644 eidas_modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/authmodule_eIDASv2/service/eIDASAttributeRegistry.java
 create mode 100644 eidas_modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/authmodule_eIDASv2/szr/SZRClient.java
 create mode 100644 eidas_modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/authmodule_eIDASv2/szr/SZRService.java
 create mode 100644 eidas_modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/authmodule_eIDASv2/tasks/CreateIdentityLinkTask.java
 create mode 100644 eidas_modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/authmodule_eIDASv2/tasks/GenerateAuthnRequestTask.java
 create mode 100644 eidas_modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/authmodule_eIDASv2/tasks/ReceiveAuthnResponseTask.java
 create mode 100644 eidas_modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/authmodule_eIDASv2/utils/LoggingHandler.java
 create mode 100644 eidas_modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/authmodule_eIDASv2/utils/eIDASResponseUtils.java
 create mode 100644 eidas_modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/authmodule_eIDASv2/validator/eIDASResponseValidator.java

(limited to 'eidas_modules/authmodule-eIDAS-v2/src/main/java/at/asitplus')

diff --git a/eidas_modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/authmodule_eIDASv2/Constants.java b/eidas_modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/authmodule_eIDASv2/Constants.java
new file mode 100644
index 00000000..64cf6af2
--- /dev/null
+++ b/eidas_modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/authmodule_eIDASv2/Constants.java
@@ -0,0 +1,110 @@
+/*******************************************************************************
+ *******************************************************************************/
+package at.asitplus.eidas.specific.modules.authmodule_eIDASv2;
+
+import java.net.URI;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+import at.gv.egiz.eaaf.core.api.data.EAAFConstants;
+
+public class Constants {
+ 	
+	public static final String DATA_REQUESTERID = "req_requesterId";
+	public static final String DATA_PROVIDERNAME = "req_providerName";
+	public static final String DATA_REQUESTED_LOA_LIST = "req_requestedLoA";
+	public static final String DATA_REQUESTED_LOA_COMPERISON = "req_requestedLoAComperision";	
+	public static final String DATA_FULL_EIDAS_RESPONSE = "resp_fulleIDASResponse";
+	
+	
+	//templates for post-binding forwarding
+	public static final String TEMPLATE_POST_FORWARD_NAME = "eidas_node_forward.html";
+	public static final String TEMPLATE_POST_FORWARD_ENDPOINT = "endPoint";
+	public static final String TEMPLATE_POST_FORWARD_TOKEN_NAME = "tokenName";
+	public static final String TEMPLATE_POST_FORWARD_TOKEN_VALUE = "tokenValue";
+	
+	
+	//configuration properties
+	public static final String CONIG_PROPS_EIDAS_PREFIX="auth.eIDAS";
+	public static final String CONIG_PROPS_EIDAS_NODE= CONIG_PROPS_EIDAS_PREFIX + ".node_v2";
+	public static final String CONIG_PROPS_EIDAS_NODE_COUNTRYCODE = CONIG_PROPS_EIDAS_NODE + ".countrycode";
+	public static final String CONIG_PROPS_EIDAS_NODE_PUBLICSECTOR_TARGETS = CONIG_PROPS_EIDAS_NODE + ".publicSectorTargets";
+	public static final String CONIG_PROPS_EIDAS_NODE_ENTITYID = CONIG_PROPS_EIDAS_NODE + ".entityId";
+	public static final String CONIG_PROPS_EIDAS_NODE_FORWARD_URL = CONIG_PROPS_EIDAS_NODE + ".forward.endpoint";
+	public static final String CONIG_PROPS_EIDAS_NODE_FORWARD_METHOD = CONIG_PROPS_EIDAS_NODE + ".forward.method";
+	public static final String CONIG_PROPS_EIDAS_NODE_ATTRIBUTES_REQUESTED_ONLYNATURAL = CONIG_PROPS_EIDAS_NODE + ".attributes.requested.onlynatural.";
+	public static final String CONIG_PROPS_EIDAS_NODE_ATTRIBUTES_REQUESTED_REPRESENTATION = CONIG_PROPS_EIDAS_NODE + ".attributes.requested.representation.";
+	public static final String CONIG_PROPS_EIDAS_NODE_WORKAROUND_ADD_ALWAYS_PROVIDERNAME = CONIG_PROPS_EIDAS_NODE + ".workarounds.addAlwaysProviderName";;
+	public static final String CONIG_PROPS_EIDAS_NODE_WORKAROUND_USEREQUESTIDASTRANSACTIONIDENTIFIER = CONIG_PROPS_EIDAS_NODE + ".workarounds.useRequestIdAsTransactionIdentifier";
+	
+	public static final String FORWARD_METHOD_POST = "POST";
+	public static final String FORWARD_METHOD_GET = "GET";
+	
+	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";
+	public static final String CONIG_PROPS_EIDAS_SZRCLIENT_DEBUG_TRACEMESSAGES= CONIG_PROPS_EIDAS_SZRCLIENT + ".debug.logfullmessages";
+	public static final String CONIG_PROPS_EIDAS_SZRCLIENT_DEBUG_USEDUMMY= CONIG_PROPS_EIDAS_SZRCLIENT + ".debug.useDummySolution";
+	public static final String CONIG_PROPS_EIDAS_SZRCLIENT_DEBUG_INSERTERNB= CONIG_PROPS_EIDAS_SZRCLIENT + ".debug.insertERnB";
+	public static final String CONIG_PROPS_EIDAS_SZRCLIENT_TIMEOUT_CONNECTION= CONIG_PROPS_EIDAS_SZRCLIENT + ".timeout.connection";
+	public static final String CONIG_PROPS_EIDAS_SZRCLIENT_TIMEOUT_RESPONSE= CONIG_PROPS_EIDAS_SZRCLIENT + ".timeout.response";
+	public static final String CONIG_PROPS_EIDAS_SZRCLIENT_ENDPOINT_PROD= CONIG_PROPS_EIDAS_SZRCLIENT + ".endpoint.prod";
+	public static final String CONIG_PROPS_EIDAS_SZRCLIENT_ENDPOINT_TEST= CONIG_PROPS_EIDAS_SZRCLIENT + ".endpoint.test";
+	public static final String CONIG_PROPS_EIDAS_SZRCLIENT_SSL_KEYSTORE_PATH = CONIG_PROPS_EIDAS_SZRCLIENT + ".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_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_PARAMS_EDOCUMENTTYPE = CONIG_PROPS_EIDAS_SZRCLIENT + ".params.documenttype";
+	public static final String CONIG_PROPS_EIDAS_SZRCLIENT_PARAMS_VKZ = CONIG_PROPS_EIDAS_SZRCLIENT + ".params.vkz";
+	public static final String CONIG_PROPS_EIDAS_SZRCLIENT_PARAMS_ISSUING_DATE = CONIG_PROPS_EIDAS_SZRCLIENT + ".params.issuingdate";
+	public static final String CONIG_PROPS_EIDAS_SZRCLIENT_PARAMS_ISSUING_AUTHORITY = CONIG_PROPS_EIDAS_SZRCLIENT + ".params.issuingauthority";
+	public static final String CONIG_PROPS_EIDAS_SZRCLIENT_PARAMS_KEYS_USEDUMMY= CONIG_PROPS_EIDAS_SZRCLIENT + ".params.usedummykeys";
+	
+	//http endpoint descriptions
+	public static final String eIDAS_HTTP_ENDPOINT_SP_POST = "/eidas/light/sp/post";
+	public static final String eIDAS_HTTP_ENDPOINT_SP_REDIRECT = "/eidas/light/sp/redirect";
+	public static final String eIDAS_HTTP_ENDPOINT_IDP_COLLEAGUEREQUEST = "/eidas/light/ColleagueRequest";
+	public static final String eIDAS_HTTP_ENDPOINT_METADATA = "/eidas/light/metadata";
+	
+	//eIDAS request parameters
+	public static final String eIDAS_REQ_NAMEID_FORMAT = "urn:oasis:names:tc:SAML:2.0:nameid-format:persistent";
+	
+	//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";	
+	public static final String eIDAS_ATTR_CURRENTFAMILYNAME = "FamilyName";	
+	public static final String eIDAS_ATTR_LEGALPERSONIDENTIFIER = "LegalPersonIdentifier";
+	public static final String eIDAS_ATTR_LEGALNAME = "LegalName";
+	
+	 public static final List<URI> NATURALPERSONMINIMUMDATASETLIST = Collections.unmodifiableList(new ArrayList<URI>() {
+			private static final long serialVersionUID = 1L;
+			{
+				//TODO: find correct location of attribute definitions
+//				add(eu.eidas.auth.engine.core.eidas.spec.NaturalPersonSpec.Definitions.CURRENT_FAMILY_NAME.getNameUri());
+//				add(eu.eidas.auth.engine.core.eidas.spec.NaturalPersonSpec.Definitions.CURRENT_GIVEN_NAME.getNameUri());
+//				add(eu.eidas.auth.engine.core.eidas.spec.NaturalPersonSpec.Definitions.DATE_OF_BIRTH.getNameUri());
+//				add(eu.eidas.auth.engine.core.eidas.spec.NaturalPersonSpec.Definitions.PERSON_IDENTIFIER.getNameUri());
+			}
+		});
+	 
+	 public static final String POLICY_DEFAULT_ALLOWED_TARGETS = 
+				EAAFConstants.URN_PREFIX_CDID.replaceAll("\\.", "\\\\.").replaceAll("\\+", "\\\\+") + ".*";
+	 
+	 //SAML2 Constants
+	 public static final String SUCCESS_URI = "urn:oasis:names:tc:SAML:2.0:status:Success";
+	 
+	 public static final String HTTP_CLIENT_DEFAULT_TIMEOUT_CONNECTION = "30";  //seconds
+	 public static final String HTTP_CLIENT_DEFAULT_TIMEOUT_RESPONSE = "60";    //seconds
+	
+	 
+	 //Default values for SZR communication
+	 public static final String SZR_CONSTANTS_DEFAULT_DOCUMENT_TYPE = "ELEKTR_DOKUMENT";
+	 
+	 //TODO remove!!!
+	 public static final String SZR_CONSTANTS_DEFAULT_ISSUING_DATE = "2014-01-01";
+	 public static final String SZR_CONSTANTS_DEFAULT_ISSUING_AUTHORITY = "ms-specific eIDAS-Node for AT";
+	 public final static byte[] SZR_CONSTANTS_DEFAULT_PUBL_KEY = new byte[] {48, -127, -97, 48, 13, 6, 9, 42, -122, 72, -122, -9, 13, 1, 1, 1, 5, 0, 3, -127, -115, 0, 48, -127, -119, 2, -127, -127, 0, -106, 114, -113, -1, -84, 116, 35, 3, 70, -81, 81, -110, -10, -59, 114, 4, -109, 86, 127, -50, 125, 47, 4, 80, 79, 53, 117, -36, 15, -16, -61, 110, 39, 89, 29, -43, 37, -127, 80, -109, -38, 65, 125, -119, 44, -111, -21, 47, -98, 38, -112, -24, 107, -110, 17, -10, 51, -4, -36, -72, -28, -18, -14, 117, -67, 76, -31, 32, 92, 104, -21, 68, 31, -12, 30, -104, -104, 42, -107, 126, 84, 50, 85, -117, 44, -100, -4, 102, -100, 52, -68, 77, -32, 9, -16, -30, -104, -90, 107, -88, 7, 97, -94, 72, -61, -40, 80, -112, -65, -25, -72, -19, -95, -54, 31, 15, 24, -105, 123, -81, 23, -123, 92, -103, -101, 47, 47, -105, 2, 3, 1, 0, 1};
+
+}
diff --git a/eidas_modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/authmodule_eIDASv2/eIDASAuthenticationModulImpl.java b/eidas_modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/authmodule_eIDASv2/eIDASAuthenticationModulImpl.java
new file mode 100644
index 00000000..39be3fbd
--- /dev/null
+++ b/eidas_modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/authmodule_eIDASv2/eIDASAuthenticationModulImpl.java
@@ -0,0 +1,53 @@
+/*******************************************************************************
+ *******************************************************************************/
+package at.asitplus.eidas.specific.modules.authmodule_eIDASv2;
+
+import org.apache.commons.lang3.StringUtils;
+
+import at.asitplus.eidas.specific.connector.MSeIDASNodeConstants;
+import at.gv.egiz.eaaf.core.api.idp.auth.modules.AuthModule;
+import at.gv.egiz.eaaf.core.api.idp.process.ExecutionContext;
+
+/**
+ * @author tlenz
+ *
+ */
+public class eIDASAuthenticationModulImpl implements AuthModule {
+
+	private int priority = 1;
+
+	@Override
+	public int getPriority() { 
+		return priority;
+	} 
+
+	/**
+	 * Sets the priority of this module. Default value is {@code 0}.
+	 * @param priority The priority.
+	 */
+	public void setPriority(int priority) {
+		this.priority = priority;
+	}
+
+	/* (non-Javadoc)
+	 * @see at.gv.egovernment.moa.id.auth.modules.AuthModule#selectProcess(at.gv.egovernment.moa.id.process.api.ExecutionContext)
+	 */
+	@Override
+	public String selectProcess(ExecutionContext context) {
+		if (StringUtils.isNotBlank((String) context.get(MSeIDASNodeConstants.REQ_PARAM_SELECTED_COUNTRY)) || 
+				StringUtils.isNotBlank((String) context.get(MSeIDASNodeConstants.REQ_PARAM_SELECTED_COUNTRY)))
+			return "eIDASAuthentication_v2";
+		else
+			return null;
+		
+	}
+
+	/* (non-Javadoc)
+	 * @see at.gv.egovernment.moa.id.auth.modules.AuthModule#getProcessDefinitions()
+	 */
+	@Override
+	public String[] getProcessDefinitions() {
+		return new String[] { "classpath:eIDAS.Authentication.process.xml" };
+	}
+
+}
diff --git a/eidas_modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/authmodule_eIDASv2/eIDASAuthenticationSpringResourceProvider.java b/eidas_modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/authmodule_eIDASv2/eIDASAuthenticationSpringResourceProvider.java
new file mode 100644
index 00000000..d44ef348
--- /dev/null
+++ b/eidas_modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/authmodule_eIDASv2/eIDASAuthenticationSpringResourceProvider.java
@@ -0,0 +1,30 @@
+/*******************************************************************************
+ *******************************************************************************/
+package at.asitplus.eidas.specific.modules.authmodule_eIDASv2;
+
+import org.springframework.core.io.ClassPathResource;
+import org.springframework.core.io.Resource;
+
+import at.gv.egiz.components.spring.api.SpringResourceProvider;
+
+public class eIDASAuthenticationSpringResourceProvider implements SpringResourceProvider {
+
+	@Override
+	public String getName() {
+		return "Auth. module for eIDAS Ref. Impl. v2.x";
+	}
+
+	@Override
+	public String[] getPackagesToScan() {
+		// TODO Auto-generated method stub
+		return null;
+	}
+
+	@Override
+	public Resource[] getResourcesToLoad() {
+		ClassPathResource eIDASAuthConfig = new ClassPathResource("/eidas_v2_auth.beans.xml", eIDASAuthenticationSpringResourceProvider.class);					
+		
+		return new Resource[] {eIDASAuthConfig};
+	}
+
+}
diff --git a/eidas_modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/authmodule_eIDASv2/eIDASSignalServlet.java b/eidas_modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/authmodule_eIDASv2/eIDASSignalServlet.java
new file mode 100644
index 00000000..41e2aa03
--- /dev/null
+++ b/eidas_modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/authmodule_eIDASv2/eIDASSignalServlet.java
@@ -0,0 +1,131 @@
+/*******************************************************************************
+ *******************************************************************************/
+package at.asitplus.eidas.specific.modules.authmodule_eIDASv2;
+
+import java.io.IOException;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.apache.commons.lang3.StringUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.ApplicationContext;
+import org.springframework.stereotype.Controller;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestMethod;
+
+import com.google.common.collect.ImmutableSortedSet;
+
+import at.asitplus.eidas.specific.modules.authmodule_eIDASv2.exception.eIDASAuthenticationException;
+import at.asitplus.eidas.specific.modules.authmodule_eIDASv2.service.eIDASAttributeRegistry;
+import at.gv.egiz.eaaf.core.impl.idp.controller.AbstractProcessEngineSignalController;
+import eu.eidas.auth.commons.EidasParameterKeys;
+import eu.eidas.auth.commons.light.ILightResponse;
+import eu.eidas.specificcommunication.SpecificCommunicationDefinitionBeanNames;
+import eu.eidas.specificcommunication.exception.SpecificCommunicationException;
+import eu.eidas.specificcommunication.protocol.impl.SpecificConnectorCommunicationServiceImpl;
+
+
+/**
+ * @author tlenz
+ *
+ */
+@Controller
+public class eIDASSignalServlet extends AbstractProcessEngineSignalController {
+	
+	private static final Logger log = LoggerFactory.getLogger(eIDASSignalServlet.class);
+	@Autowired private ApplicationContext context;
+	@Autowired private eIDASAttributeRegistry attrRegistry;
+	
+	public eIDASSignalServlet() { 
+		super();
+		log.debug("Registering servlet " + getClass().getName() + 
+				" with mappings '"+ Constants.eIDAS_HTTP_ENDPOINT_SP_POST + 
+				"' and '"+ Constants.eIDAS_HTTP_ENDPOINT_SP_REDIRECT + "'.");
+		
+	}
+	
+	@RequestMapping(value = { Constants.eIDAS_HTTP_ENDPOINT_SP_POST, 
+							  Constants.eIDAS_HTTP_ENDPOINT_SP_REDIRECT
+							}, 
+					method = {RequestMethod.POST, RequestMethod.GET})
+	public void restoreEidasAuthProcess(HttpServletRequest req, HttpServletResponse resp) throws IOException {
+		signalProcessManagement(req, resp);
+	}
+	
+	
+	/**
+	 * Protocol specific implementation to get the pending-requestID 
+	 * from http request object
+	 * 
+	 * @param request The http Servlet-Request object
+	 * @return The Pending-request id 
+	 * 
+	 */
+	@Override
+	public String getPendingRequestId(HttpServletRequest request) {
+		//String sessionId = super.getPendingRequestId(request);
+		
+		try {
+			//get token from Request
+			final String tokenBase64 = request.getParameter(EidasParameterKeys.TOKEN.toString());			
+			if (StringUtils.isEmpty(tokenBase64)) {
+				log.warn("NO eIDAS message token found.");
+				throw new eIDASAuthenticationException("eidas.04", null);
+				
+			}
+			log.trace("Receive eIDAS-node token: " + tokenBase64 + " Starting transaction-restore process ... ");
+			
+			
+			
+			final SpecificConnectorCommunicationServiceImpl specificConnectorCommunicationService =
+	                (SpecificConnectorCommunicationServiceImpl) context.getBean(SpecificCommunicationDefinitionBeanNames.SPECIFIC_CONNECTOR_COMMUNICATION_SERVICE.toString());
+			ILightResponse eIDASResponse = specificConnectorCommunicationService.getAndRemoveResponse(tokenBase64, 
+    			ImmutableSortedSet.copyOf(attrRegistry.getCoreAttributeRegistry().getAttributes()));
+				
+			String pendingReqId = null;
+			if (StringUtils.isEmpty(eIDASResponse.getRelayState())) {
+				log.debug("eIDAS Node returns no RelayState. ");
+				
+				if (authConfig.getBasicMOAIDConfigurationBoolean(
+						Constants.CONIG_PROPS_EIDAS_NODE_WORKAROUND_USEREQUESTIDASTRANSACTIONIDENTIFIER, 
+						false)) {
+					log.trace("Use lightRequestId to recover session ... ");
+					pendingReqId = transactionStorage.get(eIDASResponse.getInResponseToId(), String.class);
+					if (StringUtils.isNotEmpty(pendingReqId)) {
+						log.debug("Restoring session with lightRequestId ... ");
+						transactionStorage.remove(eIDASResponse.getInResponseToId());
+						
+					}		
+				} 
+											
+			} else {			
+				log.debug("Find transaction identifier in SAML2 'RelayState': " + eIDASResponse.getRelayState());
+				pendingReqId = eIDASResponse.getRelayState();
+				 				
+			}
+
+			if (StringUtils.isNotEmpty(pendingReqId)) {
+				request.setAttribute(Constants.DATA_FULL_EIDAS_RESPONSE, eIDASResponse);
+				return pendingReqId;
+				
+			}
+
+			log.info("NO transaction identifier found! Stopping process ....");
+			log.trace("FullResponse: " + eIDASResponse.toString());
+			
+		} catch (SpecificCommunicationException e) {
+			log.warn("Can NOT load eIDAS Response from cache.", e);
+			log.debug("eIDAS response token was: " + request.getParameter(EidasParameterKeys.TOKEN.toString()));
+			
+		} catch (Exception e) {
+			log.warn("Unable to retrieve moa session id.", e);
+			
+		}
+
+		return null;
+	}
+	
+}
diff --git a/eidas_modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/authmodule_eIDASv2/exception/SZRCommunicationException.java b/eidas_modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/authmodule_eIDASv2/exception/SZRCommunicationException.java
new file mode 100644
index 00000000..defc03db
--- /dev/null
+++ b/eidas_modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/authmodule_eIDASv2/exception/SZRCommunicationException.java
@@ -0,0 +1,15 @@
+package at.asitplus.eidas.specific.modules.authmodule_eIDASv2.exception;
+
+public class SZRCommunicationException extends eIDASAuthenticationException {
+
+	private static final long serialVersionUID = 1L;
+
+	public SZRCommunicationException(String internalMsgId, Object[] params) {
+		super(internalMsgId, params);
+	}
+
+	public SZRCommunicationException(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/authmodule_eIDASv2/exception/eIDASAttributeException.java b/eidas_modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/authmodule_eIDASv2/exception/eIDASAttributeException.java
new file mode 100644
index 00000000..2ce9fcd7
--- /dev/null
+++ b/eidas_modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/authmodule_eIDASv2/exception/eIDASAttributeException.java
@@ -0,0 +1,15 @@
+package at.asitplus.eidas.specific.modules.authmodule_eIDASv2.exception;
+
+public class eIDASAttributeException extends eIDASAuthenticationException {
+
+	/**
+	 * 
+	 */
+	private static final long serialVersionUID = 1L;
+
+	public eIDASAttributeException(String attrbuteName) {
+		super("eidas.00", new Object[] {attrbuteName});
+
+	}
+
+}
diff --git a/eidas_modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/authmodule_eIDASv2/exception/eIDASAuthenticationException.java b/eidas_modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/authmodule_eIDASv2/exception/eIDASAuthenticationException.java
new file mode 100644
index 00000000..93298a92
--- /dev/null
+++ b/eidas_modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/authmodule_eIDASv2/exception/eIDASAuthenticationException.java
@@ -0,0 +1,20 @@
+package at.asitplus.eidas.specific.modules.authmodule_eIDASv2.exception;
+
+import at.gv.egiz.eaaf.core.exceptions.EAAFAuthenticationException;
+
+public class eIDASAuthenticationException extends EAAFAuthenticationException{
+
+	/**
+	 * 
+	 */
+	private static final long serialVersionUID = 1L;
+
+	public eIDASAuthenticationException(String internalMsgId, Object[] params) {
+		super(internalMsgId, params);
+	}
+	
+	public eIDASAuthenticationException(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/authmodule_eIDASv2/exception/eIDASValidationException.java b/eidas_modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/authmodule_eIDASv2/exception/eIDASValidationException.java
new file mode 100644
index 00000000..2bac7d04
--- /dev/null
+++ b/eidas_modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/authmodule_eIDASv2/exception/eIDASValidationException.java
@@ -0,0 +1,14 @@
+package at.asitplus.eidas.specific.modules.authmodule_eIDASv2.exception;
+
+public class eIDASValidationException extends eIDASAuthenticationException {
+
+	/**
+	 * 
+	 */
+	private static final long serialVersionUID = 1L;
+
+	public eIDASValidationException(String internalMsgId, Object[] params) {
+		super(internalMsgId, params);
+	}
+
+}
diff --git a/eidas_modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/authmodule_eIDASv2/service/eIDASAttributeRegistry.java b/eidas_modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/authmodule_eIDASv2/service/eIDASAttributeRegistry.java
new file mode 100644
index 00000000..de9f6455
--- /dev/null
+++ b/eidas_modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/authmodule_eIDASv2/service/eIDASAttributeRegistry.java
@@ -0,0 +1,115 @@
+package at.asitplus.eidas.specific.modules.authmodule_eIDASv2.service;
+
+import java.io.File;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import javax.annotation.PostConstruct;
+
+import org.apache.commons.lang3.StringUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import at.asitplus.eidas.specific.modules.authmodule_eIDASv2.Constants;
+import at.gv.egiz.eaaf.core.api.idp.IConfiguration;
+import at.gv.egiz.eaaf.core.exceptions.EAAFConfigurationException;
+import at.gv.egiz.eaaf.core.impl.utils.KeyValueUtils;
+import eu.eidas.auth.commons.attribute.AttributeRegistries;
+import eu.eidas.auth.commons.attribute.AttributeRegistry;
+
+@Service("attributeRegistry")
+public class eIDASAttributeRegistry {
+	private static final Logger log = LoggerFactory.getLogger(eIDASAttributeRegistry.class);	
+	@Autowired private IConfiguration basicConfig;
+	
+	private AttributeRegistry coreAttributeRegistry;
+	 
+	private String eidasAttributesFile;
+	private String additionalAttributesFile;
+	
+	@PostConstruct
+	private void initialize() throws RuntimeException {
+		try {
+			if (eidasAttributesFile.isEmpty()) {
+				log.error("Basic eIDAS addribute definition NOT defined");
+				throw new EAAFConfigurationException("config.30", 
+						new Object[] {"eidas-attributes.xml"});
+			
+			}
+        
+			boolean additionalAttrAvailabe = false;
+			if (!additionalAttributesFile.isEmpty()) {
+				File file = new File(additionalAttributesFile);
+				if (file.exists())
+					additionalAttrAvailabe = true;
+								
+			}
+			
+			if (!additionalAttrAvailabe) {
+				log.info("Start eIDAS ref. impl. Core without additional eIDAS attribute definitions ... ");
+				coreAttributeRegistry = AttributeRegistries.fromFiles(eidasAttributesFile, null);
+				
+			} else {
+				//load attribute definitions
+				log.info("Start eIDAS ref. impl. Core with additional eIDAS attribute definitions ... ");
+				coreAttributeRegistry = AttributeRegistries.fromFiles(eidasAttributesFile, null, additionalAttributesFile);
+
+			}
+						
+        } catch (Throwable e) {
+			log.error("Can NOT initialize eIDAS attribute definition." , e);
+			new RuntimeException("Can NOT initialize eIDAS attribute definition.", e);
+			
+		}        	
+	}
+	
+	
+    public AttributeRegistry getCoreAttributeRegistry() {
+        return coreAttributeRegistry;
+    }
+
+	public Map<String, Boolean> getAttributeSetFromConfiguration() {
+		Map<String, Boolean> result = new HashMap<String, Boolean>();
+		
+		/*TODO: select set for representation if mandates should be used.
+		 * It's an open task in respect to requested eIDAS attributes and isRequired flag,
+		 * because there can be a decision problem in case of natural or legal person representation!
+		 * From an Austrian use-case point of view, an Austrian service provider can support mandates for 
+		 * natural and legal persons at the same time. However, we CAN NOT request attributes for natural AND
+		 * legal persons on the same time, because it's not possible to represent both simultaneously.
+		 */
+		Map<String, String> configAttributes = 
+				basicConfig.getBasicMOAIDConfigurationWithPrefix(
+						Constants.CONIG_PROPS_EIDAS_NODE_ATTRIBUTES_REQUESTED_ONLYNATURAL);
+		for (String el: configAttributes.values()) {
+			if (StringUtils.isNotEmpty(el.trim())) {
+				List<String> attrDef = KeyValueUtils.getListOfCSVValues(el.trim());
+				boolean isRequired = false;
+				if (attrDef.size() == 2)
+					isRequired = Boolean.parseBoolean(attrDef.get(1));
+				
+				result.put(attrDef.get(0), isRequired);
+				
+			}			
+		}
+		
+		log.trace("Load #" + result.size() + " requested attributes from configuration");
+		return result;
+		
+	}
+
+
+	public void setEidasAttributesFile(String eidasAttributesFile) {
+		this.eidasAttributesFile = eidasAttributesFile;
+	}
+
+	public void setAdditionalAttributesFile(String additionalAttributesFile) {
+		this.additionalAttributesFile = additionalAttributesFile;
+	}
+	
+	
+}
+
diff --git a/eidas_modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/authmodule_eIDASv2/szr/SZRClient.java b/eidas_modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/authmodule_eIDASv2/szr/SZRClient.java
new file mode 100644
index 00000000..cec36d4b
--- /dev/null
+++ b/eidas_modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/authmodule_eIDASv2/szr/SZRClient.java
@@ -0,0 +1,372 @@
+package at.asitplus.eidas.specific.modules.authmodule_eIDASv2.szr;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.net.URL;
+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.List;
+import java.util.Map;
+
+import javax.annotation.PostConstruct;
+import javax.annotation.Resource;
+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.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.WebServiceContext;
+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.xpath.XPathAPI;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import org.w3._2000._09.xmldsig.KeyValueType;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+
+import at.asitplus.eidas.specific.modules.authmodule_eIDASv2.Constants;
+import at.asitplus.eidas.specific.modules.authmodule_eIDASv2.exception.SZRCommunicationException;
+import at.asitplus.eidas.specific.modules.authmodule_eIDASv2.utils.LoggingHandler;
+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.GetIdentityLink;
+import szrservices.GetIdentityLinkResponse;
+import szrservices.IdentityLinkType;
+import szrservices.PersonInfoType;
+import szrservices.SZR;
+import szrservices.SZRException_Exception;
+
+@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";
+	
+	@Autowired private IConfiguration basicConfig;
+	@Resource private WebServiceContext wsContext;
+	 
+	//client for anything, without identitylink
+	private SZR szr = null;
+	 
+	//RAW client is needed for identitylink 
+	private Dispatch<Source> dispatch = null; 
+	
+	 
+	private SZRService szrService = null;
+	private String szrURL = null;
+	private QName qname = null;
+	
+	public IdentityLinkType getIdentityLink(PersonInfoType personInfo, List<KeyValueType> keyValue, Boolean insertERnP) throws SZRCommunicationException  {
+		try {
+			return szr.getIdentityLink(
+					personInfo, 
+					keyValue,  
+					insertERnP);
+			 
+		} catch (SZRException_Exception e) {
+			log.warn("SZR communication FAILED. Reason: " + e.getMessage(), e);
+			throw new SZRCommunicationException("ernb.02", new Object[] {e.getMessage()}, e);
+			
+		}
+				
+	}
+	
+	public IdentityLinkType getIdentityLinkInRawMode(PersonInfoType personInfo, List<KeyValueType> keyValue, Boolean insertERnP) throws SZRCommunicationException  {					
+		try {
+			GetIdentityLink getIDL = new GetIdentityLink();
+				getIDL.setInsertERnP(insertERnP);
+				getIDL.setPersonInfo(personInfo);
+				getIDL.getKeyValue().addAll(keyValue);
+		
+				JAXBContext jaxbContext = JAXBContext.newInstance(GetIdentityLink.class);
+				Marshaller jaxbMarshaller = jaxbContext.createMarshaller();
+		
+				final ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
+				jaxbMarshaller.marshal(getIDL, outputStream);
+				outputStream.flush();
+		
+				Source source = new StreamSource(new ByteArrayInputStream(outputStream.toByteArray()));
+				outputStream.close();
+		
+				log.trace("Requesting SZR ... ");
+				Source response = dispatch.invoke(source);
+				log.trace("Receive RAW response from SZR");
+				
+				byte[] szrResponse = sourceToByteArray(response);
+				JAXBContext ctx = JAXBContext.newInstance(IdentityLinkType.class
+				    .getPackage().getName());
+				GetIdentityLinkResponse jaxbElement = (GetIdentityLinkResponse) ctx
+				    .createUnmarshaller().unmarshal(new ByteArrayInputStream(szrResponse));
+		
+				
+				//build response
+				log.trace(new String(szrResponse));
+				log.trace("Signature successfully created. Extracting from MOA-SS container.");
+				
+				// ok, we have success
+				Document doc = DOMUtils.parseDocument(
+							new ByteArrayInputStream(szrResponse),
+							true, XMLNamespaceConstants.ALL_SCHEMA_LOCATIONS, null, null
+						);				
+				String xpathExpression = "//saml:Assertion";				
+				Element nsNode = doc.createElementNS("urn:oasis:names:tc:SAML:1.0:assertion", "saml:NSNode");
+
+				log.trace("Selecting signed doc " + xpathExpression);
+				Element documentNode = (Element) XPathAPI.selectSingleNode(doc,
+				    xpathExpression, nsNode);
+				log.trace("Signed document: " + DOMUtils.serializeNode(documentNode));
+
+				
+				IdentityLinkType idl = new IdentityLinkType();
+				idl.setAssertion(documentNode);
+				idl.setPersonInfo(jaxbElement.getGetIdentityLinkReturn().getPersonInfo());
+				
+				return idl;
+				
+		
+				//IdentityLinkType idlResp = this.szr.getIdentityLink(personInfo, keyValue, insertERnP);
+				
+		} catch ( Exception e) {
+			log.warn("SZR communication FAILED. Reason: " + e.getMessage(), e);
+			throw new SZRCommunicationException("ernb.02", new Object[] {e.getMessage()}, e);
+			
+		}
+				
+	}
+	
+	public String getBPK(PersonInfoType personInfo, String target, String vkz) throws SZRCommunicationException {		
+		try {
+			GetBPK parameters = new GetBPK();
+			parameters.setPersonInfo(personInfo);
+			parameters.setBereichsKennung(target);
+			parameters.setVKZ(vkz);
+			GetBPKResponse result = this.szr.getBPK(parameters);
+
+			return result.getGetBPKReturn();
+			
+		} catch (SZRException_Exception e) {
+			log.warn("SZR communication FAILED. Reason: " + e.getMessage(), e);
+			throw new SZRCommunicationException("ernb.02", new Object[] {e.getMessage()}, e);
+			
+		}
+
+	}
+	
+	
+	@PostConstruct
+	private void initialize() {
+		log.info("Starting SZR-Client initialization .... ");
+		URL url = SZRClient.class.getResource("/szr_client/SZR-1.WSDL");
+		
+		boolean useTestSZR = basicConfig.getBasicMOAIDConfigurationBoolean(
+				Constants.CONIG_PROPS_EIDAS_SZRCLIENT_USETESTSERVICE, 
+				true);
+			
+		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.");
+			
+		}
+		
+		log.info("Use SZR service-URL: " + szrURL);		
+		injectBindingProvider((BindingProvider) szr, CLIENT_DEFAULT);
+		injectBindingProvider((BindingProvider) dispatch, CLIENT_RAW);
+		
+		log.debug("Inject HTTP client settings ... ");
+		injectHTTPClient(szr, CLIENT_DEFAULT);
+		injectHTTPClient(dispatch, CLIENT_RAW);
+
+	  	log.info("SZR-Client initialization successfull");
+	}
+	
+	private void injectHTTPClient(Object raw, String clientType) {
+		//extract client from implementation
+		Client client = null;
+		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
+		HTTPConduit http = (HTTPConduit) client.getConduit();
+				
+		//set timeout policy
+		HTTPClientPolicy httpClientPolicy = new HTTPClientPolicy();			  
+		httpClientPolicy.setConnectionTimeout(
+				Integer.parseInt(basicConfig.getBasicConfiguration(
+						Constants.CONIG_PROPS_EIDAS_SZRCLIENT_TIMEOUT_CONNECTION, 
+						Constants.HTTP_CLIENT_DEFAULT_TIMEOUT_CONNECTION)) * 1000);
+		httpClientPolicy.setReceiveTimeout(
+				Integer.parseInt(basicConfig.getBasicConfiguration(
+						Constants.CONIG_PROPS_EIDAS_SZRCLIENT_TIMEOUT_RESPONSE, 
+						Constants.HTTP_CLIENT_DEFAULT_TIMEOUT_RESPONSE)) * 1000); 
+		http.setClient(httpClientPolicy);
+		
+		//inject SSL context in case of https
+	  	if (szrURL.toLowerCase().startsWith("https")) {
+	  		log.debug("Adding SSLContext to client: " + clientType +" ... "); 	  		
+			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) {
+		Map<String, Object> requestContext = bindingProvider.getRequestContext();
+		requestContext.put(BindingProvider.ENDPOINT_ADDRESS_PROPERTY, szrURL);
+		
+		log.trace("Adding JAX-WS request/response trace handler to client: " + clientType);
+	  	List<Handler> handlerList = bindingProvider.getBinding().getHandlerChain();
+	  	if (handlerList == null) {
+	  		handlerList = new ArrayList<Handler>();
+	  		bindingProvider.getBinding().setHandlerChain(handlerList);
+	  		
+	  	}
+	  	
+	  	//add logging handler to trace messages if required
+	  	if (basicConfig.getBasicMOAIDConfigurationBoolean(
+	  			Constants.CONIG_PROPS_EIDAS_SZRCLIENT_DEBUG_TRACEMESSAGES, 
+	  			false)) {	  	
+	  		LoggingHandler loggingHandler = new LoggingHandler();
+	  		handlerList.add(loggingHandler);
+	  		
+	  	}		
+	}
+
+	private SSLContext createSSLContext(String clientType) {
+		try {
+			SSLContext context = SSLContext.getInstance("TLS");
+			
+			//initialize key-mangager for SSL client-authentication
+			KeyManager[] keyManager = null;
+			String keyStorePath = basicConfig.getBasicConfiguration(Constants.CONIG_PROPS_EIDAS_SZRCLIENT_SSL_KEYSTORE_PATH);
+			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 {
+					KeyStore keyStore = KeyStoreUtils.loadKeyStore(
+							FileUtils.makeAbsoluteURL(keyStorePath, basicConfig.getConfigurationRootDirectory()), 
+							keyStorePassword);
+				
+					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);
+					
+				}				
+			}
+			
+			
+			//initialize SSL TrustStore
+			TrustManager[] trustManager = null;
+			String trustStorePath = basicConfig.getBasicConfiguration(Constants.CONIG_PROPS_EIDAS_SZRCLIENT_SSL_TRUSTSTORE_PATH);
+			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 {
+					KeyStore trustStore = KeyStoreUtils.loadKeyStore(
+							FileUtils.makeAbsoluteURL(trustStorePath, basicConfig.getConfigurationRootDirectory()), 
+							trustStorePassword);
+				
+					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);
+					
+				}	
+				
+			}
+			
+			
+			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 byte[] sourceToByteArray(Source result) throws TransformerException {
+		TransformerFactory factory = TransformerFactory.newInstance();
+		Transformer transformer = factory.newTransformer();
+		transformer.setOutputProperty("omit-xml-declaration", "yes");
+		transformer.setOutputProperty("method", "xml");
+		ByteArrayOutputStream out = new ByteArrayOutputStream();
+		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/authmodule_eIDASv2/szr/SZRService.java b/eidas_modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/authmodule_eIDASv2/szr/SZRService.java
new file mode 100644
index 00000000..ce2a1324
--- /dev/null
+++ b/eidas_modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/authmodule_eIDASv2/szr/SZRService.java
@@ -0,0 +1,139 @@
+package at.asitplus.eidas.specific.modules.authmodule_eIDASv2.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 final static URL WSDL_LOCATION;
+
+    public final static QName SERVICE = new QName("urn:SZRServices", "SZRService");
+    public final static QName SZRProduktionsumgebung = new QName("urn:SZRServices", "SZRProduktionsumgebung");
+    public final static QName SZRTestumgebung = new QName("urn:SZRServices", "SZRTestumgebung");
+    public final static 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);
+    }    
+
+
+
+
+    /**
+     *
+     * @return
+     *     returns SZR
+     */
+    @WebEndpoint(name = "SZRProduktionsumgebung")
+    public SZR getSZRProduktionsumgebung() {
+        return super.getPort(SZRProduktionsumgebung, SZR.class);
+    }
+
+    /**
+     * 
+     * @param features
+     *     A list of {@link javax.xml.ws.WebServiceFeature} to configure on the proxy.  Supported features not in the <code>features</code> parameter will have their default values.
+     * @return
+     *     returns SZR
+     */
+    @WebEndpoint(name = "SZRProduktionsumgebung")
+    public SZR getSZRProduktionsumgebung(WebServiceFeature... features) {
+        return super.getPort(SZRProduktionsumgebung, SZR.class, features);
+    }
+
+
+    /**
+     *
+     * @return
+     *     returns SZR
+     */
+    @WebEndpoint(name = "SZRTestumgebung")
+    public SZR getSZRTestumgebung() {
+        return super.getPort(SZRTestumgebung, SZR.class);
+    }
+
+    /**
+     * 
+     * @param features
+     *     A list of {@link javax.xml.ws.WebServiceFeature} to configure on the proxy.  Supported features not in the <code>features</code> parameter will have their default values.
+     * @return
+     *     returns SZR
+     */
+    @WebEndpoint(name = "SZRTestumgebung")
+    public SZR getSZRTestumgebung(WebServiceFeature... features) {
+        return super.getPort(SZRTestumgebung, SZR.class, features);
+    }
+
+
+    /**
+     *
+     * @return
+     *     returns SZR
+     */
+    @WebEndpoint(name = "SZRBusinesspartnerTestumgebung")
+    public SZR getSZRBusinesspartnerTestumgebung() {
+        return super.getPort(SZRBusinesspartnerTestumgebung, SZR.class);
+    }
+
+    /**
+     * 
+     * @param features
+     *     A list of {@link javax.xml.ws.WebServiceFeature} to configure on the proxy.  Supported features not in the <code>features</code> 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/authmodule_eIDASv2/tasks/CreateIdentityLinkTask.java b/eidas_modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/authmodule_eIDASv2/tasks/CreateIdentityLinkTask.java
new file mode 100644
index 00000000..c5d33b73
--- /dev/null
+++ b/eidas_modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/authmodule_eIDASv2/tasks/CreateIdentityLinkTask.java
@@ -0,0 +1,380 @@
+/*******************************************************************************
+ *******************************************************************************/
+package at.asitplus.eidas.specific.modules.authmodule_eIDASv2.tasks;
+
+import java.io.InputStream;
+import java.math.BigInteger;
+import java.security.KeyFactory;
+import java.security.NoSuchAlgorithmException;
+import java.security.PublicKey;
+import java.security.interfaces.RSAPublicKey;
+import java.security.spec.InvalidKeySpecException;
+import java.security.spec.PKCS8EncodedKeySpec;
+import java.text.SimpleDateFormat;
+import java.util.ArrayList;
+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.joda.time.DateTime;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+import org.springframework.util.Base64Utils;
+import org.w3._2000._09.xmldsig.KeyValueType;
+import org.w3._2000._09.xmldsig.RSAKeyValueType;
+import org.w3c.dom.Element;
+import org.w3c.dom.Node;
+
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.ImmutableSet;
+
+import at.asitplus.eidas.specific.connector.MSConnectorEventCodes;
+import at.asitplus.eidas.specific.modules.authmodule_eIDASv2.Constants;
+import at.asitplus.eidas.specific.modules.authmodule_eIDASv2.exception.SZRCommunicationException;
+import at.asitplus.eidas.specific.modules.authmodule_eIDASv2.exception.eIDASAttributeException;
+import at.asitplus.eidas.specific.modules.authmodule_eIDASv2.szr.SZRClient;
+import at.asitplus.eidas.specific.modules.authmodule_eIDASv2.utils.eIDASResponseUtils;
+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.EAAFConstants;
+import at.gv.egiz.eaaf.core.api.data.PVPAttributeDefinitions;
+import at.gv.egiz.eaaf.core.api.idp.IConfiguration;
+import at.gv.egiz.eaaf.core.api.idp.auth.data.IIdentityLink;
+import at.gv.egiz.eaaf.core.api.idp.process.ExecutionContext;
+import at.gv.egiz.eaaf.core.exceptions.EAAFException;
+import at.gv.egiz.eaaf.core.exceptions.TaskExecutionException;
+import at.gv.egiz.eaaf.core.impl.data.Pair;
+import at.gv.egiz.eaaf.core.impl.data.Trible;
+import at.gv.egiz.eaaf.core.impl.idp.auth.builder.BPKBuilder;
+import at.gv.egiz.eaaf.core.impl.idp.auth.data.AuthProcessDataWrapper;
+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 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 szrservices.IdentityLinkType;
+import szrservices.PersonInfoType;
+import szrservices.TravelDocumentType;
+
+/** 
+ * @author tlenz
+ * 
+ */
+@Component("CreateIdentityLinkTask")
+public class CreateIdentityLinkTask extends AbstractAuthServletTask {
+	private static final Logger log = LoggerFactory.getLogger(CreateIdentityLinkTask.class);
+	
+	//@Autowired private eIDASAttributeRegistry attrRegistry;
+	@Autowired private IConfiguration basicConfig;
+	@Autowired private SZRClient szrClient;
+	
+	 
+	/* (non-Javadoc) 
+	 * @see at.gv.egovernment.moa.id.process.springweb.MoaIdTask#execute(at.gv.egovernment.moa.id.process.api.ExecutionContext, javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse)
+	 */
+	@Override
+	public void execute(ExecutionContext executionContext,
+			HttpServletRequest request, HttpServletResponse response)
+			throws TaskExecutionException {
+		try{
+			AuthProcessDataWrapper authProcessData = pendingReq.getSessionData(AuthProcessDataWrapper.class);
+			ILightResponse eIDASResponse = authProcessData.getGenericDataFromSession(
+					Constants.DATA_FULL_EIDAS_RESPONSE, ILightResponse.class);																	
+		    Map<String, Object> simpleAttrMap = converteIDASAttrToSimpleMap(eIDASResponse.getAttributes().getAttributeMap());		    		    
+		    
+		    IIdentityLink identityLink = null;
+		    String bPK = null;
+		    
+		    //extract attributes
+	        Object eIdentifierObj = simpleAttrMap.get(Constants.eIDAS_ATTR_PERSONALIDENTIFIER);
+	        Object familyNameObj = simpleAttrMap.get(Constants.eIDAS_ATTR_CURRENTFAMILYNAME);
+	        Object givenNameObj = simpleAttrMap.get(Constants.eIDAS_ATTR_CURRENTGIVENNAME);
+	        Object dateOfBirthObj = simpleAttrMap.get(Constants.eIDAS_ATTR_DATEOFBIRTH);
+	        
+	        //check if availabe
+	        if (eIdentifierObj == null || !(eIdentifierObj instanceof String))
+	        	throw new eIDASAttributeException(Constants.eIDAS_ATTR_PERSONALIDENTIFIER);	
+	        	        
+	        if (familyNameObj == null || !(familyNameObj instanceof String))
+	        	throw new eIDASAttributeException(Constants.eIDAS_ATTR_CURRENTFAMILYNAME);	
+	        	        
+	        if (givenNameObj == null || !(givenNameObj instanceof String))
+	        	throw new eIDASAttributeException(Constants.eIDAS_ATTR_CURRENTGIVENNAME);
+		    	        
+	        if (dateOfBirthObj == null || !(dateOfBirthObj instanceof DateTime))
+	        	throw new eIDASAttributeException(Constants.eIDAS_ATTR_DATEOFBIRTH);
+	        
+			//connect SZR-Gateway
+			if(basicConfig.getBasicMOAIDConfigurationBoolean(
+					Constants.CONIG_PROPS_EIDAS_SZRCLIENT_DEBUG_USEDUMMY, false)) {
+				log.warn("SZR-Dummy IS ACTIVE! IdentityLink is NOT VALID!!!!");
+				// create fake IdL
+				// - fetch IdL template from resources
+				InputStream s = CreateIdentityLinkTask.class.getResourceAsStream("/resources/xmldata/fakeIdL_IdL_template.xml");
+				Element idlTemplate = DOMUtils.parseXmlValidating(s);
+
+			    identityLink = new SimpleIdentityLinkAssertionParser(idlTemplate).parseIdentityLink();
+
+			    // replace data
+	            Element idlassertion = identityLink.getSamlAssertion();
+	            	            
+	            // - set fake baseID;
+		        Node prIdentification = XPathUtils.selectSingleNode(idlassertion, SimpleIdentityLinkAssertionParser.PERSON_IDENT_VALUE_XPATH);		        		        
+		        prIdentification.getFirstChild().setNodeValue((String) eIdentifierObj);
+		        
+		        //build personal identifier which looks like a baseID		        
+//		        String fakeBaseID = new BPKBuilder().buildBPK(eIdentifier, "baseID");
+//		        Logger.info("Map eIDAS eIdentifier:" + eIdentifier + " to fake baseID:" + fakeBaseID);
+//		        prIdentification.getFirstChild().setNodeValue(fakeBaseID);
+ 
+		        // - set last name
+		        Node prFamilyName = XPathUtils.selectSingleNode(idlassertion, SimpleIdentityLinkAssertionParser.PERSON_FAMILY_NAME_XPATH);		        	        
+				prFamilyName.getFirstChild().setNodeValue((String) familyNameObj);
+
+		        // - set first name
+		        Node prGivenName = XPathUtils.selectSingleNode(idlassertion, SimpleIdentityLinkAssertionParser.PERSON_GIVEN_NAME_XPATH);
+				prGivenName.getFirstChild().setNodeValue((String) givenNameObj);
+
+		        // - set date of birth
+		        Node prDateOfBirth = XPathUtils.selectSingleNode(idlassertion, SimpleIdentityLinkAssertionParser.PERSON_DATE_OF_BIRTH_XPATH);		        		        
+				String formatedDateOfBirth = new SimpleDateFormat("yyyy-MM-dd").format(((DateTime)dateOfBirthObj).toDate());
+				prDateOfBirth.getFirstChild().setNodeValue(formatedDateOfBirth);
+
+	            identityLink = new SimpleIdentityLinkAssertionParser(idlassertion).parseIdentityLink();
+
+	            Pair<String, String> bPKCalc = new BPKBuilder().generateAreaSpecificPersonIdentifier(
+	            		identityLink.getIdentificationValue(), 
+	            		identityLink.getIdentificationType(), 
+	            		pendingReq.getServiceProviderConfiguration().getAreaSpecificTargetIdentifier());
+	            bPK = bPKCalc.getFirst();
+	            
+	            	            				
+			} else {
+				//contact SZR Gateway
+				log.debug("Starting connecting SZR Gateway");											
+				PersonInfoType personInfo = new PersonInfoType();
+				PersonNameType personName = new PersonNameType();
+				PhysicalPersonType naturalPerson = new PhysicalPersonType();
+				TravelDocumentType eDocument = new TravelDocumentType();				
+				
+				naturalPerson.setName(personName );
+				personInfo.setPerson(naturalPerson );
+				personInfo.setTravelDocument(eDocument );
+								
+				//parse some eID attributes
+				String dateOfBirth = new SimpleDateFormat("yyyy-MM-dd").format(((DateTime)dateOfBirthObj).toDate());
+				Trible<String, String, String> eIdentifier = 
+						eIDASResponseUtils.parseEidasPersonalIdentifier((String)eIdentifierObj);
+				String uniqueId = (String)eIdentifierObj;
+				String citizenCountry = eIdentifier.getFirst();
+							
+				//person information
+				personName.setFamilyName((String)familyNameObj);
+				personName.setGivenName((String)givenNameObj);
+				naturalPerson.setDateOfBirth(dateOfBirth);
+				eDocument.setIssuingCountry(citizenCountry);
+				eDocument.setDocumentNumber(uniqueId);
+				
+				//eID document information								
+				eDocument.setDocumentType(basicConfig.getBasicConfiguration(
+						Constants.CONIG_PROPS_EIDAS_SZRCLIENT_PARAMS_EDOCUMENTTYPE, 
+						Constants.SZR_CONSTANTS_DEFAULT_DOCUMENT_TYPE));
+				
+				//TODO: that should be removed
+				eDocument.setIssueDate(basicConfig.getBasicConfiguration(
+						Constants.CONIG_PROPS_EIDAS_SZRCLIENT_PARAMS_ISSUING_DATE, 
+						Constants.SZR_CONSTANTS_DEFAULT_ISSUING_DATE));
+				eDocument.setIssuingAuthority(basicConfig.getBasicConfiguration(
+						Constants.CONIG_PROPS_EIDAS_SZRCLIENT_PARAMS_ISSUING_AUTHORITY, 
+						Constants.SZR_CONSTANTS_DEFAULT_ISSUING_AUTHORITY));
+				
+				//TODO: keys are not available in eIDAS				
+				List<KeyValueType> keyValue = dummyCodeForKeys();
+				
+				/*TODO: 
+				 *  Validate if IDL signature is valid after using this method
+				*   MAYBE we had to switch to 'getIdentityLinkInRawMode' method!
+				*/
+				IdentityLinkType result = szrClient.getIdentityLink(
+											personInfo, 
+											keyValue, 
+											basicConfig.getBasicMOAIDConfigurationBoolean(
+													Constants.CONIG_PROPS_EIDAS_SZRCLIENT_DEBUG_INSERTERNB, 
+													true)
+											);
+
+				Element idlFromSZR = (Element)result.getAssertion();			
+				identityLink = new SimpleIdentityLinkAssertionParser(idlFromSZR).parseIdentityLink();
+				
+				
+				//get bPK from SZR
+				bPK = szrClient.getBPK(
+						personInfo, 
+						pendingReq.getServiceProviderConfiguration().getAreaSpecificTargetIdentifier(), 
+						basicConfig.getBasicConfiguration(
+								Constants.CONIG_PROPS_EIDAS_SZRCLIENT_PARAMS_VKZ, 
+								"no VKZ defined"));
+								
+			}
+						
+			if (identityLink == null) {
+				log.error("ERnB did not return an identity link.");
+				throw new SZRCommunicationException("ernb.00", null);
+				
+			}
+			revisionsLogger.logEvent(pendingReq, MSConnectorEventCodes.SZR_IDL_RECEIVED);
+			
+			
+			if (bPK == null) {
+				log.error("ERnB did not return a bPK for target: " + pendingReq.getServiceProviderConfiguration().getAreaSpecificTargetIdentifier());
+				throw new SZRCommunicationException("ernb.01", null);
+				
+			}
+			revisionsLogger.logEvent(pendingReq, MSConnectorEventCodes.SZR_BPK_RECEIVED);
+			
+			log.debug("ERnB communication was successfull");
+					
+			authProcessData.setForeigner(true);
+			authProcessData.setIdentityLink(identityLink);
+			authProcessData.setGenericDataToSession(
+					PVPAttributeDefinitions.EID_ISSUING_NATION_NAME, 
+					eIDASResponseUtils.parseEidasPersonalIdentifier((String) simpleAttrMap.get(Constants.eIDAS_ATTR_PERSONALIDENTIFIER)).getFirst());
+			
+			//set bPK and bPKType into auth session
+			authProcessData.setGenericDataToSession(
+					PVPAttributeDefinitions.BPK_NAME, 
+					extendBPKbyPrefix(
+							bPK, 
+							pendingReq.getServiceProviderConfiguration().getAreaSpecificTargetIdentifier())
+					);
+			authProcessData.setGenericDataToSession(
+					PVPAttributeDefinitions.EID_SECTOR_FOR_IDENTIFIER_NAME, 
+					pendingReq.getServiceProviderConfiguration().getAreaSpecificTargetIdentifier());
+
+			
+			
+			//store pending-request
+			requestStoreage.storePendingRequest(pendingReq);
+					
+		} catch (eIDASAttributeException e) {
+			throw new TaskExecutionException(pendingReq, "Minimum required eIDAS attributeset not found.", e);
+						
+		} catch (EAAFException e) {
+			throw new TaskExecutionException(pendingReq, "IdentityLink generation for foreign person FAILED.", e);
+						
+		} catch (Exception e) {
+			log.error("IdentityLink generation for foreign person FAILED.", e);
+			throw new TaskExecutionException(pendingReq, "IdentityLink generation for foreign person FAILED.", e);
+			
+		}
+	}
+
+	private List<KeyValueType> dummyCodeForKeys() {
+		if (basicConfig.getBasicMOAIDConfigurationBoolean(
+				Constants.CONIG_PROPS_EIDAS_SZRCLIENT_PARAMS_KEYS_USEDUMMY, 
+				false)) {
+			List<KeyValueType> keyvalueList = new ArrayList<KeyValueType>();
+			try {			
+				PKCS8EncodedKeySpec spec = new PKCS8EncodedKeySpec(Constants.SZR_CONSTANTS_DEFAULT_PUBL_KEY);
+				KeyFactory kf = KeyFactory.getInstance("RSA");
+
+				PublicKey pb = kf.generatePublic(spec);
+				
+				RSAPublicKey rsapb = (RSAPublicKey)pb;	        
+				BigInteger modulus = rsapb.getModulus();
+				BigInteger exponent = rsapb.getPublicExponent();
+		           	           
+				// set key values
+				RSAKeyValueType rsa = new RSAKeyValueType();
+				rsa.setExponent(new String(Base64Utils.encode(exponent.toByteArray())));
+				rsa.setModulus(new String(Base64Utils.encode(modulus.toByteArray())));
+						
+				KeyValueType key = new KeyValueType();
+				key.setRSAKeyValue(rsa);
+							
+				keyvalueList.add(key);
+			
+				return keyvalueList;
+			} catch (NoSuchAlgorithmException | InvalidKeySpecException e) {
+				log.error("TestCode has an internal ERROR", e);
+				
+			}
+			
+		}
+		
+		return null;
+		
+	}
+
+	private String extendBPKbyPrefix(String bpk, String type) {
+		String bPKType = null;
+		
+		if (type.startsWith(EAAFConstants.URN_PREFIX_WBPK))
+			bPKType = type.substring((EAAFConstants.URN_PREFIX_WBPK).length());
+		
+		else if (type.startsWith(EAAFConstants.URN_PREFIX_CDID)) 
+			bPKType = type.substring((EAAFConstants.URN_PREFIX_CDID).length());
+		
+		else if (type.startsWith(EAAFConstants.URN_PREFIX_EIDAS)) 
+			bPKType = type.substring((EAAFConstants.URN_PREFIX_EIDAS).length());
+		
+
+		if (bPKType != null ) {
+			log.trace("Authenticate user with bPK/wbPK " + bpk + " and Type=" + bPKType);
+			return bPKType + ":" + bpk;
+			
+		} else {		
+			log.warn("Service Provider Target with: " + type + " is NOT supported. Set bPK as it is ...");
+			return bpk;
+			
+		}
+		
+	}
+	
+	//TODO: update for complexe attributes
+	private Map<String, Object> converteIDASAttrToSimpleMap(
+			ImmutableMap<AttributeDefinition<?>, ImmutableSet<? extends AttributeValue<?>>> attributeMap) {
+		Map<String, Object> result = new HashMap<String, Object>();
+		
+		for (AttributeDefinition<?> el : attributeMap.keySet()) {
+			
+			final Class parameterizedType = el.getParameterizedType();
+		    if ((DateTime.class).equals(parameterizedType)) {
+		        DateTime attribute = eIDASResponseUtils.translateDateAttribute(el, attributeMap.get(el).asList());
+		        if (attribute != null)
+		        	result.put(el.getFriendlyName(), attribute);
+		        else
+		        	log.info("Ignore empty 'DateTime' attribute");
+		        
+		    } else if ((PostalAddress.class).equals(parameterizedType)) {
+		        PostalAddress addressAttribute = eIDASResponseUtils.translateAddressAttribute(el, attributeMap.get(el).asList());
+		        if (addressAttribute != null)
+		        	result.put(el.getFriendlyName(), addressAttribute);
+		        else
+		        	log.info("Ignore empty 'PostalAddress' attribute");
+		        
+		    } else {			
+		    	List<String> natPersonIdObj = eIDASResponseUtils.translateStringListAttribute(el, attributeMap.get(el).asList());		    
+		    	String stringAttr = natPersonIdObj.get(0);
+		    	if (StringUtils.isNotEmpty(stringAttr))
+		    		result.put(el.getFriendlyName(), stringAttr);
+		    	else
+		    		log.info("Ignore empty 'String' attribute");
+		    	
+		    }			
+		}
+						
+		return result;
+	}
+
+
+}
diff --git a/eidas_modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/authmodule_eIDASv2/tasks/GenerateAuthnRequestTask.java b/eidas_modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/authmodule_eIDASv2/tasks/GenerateAuthnRequestTask.java
new file mode 100644
index 00000000..74c98de1
--- /dev/null
+++ b/eidas_modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/authmodule_eIDASv2/tasks/GenerateAuthnRequestTask.java
@@ -0,0 +1,306 @@
+/*******************************************************************************
+ *******************************************************************************/
+package at.asitplus.eidas.specific.modules.authmodule_eIDASv2.tasks;
+
+import java.util.Map;
+import java.util.UUID;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.apache.commons.lang3.StringUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.ApplicationContext;
+import org.springframework.stereotype.Component;
+import org.springframework.web.util.UriComponentsBuilder;
+
+import com.google.common.collect.ImmutableSortedSet;
+
+import at.asitplus.eidas.specific.connector.MSConnectorEventCodes;
+import at.asitplus.eidas.specific.connector.MSeIDASNodeConstants;
+import at.asitplus.eidas.specific.connector.gui.StaticGuiBuilderConfiguration;
+import at.asitplus.eidas.specific.modules.authmodule_eIDASv2.Constants;
+import at.asitplus.eidas.specific.modules.authmodule_eIDASv2.exception.eIDASAuthenticationException;
+import at.asitplus.eidas.specific.modules.authmodule_eIDASv2.service.eIDASAttributeRegistry;
+import at.gv.egiz.eaaf.core.api.data.EAAFConstants;
+import at.gv.egiz.eaaf.core.api.gui.IGUIFormBuilder;
+import at.gv.egiz.eaaf.core.api.idp.IConfiguration;
+import at.gv.egiz.eaaf.core.api.idp.ISPConfiguration;
+import at.gv.egiz.eaaf.core.api.idp.process.ExecutionContext;
+import at.gv.egiz.eaaf.core.api.storage.ITransactionStorage;
+import at.gv.egiz.eaaf.core.exceptions.EAAFConfigurationException;
+import at.gv.egiz.eaaf.core.exceptions.TaskExecutionException;
+import at.gv.egiz.eaaf.core.impl.idp.auth.modules.AbstractAuthServletTask;
+import eu.eidas.auth.commons.EidasParameterKeys;
+import eu.eidas.auth.commons.attribute.AttributeDefinition;
+import eu.eidas.auth.commons.attribute.ImmutableAttributeMap;
+import eu.eidas.auth.commons.light.ILightRequest;
+import eu.eidas.auth.commons.light.impl.LightRequest;
+import eu.eidas.auth.commons.protocol.eidas.SpType;
+import eu.eidas.auth.commons.tx.BinaryLightToken;
+import eu.eidas.specificcommunication.BinaryLightTokenHelper;
+import eu.eidas.specificcommunication.SpecificCommunicationDefinitionBeanNames;
+import eu.eidas.specificcommunication.exception.SpecificCommunicationException;
+import eu.eidas.specificcommunication.protocol.impl.SpecificConnectorCommunicationServiceImpl;
+
+/**
+ * @author tlenz
+ *
+ */  
+@Component("ConnecteIDASNodeTask")
+public class GenerateAuthnRequestTask extends AbstractAuthServletTask {
+	private static final Logger log = LoggerFactory.getLogger(GenerateAuthnRequestTask.class);
+	
+	@Autowired IConfiguration basicConfig;
+	@Autowired eIDASAttributeRegistry attrRegistry;
+	@Autowired ApplicationContext context;
+	@Autowired ITransactionStorage transactionStore; 
+	@Autowired IGUIFormBuilder guiBuilder;
+	 
+	@Override
+	public void execute(ExecutionContext executionContext,
+			HttpServletRequest request, HttpServletResponse response)
+			throws TaskExecutionException {
+		
+		try{						
+			//get service-provider configuration
+			ISPConfiguration spConfig = pendingReq.getServiceProviderConfiguration();
+
+			// get target, environment and validate citizen countryCode
+			String citizenCountryCode = (String) executionContext.get(MSeIDASNodeConstants.REQ_PARAM_SELECTED_COUNTRY);
+			String environment = (String) executionContext.get(MSeIDASNodeConstants.REQ_PARAM_SELECTED_ENVIRONMENT);
+			
+			if (StringUtils.isEmpty(citizenCountryCode)) {
+				// illegal state; task should not have been executed without a selected country
+				throw new eIDASAuthenticationException("eidas.03", new Object[] { "" });
+				
+			}
+
+			//TODO: maybe add countryCode validation before request ref. impl. eIDAS node
+			log.debug("Request eIDAS auth. for citizen of country: " + citizenCountryCode);
+			revisionsLogger.logEvent(pendingReq, MSConnectorEventCodes.COUNTRY_SELECTED, citizenCountryCode);
+									
+			//build eIDAS AuthnRequest			
+			LightRequest.Builder authnRequestBuilder = LightRequest.builder();			
+			authnRequestBuilder.id(UUID.randomUUID().toString());
+			
+			
+			String issur = basicConfig.getBasicConfiguration(Constants.CONIG_PROPS_EIDAS_NODE_ENTITYID);
+			if (StringUtils.isEmpty(issur)) {
+				log.error("Found NO 'eIDAS node issuer' in configuration. Authentication NOT possible!");
+				throw new EAAFConfigurationException("config.27", 
+						new Object[] {"Application config containts NO " + Constants.CONIG_PROPS_EIDAS_NODE_ENTITYID });
+				
+			}
+			authnRequestBuilder.issuer(issur);
+			
+			
+			//TODO: set matching mode if eIDAS ref. impl. support this method
+
+				
+			//TODO: update if eIDAS ref. impl. supports exact matching for non-notified LoA schemes
+			String loa = EAAFConstants.EIDAS_LOA_HIGH;
+			if (spConfig.getRequiredLoA() != null) {
+				if (spConfig.getRequiredLoA().isEmpty())
+					log.info("No eIDAS LoA requested. Use LoA HIGH as default");
+				
+				else {					
+					if (spConfig.getRequiredLoA().size() > 1 )
+						log.info("Currently only ONE requested LoA is supported for service provider. Use first one ... ");
+					
+					loa = spConfig.getRequiredLoA().get(0);
+					
+				}									
+			}
+						
+			log.debug("Request eIdAS node with LoA: " + loa);
+			authnRequestBuilder.levelOfAssurance(loa);
+			
+			//set correct SPType for requested target sector				
+			String publicSectorTargetSelector = basicConfig.getBasicConfiguration(
+					Constants.CONIG_PROPS_EIDAS_NODE_PUBLICSECTOR_TARGETS, 
+					Constants.POLICY_DEFAULT_ALLOWED_TARGETS);		
+			Pattern p = Pattern.compile(publicSectorTargetSelector);
+			Matcher m = p.matcher(spConfig.getAreaSpecificTargetIdentifier());
+			if (m.matches()) {
+				log.debug("Map " + spConfig.getAreaSpecificTargetIdentifier() + " to 'PublicSector'");
+				authnRequestBuilder.spType(SpType.PUBLIC.getValue());
+
+				//TODO: only for eIDAS ref. node 2.0 and 2.1 because it need 'Providername' for any SPType 
+				String providerName = pendingReq.getRawData(Constants.DATA_PROVIDERNAME, String.class);
+				if (StringUtils.isNotEmpty(providerName) 
+						&& basicConfig.getBasicMOAIDConfigurationBoolean(
+								Constants.CONIG_PROPS_EIDAS_NODE_WORKAROUND_ADD_ALWAYS_PROVIDERNAME, 
+								false)
+						)
+					authnRequestBuilder.providerName(providerName);
+				
+			} else {
+				log.debug("Map " + spConfig.getAreaSpecificTargetIdentifier() + " to 'PrivateSector'");
+				authnRequestBuilder.spType(SpType.PRIVATE.getValue());
+			
+				//TODO: switch to RequesterId in further version
+				//set provider name for private sector applications
+				String providerName = pendingReq.getRawData(Constants.DATA_PROVIDERNAME, String.class);
+				if (StringUtils.isNotEmpty(providerName))
+					authnRequestBuilder.providerName(providerName);
+			
+			}
+			
+			//set nameIDFormat
+			authnRequestBuilder.nameIdFormat(Constants.eIDAS_REQ_NAMEID_FORMAT);
+			
+			//set citizen country code for foreign uses
+			authnRequestBuilder.citizenCountryCode(citizenCountryCode);
+			
+			//set relay state
+			authnRequestBuilder.relayState(pendingReq.getPendingRequestId());
+			
+			//build and add requested attribute set								
+			ImmutableAttributeMap reqAttrMap = translateToEidasAttributes(attrRegistry.getAttributeSetFromConfiguration());						
+			authnRequestBuilder.requestedAttributes(reqAttrMap);
+						
+			//build request
+			LightRequest lightAuthnReq = authnRequestBuilder.build();
+			
+			//put request into cache
+			BinaryLightToken token = putRequestInCommunicationCache(lightAuthnReq);
+			final String tokenBase64 = BinaryLightTokenHelper.encodeBinaryLightTokenBase64(token);
+
+			//Workaround, because eIDAS node ref. impl. does not return relayState
+			if (basicConfig.getBasicMOAIDConfigurationBoolean(
+					Constants.CONIG_PROPS_EIDAS_NODE_WORKAROUND_USEREQUESTIDASTRANSACTIONIDENTIFIER, 
+					false)) {
+				log.trace("Put lightRequestId into transactionstore as session-handling backup");
+				transactionStore.put(lightAuthnReq.getId(), pendingReq.getPendingRequestId(), -1);
+				
+			}
+			
+			//select forward URL regarding the selected environment
+			String forwardURL = basicConfig.getBasicConfiguration(Constants.CONIG_PROPS_EIDAS_NODE_FORWARD_URL);
+			if (StringUtils.isNotEmpty(environment))
+				forwardURL = selectedForwardURLForEnvironment(environment);
+				
+			if (StringUtils.isEmpty(forwardURL)) {
+				log.warn("NO ForwardURL defined in configuration. Can NOT forward to eIDAS node! Process stops");
+				throw new EAAFConfigurationException("config.08", new Object[] {Constants.CONIG_PROPS_EIDAS_NODE_FORWARD_URL});
+				
+			}
+			log.debug("ForwardURL: " + forwardURL + " selected to forward eIDAS request");
+			
+			if (basicConfig.getBasicConfiguration(
+						Constants.CONIG_PROPS_EIDAS_NODE_FORWARD_METHOD, 
+						Constants.FORWARD_METHOD_GET
+					).equals(Constants.FORWARD_METHOD_GET)) {
+				
+				log.debug("Use http-redirect for eIDAS node forwarding ...  ");
+				//send redirect
+				UriComponentsBuilder redirectUrl = UriComponentsBuilder.fromHttpUrl(forwardURL);
+				redirectUrl.queryParam(EidasParameterKeys.TOKEN.toString(), tokenBase64);			
+				response.sendRedirect(redirectUrl.build().encode().toString());
+				
+			} else {
+				log.debug("Use http-post for eIDAS node forwarding ...  ");
+				StaticGuiBuilderConfiguration config = new StaticGuiBuilderConfiguration(
+						basicConfig, 
+						pendingReq, 
+						Constants.TEMPLATE_POST_FORWARD_NAME, 
+						null);
+				
+				config.putCustomParameter(Constants.TEMPLATE_POST_FORWARD_ENDPOINT, forwardURL);
+				config.putCustomParameter(Constants.TEMPLATE_POST_FORWARD_TOKEN_NAME,
+						EidasParameterKeys.TOKEN.toString());				
+				config.putCustomParameter(Constants.TEMPLATE_POST_FORWARD_TOKEN_VALUE,
+						tokenBase64);
+				
+				guiBuilder.build(response, config, "BKU-Selection form");
+								
+			} 				
+			
+			revisionsLogger.logEvent(pendingReq, MSConnectorEventCodes.EIDAS_NODE_CONNECTED, lightAuthnReq.getId());
+			
+					
+		} catch (eIDASAuthenticationException  e) {
+			throw new TaskExecutionException(pendingReq, "eIDAS AuthnRequest generation FAILED.", e);
+			
+		} catch (Exception e) {
+			log.warn("eIDAS AuthnRequest generation FAILED.", e);
+			throw new TaskExecutionException(pendingReq, e.getMessage(), e);
+			
+		}
+		
+	}
+		
+	/**
+	 * Select a forward URL from configuration for a specific environment
+	 * <br><br>
+	 * <b>Info: </b> This method is needed, because eIDAS Ref. Impl only supports one countrycode on each instance. 
+	 * In consequence, more than one eIDAS Ref. Impl nodes are required to support producation, testing, or QS stages 
+	 * for one country by using one ms-specific eIDAS connector   
+	 * 
+	 * @param environment Environment selector from CountrySlection page
+	 * @return
+	 */
+    private String selectedForwardURLForEnvironment(String environment) {
+    	log.trace("Starting endpoint selection process for environment: " + environment + " ... ");
+    	if (environment.equalsIgnoreCase(MSeIDASNodeConstants.REQ_PARAM_SELECTED_ENVIRONMENT_VALUE_PRODUCTION))
+    		return basicConfig.getBasicConfiguration(Constants.CONIG_PROPS_EIDAS_NODE_FORWARD_URL);
+    	
+    	else if (environment.equalsIgnoreCase(MSeIDASNodeConstants.REQ_PARAM_SELECTED_ENVIRONMENT_VALUE_QS))
+			return basicConfig.getBasicConfiguration(Constants.CONIG_PROPS_EIDAS_NODE_FORWARD_URL 
+						+ "." + MSeIDASNodeConstants.REQ_PARAM_SELECTED_ENVIRONMENT_VALUE_QS);
+    	
+    	else if (environment.equalsIgnoreCase(MSeIDASNodeConstants.REQ_PARAM_SELECTED_ENVIRONMENT_VALUE_TESTING))
+			return basicConfig.getBasicConfiguration(Constants.CONIG_PROPS_EIDAS_NODE_FORWARD_URL 
+						+ "." + MSeIDASNodeConstants.REQ_PARAM_SELECTED_ENVIRONMENT_VALUE_TESTING);
+    	
+    	else if (environment.equalsIgnoreCase(MSeIDASNodeConstants.REQ_PARAM_SELECTED_ENVIRONMENT_VALUE_DEVELOPMENT))
+			return basicConfig.getBasicConfiguration(Constants.CONIG_PROPS_EIDAS_NODE_FORWARD_URL 
+						+ "." + MSeIDASNodeConstants.REQ_PARAM_SELECTED_ENVIRONMENT_VALUE_DEVELOPMENT);    	
+		
+    	log.info("Environment selector: " + environment + " is not supported");
+    	return null;
+		
+	}
+
+	private ImmutableAttributeMap translateToEidasAttributes(final Map<String, Boolean> requiredAttributes) {
+        ImmutableAttributeMap.Builder builder = ImmutableAttributeMap.builder();
+        for (Map.Entry<String,Boolean> attribute : requiredAttributes.entrySet()) {
+            final String name = attribute.getKey();
+            final ImmutableSortedSet<AttributeDefinition<?>> byFriendlyName = attrRegistry.getCoreAttributeRegistry().getByFriendlyName(name);            
+            if (!byFriendlyName.isEmpty()) {
+                final AttributeDefinition<?> attributeDefinition = byFriendlyName.first();
+                builder.put(AttributeDefinition.builder(attributeDefinition).required(attribute.getValue()).build());
+                                
+            } else
+            	log.warn("Can NOT request UNKNOWN attribute: " + attribute.getKey() + " Ignore it!");
+            	
+        }
+
+        return builder.build();
+        
+    }
+	
+    private BinaryLightToken putRequestInCommunicationCache(ILightRequest iLightRequest) throws ServletException {
+        final BinaryLightToken binaryLightToken;
+        try {
+            final SpecificConnectorCommunicationServiceImpl springManagedSpecificConnectorCommunicationService =
+                    (SpecificConnectorCommunicationServiceImpl) context.getBean(SpecificCommunicationDefinitionBeanNames.SPECIFIC_CONNECTOR_COMMUNICATION_SERVICE.toString());
+
+            binaryLightToken = springManagedSpecificConnectorCommunicationService.putRequest(iLightRequest);
+            
+        } catch (SpecificCommunicationException e) {
+            log.error("Unable to process specific request");
+            throw new ServletException(e);
+            
+        }
+        
+        return binaryLightToken;
+    }
+    
+}
diff --git a/eidas_modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/authmodule_eIDASv2/tasks/ReceiveAuthnResponseTask.java b/eidas_modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/authmodule_eIDASv2/tasks/ReceiveAuthnResponseTask.java
new file mode 100644
index 00000000..2970c073
--- /dev/null
+++ b/eidas_modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/authmodule_eIDASv2/tasks/ReceiveAuthnResponseTask.java
@@ -0,0 +1,97 @@
+/*******************************************************************************
+ *******************************************************************************/
+package at.asitplus.eidas.specific.modules.authmodule_eIDASv2.tasks;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.ApplicationContext;
+import org.springframework.stereotype.Component;
+
+import at.asitplus.eidas.specific.connector.MSConnectorEventCodes;
+import at.asitplus.eidas.specific.modules.authmodule_eIDASv2.Constants;
+import at.asitplus.eidas.specific.modules.authmodule_eIDASv2.exception.eIDASAuthenticationException;
+import at.asitplus.eidas.specific.modules.authmodule_eIDASv2.service.eIDASAttributeRegistry;
+import at.asitplus.eidas.specific.modules.authmodule_eIDASv2.validator.eIDASResponseValidator;
+import at.gv.egiz.eaaf.core.api.idp.IConfiguration;
+import at.gv.egiz.eaaf.core.api.idp.process.ExecutionContext;
+import at.gv.egiz.eaaf.core.exceptions.EAAFException;
+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 eu.eidas.auth.commons.light.ILightResponse;
+
+@Component("ReceiveResponseFromeIDASNodeTask")
+public class ReceiveAuthnResponseTask extends AbstractAuthServletTask {
+	private static final Logger log = LoggerFactory.getLogger(ReceiveAuthnResponseTask.class);
+	
+	@Autowired private ApplicationContext context;
+	@Autowired private IConfiguration basicConfig;
+	@Autowired private eIDASAttributeRegistry attrRegistry;
+		
+	@Override 
+	public void execute(ExecutionContext executionContext, HttpServletRequest request, HttpServletResponse response) throws TaskExecutionException {
+		try{					    
+			ILightResponse eIDASResponse = (ILightResponse) request.getAttribute(Constants.DATA_FULL_EIDAS_RESPONSE);
+			if (eIDASResponse == null) {
+				log.warn("NO eIDAS response-message found.");
+				throw new eIDASAuthenticationException("eidas.01", null);
+				
+			}  
+			
+	    	log.debug("Receive eIDAS response with RespId:" + eIDASResponse.getId() + " for ReqId:" + eIDASResponse.getInResponseToId());
+			revisionsLogger.logEvent(pendingReq, MSConnectorEventCodes.RESPONSE_FROM_EIDAS_NODE, eIDASResponse.getId());
+	    	
+	    	
+			//check response StatusCode 
+			if (!eIDASResponse.getStatus().getStatusCode().equals(Constants.SUCCESS_URI)) {
+				log.info("Receice eIDAS Response with StatusCode:" + eIDASResponse.getStatus().getStatusCode()
+				+ " Subcode:" + eIDASResponse.getStatus().getSubStatusCode() + " Msg:" + eIDASResponse.getStatus().getStatusMessage());
+				throw new eIDASAuthenticationException("eidas.02", new Object[]{eIDASResponse.getStatus().getStatusCode(), eIDASResponse.getStatus().getStatusMessage()});
+				
+			}
+
+			// extract all Attributes from response
+			
+			
+			
+			// **********************************************************
+			// *******   MS-specificresponse validation   **********
+			// **********************************************************
+			String spCountry = basicConfig.getBasicConfiguration(Constants.CONIG_PROPS_EIDAS_NODE_COUNTRYCODE, "AT");
+			eIDASResponseValidator.validateResponse(pendingReq, eIDASResponse, spCountry, attrRegistry);
+
+			
+			// **********************************************************
+			// ******* Store resonse infos into session object **********
+			// **********************************************************
+			
+			//update MOA-Session data with received information			
+			log.debug("Store eIDAS response information into pending-request.");				
+			AuthProcessDataWrapper authProcessData = pendingReq.getSessionData(AuthProcessDataWrapper.class);
+			authProcessData.setQAALevel(eIDASResponse.getLevelOfAssurance());
+			authProcessData.setGenericDataToSession(Constants.DATA_FULL_EIDAS_RESPONSE, eIDASResponse);
+			
+			//store MOA-session to database
+			requestStoreage.storePendingRequest(pendingReq);
+			
+			revisionsLogger.logEvent(pendingReq, MSConnectorEventCodes.RESPONSE_FROM_EIDAS_NODE_VALID);
+		
+		} catch (EAAFException e) {
+			revisionsLogger.logEvent(pendingReq, MSConnectorEventCodes.RESPONSE_FROM_EIDAS_NODE_NOT_VALID);
+			throw new TaskExecutionException(pendingReq, "eIDAS Response processing FAILED.", e);
+					
+		} catch (Exception e) {
+			log.warn("eIDAS Response processing FAILED.", e);
+			revisionsLogger.logEvent(pendingReq, MSConnectorEventCodes.RESPONSE_FROM_EIDAS_NODE_NOT_VALID);
+			throw new TaskExecutionException(pendingReq, e.getMessage(), 
+					new eIDASAuthenticationException("eidas.05", new Object[]{e.getMessage()}, e));
+			
+		}	
+		
+	}
+
+}
diff --git a/eidas_modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/authmodule_eIDASv2/utils/LoggingHandler.java b/eidas_modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/authmodule_eIDASv2/utils/LoggingHandler.java
new file mode 100644
index 00000000..2f6e7c3a
--- /dev/null
+++ b/eidas_modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/authmodule_eIDASv2/utils/LoggingHandler.java
@@ -0,0 +1,52 @@
+package at.asitplus.eidas.specific.modules.authmodule_eIDASv2.utils;
+
+import java.io.ByteArrayOutputStream;
+import java.util.Set;
+
+import javax.xml.namespace.QName;
+import javax.xml.soap.SOAPMessage;
+import javax.xml.ws.handler.MessageContext;
+import javax.xml.ws.handler.soap.SOAPHandler;
+import javax.xml.ws.handler.soap.SOAPMessageContext;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class LoggingHandler implements SOAPHandler<SOAPMessageContext> {
+
+	Logger log = LoggerFactory.getLogger(LoggingHandler.class);
+
+	public boolean handleMessage(SOAPMessageContext context) {
+		SOAPMessage msg = context.getMessage();
+		boolean request = ((Boolean) context
+		    .get(SOAPMessageContext.MESSAGE_OUTBOUND_PROPERTY)).booleanValue();
+		ByteArrayOutputStream bos = new ByteArrayOutputStream();
+
+		try {
+			if (request) {
+				msg.writeTo(bos);
+			} else { // This is the response message
+				msg.writeTo(bos);
+			}
+										
+			log.trace(bos.toString());
+			log.trace(new String(bos.toByteArray()));
+			
+		} catch (Exception e) {
+			log.trace(e.getMessage(), e);
+		}
+		return true;
+	}
+
+	public boolean handleFault(SOAPMessageContext context) {
+		return handleMessage(context);
+	}
+
+	public void close(MessageContext context) {
+	}
+
+	public Set<QName> getHeaders() {
+		return null;
+	}
+
+}
diff --git a/eidas_modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/authmodule_eIDASv2/utils/eIDASResponseUtils.java b/eidas_modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/authmodule_eIDASv2/utils/eIDASResponseUtils.java
new file mode 100644
index 00000000..6269d242
--- /dev/null
+++ b/eidas_modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/authmodule_eIDASv2/utils/eIDASResponseUtils.java
@@ -0,0 +1,98 @@
+package at.asitplus.eidas.specific.modules.authmodule_eIDASv2.utils;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import org.joda.time.DateTime;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.collect.ImmutableList;
+
+import at.asitplus.eidas.specific.modules.authmodule_eIDASv2.Constants;
+import at.gv.egiz.eaaf.core.impl.data.Trible;
+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.protocol.eidas.impl.PostalAddress;
+
+public class eIDASResponseUtils {
+	private static final Logger log = LoggerFactory.getLogger(eIDASResponseUtils.class);
+	
+	public static final String PERSONALIDENIFIER_VALIDATION_PATTERN = "^[A-Z,a-z]{2}/[A-Z,a-z]{2}/.*";
+	 
+	/**
+	 * Validate a eIDAS PersonalIdentifier attribute value 
+	 * This validation is done according to eIDAS SAML Attribute Profile -  Section 2.2.3 Unique Identifier 
+	 * 
+	 * @param uniqueID eIDAS attribute value of a unique identifier
+	 * @return true if the uniqueID matches to eIDAS to Unique Identifier specification, otherwise false
+	 */
+	public static boolean validateEidasPersonalIdentifier(String uniqueID) {
+		Pattern pattern = Pattern.compile(PERSONALIDENIFIER_VALIDATION_PATTERN );
+		Matcher matcher = pattern.matcher(uniqueID);	
+		return matcher.matches();
+		
+	}
+	
+	
+	/**
+	 * Parse an eIDAS PersonalIdentifier attribute value into it components. 
+	 * This processing is done according to eIDAS SAML Attribute Profile -  Section 2.2.3 Unique Identifier 
+	 * 
+	 * @param uniqueID eIDAS attribute value of a unique identifier
+	 * @return {@link Trible} that contains: 
+	 * 				<br> First : citizen country
+	 * 				<br> Second: destination country
+	 * 				<br> Third : unique identifier
+	 * 	<br> or null if the attribute value has a wrong format
+	 */					
+	public static Trible<String, String, String> parseEidasPersonalIdentifier(String uniqueID) {
+		if (!validateEidasPersonalIdentifier(uniqueID)) {
+			log.error("eIDAS attribute value for " + Constants.eIDAS_ATTR_PERSONALIDENTIFIER 
+					+ " looks wrong formated. Value:" + ((String)uniqueID));				
+			return null;
+			
+		}		
+		return Trible.newInstance(uniqueID.substring(0, 2), uniqueID.substring(3, 5), uniqueID.substring(6)); 
+		
+	}
+
+    public static List<String> translateStringListAttribute(AttributeDefinition<?> attributeDefinition, ImmutableList<? extends AttributeValue<?>> attributeValues) {
+        final List<String> stringListAttribute = new ArrayList<String>();
+        AttributeValueMarshaller<?> attributeValueMarshaller = attributeDefinition.getAttributeValueMarshaller();
+        for (AttributeValue<?> attributeValue : attributeValues) {
+            String valueString = null;
+            try {
+                valueString = attributeValueMarshaller.marshal((AttributeValue) attributeValue);
+                stringListAttribute.add(valueString);
+            } catch (AttributeValueMarshallingException e) {
+                throw new IllegalStateException(e);
+                
+            }
+        }
+        
+        return stringListAttribute;
+        
+    }
+    
+    public static DateTime translateDateAttribute(AttributeDefinition<?> attributeDefinition, ImmutableList<? extends AttributeValue<?>> attributeValues) {
+        if (attributeValues.size() != 0) {
+            final AttributeValue<?> firstAttributeValue = attributeValues.get(0);
+            return (DateTime) firstAttributeValue.getValue();
+
+        }
+        
+        return null;
+    }
+    
+    public static PostalAddress translateAddressAttribute(AttributeDefinition<?> attributeDefinition, ImmutableList<? extends AttributeValue<?>> attributeValues) {
+        final AttributeValue<?> firstAttributeValue = attributeValues.get(0);
+        return (PostalAddress) firstAttributeValue.getValue();
+
+    }
+	
+}
diff --git a/eidas_modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/authmodule_eIDASv2/validator/eIDASResponseValidator.java b/eidas_modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/authmodule_eIDASv2/validator/eIDASResponseValidator.java
new file mode 100644
index 00000000..4af4e7cf
--- /dev/null
+++ b/eidas_modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/authmodule_eIDASv2/validator/eIDASResponseValidator.java
@@ -0,0 +1,135 @@
+package at.asitplus.eidas.specific.modules.authmodule_eIDASv2.validator;
+
+import java.util.List;
+
+import org.apache.commons.lang3.StringUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.collect.ImmutableList;
+
+import at.asitplus.eidas.specific.modules.authmodule_eIDASv2.Constants;
+import at.asitplus.eidas.specific.modules.authmodule_eIDASv2.exception.eIDASValidationException;
+import at.asitplus.eidas.specific.modules.authmodule_eIDASv2.service.eIDASAttributeRegistry;
+import at.asitplus.eidas.specific.modules.authmodule_eIDASv2.utils.eIDASResponseUtils;
+import at.gv.egiz.eaaf.core.api.IRequest;
+import at.gv.egiz.eaaf.core.impl.data.Trible;
+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.LevelOfAssurance;
+
+/**
+ * @author tlenz
+ *
+ */
+public class eIDASResponseValidator {
+	private static final Logger log = LoggerFactory.getLogger(eIDASResponseValidator.class);
+
+	public static void validateResponse(IRequest pendingReq, ILightResponse eIDASResponse, String spCountry, eIDASAttributeRegistry attrRegistry) throws eIDASValidationException {		
+
+		/*-----------------------------------------------------|
+		 * validate received LoA against minimum required LoA  |
+		 *_____________________________________________________|
+		 */ 
+		LevelOfAssurance respLoA = LevelOfAssurance.fromString(eIDASResponse.getLevelOfAssurance());		
+		List<String> allowedLoAs = pendingReq.getServiceProviderConfiguration().getRequiredLoA();
+		boolean loaValid = false;
+		for (String allowedLoaString : allowedLoAs) {
+			LevelOfAssurance allowedLoa = LevelOfAssurance.fromString(allowedLoaString);
+			if (respLoA.numericValue() >= allowedLoa.numericValue()) {
+				log.debug("Response contains valid LoA. Resume process ... ");
+				loaValid = true;
+				break;
+				
+			} else
+				log.trace("Allowed LoA: " + allowedLoaString + " DOES NOT match response LoA: " + eIDASResponse.getLevelOfAssurance());
+			
+		}
+		
+		if (!loaValid) {
+			log.error("eIDAS Response LevelOfAssurance is lower than the required! "
+					+ "(Resp-LoA:" + respLoA.getValue() + " Req-LoA:" + allowedLoAs.toArray() + ")");
+			throw new eIDASValidationException("eidas.06", new Object[]{respLoA.getValue()});
+			
+		}
+						
+
+
+		/*-----------------------------------------------------|
+		 *     validate 'PersonalIdentifier' attribute         |
+		 *_____________________________________________________|
+		 */
+		AttributeDefinition<?> attrDefinition = attrRegistry.getCoreAttributeRegistry().getByFriendlyName(Constants.eIDAS_ATTR_PERSONALIDENTIFIER).first();        
+	    final ImmutableList<? extends AttributeValue<?>> attributeValues = eIDASResponse.getAttributes().getAttributeMap().get(attrDefinition).asList();
+	    List<String> personalIdObj = eIDASResponseUtils.translateStringListAttribute(attrDefinition, attributeValues);
+	    	   
+		//check if attribute exists
+		if (personalIdObj == null || personalIdObj.isEmpty()) {
+	        	log.warn("eIDAS Response include NO 'PersonalIdentifier' attriubte "
+	        			+ ".... That can be a BIG problem in further processing steps");	
+	        	throw new eIDASValidationException("eidas.05", new Object[] {"NO 'PersonalIdentifier' attriubte"});
+	        	
+		} else if (personalIdObj.size() > 1) {
+			log.warn("eIDAS Response include MORE THAN ONE 'PersonalIdentifier' attriubtes "
+        			+ ".... That can be a BIG problem in further processing steps");
+			throw new eIDASValidationException("eidas.05", new Object[] {"MORE THAN ONE 'PersonalIdentifier' attriubtes"});
+								
+		} else {
+			String natPersId = personalIdObj.get(0);
+			//validate attribute value format			
+			Trible<String, String, String> split = 
+					eIDASResponseUtils.parseEidasPersonalIdentifier(natPersId);
+			if (split == null) {
+				throw new eIDASValidationException("eidas.07", 
+						new Object[]{
+								Constants.eIDAS_ATTR_PERSONALIDENTIFIER,
+								"Wrong identifier format"});
+				
+			} else {
+				//validation according to eIDAS SAML Attribute Profile, Section 2.2.3 
+				if (StringUtils.isEmpty(split.getSecond())) {
+					log.warn("eIDAS attribute value for " + Constants.eIDAS_ATTR_PERSONALIDENTIFIER 
+							+ " includes NO destination country. Value:" + natPersId);				
+					throw new eIDASValidationException("eidas.07", 
+							new Object[]{
+									Constants.eIDAS_ATTR_PERSONALIDENTIFIER,
+									"No or empty destination country"});
+					
+				}
+				if (!split.getSecond().equalsIgnoreCase(spCountry)) {
+					log.warn("eIDAS attribute value for " + Constants.eIDAS_ATTR_PERSONALIDENTIFIER 
+							+ " includes wrong destination country. Value:" + natPersId
+							+ " SP-Country:" + spCountry);				
+					throw new eIDASValidationException("eidas.07", 
+							new Object[]{
+									Constants.eIDAS_ATTR_PERSONALIDENTIFIER,
+									"Destination country does not match to SP country"});
+					
+				}
+				
+				if (StringUtils.isEmpty(split.getFirst())) {
+					log.warn("eIDAS attribute value for " + Constants.eIDAS_ATTR_PERSONALIDENTIFIER 
+							+ " includes NO citizen country. Value:" + natPersId);				
+					throw new eIDASValidationException("eidas.07", 
+							new Object[]{
+									Constants.eIDAS_ATTR_PERSONALIDENTIFIER,
+									"No or empty citizen country"});
+					
+				}
+				if (!split.getSecond().equalsIgnoreCase(spCountry)) {
+					log.warn("eIDAS attribute value for " + Constants.eIDAS_ATTR_PERSONALIDENTIFIER 
+							+ " includes a relaying-party country that does not match to service-provider country. "
+							+ " Value:" + natPersId
+							+ " SP Country:" + spCountry);				
+					throw new eIDASValidationException("eidas.07", 
+							new Object[]{
+									Constants.eIDAS_ATTR_PERSONALIDENTIFIER,
+									"Citizen country does not match to eIDAS-node country that generates the response"});
+					
+				}				
+			}									
+		}
+
+	}
+}
-- 
cgit v1.2.3