aboutsummaryrefslogtreecommitdiff
path: root/modules/eidas_proxy-sevice/src
diff options
context:
space:
mode:
Diffstat (limited to 'modules/eidas_proxy-sevice/src')
-rw-r--r--modules/eidas_proxy-sevice/src/main/java/at/asitplus/eidas/specific/modules/msproxyservice/EidasProxyMessageSource.java22
-rw-r--r--modules/eidas_proxy-sevice/src/main/java/at/asitplus/eidas/specific/modules/msproxyservice/MsProxyServiceConstants.java59
-rw-r--r--modules/eidas_proxy-sevice/src/main/java/at/asitplus/eidas/specific/modules/msproxyservice/MsProxyServiceSpringResourceProvider.java55
-rw-r--r--modules/eidas_proxy-sevice/src/main/java/at/asitplus/eidas/specific/modules/msproxyservice/dto/attributes/AttrMappingElement.java43
-rw-r--r--modules/eidas_proxy-sevice/src/main/java/at/asitplus/eidas/specific/modules/msproxyservice/dto/attributes/IdaAttribute.java29
-rw-r--r--modules/eidas_proxy-sevice/src/main/java/at/asitplus/eidas/specific/modules/msproxyservice/dto/attributes/Type.java91
-rw-r--r--modules/eidas_proxy-sevice/src/main/java/at/asitplus/eidas/specific/modules/msproxyservice/exception/EidasProxyServiceException.java19
-rw-r--r--modules/eidas_proxy-sevice/src/main/java/at/asitplus/eidas/specific/modules/msproxyservice/protocol/EidasProxyServiceController.java464
-rw-r--r--modules/eidas_proxy-sevice/src/main/java/at/asitplus/eidas/specific/modules/msproxyservice/protocol/ProxyServiceAuthenticationAction.java351
-rw-r--r--modules/eidas_proxy-sevice/src/main/java/at/asitplus/eidas/specific/modules/msproxyservice/protocol/ProxyServicePendingRequest.java28
-rw-r--r--modules/eidas_proxy-sevice/src/main/java/at/asitplus/eidas/specific/modules/msproxyservice/service/ProxyEidasAttributeRegistry.java217
-rw-r--r--modules/eidas_proxy-sevice/src/main/java/at/asitplus/eidas/specific/modules/msproxyservice/utils/EidasProxyServiceUtils.java45
-rw-r--r--modules/eidas_proxy-sevice/src/main/resources/META-INF/services/at.gv.egiz.components.spring.api.SpringResourceProvider1
-rw-r--r--modules/eidas_proxy-sevice/src/main/resources/messages/eidasproxy_messages.properties14
-rw-r--r--modules/eidas_proxy-sevice/src/main/resources/spring/eidas_proxy-service.beans.xml38
-rw-r--r--modules/eidas_proxy-sevice/src/test/java/at/asitplus/eidas/specific/modules/msproxyservice/test/EidasProxyMessageSourceTest.java50
-rw-r--r--modules/eidas_proxy-sevice/src/test/java/at/asitplus/eidas/specific/modules/msproxyservice/test/MsProxyServiceSpringResourceProviderTest.java56
-rw-r--r--modules/eidas_proxy-sevice/src/test/java/at/asitplus/eidas/specific/modules/msproxyservice/test/protocol/EidasProxyServiceControllerTest.java675
-rw-r--r--modules/eidas_proxy-sevice/src/test/java/at/asitplus/eidas/specific/modules/msproxyservice/test/protocol/ProxyServiceAuthenticationActionTest.java780
-rw-r--r--modules/eidas_proxy-sevice/src/test/java/at/asitplus/eidas/specific/modules/msproxyservice/test/services/ProxyEidasAttributeRegistryTest.java139
-rw-r--r--modules/eidas_proxy-sevice/src/test/resources/config/additional-attributes.xml39
-rw-r--r--modules/eidas_proxy-sevice/src/test/resources/config/eidas-attributes.xml376
-rw-r--r--modules/eidas_proxy-sevice/src/test/resources/config/idaAttributeMapping.json183
-rw-r--r--modules/eidas_proxy-sevice/src/test/resources/config/junit_config_1.properties8
-rw-r--r--modules/eidas_proxy-sevice/src/test/resources/spring/SpringTest-context_basic_mapConfig.xml20
-rw-r--r--modules/eidas_proxy-sevice/src/test/resources/spring/SpringTest-context_basic_test.xml34
26 files changed, 3836 insertions, 0 deletions
diff --git a/modules/eidas_proxy-sevice/src/main/java/at/asitplus/eidas/specific/modules/msproxyservice/EidasProxyMessageSource.java b/modules/eidas_proxy-sevice/src/main/java/at/asitplus/eidas/specific/modules/msproxyservice/EidasProxyMessageSource.java
new file mode 100644
index 00000000..23390da8
--- /dev/null
+++ b/modules/eidas_proxy-sevice/src/main/java/at/asitplus/eidas/specific/modules/msproxyservice/EidasProxyMessageSource.java
@@ -0,0 +1,22 @@
+package at.asitplus.eidas.specific.modules.msproxyservice;
+
+import java.util.Arrays;
+import java.util.List;
+
+import at.gv.egiz.eaaf.core.api.logging.IMessageSourceLocation;
+
+/**
+ * i18n Message-Source for eIDAS Proxy-Service messages.
+ *
+ * @author tlenz
+ *
+ */
+public class EidasProxyMessageSource implements IMessageSourceLocation {
+
+ @Override
+ public List<String> getMessageSourceLocation() {
+ return Arrays.asList("classpath:messages/eidasproxy_messages");
+
+ }
+
+}
diff --git a/modules/eidas_proxy-sevice/src/main/java/at/asitplus/eidas/specific/modules/msproxyservice/MsProxyServiceConstants.java b/modules/eidas_proxy-sevice/src/main/java/at/asitplus/eidas/specific/modules/msproxyservice/MsProxyServiceConstants.java
new file mode 100644
index 00000000..a2a2e78f
--- /dev/null
+++ b/modules/eidas_proxy-sevice/src/main/java/at/asitplus/eidas/specific/modules/msproxyservice/MsProxyServiceConstants.java
@@ -0,0 +1,59 @@
+package at.asitplus.eidas.specific.modules.msproxyservice;
+
+import at.asitplus.eidas.specific.modules.core.eidas.EidasConstants;
+import at.gv.egiz.eaaf.core.api.data.EaafConfigConstants;
+
+/**
+ * Constants for MS-specific eIDAS Proxy-Service.
+ *
+ * @author tlenz
+ *
+ */
+public class MsProxyServiceConstants {
+
+ // general constants
+ public static final String TEMPLATE_SP_UNIQUE_ID = "eidasProxyAuth_from_{0}_type_{1}";
+
+ // configuration constants
+ public static final String CONIG_PROPS_EIDAS_PROXY_NODE_ENTITYID = EidasConstants.CONIG_PROPS_EIDAS_NODE
+ + ".proxy.entityId";
+ public static final String CONIG_PROPS_EIDAS_PROXY_NODE_FORWARD_URL = EidasConstants.CONIG_PROPS_EIDAS_NODE
+ + ".proxy.forward.endpoint";
+
+
+ public static final String CONIG_PROPS_EIDAS_PROXY_ATTIBUTE_CONFIGURATION =
+ EidasConstants.CONIG_PROPS_EIDAS_PREFIX + ".proxy.attribute.mapping.config";
+
+
+ // mandate configuration
+ public static final String CONIG_PROPS_EIDAS_PROXY_MANDATES_ENABLED =
+ EidasConstants.CONIG_PROPS_EIDAS_PREFIX + ".proxy.mandates.enabled";
+ public static final String CONIG_PROPS_EIDAS_PROXY_MANDATES_PROFILE_DEFAULT_NATURAL =
+ EidasConstants.CONIG_PROPS_EIDAS_PREFIX + ".proxy.mandates.profiles.natural.default";
+ public static final String CONIG_PROPS_EIDAS_PROXY_MANDATES_PROFILE_DEFAULT_LEGAL =
+ EidasConstants.CONIG_PROPS_EIDAS_PREFIX + ".proxy.mandates.profiles.legal.default";
+
+
+ public static final String CONIG_PROPS_EIDAS_PROXY_WORKAROUND_MANDATES_LEGAL_PERSON =
+ EidasConstants.CONIG_PROPS_EIDAS_PREFIX + ".proxy.workaround.mandates.legalperson";
+
+ // specific eIDAS-Connector configuration
+ public static final String CONIG_PROPS_CONNECTOR_PREFIX = "connector";
+ public static final String CONIG_PROPS_CONNECTOR_UNIQUEID = EaafConfigConstants.SERVICE_UNIQUEIDENTIFIER;
+ public static final String CONIG_PROPS_CONNECTOR_COUNTRYCODE = "countryCode";
+ public static final String CONIG_PROPS_CONNECTOR_MANDATES_ENABLED = "mandates.enabled";
+ public static final String CONIG_PROPS_CONNECTOR_MANDATES_PROFILE_NATURAL = "mandates.natural";
+ public static final String CONIG_PROPS_CONNECTOR_MANDATES_PROFILE_LEGAL = "mandates.legal";
+ public static final String CONIG_PROPS_CONNECTOR_VALIDATION_ATTR_MDS = "validation.attributes.mds";
+
+
+ //http end-points
+ public static final String EIDAS_HTTP_ENDPOINT_IDP_POST = "/eidas/light/idp/post";
+ public static final String EIDAS_HTTP_ENDPOINT_IDP_REDIRECT = "/eidas/light/idp/redirect";
+
+ private MsProxyServiceConstants() {
+ //private constructor for class with only constant values
+
+ }
+
+}
diff --git a/modules/eidas_proxy-sevice/src/main/java/at/asitplus/eidas/specific/modules/msproxyservice/MsProxyServiceSpringResourceProvider.java b/modules/eidas_proxy-sevice/src/main/java/at/asitplus/eidas/specific/modules/msproxyservice/MsProxyServiceSpringResourceProvider.java
new file mode 100644
index 00000000..571ad8ab
--- /dev/null
+++ b/modules/eidas_proxy-sevice/src/main/java/at/asitplus/eidas/specific/modules/msproxyservice/MsProxyServiceSpringResourceProvider.java
@@ -0,0 +1,55 @@
+/*
+ * Copyright 2018 A-SIT Plus GmbH
+ * AT-specific eIDAS Connector has been developed in a cooperation between EGIZ,
+ * A-SIT Plus GmbH, A-SIT, and Graz University of Technology.
+ *
+ * Licensed under the EUPL, Version 1.2 or - as soon they will be approved by
+ * the European Commission - subsequent versions of the EUPL (the "License");
+ * You may not use this work except in compliance with the License.
+ * You may obtain a copy of the License at:
+ * https://joinup.ec.europa.eu/news/understanding-eupl-v12
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * This product combines work with different licenses. See the "NOTICE" text
+ * file for details on the various modules and licenses.
+ * The "NOTICE" text file is part of the distribution. Any derivative works
+ * that you distribute must include a readable copy of the "NOTICE" text file.
+*/
+
+package at.asitplus.eidas.specific.modules.msproxyservice;
+
+import org.springframework.core.io.ClassPathResource;
+import org.springframework.core.io.Resource;
+
+import at.gv.egiz.components.spring.api.SpringResourceProvider;
+
+public class MsProxyServiceSpringResourceProvider implements SpringResourceProvider {
+
+ @Override
+ public String getName() {
+ return "MS-specific eIDAS Proxy-Service module";
+ }
+
+ @Override
+ public String[] getPackagesToScan() {
+ return null;
+
+ }
+
+ @Override
+ public Resource[] getResourcesToLoad() {
+ final ClassPathResource eidasProxyServiceConfig =
+ new ClassPathResource("/spring/eidas_proxy-service.beans.xml", MsProxyServiceSpringResourceProvider.class);
+ final ClassPathResource eidasRefImplConfig = new ClassPathResource("/eidas_v2_auth_ref_impl_config.beans.xml",
+ MsProxyServiceSpringResourceProvider.class);
+
+
+ return new Resource[] { eidasProxyServiceConfig, eidasRefImplConfig };
+ }
+
+}
diff --git a/modules/eidas_proxy-sevice/src/main/java/at/asitplus/eidas/specific/modules/msproxyservice/dto/attributes/AttrMappingElement.java b/modules/eidas_proxy-sevice/src/main/java/at/asitplus/eidas/specific/modules/msproxyservice/dto/attributes/AttrMappingElement.java
new file mode 100644
index 00000000..cf106bad
--- /dev/null
+++ b/modules/eidas_proxy-sevice/src/main/java/at/asitplus/eidas/specific/modules/msproxyservice/dto/attributes/AttrMappingElement.java
@@ -0,0 +1,43 @@
+
+package at.asitplus.eidas.specific.modules.msproxyservice.dto.attributes;
+
+import java.util.List;
+
+import com.fasterxml.jackson.annotation.JsonInclude;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import com.fasterxml.jackson.annotation.JsonPropertyOrder;
+
+import lombok.Data;
+
+@JsonInclude(JsonInclude.Include.NON_NULL)
+@JsonPropertyOrder({
+ "eidasAttribute",
+ "idaAttribute",
+ "type"
+})
+@Data
+public class AttrMappingElement {
+
+ /**
+ * eIDAS specific attribute name.
+ */
+ @JsonProperty("eidasAttribute")
+ private String eidasAttributeName;
+
+ /**
+ * IDA specific attribute name.
+ */
+ @JsonProperty("idaAttribute")
+ private IdaAttribute idaAttribute;
+
+
+ @JsonProperty("addionalRequiredAttributes")
+ private List<String> addionalRequiredAttributes;
+
+ /**
+ * attribute characteristics.
+ */
+ @JsonProperty("type")
+ private Type type;
+
+}
diff --git a/modules/eidas_proxy-sevice/src/main/java/at/asitplus/eidas/specific/modules/msproxyservice/dto/attributes/IdaAttribute.java b/modules/eidas_proxy-sevice/src/main/java/at/asitplus/eidas/specific/modules/msproxyservice/dto/attributes/IdaAttribute.java
new file mode 100644
index 00000000..ee5fc810
--- /dev/null
+++ b/modules/eidas_proxy-sevice/src/main/java/at/asitplus/eidas/specific/modules/msproxyservice/dto/attributes/IdaAttribute.java
@@ -0,0 +1,29 @@
+package at.asitplus.eidas.specific.modules.msproxyservice.dto.attributes;
+
+import com.fasterxml.jackson.annotation.JsonInclude;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import com.fasterxml.jackson.annotation.JsonPropertyOrder;
+
+import lombok.Data;
+
+@JsonInclude(JsonInclude.Include.NON_NULL)
+@JsonPropertyOrder({
+ "basic",
+ "withMandates"
+})
+@Data
+public class IdaAttribute {
+
+ /**
+ * IDA attribute name, in case of simple process without mandates.
+ */
+ @JsonProperty("basic")
+ private String basic;
+
+ /**
+ * IDA attribute name, in case of mandate process.
+ */
+ @JsonProperty("withMandates")
+ private String withMandates;
+
+}
diff --git a/modules/eidas_proxy-sevice/src/main/java/at/asitplus/eidas/specific/modules/msproxyservice/dto/attributes/Type.java b/modules/eidas_proxy-sevice/src/main/java/at/asitplus/eidas/specific/modules/msproxyservice/dto/attributes/Type.java
new file mode 100644
index 00000000..6a06a5b5
--- /dev/null
+++ b/modules/eidas_proxy-sevice/src/main/java/at/asitplus/eidas/specific/modules/msproxyservice/dto/attributes/Type.java
@@ -0,0 +1,91 @@
+
+package at.asitplus.eidas.specific.modules.msproxyservice.dto.attributes;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import com.fasterxml.jackson.annotation.JsonCreator;
+import com.fasterxml.jackson.annotation.JsonInclude;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import com.fasterxml.jackson.annotation.JsonPropertyOrder;
+import com.fasterxml.jackson.annotation.JsonValue;
+
+import lombok.Data;
+
+@JsonInclude(JsonInclude.Include.NON_NULL)
+@JsonPropertyOrder({
+ "mds",
+ "autoIncludeWithMandates",
+ "mandator"
+})
+@Data
+public class Type {
+
+ /**
+ * <code>true</code> if this attribute is part of MDS, otherwise <code>false</code>.
+ */
+ @JsonProperty("mds")
+ private Boolean mds;
+
+ /**
+ * <code>true</code> if that attribute has to be included into eIDAS response in case of mandates.
+ */
+ @JsonProperty("autoIncludeWithMandates")
+ private Boolean autoIncludeWithMandates;
+
+ /**
+ * Classifie that attribute to specific mandate modes.
+ */
+ @JsonProperty("mandator")
+ private Type.Mandator mandator;
+
+ /**
+ * Mandate type in case of a mandate attriute.
+ */
+ public enum Mandator {
+ BOTH("both"),
+ LEGAL("legal"),
+ NATURAL("natural"),
+ NONE("none");
+
+ private final String value;
+ private static final Map<String, Type.Mandator> CONSTANTS = new HashMap<>();
+
+ static {
+ for (final Type.Mandator c : values()) {
+ CONSTANTS.put(c.value, c);
+ }
+ }
+
+ Mandator(String value) {
+ this.value = value;
+ }
+
+ @Override
+ public String toString() {
+ return this.value;
+ }
+
+ @JsonValue
+ public String value() {
+ return this.value;
+ }
+
+ /**
+ * Build {@link Mandator} from textual representation.
+ *
+ * @param value textual representation
+ * @return Type of the mandator
+ */
+ @JsonCreator
+ public static Type.Mandator fromValue(String value) {
+ final Type.Mandator constant = CONSTANTS.get(value);
+ if (constant == null) {
+ throw new IllegalArgumentException(value);
+ } else {
+ return constant;
+ }
+ }
+
+ }
+}
diff --git a/modules/eidas_proxy-sevice/src/main/java/at/asitplus/eidas/specific/modules/msproxyservice/exception/EidasProxyServiceException.java b/modules/eidas_proxy-sevice/src/main/java/at/asitplus/eidas/specific/modules/msproxyservice/exception/EidasProxyServiceException.java
new file mode 100644
index 00000000..43592a28
--- /dev/null
+++ b/modules/eidas_proxy-sevice/src/main/java/at/asitplus/eidas/specific/modules/msproxyservice/exception/EidasProxyServiceException.java
@@ -0,0 +1,19 @@
+package at.asitplus.eidas.specific.modules.msproxyservice.exception;
+
+import at.gv.egiz.eaaf.core.exceptions.EaafException;
+
+public class EidasProxyServiceException extends EaafException {
+
+ private static final long serialVersionUID = 1L;
+
+ public EidasProxyServiceException(String errorId, Object[] params) {
+ super(errorId, params);
+
+ }
+
+ public EidasProxyServiceException(String errorId, Object[] params, Throwable e) {
+ super(errorId, params, e);
+
+ }
+
+}
diff --git a/modules/eidas_proxy-sevice/src/main/java/at/asitplus/eidas/specific/modules/msproxyservice/protocol/EidasProxyServiceController.java b/modules/eidas_proxy-sevice/src/main/java/at/asitplus/eidas/specific/modules/msproxyservice/protocol/EidasProxyServiceController.java
new file mode 100644
index 00000000..26cc51ee
--- /dev/null
+++ b/modules/eidas_proxy-sevice/src/main/java/at/asitplus/eidas/specific/modules/msproxyservice/protocol/EidasProxyServiceController.java
@@ -0,0 +1,464 @@
+package at.asitplus.eidas.specific.modules.msproxyservice.protocol;
+
+import java.io.IOException;
+import java.text.MessageFormat;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Objects;
+import java.util.UUID;
+import java.util.stream.Collectors;
+
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.apache.commons.lang.StringEscapeUtils;
+import org.apache.commons.lang3.StringUtils;
+import org.opensaml.saml.saml2.core.NameIDType;
+import org.opensaml.saml.saml2.core.StatusCode;
+import org.springframework.beans.factory.annotation.Autowired;
+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 com.google.common.collect.Streams;
+
+import at.asitplus.eidas.specific.core.MsEidasNodeConstants;
+import at.asitplus.eidas.specific.core.config.ServiceProviderConfiguration;
+import at.asitplus.eidas.specific.modules.core.eidas.EidasConstants;
+import at.asitplus.eidas.specific.modules.msproxyservice.MsProxyServiceConstants;
+import at.asitplus.eidas.specific.modules.msproxyservice.exception.EidasProxyServiceException;
+import at.asitplus.eidas.specific.modules.msproxyservice.service.ProxyEidasAttributeRegistry;
+import at.asitplus.eidas.specific.modules.msproxyservice.utils.EidasProxyServiceUtils;
+import at.gv.egiz.components.eventlog.api.EventConstants;
+import at.gv.egiz.eaaf.core.api.IRequest;
+import at.gv.egiz.eaaf.core.api.data.EaafConfigConstants;
+import at.gv.egiz.eaaf.core.api.data.EaafConstants;
+import at.gv.egiz.eaaf.core.api.data.ExtendedPvpAttributeDefinitions.SpMandateModes;
+import at.gv.egiz.eaaf.core.api.idp.IModulInfo;
+import at.gv.egiz.eaaf.core.api.idp.ISpConfiguration;
+import at.gv.egiz.eaaf.core.exceptions.EaafException;
+import at.gv.egiz.eaaf.core.exceptions.GuiBuildException;
+import at.gv.egiz.eaaf.core.impl.idp.controller.AbstractController;
+import at.gv.egiz.eaaf.core.impl.utils.KeyValueUtils;
+import eu.eidas.auth.commons.EIDASSubStatusCode;
+import eu.eidas.auth.commons.EidasParameterKeys;
+import eu.eidas.auth.commons.light.ILightRequest;
+import eu.eidas.auth.commons.light.impl.LightResponse;
+import eu.eidas.auth.commons.light.impl.LightResponse.Builder;
+import eu.eidas.auth.commons.light.impl.ResponseStatus;
+import eu.eidas.specificcommunication.SpecificCommunicationDefinitionBeanNames;
+import eu.eidas.specificcommunication.exception.SpecificCommunicationException;
+import eu.eidas.specificcommunication.protocol.SpecificCommunicationService;
+import lombok.extern.slf4j.Slf4j;
+
+/**
+ * End-point implementation for authentication requests from eIDAS Proxy-Service
+ * to MS-specific eIDAS Proxy-Service.
+ *
+ * @author tlenz
+ *
+ */
+@Slf4j
+@Controller
+public class EidasProxyServiceController extends AbstractController implements IModulInfo {
+
+ private static final String ERROR_01 = "eidas.proxyservice.01";
+ private static final String ERROR_02 = "eidas.proxyservice.02";
+ private static final String ERROR_03 = "eidas.proxyservice.03";
+ private static final String ERROR_04 = "eidas.proxyservice.04";
+ private static final String ERROR_05 = "eidas.proxyservice.05";
+ private static final String ERROR_07 = "eidas.proxyservice.07";
+ private static final String ERROR_08 = "eidas.proxyservice.08";
+ private static final String ERROR_09 = "eidas.proxyservice.09";
+ private static final String ERROR_10 = "eidas.proxyservice.10";
+ private static final String ERROR_11 = "eidas.proxyservice.11";
+
+ public static final String PROTOCOL_ID = "eidasProxy";
+
+ @Autowired ProxyEidasAttributeRegistry attrRegistry;
+ @Autowired ProxyServiceAuthenticationAction responseAction;
+
+ /**
+ * End-point that receives authentication requests from eIDAS Node.
+ *
+ * @param httpReq Http request
+ * @param httpResp Http response
+ * @throws IOException In case of general error
+ * @throws EaafException In case of a validation or processing error
+ */
+ @RequestMapping(value = {
+ MsProxyServiceConstants.EIDAS_HTTP_ENDPOINT_IDP_POST,
+ MsProxyServiceConstants.EIDAS_HTTP_ENDPOINT_IDP_REDIRECT
+ },
+ method = { RequestMethod.POST, RequestMethod.GET })
+ public void receiveEidasAuthnRequest(HttpServletRequest httpReq, HttpServletResponse httpResp)
+ throws IOException,
+ EaafException {
+ log.trace("Receive request on eidas proxy-service end-points");
+ ProxyServicePendingRequest pendingReq = null;
+ try {
+ // get token from Request
+ final String tokenBase64 = httpReq.getParameter(EidasParameterKeys.TOKEN.toString());
+ if (StringUtils.isEmpty(tokenBase64)) {
+ log.warn("NO eIDAS message token found.");
+ throw new EidasProxyServiceException(ERROR_02, null);
+
+ }
+ log.trace("Receive eIDAS-node token: {}. Searching authentication request from eIDAS Proxy-Service ...",
+ tokenBase64);
+
+ // read authentication request from shared cache
+ final SpecificCommunicationService specificProxyCommunicationService =
+ (SpecificCommunicationService) applicationContext.getBean(
+ SpecificCommunicationDefinitionBeanNames.SPECIFIC_PROXYSERVICE_COMMUNICATION_SERVICE
+ .toString());
+ final ILightRequest eidasRequest = specificProxyCommunicationService.getAndRemoveRequest(
+ tokenBase64,
+ ImmutableSortedSet.copyOf(attrRegistry.getCoreRegistry().getCoreAttributeRegistry().getAttributes()));
+ if (eidasRequest == null) {
+ log.info("Find no eIDAS Authn. Request with stated token.");
+ throw new EidasProxyServiceException(ERROR_11, null);
+
+ }
+
+ log.debug("Received eIDAS auth. request from: {}, Initializing authentication environment ... ",
+ eidasRequest.getSpCountryCode() != null ? eidasRequest.getSpCountryCode() : "'missing SP-country'");
+ log.trace("Received eIDAS requst: {}", eidasRequest);
+
+ // create pendingRequest object
+ pendingReq = applicationContext.getBean(ProxyServicePendingRequest.class);
+ pendingReq.initialize(httpReq, authConfig);
+ pendingReq.setModule(getName());
+
+ // log 'transaction created' event
+ revisionsLogger.logEvent(EventConstants.TRANSACTION_CREATED,
+ pendingReq.getUniqueTransactionIdentifier());
+ revisionsLogger.logEvent(pendingReq.getUniqueSessionIdentifier(),
+ pendingReq.getUniqueTransactionIdentifier(), EventConstants.TRANSACTION_IP,
+ httpReq.getRemoteAddr());
+
+ // validate eIDAS Authn. request and set into pending-request
+ validateEidasAuthnRequest(eidasRequest);
+ pendingReq.setEidasRequest(eidasRequest);
+
+ // generate Service-Provider configuration from eIDAS request
+ final ISpConfiguration spConfig = generateSpConfigurationFromEidasRequest(eidasRequest);
+
+ // validate eIDAS Authn. request by using eIDAS Connector specifc parameters
+ validateEidasAuthnRequest(spConfig, eidasRequest);
+
+ // populate pendingRequest with parameters
+ pendingReq.setOnlineApplicationConfiguration(spConfig);
+ pendingReq.setSpEntityId(spConfig.getUniqueIdentifier());
+ pendingReq.setPassiv(false);
+ pendingReq.setForce(true);
+
+ // AuthnRequest needs authentication
+ pendingReq.setNeedAuthentication(true);
+
+ // set protocol action, which should be executed after authentication
+ pendingReq.setAction(ProxyServiceAuthenticationAction.class.getName());
+
+ // switch to session authentication
+ protAuthService.performAuthentication(httpReq, httpResp, pendingReq);
+
+ } catch (final EidasProxyServiceException e) {
+ throw e;
+
+ } catch (final SpecificCommunicationException e) {
+ log.error("Can not read eIDAS Authn request from shared cache. Reason: {}", e.getMessage());
+ throw new EidasProxyServiceException(ERROR_03, new Object[] { e.getMessage() }, e);
+
+ } catch (final Throwable e) {
+ // write revision log entries
+ if (pendingReq != null) {
+ revisionsLogger.logEvent(pendingReq, EventConstants.TRANSACTION_ERROR,
+ pendingReq.getUniqueTransactionIdentifier());
+ }
+
+ throw new EidasProxyServiceException(ERROR_01, new Object[] { e.getMessage() }, e);
+ }
+
+ }
+
+ @Override
+ public boolean generateErrorMessage(Throwable e, HttpServletRequest httpReq, HttpServletResponse httpResp,
+ IRequest pendingReq) throws Throwable {
+ if (pendingReq instanceof ProxyServicePendingRequest) {
+ try {
+ ILightRequest eidasReq = ((ProxyServicePendingRequest) pendingReq).getEidasRequest();
+
+ //build eIDAS response
+ Builder lightRespBuilder = LightResponse.builder();
+ lightRespBuilder.id(UUID.randomUUID().toString());
+ lightRespBuilder.inResponseToId(eidasReq.getId());
+ lightRespBuilder.relayState(eidasReq.getRelayState());
+ lightRespBuilder.issuer(authConfig.getBasicConfiguration(
+ MsProxyServiceConstants.CONIG_PROPS_EIDAS_PROXY_NODE_ENTITYID));
+ lightRespBuilder.subject(UUID.randomUUID().toString());
+ lightRespBuilder.subjectNameIdFormat(NameIDType.TRANSIENT);
+ lightRespBuilder.status(ResponseStatus.builder()
+ .statusCode(StatusCode.RESPONDER)
+ .subStatusCode(EIDASSubStatusCode.AUTHN_FAILED_URI.getValue())
+ .statusMessage(StringEscapeUtils.escapeXml(e.getLocalizedMessage()))
+ .build());
+
+ // forward to eIDAS Proxy-Service
+ responseAction.forwardToEidasProxy(pendingReq, httpReq, httpResp, lightRespBuilder.build());
+
+ return true;
+
+ } catch (ServletException | IOException | GuiBuildException e1) {
+ log.warn("Forward error to eIDAS Proxy-Service FAILED. Handle error localy ... ", e1);
+
+ }
+
+ } else {
+ log.error("eIDAS Proxy-Service authentication requires PendingRequest of Type: {}",
+ ProxyServicePendingRequest.class.getName());
+
+ }
+
+ return false;
+
+ }
+
+ @Override
+ public String getName() {
+ return EidasProxyServiceController.class.getName();
+
+ }
+
+ @Override
+ public String getAuthProtocolIdentifier() {
+ return PROTOCOL_ID;
+
+ }
+
+ @Override
+ public boolean validate(HttpServletRequest request, HttpServletResponse response, IRequest pending) {
+ return true;
+
+ }
+
+ /**
+ * Generic validation of incoming eIDAS request.
+ *
+ * @param eidasRequest Incoming eIDAS authentication request
+ * @throws EidasProxyServiceException In case of a validation error
+ */
+ private void validateEidasAuthnRequest(ILightRequest eidasRequest) throws EidasProxyServiceException {
+ if (StringUtils.isEmpty(eidasRequest.getIssuer())) {
+ throw new EidasProxyServiceException(ERROR_05, null);
+
+ }
+
+ // TODO: validate some other stuff
+
+ }
+
+ /**
+ * eIDAS Connector specific validation of incoming eIDAS request.
+ *
+ * @param eidasRequest Incoming eIDAS authentication request
+ * @param spConfig eIDAS Connector configuration
+ * @throws EidasProxyServiceException In case of a validation error
+ */
+ private void validateEidasAuthnRequest(ISpConfiguration spConfig, ILightRequest eidasRequest)
+ throws EidasProxyServiceException {
+ // check if natural-person and legal-person attributes requested in parallel
+ if (spConfig.isConfigurationValue(MsProxyServiceConstants.CONIG_PROPS_CONNECTOR_VALIDATION_ATTR_MDS, true)
+ && EidasProxyServiceUtils.isLegalPersonRequested(eidasRequest)
+ && EidasProxyServiceUtils.isNaturalPersonRequested(eidasRequest)) {
+ throw new EidasProxyServiceException(ERROR_08, null);
+
+ }
+
+ // TODO: validate some other stuff
+
+ }
+
+ /**
+ * Generate a dummy Service-Provider configuration for processing.
+ *
+ * @param eidasRequest Incoming eIDAS authentication request
+ * @return Service-Provider configuration that can be used for authentication
+ * @throws EidasProxyServiceException In case of a configuration error
+ */
+ private ISpConfiguration generateSpConfigurationFromEidasRequest(ILightRequest eidasRequest)
+ throws EidasProxyServiceException {
+ try {
+
+ Map<String, String> connectorConfigMap = extractRawConnectorConfiguration(eidasRequest);
+
+ // check if country-code is available
+ String spCountry = connectorConfigMap.get(MsProxyServiceConstants.CONIG_PROPS_CONNECTOR_COUNTRYCODE);
+ if (StringUtils.isEmpty(spCountry)) {
+ throw new EidasProxyServiceException(ERROR_07, null);
+
+ }
+
+ // build FriendyName from CountryCode and SPType
+ connectorConfigMap.put(MsEidasNodeConstants.PROP_CONFIG_SP_FRIENDLYNAME,
+ MessageFormat.format(MsProxyServiceConstants.TEMPLATE_SP_UNIQUE_ID,
+ spCountry, eidasRequest.getSpType()));
+
+ // build Service-Provider configuration object
+ final ServiceProviderConfiguration spConfig = new ServiceProviderConfiguration(connectorConfigMap, authConfig);
+
+ // build bPK target from Country-Code
+ final String ccCountry = authConfig.getBasicConfiguration(EidasConstants.CONIG_PROPS_EIDAS_NODE_COUNTRYCODE,
+ EidasConstants.DEFAULT_MS_NODE_COUNTRY_CODE);
+ spConfig.setBpkTargetIdentifier(
+ EaafConstants.URN_PREFIX_EIDAS + ccCountry + "+" + spCountry);
+
+ // set required LoA from eIDAS request
+ spConfig.setRequiredLoA(
+ eidasRequest.getLevelsOfAssurance().stream().map(el -> el.getValue()).collect(Collectors.toList()));
+
+ // build mandate profiles for this specific request
+ buildMandateProfileConfiguration(spConfig, eidasRequest);
+
+ // map eIDAS attributes to national attributes
+ buildNationalRequestedAttributes(spConfig, eidasRequest);
+
+ return spConfig;
+
+ } catch (EidasProxyServiceException e) {
+ throw e;
+
+ } catch (final EaafException e) {
+ throw new EidasProxyServiceException(ERROR_04, new Object[] { e.getMessage() }, e);
+
+ }
+ }
+
+
+ private void buildNationalRequestedAttributes(
+ ServiceProviderConfiguration spConfig, ILightRequest eidasRequest) {
+ boolean mandatesEnabled = !SpMandateModes.NONE.equals(spConfig.getMandateMode());
+ spConfig.setRequestedAttributes(
+ Streams.concat(
+ eidasRequest.getRequestedAttributes().getAttributeMap().keySet().stream()
+ .map(el -> attrRegistry.getIdaAttributesForEidasAttribute(
+ el.getNameUri().toString(), mandatesEnabled))
+ .flatMap(Collection::stream)
+ .filter(Objects::nonNull),
+ attrRegistry.getAlwaysRequestedAttributes(mandatesEnabled))
+ .collect(Collectors.toSet()));
+ log.debug("Inject #{} attributes to request from IDA system", spConfig.getRequestedAttributes().size());
+
+ }
+
+ private Map<String, String> extractRawConnectorConfiguration(ILightRequest eidasRequest) {
+ Map<String, String> allConnectorConfigs = authConfig.getBasicConfigurationWithPrefix(
+ MsProxyServiceConstants.CONIG_PROPS_CONNECTOR_PREFIX);
+ if (log.isTraceEnabled()) {
+ log.trace("Full-connector configuration:");
+ allConnectorConfigs.entrySet().stream().forEach(
+ el -> log.trace("Key: {} -> Value: {}", el.getKey(), el.getValue()));
+
+ }
+
+ Map<String, String> connectorConfig = allConnectorConfigs.entrySet().stream()
+ .filter(el -> el.getKey().endsWith(MsEidasNodeConstants.PROP_CONFIG_SP_UNIQUEIDENTIFIER)
+ && el.getValue().equals(eidasRequest.getIssuer()))
+ .findFirst()
+ .map(el -> KeyValueUtils.getSubSetWithPrefix(allConnectorConfigs,
+ KeyValueUtils.getParentKey(el.getKey()) + KeyValueUtils.KEY_DELIMITER))
+ .orElse(new HashMap<>());
+
+
+ if (connectorConfig.isEmpty()) {
+ log.debug("No specific configuration for eIDAS Connector: {} Using default configuration ... ",
+ eidasRequest.getIssuer());
+
+ // set EntityId of the requesting eIDAS Connector
+ connectorConfig.put(EaafConfigConstants.SERVICE_UNIQUEIDENTIFIER, eidasRequest.getIssuer());
+
+ // set country-code from eIDAS request
+ connectorConfig.put(MsProxyServiceConstants.CONIG_PROPS_CONNECTOR_COUNTRYCODE,
+ eidasRequest.getSpCountryCode());
+
+ // set default mandate configuration
+ connectorConfig.put(MsProxyServiceConstants.CONIG_PROPS_CONNECTOR_MANDATES_ENABLED,
+ String.valueOf(authConfig.getBasicConfigurationBoolean(
+ MsProxyServiceConstants.CONIG_PROPS_EIDAS_PROXY_MANDATES_ENABLED, false)));
+ connectorConfig.put(MsProxyServiceConstants.CONIG_PROPS_CONNECTOR_MANDATES_PROFILE_NATURAL,
+ authConfig.getBasicConfiguration(
+ MsProxyServiceConstants.CONIG_PROPS_EIDAS_PROXY_MANDATES_PROFILE_DEFAULT_NATURAL));
+ connectorConfig.put(MsProxyServiceConstants.CONIG_PROPS_CONNECTOR_MANDATES_PROFILE_LEGAL,
+ authConfig.getBasicConfiguration(
+ MsProxyServiceConstants.CONIG_PROPS_EIDAS_PROXY_MANDATES_PROFILE_DEFAULT_LEGAL));
+
+ } else {
+ log.debug("Find specific configuration for eIDAS Connector: {}", eidasRequest.getIssuer());
+
+ }
+
+ return connectorConfig;
+
+ }
+
+
+ private void buildMandateProfileConfiguration(ServiceProviderConfiguration spConfig, ILightRequest eidasRequest)
+ throws EidasProxyServiceException {
+ // check if mandates are enabled
+ if (spConfig.isConfigurationValue(MsProxyServiceConstants.CONIG_PROPS_CONNECTOR_MANDATES_ENABLED, false)) {
+ injectMandateInfosIntoSpConfig(spConfig, eidasRequest);
+
+ } else {
+ if (EidasProxyServiceUtils.isLegalPersonRequested(eidasRequest)) {
+ throw new EidasProxyServiceException(ERROR_09, null);
+
+ }
+
+ spConfig.setMandateProfiles(Collections.emptyList());
+ spConfig.setMandateMode(SpMandateModes.NONE);
+
+ }
+
+ }
+
+ private void injectMandateInfosIntoSpConfig(ServiceProviderConfiguration spConfig,
+ ILightRequest eidasRequest) throws EidasProxyServiceException {
+ log.trace("eIDAS Proxy-Service allows mandates for Connector: {}. Selecting profiles ... ",
+ spConfig.getUniqueIdentifier());
+
+ //check if legal person is requested
+ if (EidasProxyServiceUtils.isLegalPersonRequested(eidasRequest)) {
+ spConfig.setMandateProfiles(KeyValueUtils.getListOfCsvValues(
+ spConfig.getConfigurationValue(MsProxyServiceConstants.CONIG_PROPS_CONNECTOR_MANDATES_PROFILE_LEGAL)));
+ spConfig.setMandateMode(SpMandateModes.LEGAL_FORCE);
+
+ if (spConfig.getMandateProfiles().isEmpty()) {
+ throw new EidasProxyServiceException(ERROR_10, null);
+
+ }
+
+ } else if (EidasProxyServiceUtils.isNaturalPersonRequested(eidasRequest)) {
+ spConfig.setMandateProfiles(KeyValueUtils.getListOfCsvValues(
+ spConfig.getConfigurationValue(MsProxyServiceConstants.CONIG_PROPS_CONNECTOR_MANDATES_PROFILE_NATURAL)));
+
+ spConfig.setMandateMode(SpMandateModes.NATURAL);
+
+ }
+
+
+ if (spConfig.getMandateProfiles().isEmpty()) {
+ log.debug("No mandate-profiles for issure: {}. Set mandate-mode to 'none'",
+ spConfig.getUniqueIdentifier());
+ spConfig.setMandateMode(SpMandateModes.NONE);
+
+ } else {
+ log.debug("Set mandate-profiles: {} to request from issuer: {}",
+ spConfig.getMandateProfiles(), spConfig.getUniqueIdentifier());
+
+ }
+
+ }
+}
diff --git a/modules/eidas_proxy-sevice/src/main/java/at/asitplus/eidas/specific/modules/msproxyservice/protocol/ProxyServiceAuthenticationAction.java b/modules/eidas_proxy-sevice/src/main/java/at/asitplus/eidas/specific/modules/msproxyservice/protocol/ProxyServiceAuthenticationAction.java
new file mode 100644
index 00000000..bf1c5e5f
--- /dev/null
+++ b/modules/eidas_proxy-sevice/src/main/java/at/asitplus/eidas/specific/modules/msproxyservice/protocol/ProxyServiceAuthenticationAction.java
@@ -0,0 +1,351 @@
+package at.asitplus.eidas.specific.modules.msproxyservice.protocol;
+
+import java.io.IOException;
+import java.util.Optional;
+import java.util.UUID;
+
+import javax.annotation.PostConstruct;
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.apache.commons.lang3.StringUtils;
+import org.opensaml.saml.saml2.core.NameIDType;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.ApplicationContext;
+import org.springframework.core.io.ResourceLoader;
+import org.springframework.web.util.UriComponentsBuilder;
+
+import at.asitplus.eidas.specific.core.gui.StaticGuiBuilderConfiguration;
+import at.asitplus.eidas.specific.modules.core.eidas.EidasConstants;
+import at.asitplus.eidas.specific.modules.msproxyservice.MsProxyServiceConstants;
+import at.asitplus.eidas.specific.modules.msproxyservice.exception.EidasProxyServiceException;
+import at.asitplus.eidas.specific.modules.msproxyservice.service.ProxyEidasAttributeRegistry;
+import at.asitplus.eidas.specific.modules.msproxyservice.utils.EidasProxyServiceUtils;
+import at.gv.egiz.eaaf.core.api.IRequest;
+import at.gv.egiz.eaaf.core.api.data.PvpAttributeDefinitions;
+import at.gv.egiz.eaaf.core.api.gui.ISpringMvcGuiFormBuilder;
+import at.gv.egiz.eaaf.core.api.idp.IAction;
+import at.gv.egiz.eaaf.core.api.idp.IAuthData;
+import at.gv.egiz.eaaf.core.api.idp.IConfiguration;
+import at.gv.egiz.eaaf.core.api.idp.IEidAuthData;
+import at.gv.egiz.eaaf.core.api.idp.slo.SloInformationInterface;
+import at.gv.egiz.eaaf.core.exceptions.EaafConfigurationException;
+import at.gv.egiz.eaaf.core.exceptions.EaafException;
+import at.gv.egiz.eaaf.core.exceptions.GuiBuildException;
+import at.gv.egiz.eaaf.core.impl.data.SloInformationImpl;
+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.ILightResponse;
+import eu.eidas.auth.commons.light.impl.LightResponse;
+import eu.eidas.auth.commons.light.impl.LightResponse.Builder;
+import eu.eidas.auth.commons.light.impl.ResponseStatus;
+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.SpecificCommunicationService;
+import lombok.extern.slf4j.Slf4j;
+
+/**
+ * Result action of a successfully performed eIDAS Proxy-Service authentication.
+ *
+ * @author tlenz
+ *
+ */
+@Slf4j
+public class ProxyServiceAuthenticationAction implements IAction {
+
+ private static final String PROXYSERVICE_AUTH_ACTION_NAME = "MS-specific eIDAS-Proxy action";
+
+ @Autowired
+ ApplicationContext context;
+ @Autowired
+ IConfiguration basicConfig;
+ @Autowired
+ ResourceLoader resourceLoader;
+ @Autowired
+ ISpringMvcGuiFormBuilder guiBuilder;
+ @Autowired
+ ProxyEidasAttributeRegistry attrRegistry;
+
+ @Override
+ public SloInformationInterface processRequest(IRequest pendingReq, HttpServletRequest httpReq,
+ HttpServletResponse httpResp, IAuthData authData) throws EaafException {
+ if (pendingReq instanceof ProxyServicePendingRequest) {
+ try {
+ final ILightRequest eidasReq = ((ProxyServicePendingRequest) pendingReq).getEidasRequest();
+
+ // build eIDAS response
+ final Builder lightRespBuilder = LightResponse.builder();
+ lightRespBuilder.id(UUID.randomUUID().toString());
+ lightRespBuilder.inResponseToId(eidasReq.getId());
+ lightRespBuilder.relayState(eidasReq.getRelayState());
+
+ lightRespBuilder.status(ResponseStatus.builder()
+ .statusCode(EidasConstants.SUCCESS_URI)
+ .build());
+
+ // TODO: check if we can use transient subjectNameIds
+ lightRespBuilder.subject(UUID.randomUUID().toString());
+ lightRespBuilder.subjectNameIdFormat(NameIDType.TRANSIENT);
+
+ // TODO:
+ lightRespBuilder.issuer(basicConfig.getBasicConfiguration(
+ MsProxyServiceConstants.CONIG_PROPS_EIDAS_PROXY_NODE_ENTITYID));
+ lightRespBuilder.levelOfAssurance(authData.getEidasQaaLevel());
+ lightRespBuilder.attributes(buildAttributesFromAuthData(authData, eidasReq));
+
+ // set SLO response object of EAAF framework
+ final SloInformationImpl sloInformation = new SloInformationImpl();
+ sloInformation.setProtocolType(pendingReq.requestedModule());
+ sloInformation
+ .setSpEntityID(pendingReq.getServiceProviderConfiguration().getUniqueIdentifier());
+
+ // forward to eIDAS Proxy-Service
+ forwardToEidasProxy(pendingReq, httpReq, httpResp, lightRespBuilder.build());
+
+ return sloInformation;
+
+ } catch (ServletException | IOException | GuiBuildException e) {
+ throw new EidasProxyServiceException("eidas.proxyservice.06", null, e);
+
+ }
+
+ } else {
+ log.error("eIDAS Proxy-Service authentication requires PendingRequest of Type: {}",
+ ProxyServicePendingRequest.class.getName());
+ throw new EaafException("eidas.proxyservice.99");
+
+ }
+ }
+
+ @Override
+ public boolean needAuthentication(IRequest req, HttpServletRequest httpReq, HttpServletResponse httpResp) {
+ return true;
+
+ }
+
+ @Override
+ public String getDefaultActionName() {
+ return PROXYSERVICE_AUTH_ACTION_NAME;
+
+ }
+
+ /**
+ * Forward eIDAS Light response to eIDAS node.
+ *
+ * @param pendingReq Current pending request.
+ * @param httpReq Current HTTP request
+ * @param httpResp Current HTTP response
+ * @param lightResponse eIDAS LightResponse
+ * @throws EaafConfigurationException In case of a configuration error
+ * @throws IOException In case of a general error
+ * @throws GuiBuildException In case of a GUI rendering error, if http
+ * POST binding is used
+ * @throws ServletException In case of a general error
+ */
+ public void forwardToEidasProxy(IRequest pendingReq, HttpServletRequest httpReq,
+ HttpServletResponse httpResp, LightResponse lightResponse) throws EaafConfigurationException,
+ IOException,
+ GuiBuildException, ServletException {
+
+ // put request into shared cache
+ final BinaryLightToken token = putResponseInCommunicationCache(lightResponse);
+ final String tokenBase64 = BinaryLightTokenHelper.encodeBinaryLightTokenBase64(token);
+
+ // select forward URL regarding the selected environment
+ final String forwardUrl = basicConfig.getBasicConfiguration(
+ MsProxyServiceConstants.CONIG_PROPS_EIDAS_PROXY_NODE_FORWARD_URL);
+
+ 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[] { MsProxyServiceConstants.CONIG_PROPS_EIDAS_PROXY_NODE_FORWARD_URL });
+
+ }
+ log.debug("ForwardURL: " + forwardUrl + " selected to forward eIDAS request");
+
+ if (basicConfig.getBasicConfiguration(
+ EidasConstants.CONIG_PROPS_EIDAS_NODE_FORWARD_METHOD,
+ EidasConstants.FORWARD_METHOD_GET).equals(EidasConstants.FORWARD_METHOD_GET)) {
+
+ log.debug("Use http-redirect for eIDAS node forwarding ... ");
+ // send redirect
+ final UriComponentsBuilder redirectUrl = UriComponentsBuilder.fromHttpUrl(forwardUrl);
+ redirectUrl.queryParam(EidasParameterKeys.TOKEN.toString(), tokenBase64);
+ httpResp.sendRedirect(redirectUrl.build().encode().toString());
+
+ } else {
+ log.debug("Use http-post for eIDAS node forwarding ... ");
+ final StaticGuiBuilderConfiguration config = new StaticGuiBuilderConfiguration(
+ basicConfig,
+ pendingReq,
+ EidasConstants.TEMPLATE_POST_FORWARD_NAME,
+ null,
+ resourceLoader);
+
+ config.putCustomParameter(null, EidasConstants.TEMPLATE_POST_FORWARD_ENDPOINT, forwardUrl);
+ config.putCustomParameter(null, EidasConstants.TEMPLATE_POST_FORWARD_TOKEN_NAME,
+ EidasParameterKeys.TOKEN.toString());
+ config.putCustomParameter(null, EidasConstants.TEMPLATE_POST_FORWARD_TOKEN_VALUE,
+ tokenBase64);
+
+ guiBuilder.build(httpReq, httpResp, config, "Forward to eIDASNode form");
+
+ }
+ }
+
+ @PostConstruct
+ private void checkConfiguration() {
+ // TODO: validate configuration on start-up
+
+ }
+
+ private ImmutableAttributeMap buildAttributesFromAuthData(IAuthData authData,
+ ILightRequest eidasReq) {
+ final IEidAuthData eidAuthData = (IEidAuthData) authData;
+ final ImmutableAttributeMap.Builder attributeMap = ImmutableAttributeMap.builder();
+
+ // inject all requested attributres
+ injectRequestedAttributes(attributeMap, eidasReq, eidAuthData);
+
+ if (eidAuthData.isUseMandate()) {
+ log.debug("Building eIDAS Proxy-Service response with mandate ... ");
+ injectMdsRepesentativeInformation(attributeMap, eidAuthData, eidasReq.getRequestedAttributes());
+
+ // work-around that injects nat. person subject to bypass validation on eIDAS
+ // Node
+ injectJurPersonWorkaroundIfRequired(attributeMap, eidasReq, authData);
+
+ }
+
+ return attributeMap.build();
+
+ }
+
+ private void injectRequestedAttributes(ImmutableAttributeMap.Builder attributeMap, ILightRequest eidasReq,
+ IEidAuthData eidAuthData) {
+ eidasReq.getRequestedAttributes().getAttributeMap().keySet().stream()
+ .forEach(el -> injectEidasAttribute(attributeMap, eidAuthData,
+ el.getNameUri().toString(), eidAuthData.isUseMandate()));
+
+ }
+
+ private void injectMdsRepesentativeInformation(
+ ImmutableAttributeMap.Builder attributeMap, IEidAuthData eidAuthData,
+ ImmutableAttributeMap requestedAttributes) {
+ attrRegistry.getRepresentativeAttributesToAddByDefault()
+ .filter(el -> requestedAttributes.getAttributeValuesByNameUri(el) == null)
+ .forEach(el -> injectEidasAttribute(attributeMap, eidAuthData, el, true));
+
+ }
+
+ private void injectEidasAttribute(ImmutableAttributeMap.Builder attributeMap, IEidAuthData eidAuthData,
+ String eidasAttrName, boolean mandatesUsed) {
+ final Optional<String> releatedIdaAttribute =
+ attrRegistry.mapEidasAttributeToSpecificIdaAttribute(eidasAttrName, mandatesUsed);
+ if (releatedIdaAttribute.isPresent()) {
+ log.trace("Mapping IDA attribute: {} to eIDAS attribute: {}", releatedIdaAttribute.get(),
+ eidasAttrName);
+ final String idaAttrValue = eidAuthData.getGenericData(releatedIdaAttribute.get(), String.class);
+ if (StringUtils.isNotEmpty(idaAttrValue)) {
+ log.debug("Build eIDAS attribute: {} from IDA attribute: {}", eidasAttrName, releatedIdaAttribute
+ .get());
+ attributeMap.put(
+ attrRegistry.getCoreRegistry().getCoreAttributeRegistry().getByName(eidasAttrName),
+ idaAttrValue);
+
+ } else {
+ log.info("No IDA attribute: {}, eIDAS attribute: {} will be ignored", releatedIdaAttribute.get(),
+ eidasAttrName);
+
+ }
+
+ } else {
+ log.warn("Can not build eIDAS attribute: {}, because there is not corresponding IDA attribute defined",
+ eidasAttrName);
+
+ }
+ }
+
+ private BinaryLightToken putResponseInCommunicationCache(ILightResponse lightResponse)
+ throws ServletException {
+ final BinaryLightToken binaryLightToken;
+ try {
+ final SpecificCommunicationService springManagedSpecificConnectorCommunicationService =
+ (SpecificCommunicationService) context.getBean(
+ SpecificCommunicationDefinitionBeanNames.SPECIFIC_PROXYSERVICE_COMMUNICATION_SERVICE
+ .toString());
+
+ binaryLightToken = springManagedSpecificConnectorCommunicationService.putResponse(lightResponse);
+
+ } catch (final SpecificCommunicationException e) {
+ log.error("Unable to process specific request");
+ throw new ServletException(e);
+
+ }
+
+ return binaryLightToken;
+ }
+
+ /**
+ * Work-around to inject representative information as nat. person subject to
+ * bypass eIDAS Node validation.
+ *
+ * <p>
+ * <b>Injection will only be done if this work-around is enabled by
+ * configuration, the mandator is a legal person, and both legal and natural
+ * person subject's is requested.</b>
+ * </p>
+ *
+ * @param attributeMap Attribute set for eIDAS response
+ * @param eidasReq Incoming eIDAS request
+ * @param authData Authentication data
+ */
+ private void injectJurPersonWorkaroundIfRequired(
+ ImmutableAttributeMap.Builder attributeMap, ILightRequest eidasReq, IAuthData authData) {
+ if (isLegalPersonWorkaroundActive() && isLegalPersonMandateAvailable(authData)
+ && EidasProxyServiceUtils.isNaturalPersonRequested(eidasReq)
+ && EidasProxyServiceUtils.isLegalPersonRequested(eidasReq)) {
+ log.debug(
+ "Injecting representative information as nat. person subject to bypass eIDAS Node validation");
+
+ final AttributeDefinition<?> attrDefPersonalId =
+ attrRegistry.getCoreRegistry().getCoreAttributeRegistry().getByFriendlyName(
+ EidasConstants.eIDAS_ATTR_PERSONALIDENTIFIER).first();
+ final AttributeDefinition<?> attrDefFamilyName =
+ attrRegistry.getCoreRegistry().getCoreAttributeRegistry().getByFriendlyName(
+ EidasConstants.eIDAS_ATTR_CURRENTFAMILYNAME).first();
+ final AttributeDefinition<?> attrDefGivenName =
+ attrRegistry.getCoreRegistry().getCoreAttributeRegistry().getByFriendlyName(
+ EidasConstants.eIDAS_ATTR_CURRENTGIVENNAME).first();
+ final AttributeDefinition<?> attrDefDateOfBirth =
+ attrRegistry.getCoreRegistry().getCoreAttributeRegistry().getByFriendlyName(
+ EidasConstants.eIDAS_ATTR_DATEOFBIRTH).first();
+
+ attributeMap.put(attrDefPersonalId, authData.getGenericData(PvpAttributeDefinitions.BPK_NAME,
+ String.class));
+ attributeMap.put(attrDefFamilyName, authData.getFamilyName());
+ attributeMap.put(attrDefGivenName, authData.getGivenName());
+ attributeMap.put(attrDefDateOfBirth, authData.getDateOfBirth());
+
+ }
+ }
+
+ private boolean isLegalPersonWorkaroundActive() {
+ return basicConfig.getBasicConfigurationBoolean(
+ MsProxyServiceConstants.CONIG_PROPS_EIDAS_PROXY_WORKAROUND_MANDATES_LEGAL_PERSON,
+ false);
+
+ }
+
+ private boolean isLegalPersonMandateAvailable(IAuthData authData) {
+ return StringUtils.isNoneEmpty(authData.getGenericData(
+ PvpAttributeDefinitions.MANDATE_LEG_PER_SOURCE_PIN_NAME, String.class));
+
+ }
+
+}
diff --git a/modules/eidas_proxy-sevice/src/main/java/at/asitplus/eidas/specific/modules/msproxyservice/protocol/ProxyServicePendingRequest.java b/modules/eidas_proxy-sevice/src/main/java/at/asitplus/eidas/specific/modules/msproxyservice/protocol/ProxyServicePendingRequest.java
new file mode 100644
index 00000000..a3b5007a
--- /dev/null
+++ b/modules/eidas_proxy-sevice/src/main/java/at/asitplus/eidas/specific/modules/msproxyservice/protocol/ProxyServicePendingRequest.java
@@ -0,0 +1,28 @@
+package at.asitplus.eidas.specific.modules.msproxyservice.protocol;
+
+import org.springframework.beans.factory.config.BeanDefinition;
+import org.springframework.context.annotation.Scope;
+import org.springframework.stereotype.Component;
+
+import at.gv.egiz.eaaf.core.impl.idp.controller.protocols.RequestImpl;
+import eu.eidas.auth.commons.light.ILightRequest;
+import lombok.Getter;
+import lombok.Setter;
+
+/**
+ * Pending-request of an authentication process from eIDAS Proxy-Service.
+ *
+ * @author tlenz
+ *
+ */
+@Component("ProxyServicePendingRequest")
+@Scope(value = BeanDefinition.SCOPE_PROTOTYPE)
+public class ProxyServicePendingRequest extends RequestImpl {
+
+ private static final long serialVersionUID = 4227378344716277935L;
+
+ @Getter
+ @Setter
+ ILightRequest eidasRequest;
+
+}
diff --git a/modules/eidas_proxy-sevice/src/main/java/at/asitplus/eidas/specific/modules/msproxyservice/service/ProxyEidasAttributeRegistry.java b/modules/eidas_proxy-sevice/src/main/java/at/asitplus/eidas/specific/modules/msproxyservice/service/ProxyEidasAttributeRegistry.java
new file mode 100644
index 00000000..a6a50100
--- /dev/null
+++ b/modules/eidas_proxy-sevice/src/main/java/at/asitplus/eidas/specific/modules/msproxyservice/service/ProxyEidasAttributeRegistry.java
@@ -0,0 +1,217 @@
+package at.asitplus.eidas.specific.modules.msproxyservice.service;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URISyntaxException;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+import java.util.Objects;
+import java.util.Optional;
+import java.util.Set;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+
+import javax.annotation.PostConstruct;
+
+import org.apache.commons.io.IOUtils;
+import org.apache.commons.lang3.StringUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.core.io.Resource;
+import org.springframework.core.io.ResourceLoader;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.type.CollectionType;
+import com.google.common.collect.Sets;
+
+import at.asitplus.eidas.specific.modules.core.eidas.service.EidasAttributeRegistry;
+import at.asitplus.eidas.specific.modules.msproxyservice.MsProxyServiceConstants;
+import at.asitplus.eidas.specific.modules.msproxyservice.dto.attributes.AttrMappingElement;
+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.FileUtils;
+import lombok.Getter;
+import lombok.NonNull;
+import lombok.extern.slf4j.Slf4j;
+
+@Slf4j
+public class ProxyEidasAttributeRegistry {
+
+ private static final String ATTR_CONFIG_ALL = "*";
+
+ private static ObjectMapper mapper = new ObjectMapper();
+
+ @Autowired IConfiguration basicConfig;
+ @Autowired ResourceLoader resourceLoader;
+
+
+ @Getter
+ private EidasAttributeRegistry coreRegistry;
+
+ private Set<AttrMappingElement> attributeConfiguration;
+
+
+ /**
+ * Attribute Registry for eIDAS Proxy-Service implementation.
+ * @param registry Core attribute registry
+ */
+ public ProxyEidasAttributeRegistry(@Autowired EidasAttributeRegistry registry) {
+ this.coreRegistry = registry;
+
+ }
+
+
+ /**
+ * Get all attributes that requested from IDA by default.
+ *
+ * @param withMandates <code>true</code> if mandates are supported, otherwise <code>false</code>
+ * @return {@link Stream} of IDA specific attribute names
+ */
+ @NonNull
+ public Stream<String> getAlwaysRequestedAttributes(boolean withMandates) {
+ return attributeConfiguration.stream()
+ .filter(el -> ATTR_CONFIG_ALL.equals(el.getEidasAttributeName()))
+ .map(el -> getReleadedIdaAttribute(el, withMandates))
+ .flatMap(Collection::stream)
+ .filter(Objects::nonNull);
+
+ }
+
+ /**
+ * Get all eIDAS attributes that are added by default in case of mandates.
+ *
+ * @return {@link Stream} of eIDAS attributes
+ */
+ @NonNull
+ public Stream<String> getRepresentativeAttributesToAddByDefault() {
+ return attributeConfiguration.stream()
+ .filter(el -> el.getType() != null && el.getType().getAutoIncludeWithMandates())
+ .map(el -> el.getEidasAttributeName());
+
+ }
+
+ /**
+ * Get IDA attributes for a specific eIDAS attribute.
+ *
+ * @param eidasAttributeName Name of the eIDAS attribute.
+ * @param withMandates <code>true</code> if mandates are supported, otherwise <code>false</code>
+ * @return {@link Set} of IDA specific attribute names
+ */
+ @NonNull
+ public Set<String> getIdaAttributesForEidasAttribute(String eidasAttributeName, boolean withMandates) {
+ return attributeConfiguration.stream()
+ .filter(el -> el.getEidasAttributeName().equals(eidasAttributeName))
+ .findFirst()
+ .map(el -> getReleadedIdaAttribute(el, withMandates))
+ .orElse(Collections.emptySet())
+ .stream()
+ .filter(Objects::nonNull)
+ .collect(Collectors.toSet());
+
+ }
+
+ /**
+ * Get eIDAS related IDA attribute.
+ *
+ * @param eidasAttributeName Name of the eIDAS attribute.
+ * @param withMandates <code>true</code> if mandates are supported, otherwise <code>false</code>
+ * @return Name of the related IDA attribute if available
+ */
+ public Optional<String> mapEidasAttributeToSpecificIdaAttribute(
+ String eidasAttributeName, boolean withMandates) {
+ return attributeConfiguration.stream()
+ .filter(el -> el.getEidasAttributeName().equals(eidasAttributeName))
+ .findFirst()
+ .map(el -> withMandates ? el.getIdaAttribute().getWithMandates() : el.getIdaAttribute().getBasic())
+ .filter(el -> StringUtils.isNotEmpty(el));
+
+ }
+
+ @PostConstruct
+ private void initialize() throws EaafConfigurationException {
+ final String attrConfPath = basicConfig.getBasicConfiguration(
+ MsProxyServiceConstants.CONIG_PROPS_EIDAS_PROXY_ATTIBUTE_CONFIGURATION);
+
+ log.debug("Initializing eIDAS <--> IDA attribute mapping from: {} ... ", attrConfPath);
+
+ if (StringUtils.isEmpty(attrConfPath)) {
+ log.error("Error: Path to attribute-mapping config is unknown");
+ throw new EaafConfigurationException("internal.configuration.00",
+ new Object[]{MsProxyServiceConstants.CONIG_PROPS_EIDAS_PROXY_ATTIBUTE_CONFIGURATION});
+
+ }
+
+ try {
+ // reading attribute-configuration file
+ final CollectionType javaType =
+ mapper.getTypeFactory().constructCollectionType(List.class, AttrMappingElement.class);
+ List<AttrMappingElement> internalAttributeConfiguration =
+ mapper.readValue(readFromFile(attrConfPath), javaType);
+ log.debug("Found #{} eIDAS <--> IDA attribute-mappings . Starting import process ... ",
+ internalAttributeConfiguration.size());
+
+ // post-validation of attribute configuration
+ attributeConfiguration = internalAttributeConfiguration.stream()
+ .filter(el -> checkEidasAttributeName(el))
+ .collect(Collectors.toSet());
+ log.info("Load {} eIDAS <--> IDA attribute-mappings into attribute-registry", attributeConfiguration.size());
+
+ } catch (Exception e) {
+ log.error("Error reading eIDAS <--> IDA attribute-mapping configuration file", e);
+ throw new EaafConfigurationException("internal.configuration.01",
+ new Object[]{MsProxyServiceConstants.CONIG_PROPS_EIDAS_PROXY_ATTIBUTE_CONFIGURATION,
+ "Error reading Configurations file"}, e);
+
+ }
+ }
+
+ private Set<String> getReleadedIdaAttribute(AttrMappingElement el, boolean withMandates) {
+ if (el.getIdaAttribute() != null) {
+ Set<String> directMapping = withMandates
+ ? Sets.newHashSet(el.getIdaAttribute().getBasic(), el.getIdaAttribute().getWithMandates())
+ : Sets.newHashSet(el.getIdaAttribute().getBasic());
+
+ if (el.getAddionalRequiredAttributes() != null) {
+ el.getAddionalRequiredAttributes().forEach(
+ attr -> directMapping.add(attr));
+
+ }
+ return directMapping;
+
+ } else {
+ return Collections.emptySet();
+
+ }
+ }
+
+ private boolean checkEidasAttributeName(AttrMappingElement el) {
+ if (StringUtils.isNotEmpty(el.getEidasAttributeName())) {
+ if (ATTR_CONFIG_ALL.equals(el.getEidasAttributeName())
+ || coreRegistry.getCoreAttributeRegistry().getByName(el.getEidasAttributeName()) != null) {
+ return true;
+
+ } else {
+ log.warn("eIDAS attribute: {} is UNKNOWN by eIDAS node. Ignore it!", el.getEidasAttributeName());
+
+ }
+
+ } else {
+ log.warn("Find attribute-mapping element WITHOUT eIDAS attribute-name. Ignore it!");
+
+ }
+
+ return false;
+ }
+
+ private byte[] readFromFile(final String filePath) throws URISyntaxException, IOException {
+ final String fullFilePath = FileUtils.makeAbsoluteUrl(filePath, basicConfig.getConfigurationRootDirectory());
+ final Resource ressource = resourceLoader.getResource(fullFilePath);
+ final InputStream is = ressource.getInputStream();
+ final byte[] result = IOUtils.toByteArray(is);
+ is.close();
+ return result;
+
+ }
+
+
+}
diff --git a/modules/eidas_proxy-sevice/src/main/java/at/asitplus/eidas/specific/modules/msproxyservice/utils/EidasProxyServiceUtils.java b/modules/eidas_proxy-sevice/src/main/java/at/asitplus/eidas/specific/modules/msproxyservice/utils/EidasProxyServiceUtils.java
new file mode 100644
index 00000000..b8a4c598
--- /dev/null
+++ b/modules/eidas_proxy-sevice/src/main/java/at/asitplus/eidas/specific/modules/msproxyservice/utils/EidasProxyServiceUtils.java
@@ -0,0 +1,45 @@
+package at.asitplus.eidas.specific.modules.msproxyservice.utils;
+
+import at.asitplus.eidas.specific.modules.core.eidas.EidasConstants;
+import eu.eidas.auth.commons.light.ILightRequest;
+
+/**
+ * Common utils for eIDAS Proxy-Service implementation.
+ *
+ * @author tlenz
+ *
+ */
+public class EidasProxyServiceUtils {
+
+ /**
+ * Check if legal person subject is requested by eIDAS Connector.
+ *
+ * @param eidasRequest Authentication request from eIDAS Connector.
+ * @return <code>true</code> if <i>LegalPersonIdentifier</i> is requested, otherwise <code>false</code>lse
+ */
+ public static boolean isLegalPersonRequested(ILightRequest eidasRequest) {
+ return eidasRequest.getRequestedAttributes().entrySet().stream()
+ .filter(el -> el.getKey().getFriendlyName().equals(EidasConstants.eIDAS_ATTR_LEGALPERSONIDENTIFIER))
+ .findFirst()
+ .isPresent();
+
+ }
+
+ /**
+ * Check if natural person subject is requested by eIDAS Connector.
+ *
+ * @param eidasRequest Authentication request from eIDAS Connector.
+ * @return <code>true</code> if <i>PersonIdentifier</i> is requested, otherwise <code>false</code>lse
+ */
+ public static boolean isNaturalPersonRequested(ILightRequest eidasRequest) {
+ return eidasRequest.getRequestedAttributes().entrySet().stream()
+ .filter(el -> el.getKey().getFriendlyName().equals(EidasConstants.eIDAS_ATTR_PERSONALIDENTIFIER))
+ .findFirst()
+ .isPresent();
+
+ }
+
+ private EidasProxyServiceUtils() {
+ //hide constructor for class with static methods only
+ }
+}
diff --git a/modules/eidas_proxy-sevice/src/main/resources/META-INF/services/at.gv.egiz.components.spring.api.SpringResourceProvider b/modules/eidas_proxy-sevice/src/main/resources/META-INF/services/at.gv.egiz.components.spring.api.SpringResourceProvider
new file mode 100644
index 00000000..9158d2e6
--- /dev/null
+++ b/modules/eidas_proxy-sevice/src/main/resources/META-INF/services/at.gv.egiz.components.spring.api.SpringResourceProvider
@@ -0,0 +1 @@
+at.asitplus.eidas.specific.modules.msproxyservice.MsProxyServiceSpringResourceProvider \ No newline at end of file
diff --git a/modules/eidas_proxy-sevice/src/main/resources/messages/eidasproxy_messages.properties b/modules/eidas_proxy-sevice/src/main/resources/messages/eidasproxy_messages.properties
new file mode 100644
index 00000000..3f92d58a
--- /dev/null
+++ b/modules/eidas_proxy-sevice/src/main/resources/messages/eidasproxy_messages.properties
@@ -0,0 +1,14 @@
+eidas.proxyservice.01=General error on request-validation from national eIDAS Proxy-Service
+eidas.proxyservice.02=Authentication request contains not communication token.
+eidas.proxyservice.03=General error during eIDAS-Node communication. Reason: {}
+eidas.proxyservice.04=Validation of eIDAS Authn request failed. Reason: {}
+eidas.proxyservice.05=No eIDAS-Connector Issuer in Authn. request. Authentication not possible
+eidas.proxyservice.06=Can not build eIDAS Proxy-Service response. Authentication FAILED.
+eidas.proxyservice.07=Can not determine eIDAS-Connector CountryCode. Authentication not possible
+eidas.proxyservice.08=Validation of eIDAS Authn request failed. Reason: Legal person and natural person can not be requested at once.
+eidas.proxyservice.09=eIDAS authentication not possible, because legal person is requested but mandates are disabled in general
+eidas.proxyservice.10=eIDAS authentication not possible, because legal person is requested but not mandate profiles are defined
+eidas.proxyservice.11=No Authentication request with stated communication token.
+
+
+eidas.proxyservice.99=Internal error during eIDAS Proxy-Service authentication \ No newline at end of file
diff --git a/modules/eidas_proxy-sevice/src/main/resources/spring/eidas_proxy-service.beans.xml b/modules/eidas_proxy-sevice/src/main/resources/spring/eidas_proxy-service.beans.xml
new file mode 100644
index 00000000..78b7640a
--- /dev/null
+++ b/modules/eidas_proxy-sevice/src/main/resources/spring/eidas_proxy-service.beans.xml
@@ -0,0 +1,38 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<beans xmlns="http://www.springframework.org/schema/beans"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xmlns:context="http://www.springframework.org/schema/context"
+ xmlns:tx="http://www.springframework.org/schema/tx"
+ xmlns:aop="http://www.springframework.org/schema/aop"
+ xsi:schemaLocation="http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.1.xsd
+ http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
+ http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.1.xsd
+ http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd">
+
+ <context:annotation-config />
+
+ <bean id="ProxyServicePendingRequest"
+ class="at.asitplus.eidas.specific.modules.msproxyservice.protocol.ProxyServicePendingRequest"
+ scope="prototype"/>
+
+ <bean id="ProxyServiceAuthenticationAction"
+ class="at.asitplus.eidas.specific.modules.msproxyservice.protocol.ProxyServiceAuthenticationAction"/>
+
+ <bean id="msSpecificProxyController"
+ class="at.asitplus.eidas.specific.modules.msproxyservice.protocol.EidasProxyServiceController"/>
+
+ <bean id="eidasProxyMessageSource"
+ class="at.asitplus.eidas.specific.modules.msproxyservice.EidasProxyMessageSource"/>
+
+ <bean id="attributeRegistry"
+ class="at.asitplus.eidas.specific.modules.core.eidas.service.EidasAttributeRegistry">
+ <property name="eidasAttributesFile"
+ ref="specificConnectorAttributesFileWithPath" />
+ <property name="additionalAttributesFile"
+ ref="specificConnectorAdditionalAttributesFileWithPath" />
+ </bean>
+
+ <bean id="proxyAttributeRegistry"
+ class="at.asitplus.eidas.specific.modules.msproxyservice.service.ProxyEidasAttributeRegistry" />
+
+</beans> \ No newline at end of file
diff --git a/modules/eidas_proxy-sevice/src/test/java/at/asitplus/eidas/specific/modules/msproxyservice/test/EidasProxyMessageSourceTest.java b/modules/eidas_proxy-sevice/src/test/java/at/asitplus/eidas/specific/modules/msproxyservice/test/EidasProxyMessageSourceTest.java
new file mode 100644
index 00000000..fc4ad2b6
--- /dev/null
+++ b/modules/eidas_proxy-sevice/src/test/java/at/asitplus/eidas/specific/modules/msproxyservice/test/EidasProxyMessageSourceTest.java
@@ -0,0 +1,50 @@
+package at.asitplus.eidas.specific.modules.msproxyservice.test;
+
+import java.util.List;
+
+import org.junit.Assert;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.core.io.Resource;
+import org.springframework.core.io.ResourceLoader;
+import org.springframework.test.context.ContextConfiguration;
+import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
+
+import at.asitplus.eidas.specific.modules.msproxyservice.EidasProxyMessageSource;
+import at.gv.egiz.eaaf.core.api.logging.IMessageSourceLocation;
+
+@RunWith(SpringJUnit4ClassRunner.class)
+@ContextConfiguration(locations = {
+ "/spring/SpringTest-context_basic_test.xml",
+ "/spring/SpringTest-context_basic_mapConfig.xml",
+ })
+public class EidasProxyMessageSourceTest {
+
+ @Autowired
+ private ResourceLoader loader;
+ @Autowired(required = false)
+ private List<IMessageSourceLocation> messageSources;
+
+ @Test
+ public void checkMessageSources() {
+ Assert.assertNotNull("No messageSource", messageSources);
+ Assert.assertFalse("No message source", messageSources.isEmpty());
+
+ boolean found = false;
+
+ for (final IMessageSourceLocation messageSource : messageSources) {
+ found = found ? found : messageSource instanceof EidasProxyMessageSource;
+
+ Assert.assertNotNull("No sourcePath", messageSource.getMessageSourceLocation());
+ for (final String el : messageSource.getMessageSourceLocation()) {
+ final Resource messages = loader.getResource(el + ".properties");
+ Assert.assertTrue("Source not exist", messages.exists());
+
+ }
+ }
+
+ Assert.assertTrue("Internal messagesource not found", found);
+
+ }
+}
diff --git a/modules/eidas_proxy-sevice/src/test/java/at/asitplus/eidas/specific/modules/msproxyservice/test/MsProxyServiceSpringResourceProviderTest.java b/modules/eidas_proxy-sevice/src/test/java/at/asitplus/eidas/specific/modules/msproxyservice/test/MsProxyServiceSpringResourceProviderTest.java
new file mode 100644
index 00000000..9a690664
--- /dev/null
+++ b/modules/eidas_proxy-sevice/src/test/java/at/asitplus/eidas/specific/modules/msproxyservice/test/MsProxyServiceSpringResourceProviderTest.java
@@ -0,0 +1,56 @@
+package at.asitplus.eidas.specific.modules.msproxyservice.test;
+
+import java.io.IOException;
+import java.io.InputStream;
+
+import org.apache.commons.io.IOUtils;
+import org.junit.Assert;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.BlockJUnit4ClassRunner;
+import org.springframework.core.io.Resource;
+
+import at.asitplus.eidas.specific.modules.msproxyservice.MsProxyServiceSpringResourceProvider;
+import at.gv.egiz.eaaf.core.test.TestConstants;
+
+
+
+@RunWith(BlockJUnit4ClassRunner.class)
+public class MsProxyServiceSpringResourceProviderTest {
+
+ @Test
+ public void testSpringConfig() {
+ final MsProxyServiceSpringResourceProvider test =
+ new MsProxyServiceSpringResourceProvider();
+ for (final Resource el : test.getResourcesToLoad()) {
+ try {
+ IOUtils.toByteArray(el.getInputStream());
+
+ } catch (final IOException e) {
+ Assert.fail("Ressouce: " + el.getFilename() + " not found");
+ }
+
+ }
+
+ Assert.assertNotNull("no Name", test.getName());
+ Assert.assertNull("Find package definitions", test.getPackagesToScan());
+
+ }
+
+ @Test
+ public void testSpILoaderConfig() {
+ final InputStream el = this.getClass().getResourceAsStream(TestConstants.TEST_SPI_LOADER_PATH);
+ try {
+ final String spiFile = IOUtils.toString(el, "UTF-8");
+
+ Assert.assertEquals("Wrong classpath in SPI file",
+ MsProxyServiceSpringResourceProvider.class.getName(), spiFile);
+
+
+ } catch (final IOException e) {
+ Assert.fail("Ressouce: " + TestConstants.TEST_SPI_LOADER_PATH + " not found");
+
+ }
+ }
+
+}
diff --git a/modules/eidas_proxy-sevice/src/test/java/at/asitplus/eidas/specific/modules/msproxyservice/test/protocol/EidasProxyServiceControllerTest.java b/modules/eidas_proxy-sevice/src/test/java/at/asitplus/eidas/specific/modules/msproxyservice/test/protocol/EidasProxyServiceControllerTest.java
new file mode 100644
index 00000000..b491c2bf
--- /dev/null
+++ b/modules/eidas_proxy-sevice/src/test/java/at/asitplus/eidas/specific/modules/msproxyservice/test/protocol/EidasProxyServiceControllerTest.java
@@ -0,0 +1,675 @@
+package at.asitplus.eidas.specific.modules.msproxyservice.test.protocol;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertThrows;
+import static org.junit.Assert.assertTrue;
+
+import java.io.IOException;
+import java.net.URISyntaxException;
+import java.net.URLDecoder;
+import java.text.MessageFormat;
+import java.util.Arrays;
+import java.util.List;
+import java.util.UUID;
+
+import org.apache.commons.lang3.RandomStringUtils;
+import org.apache.commons.lang3.StringUtils;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.opensaml.saml.saml2.core.NameIDType;
+import org.opensaml.saml.saml2.core.StatusCode;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.ApplicationContext;
+import org.springframework.mock.web.MockHttpServletRequest;
+import org.springframework.mock.web.MockHttpServletResponse;
+import org.springframework.test.context.ContextConfiguration;
+import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
+import org.springframework.web.context.request.RequestContextHolder;
+import org.springframework.web.context.request.ServletRequestAttributes;
+import org.springframework.web.servlet.config.annotation.EnableWebMvc;
+
+import com.google.common.collect.ImmutableSortedSet;
+
+import at.asitplus.eidas.specific.core.config.ServiceProviderConfiguration;
+import at.asitplus.eidas.specific.core.test.config.dummy.MsConnectorDummyConfigMap;
+import at.asitplus.eidas.specific.modules.core.eidas.EidasConstants;
+import at.asitplus.eidas.specific.modules.core.eidas.service.EidasAttributeRegistry;
+import at.asitplus.eidas.specific.modules.core.eidas.test.dummy.DummySpecificCommunicationService;
+import at.asitplus.eidas.specific.modules.msproxyservice.MsProxyServiceConstants;
+import at.asitplus.eidas.specific.modules.msproxyservice.exception.EidasProxyServiceException;
+import at.asitplus.eidas.specific.modules.msproxyservice.protocol.EidasProxyServiceController;
+import at.asitplus.eidas.specific.modules.msproxyservice.protocol.ProxyServicePendingRequest;
+import at.gv.egiz.eaaf.core.api.data.EaafConstants;
+import at.gv.egiz.eaaf.core.api.data.ExtendedPvpAttributeDefinitions.SpMandateModes;
+import at.gv.egiz.eaaf.core.exceptions.EaafException;
+import at.gv.egiz.eaaf.core.exceptions.EaafStorageException;
+import at.gv.egiz.eaaf.core.impl.idp.module.test.DummyProtocolAuthService;
+import eu.eidas.auth.commons.EidasParameterKeys;
+import eu.eidas.auth.commons.attribute.ImmutableAttributeMap;
+import eu.eidas.auth.commons.light.ILightResponse;
+import eu.eidas.auth.commons.light.impl.LightRequest;
+import eu.eidas.specificcommunication.SpecificCommunicationDefinitionBeanNames;
+import eu.eidas.specificcommunication.exception.SpecificCommunicationException;
+import eu.eidas.specificcommunication.protocol.SpecificCommunicationService;
+
+@RunWith(SpringJUnit4ClassRunner.class)
+@ContextConfiguration(locations = {
+ "/spring/SpringTest-context_basic_test.xml",
+ "/spring/SpringTest-context_basic_mapConfig.xml",
+ })
+@EnableWebMvc
+public class EidasProxyServiceControllerTest {
+
+ @Autowired private EidasProxyServiceController controller;
+
+ @Autowired private DummySpecificCommunicationService proxyService;
+ @Autowired private DummyProtocolAuthService authService;
+ @Autowired private EidasAttributeRegistry attrRegistry;
+ @Autowired private ApplicationContext context;
+
+ @Autowired MsConnectorDummyConfigMap config;
+
+ private MockHttpServletRequest httpReq;
+ private MockHttpServletResponse httpResp;
+
+ private SpecificCommunicationService springManagedSpecificConnectorCommunicationService;
+
+ /**
+ * jUnit test set-up.
+ */
+ @Before
+ public void setUp() throws EaafStorageException, URISyntaxException {
+ httpReq = new MockHttpServletRequest("POST", "http://localhost/ms_connector/eidas/light/idp/redirect");
+ httpResp = new MockHttpServletResponse();
+ RequestContextHolder.resetRequestAttributes();
+ RequestContextHolder.setRequestAttributes(new ServletRequestAttributes(httpReq, httpResp));
+
+ proxyService.setiLightRequest(null);
+ proxyService.setError(null);
+
+ config.putConfigValue("eidas.ms.auth.eIDAS.node_v2.proxy.forward.endpoint",
+ "http://eidas.proxy/endpoint");
+
+ springManagedSpecificConnectorCommunicationService =
+ (SpecificCommunicationService) context.getBean(
+ SpecificCommunicationDefinitionBeanNames.SPECIFIC_PROXYSERVICE_COMMUNICATION_SERVICE
+ .toString());
+
+ }
+
+ @Test
+ public void generateErrorResponseWrongPendingReq() throws Throwable {
+ Assert.assertFalse("wrong statusCode", controller.generateErrorMessage(
+ new EaafException("1000"),
+ httpReq, httpResp, null));
+
+ }
+
+ @Test
+ public void generateErrorResponse() throws Throwable {
+ ProxyServicePendingRequest pendingReq = new ProxyServicePendingRequest();
+ pendingReq.initialize(httpReq, config);
+
+ LightRequest.Builder eidasRequestBuilder = LightRequest.builder()
+ .id(UUID.randomUUID().toString())
+ .issuer(RandomStringUtils.randomAlphabetic(10))
+ .citizenCountryCode(RandomStringUtils.randomAlphabetic(2).toUpperCase())
+ .levelOfAssurance(EaafConstants.EIDAS_LOA_HIGH)
+ .spCountryCode(RandomStringUtils.randomAlphabetic(2).toUpperCase())
+ .spType("public")
+ .requesterId(RandomStringUtils.randomAlphanumeric(10))
+ .providerName(RandomStringUtils.randomAlphanumeric(10));
+ pendingReq.setEidasRequest(eidasRequestBuilder.build());
+
+
+ // execute test
+ Assert.assertTrue("wrong statusCode", controller.generateErrorMessage(
+ new EaafException("1000"),
+ httpReq, httpResp,
+ pendingReq));
+
+ // validate state
+ assertNotNull("not redirct Header", httpResp.getHeader("Location"));
+ assertTrue("wrong redirect URL", httpResp.getHeader("Location").startsWith("http://eidas.proxy/endpoint?token="));
+ String token = httpResp.getHeader("Location").substring("http://eidas.proxy/endpoint?token=".length());
+
+ ILightResponse resp = springManagedSpecificConnectorCommunicationService.getAndRemoveResponse(URLDecoder.decode(token, "UTF-8"),
+ ImmutableSortedSet.copyOf(attrRegistry.getCoreAttributeRegistry().getAttributes()));
+
+ assertNotNull("responseId", resp.getId());
+ assertEquals("inResponseTo", pendingReq.getEidasRequest().getId(), resp.getInResponseToId());
+ assertEquals("relayState", pendingReq.getEidasRequest().getRelayState(), resp.getRelayState());
+
+ assertNotNull("subjectNameId", resp.getSubject());
+ assertEquals("subjectNameIdFormat", NameIDType.TRANSIENT, resp.getSubjectNameIdFormat());
+ assertTrue("not attributes", resp.getAttributes().isEmpty());
+
+ assertEquals("StatusCode", StatusCode.RESPONDER, resp.getStatus().getStatusCode());
+ //assertEquals("SubStatusCode", "", resp.getStatus().getSubStatusCode());
+ //assertEquals("StatusMsg", "", resp.getStatus().getStatusMessage());
+
+ }
+
+ @Test
+ public void missingEidasToken() {
+ EidasProxyServiceException exception = assertThrows(EidasProxyServiceException.class,
+ () -> controller.receiveEidasAuthnRequest(httpReq, httpResp));
+ Assert.assertEquals("wrong errorCode", "eidas.proxyservice.02", exception.getErrorId());
+
+ }
+
+ @Test
+ public void wrongEidasTokenWithNullpointerException() {
+ //initialize state
+ httpReq.addParameter(EidasParameterKeys.TOKEN.toString(), RandomStringUtils.randomAlphanumeric(10));
+
+ //validate state
+ EidasProxyServiceException exception = assertThrows(EidasProxyServiceException.class,
+ () -> controller.receiveEidasAuthnRequest(httpReq, httpResp));
+ Assert.assertEquals("wrong errorCode", "eidas.proxyservice.11", exception.getErrorId());
+
+ }
+
+ @Test
+ public void wrongEidasTokenCacheCommunicationError() {
+ //initialize state
+ httpReq.addParameter(EidasParameterKeys.TOKEN.toString(), RandomStringUtils.randomAlphanumeric(10));
+ proxyService.setError(new SpecificCommunicationException(RandomStringUtils.randomAlphanumeric(10)));
+
+ //validate state
+ EidasProxyServiceException exception = assertThrows(EidasProxyServiceException.class,
+ () -> controller.receiveEidasAuthnRequest(httpReq, httpResp));
+ Assert.assertEquals("wrong errorCode", "eidas.proxyservice.03", exception.getErrorId());
+ Assert.assertTrue("Wrong exception", (exception.getCause() instanceof SpecificCommunicationException));
+
+ }
+
+ @Test
+ public void missingServiceProviderCountry() {
+ //initialize state
+ httpReq.addParameter(EidasParameterKeys.TOKEN.toString(), RandomStringUtils.randomAlphanumeric(10));
+ LightRequest.Builder authnReqBuilder = LightRequest.builder()
+ .id(UUID.randomUUID().toString())
+ .issuer(RandomStringUtils.randomAlphabetic(10))
+ .citizenCountryCode(RandomStringUtils.randomAlphabetic(2).toUpperCase())
+ .levelOfAssurance(EaafConstants.EIDAS_LOA_HIGH);
+
+ proxyService.setiLightRequest(authnReqBuilder.build());
+
+ //validate state
+ EidasProxyServiceException exception = assertThrows(EidasProxyServiceException.class,
+ () -> controller.receiveEidasAuthnRequest(httpReq, httpResp));
+ Assert.assertEquals("wrong errorCode", "eidas.proxyservice.07", exception.getErrorId());
+
+ }
+
+ @Test
+ public void requestingLegalAndNaturalPerson() {
+ //initialize state
+ httpReq.addParameter(EidasParameterKeys.TOKEN.toString(), RandomStringUtils.randomAlphanumeric(10));
+ LightRequest.Builder authnReqBuilder = LightRequest.builder()
+ .id(UUID.randomUUID().toString())
+ .issuer(RandomStringUtils.randomAlphabetic(10))
+ .citizenCountryCode(RandomStringUtils.randomAlphabetic(2).toUpperCase())
+ .spCountryCode(RandomStringUtils.randomAlphabetic(2).toUpperCase())
+ .levelOfAssurance(EaafConstants.EIDAS_LOA_HIGH)
+ .requestedAttributes(ImmutableAttributeMap.builder()
+ .put(attrRegistry.getCoreAttributeRegistry().getByFriendlyName(
+ EidasConstants.eIDAS_ATTR_PERSONALIDENTIFIER).first())
+ .put(attrRegistry.getCoreAttributeRegistry().getByFriendlyName(
+ EidasConstants.eIDAS_ATTR_LEGALPERSONIDENTIFIER).first())
+ .build());
+
+ proxyService.setiLightRequest(authnReqBuilder.build());
+
+ //validate state
+ EidasProxyServiceException exception = assertThrows(EidasProxyServiceException.class,
+ () -> controller.receiveEidasAuthnRequest(httpReq, httpResp));
+ Assert.assertEquals("wrong errorCode", "eidas.proxyservice.08", exception.getErrorId());
+
+ }
+
+ @Test
+ public void requestLegalPersonButNoMandates() throws IOException, EaafException {
+ //initialize state
+ httpReq.addParameter(EidasParameterKeys.TOKEN.toString(), RandomStringUtils.randomAlphanumeric(10));
+ String spCountryCode = RandomStringUtils.randomAlphabetic(2).toUpperCase();
+ LightRequest.Builder authnReqBuilder = LightRequest.builder()
+ .id(UUID.randomUUID().toString())
+ .issuer(RandomStringUtils.randomAlphabetic(10))
+ .citizenCountryCode(RandomStringUtils.randomAlphabetic(2).toUpperCase())
+ .levelOfAssurance(EaafConstants.EIDAS_LOA_HIGH)
+ .spCountryCode(spCountryCode)
+ .spType("public")
+ .requestedAttributes(ImmutableAttributeMap.builder()
+ .put(attrRegistry.getCoreAttributeRegistry().getByFriendlyName(
+ EidasConstants.eIDAS_ATTR_LEGALPERSONIDENTIFIER).first()).build());
+
+ proxyService.setiLightRequest(authnReqBuilder.build());
+
+ config.putConfigValue(MsProxyServiceConstants.CONIG_PROPS_EIDAS_PROXY_MANDATES_ENABLED, "false");
+ config.putConfigValue(MsProxyServiceConstants.CONIG_PROPS_EIDAS_PROXY_MANDATES_PROFILE_DEFAULT_NATURAL,
+ StringUtils.join(Arrays.asList(
+ RandomStringUtils.randomAlphabetic(5), RandomStringUtils.randomAlphabetic(5)), ","));
+
+ //validate state
+ EidasProxyServiceException exception = assertThrows(EidasProxyServiceException.class,
+ () -> controller.receiveEidasAuthnRequest(httpReq, httpResp));
+ Assert.assertEquals("wrong errorCode", "eidas.proxyservice.09", exception.getErrorId());
+
+ }
+
+ @Test
+ public void validAuthnRequest() throws IOException, EaafException {
+ //initialize state
+ httpReq.addParameter(EidasParameterKeys.TOKEN.toString(), RandomStringUtils.randomAlphanumeric(10));
+ String spCountryCode = RandomStringUtils.randomAlphabetic(2).toUpperCase();
+ LightRequest.Builder authnReqBuilder = LightRequest.builder()
+ .id(UUID.randomUUID().toString())
+ .issuer(RandomStringUtils.randomAlphabetic(10))
+ .citizenCountryCode(RandomStringUtils.randomAlphabetic(2).toUpperCase())
+ .levelOfAssurance(EaafConstants.EIDAS_LOA_HIGH)
+ .spCountryCode(spCountryCode)
+ .spType("public")
+ .requestedAttributes(ImmutableAttributeMap.builder()
+ .put(attrRegistry.getCoreAttributeRegistry().getByFriendlyName(
+ EidasConstants.eIDAS_ATTR_PERSONALIDENTIFIER).first())
+ .put(attrRegistry.getCoreAttributeRegistry().getByFriendlyName(
+ EidasConstants.eIDAS_ATTR_BIRTHNAME).first())
+ .build());
+
+ proxyService.setiLightRequest(authnReqBuilder.build());
+
+
+ config.putConfigValue(MsProxyServiceConstants.CONIG_PROPS_EIDAS_PROXY_MANDATES_ENABLED, "false");
+ config.putConfigValue(MsProxyServiceConstants.CONIG_PROPS_EIDAS_PROXY_MANDATES_PROFILE_DEFAULT_NATURAL,
+ StringUtils.join(Arrays.asList(
+ RandomStringUtils.randomAlphabetic(5), RandomStringUtils.randomAlphabetic(5)), ","));
+
+
+ //execute
+ controller.receiveEidasAuthnRequest(httpReq, httpResp);
+
+ //validate state
+ Assert.assertNotNull("pendingRequest", authService.getPendingReq());
+ Assert.assertTrue("wrong pendingRequest", authService.getPendingReq() instanceof ProxyServicePendingRequest);
+ ProxyServicePendingRequest pendingReq = (ProxyServicePendingRequest) authService.getPendingReq();
+ Assert.assertNotNull("missing uniqueSpId", pendingReq.getSpEntityId());
+ Assert.assertNotNull("missing eidasReq", pendingReq.getEidasRequest());
+
+ Assert.assertFalse("isPassive", pendingReq.isPassiv());
+ Assert.assertTrue("isPassive", pendingReq.forceAuth());
+ Assert.assertFalse("isPassive", pendingReq.isAuthenticated());
+ Assert.assertFalse("isPassive", pendingReq.isAbortedByUser());
+ Assert.assertTrue("isPassive", pendingReq.isNeedAuthentication());
+
+ Assert.assertNotNull("missing spConfig", pendingReq.getServiceProviderConfiguration());
+ ServiceProviderConfiguration spConfig =
+ pendingReq.getServiceProviderConfiguration(ServiceProviderConfiguration.class);
+ Assert.assertNotNull("uniqueId", spConfig.getUniqueIdentifier());
+ Assert.assertEquals("uniqueId wrong pattern",
+ authnReqBuilder.build().getIssuer(),
+ spConfig.getUniqueIdentifier());
+ Assert.assertEquals("friendlyName wrong pattern",
+ MessageFormat.format(MsProxyServiceConstants.TEMPLATE_SP_UNIQUE_ID, spCountryCode, "public"),
+ spConfig.getFriendlyName());
+
+ Assert.assertEquals("uniqueId not match to pendingReq",
+ pendingReq.getSpEntityId(), spConfig.getUniqueIdentifier());
+ Assert.assertNotNull("bpkTarget", spConfig.getAreaSpecificTargetIdentifier());
+ Assert.assertEquals("wrong bPK Target",
+ EaafConstants.URN_PREFIX_EIDAS + "AT+" + spCountryCode,
+ spConfig.getAreaSpecificTargetIdentifier());
+
+ assertNotNull("mandateprofiles", spConfig.getMandateProfiles());
+ assertTrue("mandateprofiles not empty", spConfig.getMandateProfiles().isEmpty());
+ assertEquals("MandateMode", SpMandateModes.NONE, spConfig.getMandateMode());
+
+ assertEquals("requested IDA attributes", 4, spConfig.getRequestedAttributes().size());
+
+
+ }
+
+ @Test
+ public void validAuthnRequestWithMandatesDefaultProfilesNat() throws IOException, EaafException {
+ //initialize state
+ httpReq.addParameter(EidasParameterKeys.TOKEN.toString(), RandomStringUtils.randomAlphanumeric(10));
+ String spCountryCode = RandomStringUtils.randomAlphabetic(2).toUpperCase();
+ LightRequest.Builder authnReqBuilder = LightRequest.builder()
+ .id(UUID.randomUUID().toString())
+ .issuer(RandomStringUtils.randomAlphabetic(10))
+ .citizenCountryCode(RandomStringUtils.randomAlphabetic(2).toUpperCase())
+ .levelOfAssurance(EaafConstants.EIDAS_LOA_HIGH)
+ .spCountryCode(spCountryCode)
+ .spType("public")
+ .requestedAttributes(ImmutableAttributeMap.builder()
+ .put(attrRegistry.getCoreAttributeRegistry().getByFriendlyName(
+ EidasConstants.eIDAS_ATTR_PERSONALIDENTIFIER).first()).build());
+
+
+ proxyService.setiLightRequest(authnReqBuilder.build());
+
+ List<String> mandateProfilesNat =
+ Arrays.asList(RandomStringUtils.randomAlphabetic(5), RandomStringUtils.randomAlphabetic(5));
+ List<String> mandateProfilesJur =
+ Arrays.asList(RandomStringUtils.randomAlphabetic(5), RandomStringUtils.randomAlphabetic(5));
+ config.putConfigValue(MsProxyServiceConstants.CONIG_PROPS_EIDAS_PROXY_MANDATES_ENABLED, "true");
+ config.putConfigValue(MsProxyServiceConstants.CONIG_PROPS_EIDAS_PROXY_MANDATES_PROFILE_DEFAULT_NATURAL,
+ StringUtils.join(mandateProfilesNat, ","));
+ config.putConfigValue(MsProxyServiceConstants.CONIG_PROPS_EIDAS_PROXY_MANDATES_PROFILE_DEFAULT_LEGAL,
+ StringUtils.join(mandateProfilesJur, ","));
+
+ //execute
+ controller.receiveEidasAuthnRequest(httpReq, httpResp);
+
+ //validate state
+ ServiceProviderConfiguration spConfig =
+ authService.getPendingReq().getServiceProviderConfiguration(ServiceProviderConfiguration.class);
+ assertNotNull("mandateprofiles", spConfig.getMandateProfiles());
+ assertFalse("mandateprofiles not empty", spConfig.getMandateProfiles().isEmpty());
+ assertEquals("mandateprofile size", mandateProfilesNat.size(), spConfig.getMandateProfiles().size());
+ spConfig.getMandateProfiles().stream()
+ .forEach(el -> assertTrue("missing mandateProfile: " + el, mandateProfilesNat.contains(el)));
+ assertEquals("MandateMode", SpMandateModes.NATURAL, spConfig.getMandateMode());
+
+ assertEquals("requested IDA attributes", 6, spConfig.getRequestedAttributes().size());
+
+ }
+
+ @Test
+ public void validAuthnRequestWithMandatesDefaultProfilesJur() throws IOException, EaafException {
+ //initialize state
+ httpReq.addParameter(EidasParameterKeys.TOKEN.toString(), RandomStringUtils.randomAlphanumeric(10));
+ String spCountryCode = RandomStringUtils.randomAlphabetic(2).toUpperCase();
+ LightRequest.Builder authnReqBuilder = LightRequest.builder()
+ .id(UUID.randomUUID().toString())
+ .issuer(RandomStringUtils.randomAlphabetic(10))
+ .citizenCountryCode(RandomStringUtils.randomAlphabetic(2).toUpperCase())
+ .levelOfAssurance(EaafConstants.EIDAS_LOA_HIGH)
+ .spCountryCode(spCountryCode)
+ .spType("public")
+ .requestedAttributes(ImmutableAttributeMap.builder()
+ .put(attrRegistry.getCoreAttributeRegistry().getByFriendlyName(
+ EidasConstants.eIDAS_ATTR_LEGALPERSONIDENTIFIER).first()).build());
+
+
+ proxyService.setiLightRequest(authnReqBuilder.build());
+
+ List<String> mandateProfilesNat =
+ Arrays.asList(RandomStringUtils.randomAlphabetic(5), RandomStringUtils.randomAlphabetic(5));
+ List<String> mandateProfilesJur =
+ Arrays.asList(RandomStringUtils.randomAlphabetic(5), RandomStringUtils.randomAlphabetic(5));
+ config.putConfigValue(MsProxyServiceConstants.CONIG_PROPS_EIDAS_PROXY_MANDATES_ENABLED, "true");
+ config.putConfigValue(MsProxyServiceConstants.CONIG_PROPS_EIDAS_PROXY_MANDATES_PROFILE_DEFAULT_NATURAL,
+ StringUtils.join(mandateProfilesNat, ","));
+ config.putConfigValue(MsProxyServiceConstants.CONIG_PROPS_EIDAS_PROXY_MANDATES_PROFILE_DEFAULT_LEGAL,
+ StringUtils.join(mandateProfilesJur, ","));
+
+ //execute
+ controller.receiveEidasAuthnRequest(httpReq, httpResp);
+
+ //validate state
+ ServiceProviderConfiguration spConfig =
+ authService.getPendingReq().getServiceProviderConfiguration(ServiceProviderConfiguration.class);
+ assertNotNull("mandateprofiles", spConfig.getMandateProfiles());
+ assertFalse("mandateprofiles not empty", spConfig.getMandateProfiles().isEmpty());
+ assertEquals("mandateprofile size", mandateProfilesJur.size(), spConfig.getMandateProfiles().size());
+ spConfig.getMandateProfiles().stream()
+ .forEach(el -> assertTrue("missing mandateProfile: " + el, mandateProfilesJur.contains(el)));
+ assertEquals("MandateMode", SpMandateModes.LEGAL_FORCE, spConfig.getMandateMode());
+
+ assertEquals("requested IDA attributes", 9, spConfig.getRequestedAttributes().size());
+
+ }
+
+ @Test
+ public void validAuthnRequestWithMandatesDefaultNoJurProfiles() throws IOException, EaafException {
+ //initialize state
+ httpReq.addParameter(EidasParameterKeys.TOKEN.toString(), RandomStringUtils.randomAlphanumeric(10));
+ String spCountryCode = RandomStringUtils.randomAlphabetic(2).toUpperCase();
+ LightRequest.Builder authnReqBuilder = LightRequest.builder()
+ .id(UUID.randomUUID().toString())
+ .issuer(RandomStringUtils.randomAlphabetic(10))
+ .citizenCountryCode(RandomStringUtils.randomAlphabetic(2).toUpperCase())
+ .levelOfAssurance(EaafConstants.EIDAS_LOA_HIGH)
+ .spCountryCode(spCountryCode)
+ .spType("public")
+ .requestedAttributes(ImmutableAttributeMap.builder()
+ .put(attrRegistry.getCoreAttributeRegistry().getByFriendlyName(
+ EidasConstants.eIDAS_ATTR_LEGALPERSONIDENTIFIER).first()).build());
+
+
+ proxyService.setiLightRequest(authnReqBuilder.build());
+
+ List<String> mandateProfilesNat =
+ Arrays.asList(RandomStringUtils.randomAlphabetic(5), RandomStringUtils.randomAlphabetic(5));
+ config.putConfigValue(MsProxyServiceConstants.CONIG_PROPS_EIDAS_PROXY_MANDATES_ENABLED, "true");
+ config.putConfigValue(MsProxyServiceConstants.CONIG_PROPS_EIDAS_PROXY_MANDATES_PROFILE_DEFAULT_NATURAL,
+ StringUtils.join(mandateProfilesNat, ","));
+ config.putConfigValue(MsProxyServiceConstants.CONIG_PROPS_EIDAS_PROXY_MANDATES_PROFILE_DEFAULT_LEGAL, "");
+
+ //validate state
+ EidasProxyServiceException exception = assertThrows(EidasProxyServiceException.class,
+ () -> controller.receiveEidasAuthnRequest(httpReq, httpResp));
+ Assert.assertEquals("wrong errorCode", "eidas.proxyservice.10", exception.getErrorId());
+
+ }
+
+ @Test
+ public void validAuthnRequestWithMandatesDefaultNoNatProfiles() throws IOException, EaafException {
+ //initialize state
+ httpReq.addParameter(EidasParameterKeys.TOKEN.toString(), RandomStringUtils.randomAlphanumeric(10));
+ String spCountryCode = RandomStringUtils.randomAlphabetic(2).toUpperCase();
+ LightRequest.Builder authnReqBuilder = LightRequest.builder()
+ .id(UUID.randomUUID().toString())
+ .issuer(RandomStringUtils.randomAlphabetic(10))
+ .citizenCountryCode(RandomStringUtils.randomAlphabetic(2).toUpperCase())
+ .levelOfAssurance(EaafConstants.EIDAS_LOA_HIGH)
+ .spCountryCode(spCountryCode)
+ .spType("public")
+ .requestedAttributes(ImmutableAttributeMap.builder()
+ .put(attrRegistry.getCoreAttributeRegistry().getByFriendlyName(
+ EidasConstants.eIDAS_ATTR_PERSONALIDENTIFIER).first()).build());
+
+
+ proxyService.setiLightRequest(authnReqBuilder.build());
+
+ config.putConfigValue(MsProxyServiceConstants.CONIG_PROPS_EIDAS_PROXY_MANDATES_ENABLED, "true");
+ config.putConfigValue(MsProxyServiceConstants.CONIG_PROPS_EIDAS_PROXY_MANDATES_PROFILE_DEFAULT_NATURAL, "");
+ config.putConfigValue(MsProxyServiceConstants.CONIG_PROPS_EIDAS_PROXY_MANDATES_PROFILE_DEFAULT_LEGAL, "");
+
+ //execute
+ controller.receiveEidasAuthnRequest(httpReq, httpResp);
+
+ //validate state
+ ServiceProviderConfiguration spConfig =
+ authService.getPendingReq().getServiceProviderConfiguration(ServiceProviderConfiguration.class);
+ assertNotNull("mandateprofiles", spConfig.getMandateProfiles());
+ assertTrue("mandateprofiles not empty", spConfig.getMandateProfiles().isEmpty());
+ assertEquals("MandateMode", SpMandateModes.NONE, spConfig.getMandateMode());
+
+ assertEquals("requested IDA attributes", 3, spConfig.getRequestedAttributes().size());
+
+ }
+
+ @Test
+ public void validAuthnRequestIssueSpecificNoMandates() throws IOException, EaafException {
+ //initialize state
+ httpReq.addParameter(EidasParameterKeys.TOKEN.toString(), RandomStringUtils.randomAlphanumeric(10));
+
+ String issuer = RandomStringUtils.randomAlphabetic(10);
+ LightRequest.Builder authnReqBuilder = LightRequest.builder()
+ .id(UUID.randomUUID().toString())
+ .issuer(issuer)
+ .citizenCountryCode(RandomStringUtils.randomAlphabetic(2).toUpperCase())
+ .levelOfAssurance(EaafConstants.EIDAS_LOA_HIGH)
+ .spCountryCode(RandomStringUtils.randomAlphabetic(2).toUpperCase())
+ .spType("public")
+ .requestedAttributes(ImmutableAttributeMap.builder()
+ .put(attrRegistry.getCoreAttributeRegistry().getByFriendlyName(
+ EidasConstants.eIDAS_ATTR_PERSONALIDENTIFIER).first()).build());
+
+ proxyService.setiLightRequest(authnReqBuilder.build());
+
+
+ // set default mandate configuration
+ config.putConfigValue(MsProxyServiceConstants.CONIG_PROPS_EIDAS_PROXY_MANDATES_ENABLED, "true");
+ config.putConfigValue(MsProxyServiceConstants.CONIG_PROPS_EIDAS_PROXY_MANDATES_PROFILE_DEFAULT_NATURAL,
+ StringUtils.join(Arrays.asList(
+ RandomStringUtils.randomAlphabetic(5), RandomStringUtils.randomAlphabetic(5)), ","));
+ config.putConfigValue(MsProxyServiceConstants.CONIG_PROPS_EIDAS_PROXY_MANDATES_PROFILE_DEFAULT_LEGAL,
+ StringUtils.join(Arrays.asList(
+ RandomStringUtils.randomAlphabetic(5), RandomStringUtils.randomAlphabetic(5)), ","));
+
+ // set specific mandate configuration
+ String spCountryCode = RandomStringUtils.randomAlphabetic(2).toUpperCase();
+ addConnectorConfig(0, MsProxyServiceConstants.CONIG_PROPS_CONNECTOR_UNIQUEID, issuer);
+ addConnectorConfig(0, MsProxyServiceConstants.CONIG_PROPS_CONNECTOR_COUNTRYCODE, spCountryCode);
+ addConnectorConfig(0, MsProxyServiceConstants.CONIG_PROPS_CONNECTOR_MANDATES_ENABLED, "false");
+
+ List<String> mandateProfiles =
+ Arrays.asList(RandomStringUtils.randomAlphabetic(5), RandomStringUtils.randomAlphabetic(5));
+ addConnectorConfig(0, MsProxyServiceConstants.CONIG_PROPS_CONNECTOR_MANDATES_PROFILE_NATURAL,
+ StringUtils.join(mandateProfiles, ","));
+ addConnectorConfig(0, MsProxyServiceConstants.CONIG_PROPS_CONNECTOR_MANDATES_PROFILE_LEGAL,
+ StringUtils.join(Arrays.asList(RandomStringUtils.randomAlphabetic(5), RandomStringUtils.randomAlphabetic(5)), ","));
+
+ //execute
+ controller.receiveEidasAuthnRequest(httpReq, httpResp);
+
+ //validate state
+ ServiceProviderConfiguration spConfig =
+ authService.getPendingReq().getServiceProviderConfiguration(ServiceProviderConfiguration.class);
+ assertNotNull("mandateprofiles", spConfig.getMandateProfiles());
+ assertTrue("mandateprofiles not empty", spConfig.getMandateProfiles().isEmpty());
+ assertEquals("MandateMode", SpMandateModes.NONE, spConfig.getMandateMode());
+
+ }
+
+ @Test
+ public void validAuthnRequestIssueSpecificMandatesNat() throws IOException, EaafException {
+ //initialize state
+ httpReq.addParameter(EidasParameterKeys.TOKEN.toString(), RandomStringUtils.randomAlphanumeric(10));
+
+ String issuer = "https://apps.egiz.gv.at/EidasNode//ConnectorMetadata";
+ LightRequest.Builder authnReqBuilder = LightRequest.builder()
+ .id(UUID.randomUUID().toString())
+ .issuer(issuer)
+ .citizenCountryCode(RandomStringUtils.randomAlphabetic(2).toUpperCase())
+ .levelOfAssurance(EaafConstants.EIDAS_LOA_HIGH)
+ .spCountryCode(RandomStringUtils.randomAlphabetic(2).toUpperCase())
+ .spType("public")
+ .requestedAttributes(ImmutableAttributeMap.builder()
+ .put(attrRegistry.getCoreAttributeRegistry().getByFriendlyName(
+ EidasConstants.eIDAS_ATTR_PERSONALIDENTIFIER).first()).build());
+
+ proxyService.setiLightRequest(authnReqBuilder.build());
+
+
+ // set default mandate configuration
+ config.putConfigValue(MsProxyServiceConstants.CONIG_PROPS_EIDAS_PROXY_MANDATES_ENABLED, "false");
+ config.putConfigValue(MsProxyServiceConstants.CONIG_PROPS_EIDAS_PROXY_MANDATES_PROFILE_DEFAULT_NATURAL,
+ StringUtils.join(Arrays.asList(
+ RandomStringUtils.randomAlphabetic(5), RandomStringUtils.randomAlphabetic(5)), ","));
+ config.putConfigValue(MsProxyServiceConstants.CONIG_PROPS_EIDAS_PROXY_MANDATES_PROFILE_DEFAULT_LEGAL,
+ StringUtils.join(Arrays.asList(
+ RandomStringUtils.randomAlphabetic(5), RandomStringUtils.randomAlphabetic(5)), ","));
+
+ // set specific mandate configuration
+ String spCountryCode = RandomStringUtils.randomAlphabetic(2).toUpperCase();
+ addConnectorConfig(0, MsProxyServiceConstants.CONIG_PROPS_CONNECTOR_UNIQUEID, issuer);
+ addConnectorConfig(0, MsProxyServiceConstants.CONIG_PROPS_CONNECTOR_COUNTRYCODE, spCountryCode);
+ addConnectorConfig(0, MsProxyServiceConstants.CONIG_PROPS_CONNECTOR_MANDATES_ENABLED, "true");
+
+ List<String> mandateProfiles =
+ Arrays.asList(RandomStringUtils.randomAlphabetic(5), RandomStringUtils.randomAlphabetic(5));
+ addConnectorConfig(0, MsProxyServiceConstants.CONIG_PROPS_CONNECTOR_MANDATES_PROFILE_NATURAL,
+ StringUtils.join(mandateProfiles, ","));
+ addConnectorConfig(0, MsProxyServiceConstants.CONIG_PROPS_CONNECTOR_MANDATES_PROFILE_LEGAL,
+ StringUtils.join(Arrays.asList(RandomStringUtils.randomAlphabetic(5), RandomStringUtils.randomAlphabetic(5)), ","));
+
+ //execute
+ controller.receiveEidasAuthnRequest(httpReq, httpResp);
+
+ //validate state
+ ServiceProviderConfiguration spConfig =
+ authService.getPendingReq().getServiceProviderConfiguration(ServiceProviderConfiguration.class);
+ assertNotNull("mandateprofiles", spConfig.getMandateProfiles());
+ assertFalse("mandateprofiles not empty", spConfig.getMandateProfiles().isEmpty());
+ assertEquals("mandateprofile size", mandateProfiles.size(), spConfig.getMandateProfiles().size());
+ spConfig.getMandateProfiles().stream()
+ .forEach(el -> assertTrue("missing mandateProfile: " + el, mandateProfiles.contains(el)));
+ assertEquals("MandateMode", SpMandateModes.NATURAL, spConfig.getMandateMode());
+
+ }
+
+ @Test
+ public void validAuthnRequestIssueSpecificMandatesJur() throws IOException, EaafException {
+ //initialize state
+ httpReq.addParameter(EidasParameterKeys.TOKEN.toString(), RandomStringUtils.randomAlphanumeric(10));
+
+ String issuer = RandomStringUtils.randomAlphabetic(10);
+ LightRequest.Builder authnReqBuilder = LightRequest.builder()
+ .id(UUID.randomUUID().toString())
+ .issuer(issuer)
+ .citizenCountryCode(RandomStringUtils.randomAlphabetic(2).toUpperCase())
+ .levelOfAssurance(EaafConstants.EIDAS_LOA_HIGH)
+ .spCountryCode(RandomStringUtils.randomAlphabetic(2).toUpperCase())
+ .spType("public")
+ .requestedAttributes(ImmutableAttributeMap.builder()
+ .put(attrRegistry.getCoreAttributeRegistry().getByFriendlyName(
+ EidasConstants.eIDAS_ATTR_LEGALPERSONIDENTIFIER).first()).build());
+
+ proxyService.setiLightRequest(authnReqBuilder.build());
+
+
+ // set default mandate configuration
+ config.putConfigValue(MsProxyServiceConstants.CONIG_PROPS_EIDAS_PROXY_MANDATES_ENABLED, "true");
+ config.putConfigValue(MsProxyServiceConstants.CONIG_PROPS_EIDAS_PROXY_MANDATES_PROFILE_DEFAULT_NATURAL,
+ StringUtils.join(Arrays.asList(
+ RandomStringUtils.randomAlphabetic(5), RandomStringUtils.randomAlphabetic(5)), ","));
+ config.putConfigValue(MsProxyServiceConstants.CONIG_PROPS_EIDAS_PROXY_MANDATES_PROFILE_DEFAULT_LEGAL,
+ StringUtils.join(Arrays.asList(
+ RandomStringUtils.randomAlphabetic(5), RandomStringUtils.randomAlphabetic(5)), ","));
+
+ // set specific mandate configuration
+ String spCountryCode = RandomStringUtils.randomAlphabetic(2).toUpperCase();
+ addConnectorConfig(0, MsProxyServiceConstants.CONIG_PROPS_CONNECTOR_UNIQUEID, issuer);
+ addConnectorConfig(0, MsProxyServiceConstants.CONIG_PROPS_CONNECTOR_COUNTRYCODE, spCountryCode);
+ addConnectorConfig(0, MsProxyServiceConstants.CONIG_PROPS_CONNECTOR_MANDATES_ENABLED, "true");
+
+ List<String> mandateProfiles =
+ Arrays.asList(RandomStringUtils.randomAlphabetic(5), RandomStringUtils.randomAlphabetic(5));
+ addConnectorConfig(0, MsProxyServiceConstants.CONIG_PROPS_CONNECTOR_MANDATES_PROFILE_LEGAL,
+ StringUtils.join(mandateProfiles, ","));
+ addConnectorConfig(0, MsProxyServiceConstants.CONIG_PROPS_CONNECTOR_MANDATES_PROFILE_NATURAL,
+ StringUtils.join(Arrays.asList(RandomStringUtils.randomAlphabetic(5), RandomStringUtils.randomAlphabetic(5)), ","));
+
+ //execute
+ controller.receiveEidasAuthnRequest(httpReq, httpResp);
+
+ //validate state
+ ServiceProviderConfiguration spConfig =
+ authService.getPendingReq().getServiceProviderConfiguration(ServiceProviderConfiguration.class);
+ assertNotNull("mandateprofiles", spConfig.getMandateProfiles());
+ assertFalse("mandateprofiles not empty", spConfig.getMandateProfiles().isEmpty());
+ assertEquals("mandateprofile size", mandateProfiles.size(), spConfig.getMandateProfiles().size());
+ spConfig.getMandateProfiles().stream()
+ .forEach(el -> assertTrue("missing mandateProfile: " + el, mandateProfiles.contains(el)));
+ assertEquals("MandateMode", SpMandateModes.LEGAL_FORCE, spConfig.getMandateMode());
+
+ }
+
+ private void addConnectorConfig(int i, String key, String value) {
+ config.putConfigValue(MsProxyServiceConstants.CONIG_PROPS_CONNECTOR_PREFIX + String.valueOf(i) + "." + key,
+ value);
+
+ }
+
+}
+
+
diff --git a/modules/eidas_proxy-sevice/src/test/java/at/asitplus/eidas/specific/modules/msproxyservice/test/protocol/ProxyServiceAuthenticationActionTest.java b/modules/eidas_proxy-sevice/src/test/java/at/asitplus/eidas/specific/modules/msproxyservice/test/protocol/ProxyServiceAuthenticationActionTest.java
new file mode 100644
index 00000000..d44ffc2d
--- /dev/null
+++ b/modules/eidas_proxy-sevice/src/test/java/at/asitplus/eidas/specific/modules/msproxyservice/test/protocol/ProxyServiceAuthenticationActionTest.java
@@ -0,0 +1,780 @@
+package at.asitplus.eidas.specific.modules.msproxyservice.test.protocol;
+
+import static at.asitplus.eidas.specific.core.MsEidasNodeConstants.PROP_CONFIG_SP_NEW_EID_MODE;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertThrows;
+import static org.junit.Assert.assertTrue;
+
+import java.net.URISyntaxException;
+import java.net.URLDecoder;
+import java.time.Instant;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.UUID;
+
+import org.apache.commons.lang3.RandomStringUtils;
+import org.joda.time.DateTime;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.opensaml.saml.saml2.core.NameIDType;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.ApplicationContext;
+import org.springframework.mock.web.MockHttpServletRequest;
+import org.springframework.mock.web.MockHttpServletResponse;
+import org.springframework.test.context.ContextConfiguration;
+import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
+import org.springframework.web.context.request.RequestContextHolder;
+import org.springframework.web.context.request.ServletRequestAttributes;
+
+import com.google.common.collect.ImmutableSortedSet;
+
+import at.asitplus.eidas.specific.core.test.config.dummy.MsConnectorDummyConfigMap;
+import at.asitplus.eidas.specific.core.test.config.dummy.MsConnectorDummySpConfiguration;
+import at.asitplus.eidas.specific.modules.core.eidas.EidasConstants;
+import at.asitplus.eidas.specific.modules.core.eidas.service.EidasAttributeRegistry;
+import at.asitplus.eidas.specific.modules.msproxyservice.protocol.ProxyServiceAuthenticationAction;
+import at.asitplus.eidas.specific.modules.msproxyservice.protocol.ProxyServicePendingRequest;
+import at.gv.egiz.eaaf.core.api.data.EaafConfigConstants;
+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.data.PvpAttributeDefinitions.EidIdentityStatusLevelValues;
+import at.gv.egiz.eaaf.core.api.idp.IAuthData;
+import at.gv.egiz.eaaf.core.api.idp.IEidAuthData;
+import at.gv.egiz.eaaf.core.api.idp.auth.data.IIdentityLink;
+import at.gv.egiz.eaaf.core.api.idp.slo.SloInformationInterface;
+import at.gv.egiz.eaaf.core.exceptions.EaafException;
+import at.gv.egiz.eaaf.core.impl.idp.module.test.TestRequestImpl;
+import eu.eidas.auth.commons.attribute.AttributeDefinition;
+import eu.eidas.auth.commons.attribute.ImmutableAttributeMap;
+import eu.eidas.auth.commons.light.ILightResponse;
+import eu.eidas.auth.commons.light.impl.LightRequest;
+import eu.eidas.auth.commons.light.impl.LightRequest.Builder;
+import eu.eidas.specificcommunication.SpecificCommunicationDefinitionBeanNames;
+import eu.eidas.specificcommunication.exception.SpecificCommunicationException;
+import eu.eidas.specificcommunication.protocol.SpecificCommunicationService;
+
+@RunWith(SpringJUnit4ClassRunner.class)
+@ContextConfiguration(locations = {
+ "/spring/SpringTest-context_basic_test.xml",
+ "/spring/SpringTest-context_basic_mapConfig.xml",
+ })
+public class ProxyServiceAuthenticationActionTest {
+
+ @Autowired private MsConnectorDummyConfigMap basicConfig;
+ @Autowired private ProxyServiceAuthenticationAction action;
+ @Autowired private ApplicationContext context;
+ @Autowired EidasAttributeRegistry attrRegistry;
+
+ private MockHttpServletRequest httpReq;
+ private MockHttpServletResponse httpResp;
+ private ProxyServicePendingRequest pendingReq;
+ private MsConnectorDummySpConfiguration oaParam;
+ private SpecificCommunicationService springManagedSpecificConnectorCommunicationService;
+
+
+ /**
+ * jUnit test set-up.
+ * @throws EaafException In case of an error
+ */
+ @Before
+ public void setUp() throws URISyntaxException, EaafException {
+ httpReq = new MockHttpServletRequest("POST", "https://localhost/authhandler");
+ httpResp = new MockHttpServletResponse();
+ RequestContextHolder.resetRequestAttributes();
+ RequestContextHolder.setRequestAttributes(new ServletRequestAttributes(httpReq, httpResp));
+
+ basicConfig.putConfigValue("eidas.ms.auth.eIDAS.node_v2.proxy.forward.endpoint",
+ "http://eidas.proxy/endpoint");
+ basicConfig.putConfigValue("auth.eIDAS.proxy.workaround.mandates.legalperson",
+ "false");
+
+ final Map<String, String> spConfig = new HashMap<>();
+ spConfig.put(EaafConfigConstants.SERVICE_UNIQUEIDENTIFIER, "testSp");
+ spConfig.put("target", "urn:publicid:gv.at:cdid+XX");
+ spConfig.put(PROP_CONFIG_SP_NEW_EID_MODE, "true");
+ oaParam = new MsConnectorDummySpConfiguration(spConfig, basicConfig);
+ oaParam.setLoa(Arrays.asList(EaafConstants.EIDAS_LOA_HIGH));
+
+ pendingReq = new ProxyServicePendingRequest();
+ pendingReq.initialize(httpReq, basicConfig);
+ pendingReq.setOnlineApplicationConfiguration(oaParam);
+
+ LightRequest.Builder eidasRequestBuilder = generateBasicLightRequest();
+ pendingReq.setEidasRequest(eidasRequestBuilder.build());
+
+
+ springManagedSpecificConnectorCommunicationService =
+ (SpecificCommunicationService) context.getBean(
+ SpecificCommunicationDefinitionBeanNames.SPECIFIC_PROXYSERVICE_COMMUNICATION_SERVICE
+ .toString());
+
+ }
+
+ @Test
+ public void wrongPendingRequestType() {
+ IAuthData authData = generateDummyAuthData();
+ TestRequestImpl internalPendingReq = new TestRequestImpl();
+
+ EaafException exception = assertThrows(EaafException.class,
+ () -> action.processRequest(internalPendingReq, httpReq, httpResp, authData));
+ Assert.assertEquals("wrong errorCode", "eidas.proxyservice.99", exception.getErrorId());
+
+ }
+
+ @Test
+ public void missingForwardUrl() {
+ Map<String, Object> attr = new HashMap<>();
+ attr.put(PvpAttributeDefinitions.BPK_NAME,
+ "AT+XX:" + RandomStringUtils.randomAlphanumeric(10));
+ IAuthData authData = generateDummyAuthData(attr , EaafConstants.EIDAS_LOA_HIGH,
+ RandomStringUtils.randomAlphanumeric(10), RandomStringUtils.randomAlphanumeric(10), "1945-04-18", false);
+ basicConfig.removeConfigValue("eidas.ms.auth.eIDAS.node_v2.proxy.forward.endpoint");
+
+ EaafException exception = assertThrows(EaafException.class,
+ () -> action.processRequest(pendingReq, httpReq, httpResp, authData));
+ Assert.assertEquals("wrong errorCode", "config.08", exception.getErrorId());
+
+ }
+
+ @Test
+ public void responseWithoutMandate() throws EaafException, SpecificCommunicationException {
+ Map<String, Object> attr = new HashMap<>();
+ attr.put(PvpAttributeDefinitions.BPK_NAME, RandomStringUtils.randomAlphanumeric(10));
+ IAuthData authData = generateDummyAuthData(attr , EaafConstants.EIDAS_LOA_HIGH,
+ RandomStringUtils.randomAlphanumeric(10), RandomStringUtils.randomAlphanumeric(10), "1945-04-18", false);
+
+ //perform test
+ SloInformationInterface result = action.processRequest(pendingReq, httpReq, httpResp, authData);
+
+ //validate state
+ Assert.assertNotNull("Result should be not null", result);
+
+ ImmutableAttributeMap respAttr = validateBasicEidasResponse(authData);
+ assertEquals("wrong attr. size", 4, respAttr.size());
+ checkAttrValue(respAttr, EidasConstants.eIDAS_ATTR_PERSONALIDENTIFIER,
+ (String) attr.get(PvpAttributeDefinitions.BPK_NAME));
+ checkAttrValue(respAttr, EidasConstants.eIDAS_ATTR_CURRENTFAMILYNAME, authData.getFamilyName());
+ checkAttrValue(respAttr, EidasConstants.eIDAS_ATTR_CURRENTGIVENNAME, authData.getGivenName());
+ checkAttrValue(respAttr, EidasConstants.eIDAS_ATTR_DATEOFBIRTH,
+ authData.getDateOfBirth());
+
+ }
+
+ @Test
+ public void responseWithoutMandateAndOptionalAttributesExist() throws EaafException, SpecificCommunicationException {
+ LightRequest.Builder eidasRequestBuilder = generateBasicLightRequest();
+ eidasRequestBuilder.requestedAttributes(ImmutableAttributeMap.builder()
+ .put(attrRegistry.getCoreAttributeRegistry().getByFriendlyName(EidasConstants.eIDAS_ATTR_PERSONALIDENTIFIER).first())
+ .put(attrRegistry.getCoreAttributeRegistry().getByFriendlyName(EidasConstants.eIDAS_ATTR_CURRENTGIVENNAME).first())
+ .put(attrRegistry.getCoreAttributeRegistry().getByFriendlyName(EidasConstants.eIDAS_ATTR_CURRENTFAMILYNAME).first())
+ .put(attrRegistry.getCoreAttributeRegistry().getByFriendlyName(EidasConstants.eIDAS_ATTR_DATEOFBIRTH).first())
+ .put(attrRegistry.getCoreAttributeRegistry().getByName("http://eidas.europa.eu/attributes/naturalperson/BirthName"))
+ .build());
+ pendingReq.setEidasRequest(eidasRequestBuilder.build());
+
+
+ Map<String, Object> attr = new HashMap<>();
+ attr.put(PvpAttributeDefinitions.BPK_NAME,
+ "AT+XX:" + RandomStringUtils.randomAlphanumeric(10));
+ attr.put("ida_birthname", RandomStringUtils.randomAlphanumeric(10));
+
+ IAuthData authData = generateDummyAuthData(attr , EaafConstants.EIDAS_LOA_HIGH,
+ RandomStringUtils.randomAlphanumeric(10), RandomStringUtils.randomAlphanumeric(10), "1945-04-18", false);
+
+ //perform test
+ SloInformationInterface result = action.processRequest(pendingReq, httpReq, httpResp, authData);
+
+ //validate state
+ Assert.assertNotNull("Result should be not null", result);
+
+ ImmutableAttributeMap respAttr = validateBasicEidasResponse(authData);
+ assertEquals("wrong attr. size", 5, respAttr.size());
+ checkAttrValue(respAttr, EidasConstants.eIDAS_ATTR_PERSONALIDENTIFIER,
+ (String) attr.get(PvpAttributeDefinitions.BPK_NAME));
+ checkAttrValue(respAttr, EidasConstants.eIDAS_ATTR_CURRENTFAMILYNAME, authData.getFamilyName());
+ checkAttrValue(respAttr, EidasConstants.eIDAS_ATTR_CURRENTGIVENNAME, authData.getGivenName());
+ checkAttrValue(respAttr, EidasConstants.eIDAS_ATTR_DATEOFBIRTH,
+ authData.getDateOfBirth());
+ checkAttrValue(respAttr, EidasConstants.eIDAS_ATTR_BIRTHNAME,
+ (String) attr.get("ida_birthname"));
+
+ }
+
+ @Test
+ public void responseWithoutMandateAndOptionalAttributesNotExist() throws EaafException, SpecificCommunicationException {
+ LightRequest.Builder eidasRequestBuilder = generateBasicLightRequest();
+ eidasRequestBuilder.requestedAttributes(ImmutableAttributeMap.builder()
+ .put(attrRegistry.getCoreAttributeRegistry().getByFriendlyName(EidasConstants.eIDAS_ATTR_PERSONALIDENTIFIER).first())
+ .put(attrRegistry.getCoreAttributeRegistry().getByFriendlyName(EidasConstants.eIDAS_ATTR_CURRENTGIVENNAME).first())
+ .put(attrRegistry.getCoreAttributeRegistry().getByFriendlyName(EidasConstants.eIDAS_ATTR_CURRENTFAMILYNAME).first())
+ .put(attrRegistry.getCoreAttributeRegistry().getByFriendlyName(EidasConstants.eIDAS_ATTR_DATEOFBIRTH).first())
+ .put(attrRegistry.getCoreAttributeRegistry().getByName("http://eidas.europa.eu/attributes/naturalperson/BirthName"))
+ .build());
+ pendingReq.setEidasRequest(eidasRequestBuilder.build());
+
+
+ Map<String, Object> attr = new HashMap<>();
+ attr.put(PvpAttributeDefinitions.BPK_NAME,
+ "AT+XX:" + RandomStringUtils.randomAlphanumeric(10));
+
+ IAuthData authData = generateDummyAuthData(attr , EaafConstants.EIDAS_LOA_HIGH,
+ RandomStringUtils.randomAlphanumeric(10), RandomStringUtils.randomAlphanumeric(10), "1945-04-18", false);
+
+ //perform test
+ SloInformationInterface result = action.processRequest(pendingReq, httpReq, httpResp, authData);
+
+ //validate state
+ Assert.assertNotNull("Result should be not null", result);
+
+ ImmutableAttributeMap respAttr = validateBasicEidasResponse(authData);
+ assertEquals("wrong attr. size", 4, respAttr.size());
+ checkAttrValue(respAttr, EidasConstants.eIDAS_ATTR_PERSONALIDENTIFIER,
+ (String) attr.get(PvpAttributeDefinitions.BPK_NAME));
+ checkAttrValue(respAttr, EidasConstants.eIDAS_ATTR_CURRENTFAMILYNAME, authData.getFamilyName());
+ checkAttrValue(respAttr, EidasConstants.eIDAS_ATTR_CURRENTGIVENNAME, authData.getGivenName());
+ checkAttrValue(respAttr, EidasConstants.eIDAS_ATTR_DATEOFBIRTH,
+ authData.getDateOfBirth());
+
+ }
+
+
+ @Test
+ public void responseWithNatMandate() throws EaafException, SpecificCommunicationException {
+ Map<String, Object> attr = new HashMap<>();
+ attr.put(PvpAttributeDefinitions.BPK_NAME,
+ "AT+XX:" + RandomStringUtils.randomAlphanumeric(10));
+ attr.put(PvpAttributeDefinitions.MANDATE_NAT_PER_BPK_NAME,
+ RandomStringUtils.randomAlphabetic(10));
+ attr.put(PvpAttributeDefinitions.MANDATE_NAT_PER_GIVEN_NAME_NAME,
+ RandomStringUtils.randomAlphabetic(10));
+ attr.put(PvpAttributeDefinitions.MANDATE_NAT_PER_FAMILY_NAME_NAME,
+ RandomStringUtils.randomAlphabetic(10));
+ attr.put(PvpAttributeDefinitions.MANDATE_NAT_PER_BIRTHDATE_NAME,
+ "1985-11-15");
+
+
+ IAuthData authData = generateDummyAuthData(attr , EaafConstants.EIDAS_LOA_HIGH,
+ RandomStringUtils.randomAlphanumeric(10), RandomStringUtils.randomAlphanumeric(10), "1945-04-18", true);
+
+ //perform test
+ SloInformationInterface result = action.processRequest(pendingReq, httpReq, httpResp, authData);
+
+ //validate state
+ Assert.assertNotNull("Result should be not null", result);
+
+ ImmutableAttributeMap respAttr = validateBasicEidasResponse(authData);
+ assertEquals("wrong attr. size", 8, respAttr.size());
+ checkAttrValue(respAttr, EidasConstants.eIDAS_ATTR_REPRESENTATIVE_PERSONALIDENTIFIER,
+ (String) attr.get(PvpAttributeDefinitions.BPK_NAME));
+ checkAttrValue(respAttr, EidasConstants.eIDAS_ATTR_REPRESENTATIVE_CURRENTFAMILYNAME, authData.getFamilyName());
+ checkAttrValue(respAttr, EidasConstants.eIDAS_ATTR_REPRESENTATIVE_CURRENTGIVENNAME, authData.getGivenName());
+ checkAttrValue(respAttr, EidasConstants.eIDAS_ATTR_REPRESENTATIVE_DATEOFBIRTH, authData.getDateOfBirth());
+
+ checkAttrValue(respAttr, EidasConstants.eIDAS_ATTR_PERSONALIDENTIFIER,
+ (String) attr.get(PvpAttributeDefinitions.MANDATE_NAT_PER_BPK_NAME));
+ checkAttrValue(respAttr, EidasConstants.eIDAS_ATTR_CURRENTFAMILYNAME,
+ (String) attr.get(PvpAttributeDefinitions.MANDATE_NAT_PER_FAMILY_NAME_NAME));
+ checkAttrValue(respAttr, EidasConstants.eIDAS_ATTR_CURRENTGIVENNAME,
+ (String) attr.get(PvpAttributeDefinitions.MANDATE_NAT_PER_GIVEN_NAME_NAME));
+ checkAttrValue(respAttr, EidasConstants.eIDAS_ATTR_DATEOFBIRTH,
+ (String) attr.get(PvpAttributeDefinitions.MANDATE_NAT_PER_BIRTHDATE_NAME));
+
+ }
+
+ @Test
+ public void responseWithNatMandateOptionalAttribute() throws EaafException, SpecificCommunicationException {
+ LightRequest.Builder eidasRequestBuilder = generateBasicLightRequest();
+ eidasRequestBuilder.requestedAttributes(ImmutableAttributeMap.builder()
+ .put(attrRegistry.getCoreAttributeRegistry().getByFriendlyName(EidasConstants.eIDAS_ATTR_PERSONALIDENTIFIER).first())
+ .put(attrRegistry.getCoreAttributeRegistry().getByFriendlyName(EidasConstants.eIDAS_ATTR_CURRENTGIVENNAME).first())
+ .put(attrRegistry.getCoreAttributeRegistry().getByFriendlyName(EidasConstants.eIDAS_ATTR_CURRENTFAMILYNAME).first())
+ .put(attrRegistry.getCoreAttributeRegistry().getByFriendlyName(EidasConstants.eIDAS_ATTR_DATEOFBIRTH).first())
+ .put(attrRegistry.getCoreAttributeRegistry().getByName("http://eidas.europa.eu/attributes/naturalperson/BirthName"))
+ .build());
+ pendingReq.setEidasRequest(eidasRequestBuilder.build());
+
+ Map<String, Object> attr = new HashMap<>();
+ attr.put(PvpAttributeDefinitions.BPK_NAME,
+ "AT+XX:" + RandomStringUtils.randomAlphanumeric(10));
+ attr.put("ida_birthName_mandator", RandomStringUtils.randomAlphanumeric(10));
+ attr.put("ida_birthName", RandomStringUtils.randomAlphanumeric(10));
+
+ attr.put(PvpAttributeDefinitions.MANDATE_NAT_PER_BPK_NAME,
+ RandomStringUtils.randomAlphabetic(10));
+ attr.put(PvpAttributeDefinitions.MANDATE_NAT_PER_GIVEN_NAME_NAME,
+ RandomStringUtils.randomAlphabetic(10));
+ attr.put(PvpAttributeDefinitions.MANDATE_NAT_PER_FAMILY_NAME_NAME,
+ RandomStringUtils.randomAlphabetic(10));
+ attr.put(PvpAttributeDefinitions.MANDATE_NAT_PER_BIRTHDATE_NAME,
+ "1985-11-15");
+
+
+ IAuthData authData = generateDummyAuthData(attr , EaafConstants.EIDAS_LOA_HIGH,
+ RandomStringUtils.randomAlphanumeric(10), RandomStringUtils.randomAlphanumeric(10), "1945-04-18", true);
+
+ //perform test
+ SloInformationInterface result = action.processRequest(pendingReq, httpReq, httpResp, authData);
+
+ //validate state
+ Assert.assertNotNull("Result should be not null", result);
+
+ ImmutableAttributeMap respAttr = validateBasicEidasResponse(authData);
+ assertEquals("wrong attr. size", 9, respAttr.size());
+ checkAttrValue(respAttr, EidasConstants.eIDAS_ATTR_REPRESENTATIVE_PERSONALIDENTIFIER,
+ (String) attr.get(PvpAttributeDefinitions.BPK_NAME));
+ checkAttrValue(respAttr, EidasConstants.eIDAS_ATTR_REPRESENTATIVE_CURRENTFAMILYNAME, authData.getFamilyName());
+ checkAttrValue(respAttr, EidasConstants.eIDAS_ATTR_REPRESENTATIVE_CURRENTGIVENNAME, authData.getGivenName());
+ checkAttrValue(respAttr, EidasConstants.eIDAS_ATTR_REPRESENTATIVE_DATEOFBIRTH, authData.getDateOfBirth());
+
+ checkAttrValue(respAttr, EidasConstants.eIDAS_ATTR_PERSONALIDENTIFIER,
+ (String) attr.get(PvpAttributeDefinitions.MANDATE_NAT_PER_BPK_NAME));
+ checkAttrValue(respAttr, EidasConstants.eIDAS_ATTR_CURRENTFAMILYNAME,
+ (String) attr.get(PvpAttributeDefinitions.MANDATE_NAT_PER_FAMILY_NAME_NAME));
+ checkAttrValue(respAttr, EidasConstants.eIDAS_ATTR_CURRENTGIVENNAME,
+ (String) attr.get(PvpAttributeDefinitions.MANDATE_NAT_PER_GIVEN_NAME_NAME));
+ checkAttrValue(respAttr, EidasConstants.eIDAS_ATTR_DATEOFBIRTH,
+ (String) attr.get(PvpAttributeDefinitions.MANDATE_NAT_PER_BIRTHDATE_NAME));
+
+ checkAttrValue(respAttr, EidasConstants.eIDAS_ATTR_BIRTHNAME,
+ (String) attr.get("ida_birthName_mandator"));
+
+ }
+
+ @Test
+ public void responseWithJurMandate() throws EaafException, SpecificCommunicationException {
+ Map<String, Object> attr = new HashMap<>();
+ attr.put(PvpAttributeDefinitions.BPK_NAME,
+ "AT+XX:" + RandomStringUtils.randomAlphanumeric(10));
+ IAuthData authData = generateDummyAuthData(attr , EaafConstants.EIDAS_LOA_HIGH,
+ RandomStringUtils.randomAlphanumeric(10), RandomStringUtils.randomAlphanumeric(10), "1945-04-18", true);
+
+ attr.put(PvpAttributeDefinitions.MANDATE_LEG_PER_SOURCE_PIN_NAME,
+ RandomStringUtils.randomAlphabetic(10));
+ attr.put(PvpAttributeDefinitions.MANDATE_LEG_PER_FULL_NAME_NAME,
+ RandomStringUtils.randomAlphabetic(10));
+
+ LightRequest.Builder eidasRequestBuilder = generateBasicLightRequest();
+ eidasRequestBuilder.requestedAttributes(ImmutableAttributeMap.builder()
+ .put(attrRegistry.getCoreAttributeRegistry().getByFriendlyName(EidasConstants.eIDAS_ATTR_LEGALPERSONIDENTIFIER).first())
+ .put(attrRegistry.getCoreAttributeRegistry().getByFriendlyName(EidasConstants.eIDAS_ATTR_LEGALNAME).first())
+ .build());
+ pendingReq.setEidasRequest(eidasRequestBuilder.build());
+
+
+ //perform test
+ SloInformationInterface result = action.processRequest(pendingReq, httpReq, httpResp, authData);
+
+ //validate state
+ Assert.assertNotNull("Result should be not null", result);
+
+ ImmutableAttributeMap respAttr = validateBasicEidasResponse(authData);
+ assertEquals("wrong attr. size", 6, respAttr.size());
+ checkAttrValue(respAttr, EidasConstants.eIDAS_ATTR_REPRESENTATIVE_PERSONALIDENTIFIER,
+ (String) attr.get(PvpAttributeDefinitions.BPK_NAME));
+ checkAttrValue(respAttr, EidasConstants.eIDAS_ATTR_REPRESENTATIVE_CURRENTFAMILYNAME, authData.getFamilyName());
+ checkAttrValue(respAttr, EidasConstants.eIDAS_ATTR_REPRESENTATIVE_CURRENTGIVENNAME, authData.getGivenName());
+ checkAttrValue(respAttr, EidasConstants.eIDAS_ATTR_REPRESENTATIVE_DATEOFBIRTH, authData.getDateOfBirth());
+
+ checkAttrValue(respAttr, EidasConstants.eIDAS_ATTR_LEGALPERSONIDENTIFIER,
+ (String) attr.get(PvpAttributeDefinitions.MANDATE_LEG_PER_SOURCE_PIN_NAME));
+ checkAttrValue(respAttr, EidasConstants.eIDAS_ATTR_LEGALNAME,
+ (String) attr.get(PvpAttributeDefinitions.MANDATE_LEG_PER_FULL_NAME_NAME));
+
+ assertNull("find nat. person subject: personalId",
+ getAttrValue(respAttr, EidasConstants.eIDAS_ATTR_PERSONALIDENTIFIER));
+ assertNull("find nat. person subject: familyName",
+ getAttrValue(respAttr, EidasConstants.eIDAS_ATTR_CURRENTFAMILYNAME));
+ assertNull("find nat. person subject: givenName",
+ getAttrValue(respAttr, EidasConstants.eIDAS_ATTR_CURRENTGIVENNAME));
+ assertNull("find nat. person subject: dateOfBirth",
+ getAttrValue(respAttr, EidasConstants.eIDAS_ATTR_DATEOFBIRTH));
+
+ }
+
+ @Test
+ public void responseWithNatMandateWithWorkAround() throws EaafException, SpecificCommunicationException {
+ basicConfig.putConfigValue("auth.eIDAS.proxy.workaround.mandates.legalperson",
+ "true");
+
+ Map<String, Object> attr = new HashMap<>();
+ attr.put(PvpAttributeDefinitions.BPK_NAME,
+ "AT+XX:" + RandomStringUtils.randomAlphanumeric(10));
+
+ attr.put(PvpAttributeDefinitions.MANDATE_NAT_PER_BPK_NAME,
+ RandomStringUtils.randomAlphabetic(10));
+ attr.put(PvpAttributeDefinitions.MANDATE_NAT_PER_GIVEN_NAME_NAME,
+ RandomStringUtils.randomAlphabetic(10));
+ attr.put(PvpAttributeDefinitions.MANDATE_NAT_PER_FAMILY_NAME_NAME,
+ RandomStringUtils.randomAlphabetic(10));
+ attr.put(PvpAttributeDefinitions.MANDATE_NAT_PER_BIRTHDATE_NAME,
+ "1985-11-15");
+
+
+ IAuthData authData = generateDummyAuthData(attr , EaafConstants.EIDAS_LOA_HIGH,
+ RandomStringUtils.randomAlphanumeric(10), RandomStringUtils.randomAlphanumeric(10), "1945-04-18", true);
+
+ //perform test
+ SloInformationInterface result = action.processRequest(pendingReq, httpReq, httpResp, authData);
+
+ //validate state
+ Assert.assertNotNull("Result should be not null", result);
+
+ ImmutableAttributeMap respAttr = validateBasicEidasResponse(authData);
+ assertEquals("wrong attr. size", 8, respAttr.size());
+
+ }
+
+ @Test
+ public void responseWithJurMandateWithWorkAround() throws EaafException, SpecificCommunicationException {
+ basicConfig.putConfigValue("auth.eIDAS.proxy.workaround.mandates.legalperson",
+ "true");
+
+ //request natural person subject only
+ LightRequest.Builder eidasRequestBuilder = generateBasicLightRequest();
+ eidasRequestBuilder.requestedAttributes(ImmutableAttributeMap.builder()
+ .put(attrRegistry.getCoreAttributeRegistry().getByFriendlyName(EidasConstants.eIDAS_ATTR_PERSONALIDENTIFIER).first())
+ .put(attrRegistry.getCoreAttributeRegistry().getByFriendlyName(EidasConstants.eIDAS_ATTR_LEGALPERSONIDENTIFIER).first())
+ .put(attrRegistry.getCoreAttributeRegistry().getByFriendlyName(EidasConstants.eIDAS_ATTR_LEGALNAME).first())
+ .build());
+ pendingReq.setEidasRequest(eidasRequestBuilder.build());
+
+ Map<String, Object> attr = new HashMap<>();
+ attr.put(PvpAttributeDefinitions.BPK_NAME,
+ "AT+XX:" + RandomStringUtils.randomAlphanumeric(10));
+ IAuthData authData = generateDummyAuthData(attr , EaafConstants.EIDAS_LOA_HIGH,
+ RandomStringUtils.randomAlphanumeric(10), RandomStringUtils.randomAlphanumeric(10), "1945-04-18", true);
+
+ attr.put(PvpAttributeDefinitions.MANDATE_LEG_PER_SOURCE_PIN_NAME,
+ RandomStringUtils.randomAlphabetic(10));
+ attr.put(PvpAttributeDefinitions.MANDATE_LEG_PER_FULL_NAME_NAME,
+ RandomStringUtils.randomAlphabetic(10));
+
+ //perform test
+ SloInformationInterface result = action.processRequest(pendingReq, httpReq, httpResp, authData);
+
+ //validate state
+ Assert.assertNotNull("Result should be not null", result);
+
+ ImmutableAttributeMap respAttr = validateBasicEidasResponse(authData);
+ assertEquals("wrong attr. size", 10, respAttr.size());
+ checkAttrValue(respAttr, EidasConstants.eIDAS_ATTR_PERSONALIDENTIFIER,
+ (String) attr.get(PvpAttributeDefinitions.BPK_NAME));
+ checkAttrValue(respAttr, EidasConstants.eIDAS_ATTR_CURRENTFAMILYNAME, authData.getFamilyName());
+ checkAttrValue(respAttr, EidasConstants.eIDAS_ATTR_CURRENTGIVENNAME, authData.getGivenName());
+ checkAttrValue(respAttr, EidasConstants.eIDAS_ATTR_DATEOFBIRTH, authData.getDateOfBirth());
+
+ }
+
+ @Test
+ public void responseWithJurMandateWithWorkAroundNoNatSubject() throws EaafException, SpecificCommunicationException {
+ basicConfig.putConfigValue("auth.eIDAS.proxy.workaround.mandates.legalperson",
+ "true");
+
+ //request natural person subject only
+ LightRequest.Builder eidasRequestBuilder = generateBasicLightRequest();
+ eidasRequestBuilder.requestedAttributes(ImmutableAttributeMap.builder()
+ .put(attrRegistry.getCoreAttributeRegistry().getByFriendlyName(EidasConstants.eIDAS_ATTR_LEGALPERSONIDENTIFIER).first())
+ .put(attrRegistry.getCoreAttributeRegistry().getByFriendlyName(EidasConstants.eIDAS_ATTR_LEGALNAME).first())
+ .build());
+ pendingReq.setEidasRequest(eidasRequestBuilder.build());
+
+ Map<String, Object> attr = new HashMap<>();
+ attr.put(PvpAttributeDefinitions.BPK_NAME,
+ "AT+XX:" + RandomStringUtils.randomAlphanumeric(10));
+ IAuthData authData = generateDummyAuthData(attr , EaafConstants.EIDAS_LOA_HIGH,
+ RandomStringUtils.randomAlphanumeric(10), RandomStringUtils.randomAlphanumeric(10), "1945-04-18", true);
+
+ attr.put(PvpAttributeDefinitions.MANDATE_LEG_PER_SOURCE_PIN_NAME,
+ RandomStringUtils.randomAlphabetic(10));
+ attr.put(PvpAttributeDefinitions.MANDATE_LEG_PER_FULL_NAME_NAME,
+ RandomStringUtils.randomAlphabetic(10));
+
+ //perform test
+ SloInformationInterface result = action.processRequest(pendingReq, httpReq, httpResp, authData);
+
+ //validate state
+ Assert.assertNotNull("Result should be not null", result);
+
+ ImmutableAttributeMap respAttr = validateBasicEidasResponse(authData);
+ assertEquals("wrong attr. size", 6, respAttr.size());
+ assertNull("find nat. person subject: personalId",
+ getAttrValue(respAttr, EidasConstants.eIDAS_ATTR_PERSONALIDENTIFIER));
+ assertNull("find nat. person subject: familyName",
+ getAttrValue(respAttr, EidasConstants.eIDAS_ATTR_CURRENTFAMILYNAME));
+ assertNull("find nat. person subject: givenName",
+ getAttrValue(respAttr, EidasConstants.eIDAS_ATTR_CURRENTGIVENNAME));
+ assertNull("find nat. person subject: dateOfBirth",
+ getAttrValue(respAttr, EidasConstants.eIDAS_ATTR_DATEOFBIRTH));
+
+ }
+
+ @Test
+ public void checkBasicConstrainsInAction() {
+
+ Assert.assertTrue("Wrong NeedAuthentication", action.needAuthentication(pendingReq, httpReq, httpResp));
+ Assert.assertNotNull("Missing ActionName", action.getDefaultActionName());
+
+ Assert.assertNotNull("missing ActionBean", context.getBean(ProxyServiceAuthenticationAction.class));
+
+ }
+
+ private IAuthData generateDummyAuthData() {
+ return generateDummyAuthData(new HashMap<>(), EaafConstants.EIDAS_LOA_LOW,
+ RandomStringUtils.randomAlphanumeric(10), RandomStringUtils.randomAlphanumeric(10), "1940-01-01", false);
+
+ }
+
+ private Object getAttrValue(ImmutableAttributeMap respAttr, String attrName) {
+ final AttributeDefinition<?> attrDef =
+ attrRegistry.getCoreAttributeRegistry().getByFriendlyName(attrName).first();
+ return respAttr.getFirstValue(attrDef);
+
+ }
+
+ private void checkAttrValue(ImmutableAttributeMap respAttr, String attrName, String expected) {
+ Object value = getAttrValue(respAttr, attrName);
+ assertNotNull("not attr value: " + attrName, value);
+
+ if (value instanceof String) {
+ assertEquals("wrong attr. value: " + attrName, expected, value);
+
+ } else if ( value instanceof DateTime) {
+ assertEquals("wrong attr. value: " + attrName, expected, ((DateTime)value).toString("yyyy-MM-dd"));
+
+ }
+ }
+
+ private ImmutableAttributeMap validateBasicEidasResponse(IAuthData authData) throws SpecificCommunicationException {
+ assertNotNull("not redirct Header", httpResp.getHeader("Location"));
+ assertTrue("wrong redirect URL", httpResp.getHeader("Location").startsWith("http://eidas.proxy/endpoint?token="));
+ String token = httpResp.getHeader("Location").substring("http://eidas.proxy/endpoint?token=".length());
+
+ ILightResponse resp = springManagedSpecificConnectorCommunicationService.getAndRemoveResponse(URLDecoder.decode(token),
+ ImmutableSortedSet.copyOf(attrRegistry.getCoreAttributeRegistry().getAttributes()));
+
+ assertNotNull("responseId", resp.getId());
+ assertEquals("inResponseTo", pendingReq.getEidasRequest().getId(), resp.getInResponseToId());
+ assertEquals("relayState", pendingReq.getEidasRequest().getRelayState(), resp.getRelayState());
+ assertEquals("LoA", authData.getEidasQaaLevel(), resp.getLevelOfAssurance());
+
+ assertNotNull("subjectNameId", resp.getSubject());
+ assertEquals("subjectNameIdFormat", NameIDType.TRANSIENT, resp.getSubjectNameIdFormat());
+
+ assertFalse("not attributes", resp.getAttributes().isEmpty());
+ return resp.getAttributes();
+
+ }
+
+ private Builder generateBasicLightRequest() {
+ return LightRequest.builder()
+ .id(UUID.randomUUID().toString())
+ .issuer(RandomStringUtils.randomAlphabetic(10))
+ .citizenCountryCode(RandomStringUtils.randomAlphabetic(2).toUpperCase())
+ .levelOfAssurance(EaafConstants.EIDAS_LOA_HIGH)
+ .spCountryCode(RandomStringUtils.randomAlphabetic(2).toUpperCase())
+ .spType("public")
+ .requesterId(RandomStringUtils.randomAlphanumeric(10))
+ .providerName(RandomStringUtils.randomAlphanumeric(10))
+ .requestedAttributes(ImmutableAttributeMap.builder()
+ .put(attrRegistry.getCoreAttributeRegistry().getByFriendlyName(EidasConstants.eIDAS_ATTR_PERSONALIDENTIFIER).first())
+ .put(attrRegistry.getCoreAttributeRegistry().getByFriendlyName(EidasConstants.eIDAS_ATTR_CURRENTGIVENNAME).first())
+ .put(attrRegistry.getCoreAttributeRegistry().getByFriendlyName(EidasConstants.eIDAS_ATTR_CURRENTFAMILYNAME).first())
+ .put(attrRegistry.getCoreAttributeRegistry().getByFriendlyName(EidasConstants.eIDAS_ATTR_DATEOFBIRTH).first())
+ .build()
+ );
+ }
+
+ private IAuthData generateDummyAuthData(Map<String, Object> attrs, String loa, String familyName, String givenName, String dateOfBirth,
+ boolean useMandates) {
+ attrs.put(PvpAttributeDefinitions.BIRTHDATE_NAME, dateOfBirth);
+ attrs.put(PvpAttributeDefinitions.GIVEN_NAME_NAME, givenName);
+ attrs.put(PvpAttributeDefinitions.PRINCIPAL_NAME_NAME, familyName);
+
+ return new IEidAuthData() {
+
+ @Override
+ public boolean isSsoSession() {
+ // TODO Auto-generated method stub
+ return false;
+ }
+
+ @Override
+ public boolean isForeigner() {
+ // TODO Auto-generated method stub
+ return false;
+ }
+
+ @Override
+ public boolean isBaseIdTransferRestrication() {
+ // TODO Auto-generated method stub
+ return false;
+ }
+
+ @Override
+ public Instant getSsoSessionValidTo() {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ public String getSessionIndex() {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ public String getNameIdFormat() {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ public String getNameID() {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ public IIdentityLink getIdentityLink() {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ public String getIdentificationValue() {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ public String getIdentificationType() {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ public String getGivenName() {
+ return givenName;
+ }
+
+ @Override
+ public <T> T getGenericData(String key, Class<T> clazz) {
+ if (attrs.containsKey(key)) {
+ return (T) attrs.get(key);
+
+ } else {
+ return null;
+ }
+
+ }
+
+ @Override
+ public String getDateOfBirth() {
+ return dateOfBirth;
+ }
+
+ @Override
+ public String getFamilyName() {
+ return familyName;
+ }
+
+ @Override
+ public String getEncryptedSourceIdType() {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ public String getEncryptedSourceId() {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ public String getEidasQaaLevel() {
+ return loa;
+
+ }
+
+
+ @Override
+ public String getCiticenCountryCode() {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ public String getBpkType() {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ public String getBpk() {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ public String getAuthenticationIssuer() {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ public String getAuthenticationIssueInstantString() {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ public Instant getAuthenticationIssueInstant() {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ public byte[] getSignerCertificate() {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ public byte[] getEidToken() {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ public EidIdentityStatusLevelValues getEidStatus() {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ public String getVdaEndPointUrl() {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ public boolean isUseMandate() {
+ return useMandates;
+
+ }
+
+ @Override
+ public String getDateOfBirthFormated(String pattern) {
+ // TODO Auto-generated method stub
+ return null;
+ }
+ };
+
+ }
+}
diff --git a/modules/eidas_proxy-sevice/src/test/java/at/asitplus/eidas/specific/modules/msproxyservice/test/services/ProxyEidasAttributeRegistryTest.java b/modules/eidas_proxy-sevice/src/test/java/at/asitplus/eidas/specific/modules/msproxyservice/test/services/ProxyEidasAttributeRegistryTest.java
new file mode 100644
index 00000000..8d417c1a
--- /dev/null
+++ b/modules/eidas_proxy-sevice/src/test/java/at/asitplus/eidas/specific/modules/msproxyservice/test/services/ProxyEidasAttributeRegistryTest.java
@@ -0,0 +1,139 @@
+package at.asitplus.eidas.specific.modules.msproxyservice.test.services;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+import java.util.Optional;
+import java.util.Set;
+
+import org.apache.commons.lang3.RandomStringUtils;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.test.context.ContextConfiguration;
+import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
+import org.springframework.web.servlet.config.annotation.EnableWebMvc;
+
+import at.asitplus.eidas.specific.modules.msproxyservice.service.ProxyEidasAttributeRegistry;
+import lombok.NonNull;
+
+@RunWith(SpringJUnit4ClassRunner.class)
+@ContextConfiguration(locations = {
+ "/spring/SpringTest-context_basic_test.xml",
+ "/spring/SpringTest-context_basic_mapConfig.xml",
+ })
+@EnableWebMvc
+public class ProxyEidasAttributeRegistryTest {
+
+ @Autowired ProxyEidasAttributeRegistry attrRegistry;
+
+ @Test
+ public void checkDefaultAttributes() {
+ assertEquals("default attributes without mandates", 2,
+ attrRegistry.getAlwaysRequestedAttributes(false).count());
+ assertEquals("default attributes with mandates", 4,
+ attrRegistry.getAlwaysRequestedAttributes(true).count());
+
+ }
+
+ @Test
+ public void eidasAttributeMapping() {
+ checkAttributeMapping("http://eidas.europa.eu/attributes/naturalperson/PersonIdentifier", false,
+ Arrays.asList("urn:oid:1.2.40.0.10.2.1.1.149"));
+ checkAttributeMapping("http://eidas.europa.eu/attributes/naturalperson/PersonIdentifier", true,
+ Arrays.asList("urn:oid:1.2.40.0.10.2.1.1.149", "urn:oid:1.2.40.0.10.2.1.1.261.98"));
+
+ }
+
+ @Test
+ public void eidasAttributeMappingMandateOnly() {
+ checkAttributeMapping("http://eidas.europa.eu/attributes/legalperson/LegalPersonIdentifier", false,
+ Arrays.asList(
+ "urn:oid:1.2.40.0.10.2.1.1.149",
+ "urn:oid:2.5.4.42",
+ "urn:oid:1.2.40.0.10.2.1.1.261.20",
+ "urn:oid:1.2.40.0.10.2.1.1.55"));
+ checkAttributeMapping("http://eidas.europa.eu/attributes/legalperson/LegalPersonIdentifier", true,
+ Arrays.asList(
+ "urn:oid:1.2.40.0.10.2.1.1.261.100",
+ "urn:oid:1.2.40.0.10.2.1.1.149",
+ "urn:oid:2.5.4.42",
+ "urn:oid:1.2.40.0.10.2.1.1.261.20",
+ "urn:oid:1.2.40.0.10.2.1.1.55"));
+
+ }
+
+ @Test
+ public void eidasAttributeMappingWithNoIdaAttribute() {
+ checkAttributeMapping("http://eidas.europa.eu/attributes/naturalperson/PlaceOfBirth", false,
+ Collections.emptyList());
+ checkAttributeMapping("http://eidas.europa.eu/attributes/naturalperson/PlaceOfBirth", true,
+ Collections.emptyList());
+
+ }
+
+ @Test
+ public void unknownEidasAttribute() {
+ checkAttributeMapping("http://eidas.europa.eu/attributes/jUnit/not/exits", false,
+ Collections.emptyList());
+ checkAttributeMapping("http://eidas.europa.eu/attributes/jUnit/not/exits", true,
+ Collections.emptyList());
+
+ }
+
+ @Test
+ public void unknownEidasAttribute2() {
+ checkAttributeMapping(RandomStringUtils.randomAlphabetic(10), false,
+ Collections.emptyList());
+ checkAttributeMapping(RandomStringUtils.randomAlphabetic(10), true,
+ Collections.emptyList());
+
+ }
+
+ @Test
+ public void attributeResponseMapping() {
+ assertFalse("find wrong IDA mapping", attrRegistry.mapEidasAttributeToSpecificIdaAttribute(
+ "http://eidas.europa.eu/attributes/naturalperson/PlaceOfBirth", false).isPresent());
+ assertFalse("find wrong IDA mapping", attrRegistry.mapEidasAttributeToSpecificIdaAttribute(
+ "http://eidas.europa.eu/attributes/naturalperson/PlaceOfBirth", true).isPresent());
+
+
+ Optional<String> attr1 = attrRegistry.mapEidasAttributeToSpecificIdaAttribute(
+ "http://eidas.europa.eu/attributes/naturalperson/BirthName", false);
+ assertTrue("find wrong IDA mapping", attr1.isPresent());
+ assertEquals("find wrong IDA mapping value", "ida_birthname", attr1.get());
+
+ Optional<String> attr2 = attrRegistry.mapEidasAttributeToSpecificIdaAttribute(
+ "http://eidas.europa.eu/attributes/naturalperson/BirthName", true);
+ assertTrue("find wrong IDA mapping", attr2.isPresent());
+ assertEquals("find wrong IDA mapping value", "ida_birthName_mandator", attr2.get());
+
+
+ assertTrue("find wrong IDA mapping", attrRegistry.mapEidasAttributeToSpecificIdaAttribute(
+ "http://eidas.europa.eu/attributes/naturalperson/PersonIdentifier", false).isPresent());
+ assertTrue("find wrong IDA mapping", attrRegistry.mapEidasAttributeToSpecificIdaAttribute(
+ "http://eidas.europa.eu/attributes/naturalperson/PersonIdentifier", true).isPresent());
+
+ }
+
+ @Test
+ public void defaultRepresentativeAttributes() {
+ assertEquals("wrong number of rep. attributes", 4,
+ attrRegistry.getRepresentativeAttributesToAddByDefault().count());
+
+ }
+
+ private void checkAttributeMapping(String eidasAttr, boolean withMandates, List<String> idaAttributes) {
+ @NonNull
+ Set<String> idaAttrResult = attrRegistry.getIdaAttributesForEidasAttribute(eidasAttr, withMandates);
+ assertEquals("wrong number of IDA attributes", idaAttributes.size(), idaAttrResult.size());
+ idaAttributes.forEach(
+ el -> assertTrue("missing: " + el, idaAttrResult.contains(el)));
+
+ }
+
+}
diff --git a/modules/eidas_proxy-sevice/src/test/resources/config/additional-attributes.xml b/modules/eidas_proxy-sevice/src/test/resources/config/additional-attributes.xml
new file mode 100644
index 00000000..6510546e
--- /dev/null
+++ b/modules/eidas_proxy-sevice/src/test/resources/config/additional-attributes.xml
@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+# Copyright (c) 2017 European Commission
+# Licensed under the EUPL, Version 1.2 or – as soon they will be
+# approved by the European Commission - subsequent versions of the
+# EUPL (the "Licence");
+# You may not use this work except in compliance with the Licence.
+# You may obtain a copy of the Licence at:
+# * https://joinup.ec.europa.eu/page/eupl-text-11-12
+# *
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the Licence is distributed on an "AS IS" basis,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the Licence for the specific language governing permissions and limitations under the Licence.
+ -->
+
+<!DOCTYPE properties SYSTEM "http://java.sun.com/dtd/properties.dtd">
+<properties>
+ <comment>Dynamic attributes</comment>
+
+ <entry key="1.NameUri">http://eidas.europa.eu/attributes/naturalperson/AdditionalAttribute</entry>
+ <entry key="1.FriendlyName">AdditionalAttribute</entry>
+ <entry key="1.PersonType">NaturalPerson</entry>
+ <entry key="1.Required">false</entry>
+ <entry key="1.XmlType.NamespaceUri">http://www.w3.org/2001/XMLSchema</entry>
+ <entry key="1.XmlType.LocalPart">string</entry>
+ <entry key="1.XmlType.NamespacePrefix">xs</entry>
+ <entry key="1.AttributeValueMarshaller">eu.eidas.auth.commons.attribute.impl.LiteralStringAttributeValueMarshaller</entry>
+
+ <entry key="2.NameUri">http://eidas.europa.eu/attributes/legalperson/LegalAdditionalAttribute</entry>
+ <entry key="2.FriendlyName">LegalAdditionalAttribute</entry>
+ <entry key="2.PersonType">LegalPerson</entry>
+ <entry key="2.Required">false</entry>
+ <entry key="2.XmlType.NamespaceUri">http://www.w3.org/2001/XMLSchema</entry>
+ <entry key="2.XmlType.LocalPart">string</entry>
+ <entry key="2.XmlType.NamespacePrefix">xs</entry>
+ <entry key="2.AttributeValueMarshaller">eu.eidas.auth.commons.attribute.impl.LiteralStringAttributeValueMarshaller</entry>
+
+</properties>
diff --git a/modules/eidas_proxy-sevice/src/test/resources/config/eidas-attributes.xml b/modules/eidas_proxy-sevice/src/test/resources/config/eidas-attributes.xml
new file mode 100644
index 00000000..cbae35db
--- /dev/null
+++ b/modules/eidas_proxy-sevice/src/test/resources/config/eidas-attributes.xml
@@ -0,0 +1,376 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+# Copyright (c) 2017 European Commission
+# Licensed under the EUPL, Version 1.2 or – as soon they will be
+# approved by the European Commission - subsequent versions of the
+# EUPL (the "Licence");
+# You may not use this work except in compliance with the Licence.
+# You may obtain a copy of the Licence at:
+# * https://joinup.ec.europa.eu/page/eupl-text-11-12
+# *
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the Licence is distributed on an "AS IS" basis,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the Licence for the specific language governing permissions and limitations under the Licence.
+ -->
+
+<!DOCTYPE properties SYSTEM "http://java.sun.com/dtd/properties.dtd">
+<properties>
+ <comment>eIDAS attributes</comment>
+
+ <entry key="1.NameUri">http://eidas.europa.eu/attributes/naturalperson/PersonIdentifier</entry>
+ <entry key="1.FriendlyName">PersonIdentifier</entry>
+ <entry key="1.PersonType">NaturalPerson</entry>
+ <entry key="1.Required">true</entry>
+ <entry key="1.UniqueIdentifier">true</entry>
+ <entry key="1.XmlType.NamespaceUri">http://eidas.europa.eu/attributes/naturalperson</entry>
+ <entry key="1.XmlType.LocalPart">PersonIdentifierType</entry>
+ <entry key="1.XmlType.NamespacePrefix">eidas-natural</entry>
+ <entry key="1.AttributeValueMarshaller">eu.eidas.auth.commons.attribute.impl.LiteralStringAttributeValueMarshaller</entry>
+
+ <entry key="2.NameUri">http://eidas.europa.eu/attributes/naturalperson/CurrentFamilyName</entry>
+ <entry key="2.FriendlyName">FamilyName</entry>
+ <entry key="2.PersonType">NaturalPerson</entry>
+ <entry key="2.Required">true</entry>
+ <entry key="2.TransliterationMandatory">true</entry>
+ <entry key="2.XmlType.NamespaceUri">http://eidas.europa.eu/attributes/naturalperson</entry>
+ <entry key="2.XmlType.LocalPart">CurrentFamilyNameType</entry>
+ <entry key="2.XmlType.NamespacePrefix">eidas-natural</entry>
+ <entry key="2.AttributeValueMarshaller">eu.eidas.auth.commons.attribute.impl.LiteralStringAttributeValueMarshaller</entry>
+
+ <entry key="3.NameUri">http://eidas.europa.eu/attributes/naturalperson/CurrentGivenName</entry>
+ <entry key="3.FriendlyName">FirstName</entry>
+ <entry key="3.PersonType">NaturalPerson</entry>
+ <entry key="3.Required">true</entry>
+ <entry key="3.TransliterationMandatory">true</entry>
+ <entry key="3.XmlType.NamespaceUri">http://eidas.europa.eu/attributes/naturalperson</entry>
+ <entry key="3.XmlType.LocalPart">CurrentGivenNameType</entry>
+ <entry key="3.XmlType.NamespacePrefix">eidas-natural</entry>
+ <entry key="3.AttributeValueMarshaller">eu.eidas.auth.commons.attribute.impl.LiteralStringAttributeValueMarshaller</entry>
+
+ <entry key="4.NameUri">http://eidas.europa.eu/attributes/naturalperson/DateOfBirth</entry>
+ <entry key="4.FriendlyName">DateOfBirth</entry>
+ <entry key="4.PersonType">NaturalPerson</entry>
+ <entry key="4.Required">true</entry>
+ <entry key="4.XmlType.NamespaceUri">http://eidas.europa.eu/attributes/naturalperson</entry>
+ <entry key="4.XmlType.LocalPart">DateOfBirthType</entry>
+ <entry key="4.XmlType.NamespacePrefix">eidas-natural</entry>
+ <entry key="4.AttributeValueMarshaller">eu.eidas.auth.commons.attribute.impl.DateTimeAttributeValueMarshaller</entry>
+
+ <entry key="5.NameUri">http://eidas.europa.eu/attributes/naturalperson/BirthName</entry>
+ <entry key="5.FriendlyName">BirthName</entry>
+ <entry key="5.PersonType">NaturalPerson</entry>
+ <entry key="5.Required">false</entry>
+ <entry key="5.TransliterationMandatory">true</entry>
+ <entry key="5.XmlType.NamespaceUri">http://eidas.europa.eu/attributes/naturalperson</entry>
+ <entry key="5.XmlType.LocalPart">BirthNameType</entry>
+ <entry key="5.XmlType.NamespacePrefix">eidas-natural</entry>
+ <entry key="5.AttributeValueMarshaller">eu.eidas.auth.commons.attribute.impl.LiteralStringAttributeValueMarshaller</entry>
+
+ <entry key="6.NameUri">http://eidas.europa.eu/attributes/naturalperson/PlaceOfBirth</entry>
+ <entry key="6.FriendlyName">PlaceOfBirth</entry>
+ <entry key="6.PersonType">NaturalPerson</entry>
+ <entry key="6.Required">false</entry>
+ <entry key="6.XmlType.NamespaceUri">http://eidas.europa.eu/attributes/naturalperson</entry>
+ <entry key="6.XmlType.LocalPart">PlaceOfBirthType</entry>
+ <entry key="6.XmlType.NamespacePrefix">eidas-natural</entry>
+ <entry key="6.AttributeValueMarshaller">eu.eidas.auth.commons.attribute.impl.LiteralStringAttributeValueMarshaller</entry>
+
+ <entry key="7.NameUri">http://eidas.europa.eu/attributes/naturalperson/CurrentAddress</entry>
+ <entry key="7.FriendlyName">CurrentAddress</entry>
+ <entry key="7.PersonType">NaturalPerson</entry>
+ <entry key="7.Required">false</entry>
+ <entry key="7.XmlType.NamespaceUri">http://eidas.europa.eu/attributes/naturalperson</entry>
+ <entry key="7.XmlType.LocalPart">CurrentAddressType</entry>
+ <entry key="7.XmlType.NamespacePrefix">eidas-natural</entry>
+ <entry key="7.AttributeValueMarshaller">eu.eidas.auth.commons.protocol.eidas.impl.CurrentAddressAttributeValueMarshaller</entry>
+
+ <entry key="8.NameUri">http://eidas.europa.eu/attributes/naturalperson/Gender</entry>
+ <entry key="8.FriendlyName">Gender</entry>
+ <entry key="8.PersonType">NaturalPerson</entry>
+ <entry key="8.Required">false</entry>
+ <entry key="8.XmlType.NamespaceUri">http://eidas.europa.eu/attributes/naturalperson</entry>
+ <entry key="8.XmlType.LocalPart">GenderType</entry>
+ <entry key="8.XmlType.NamespacePrefix">eidas-natural</entry>
+ <entry key="8.AttributeValueMarshaller">eu.eidas.auth.commons.protocol.eidas.impl.GenderAttributeValueMarshaller</entry>
+
+ <entry key="9.NameUri">http://eidas.europa.eu/attributes/legalperson/LegalPersonIdentifier</entry>
+ <entry key="9.FriendlyName">LegalPersonIdentifier</entry>
+ <entry key="9.PersonType">LegalPerson</entry>
+ <entry key="9.Required">true</entry>
+ <entry key="9.UniqueIdentifier">true</entry>
+ <entry key="9.XmlType.NamespaceUri">http://eidas.europa.eu/attributes/legalperson</entry>
+ <entry key="9.XmlType.LocalPart">LegalPersonIdentifierType</entry>
+ <entry key="9.XmlType.NamespacePrefix">eidas-legal</entry>
+ <entry key="9.AttributeValueMarshaller">eu.eidas.auth.commons.attribute.impl.LiteralStringAttributeValueMarshaller</entry>
+
+ <entry key="10.NameUri">http://eidas.europa.eu/attributes/legalperson/LegalName</entry>
+ <entry key="10.FriendlyName">LegalName</entry>
+ <entry key="10.PersonType">LegalPerson</entry>
+ <entry key="10.Required">true</entry>
+ <entry key="10.TransliterationMandatory">true</entry>
+ <entry key="10.XmlType.NamespaceUri">http://eidas.europa.eu/attributes/legalperson</entry>
+ <entry key="10.XmlType.LocalPart">LegalNameType</entry>
+ <entry key="10.XmlType.NamespacePrefix">eidas-legal</entry>
+ <entry key="10.AttributeValueMarshaller">eu.eidas.auth.commons.attribute.impl.LiteralStringAttributeValueMarshaller</entry>
+
+ <entry key="11.NameUri">http://eidas.europa.eu/attributes/legalperson/LegalPersonAddress</entry>
+ <entry key="11.FriendlyName">LegalAddress</entry>
+ <entry key="11.PersonType">LegalPerson</entry>
+ <entry key="11.Required">false</entry>
+ <entry key="11.XmlType.NamespaceUri">http://eidas.europa.eu/attributes/legalperson</entry>
+ <entry key="11.XmlType.LocalPart">LegalPersonAddressType</entry>
+ <entry key="11.XmlType.NamespacePrefix">eidas-legal</entry>
+ <entry key="11.AttributeValueMarshaller">eu.eidas.auth.commons.protocol.eidas.impl.LegalAddressAttributeValueMarshaller</entry>
+
+ <entry key="12.NameUri">http://eidas.europa.eu/attributes/legalperson/VATRegistrationNumber</entry>
+ <entry key="12.FriendlyName">VATRegistration</entry>
+ <entry key="12.PersonType">LegalPerson</entry>
+ <entry key="12.Required">false</entry>
+ <entry key="12.XmlType.NamespaceUri">http://eidas.europa.eu/attributes/legalperson</entry>
+ <entry key="12.XmlType.LocalPart">VATRegistrationNumberType</entry>
+ <entry key="12.XmlType.NamespacePrefix">eidas-legal</entry>
+ <entry key="12.AttributeValueMarshaller">eu.eidas.auth.commons.attribute.impl.LiteralStringAttributeValueMarshaller</entry>
+
+ <entry key="13.NameUri">http://eidas.europa.eu/attributes/legalperson/TaxReference</entry>
+ <entry key="13.FriendlyName">TaxReference</entry>
+ <entry key="13.PersonType">LegalPerson</entry>
+ <entry key="13.Required">false</entry>
+ <entry key="13.XmlType.NamespaceUri">http://eidas.europa.eu/attributes/legalperson</entry>
+ <entry key="13.XmlType.LocalPart">TaxReferenceType</entry>
+ <entry key="13.XmlType.NamespacePrefix">eidas-legal</entry>
+ <entry key="13.AttributeValueMarshaller">eu.eidas.auth.commons.attribute.impl.LiteralStringAttributeValueMarshaller</entry>
+
+ <entry key="14.NameUri">http://eidas.europa.eu/attributes/legalperson/D-2012-17-EUIdentifier</entry>
+ <entry key="14.FriendlyName">D-2012-17-EUIdentifier</entry>
+ <entry key="14.PersonType">LegalPerson</entry>
+ <entry key="14.Required">false</entry>
+ <entry key="14.XmlType.NamespaceUri">http://eidas.europa.eu/attributes/legalperson</entry>
+ <entry key="14.XmlType.LocalPart">D-2012-17-EUIdentifierType</entry>
+ <entry key="14.XmlType.NamespacePrefix">eidas-legal</entry>
+ <entry key="14.AttributeValueMarshaller">eu.eidas.auth.commons.attribute.impl.LiteralStringAttributeValueMarshaller</entry>
+
+ <entry key="15.NameUri">http://eidas.europa.eu/attributes/legalperson/LEI</entry>
+ <entry key="15.FriendlyName">LEI</entry>
+ <entry key="15.PersonType">LegalPerson</entry>
+ <entry key="15.Required">false</entry>
+ <entry key="15.XmlType.NamespaceUri">http://eidas.europa.eu/attributes/legalperson</entry>
+ <entry key="15.XmlType.LocalPart">LEIType</entry>
+ <entry key="15.XmlType.NamespacePrefix">eidas-legal</entry>
+ <entry key="15.AttributeValueMarshaller">eu.eidas.auth.commons.attribute.impl.LiteralStringAttributeValueMarshaller</entry>
+
+ <entry key="16.NameUri">http://eidas.europa.eu/attributes/legalperson/EORI</entry>
+ <entry key="16.FriendlyName">EORI</entry>
+ <entry key="16.PersonType">LegalPerson</entry>
+ <entry key="16.Required">false</entry>
+ <entry key="16.XmlType.NamespaceUri">http://eidas.europa.eu/attributes/legalperson</entry>
+ <entry key="16.XmlType.LocalPart">EORIType</entry>
+ <entry key="16.XmlType.NamespacePrefix">eidas-legal</entry>
+ <entry key="16.AttributeValueMarshaller">eu.eidas.auth.commons.attribute.impl.LiteralStringAttributeValueMarshaller</entry>
+
+ <entry key="17.NameUri">http://eidas.europa.eu/attributes/legalperson/SEED</entry>
+ <entry key="17.FriendlyName">SEED</entry>
+ <entry key="17.PersonType">LegalPerson</entry>
+ <entry key="17.Required">false</entry>
+ <entry key="17.XmlType.NamespaceUri">http://eidas.europa.eu/attributes/legalperson</entry>
+ <entry key="17.XmlType.LocalPart">SEEDType</entry>
+ <entry key="17.XmlType.NamespacePrefix">eidas-legal</entry>
+ <entry key="17.AttributeValueMarshaller">eu.eidas.auth.commons.attribute.impl.LiteralStringAttributeValueMarshaller</entry>
+
+ <entry key="18.NameUri">http://eidas.europa.eu/attributes/legalperson/SIC</entry>
+ <entry key="18.FriendlyName">SIC</entry>
+ <entry key="18.PersonType">LegalPerson</entry>
+ <entry key="18.Required">false</entry>
+ <entry key="18.XmlType.NamespaceUri">http://eidas.europa.eu/attributes/legalperson</entry>
+ <entry key="18.XmlType.LocalPart">SICType</entry>
+ <entry key="18.XmlType.NamespacePrefix">eidas-legal</entry>
+ <entry key="18.AttributeValueMarshaller">eu.eidas.auth.commons.attribute.impl.LiteralStringAttributeValueMarshaller</entry>
+
+ <entry key="19.NameUri">http://eidas.europa.eu/attributes/naturalperson/representative/PersonIdentifier</entry>
+ <entry key="19.FriendlyName">RepresentativePersonIdentifier</entry>
+ <entry key="19.PersonType">RepresentativeNaturalPerson</entry>
+ <entry key="19.Required">false</entry>
+ <entry key="19.UniqueIdentifier">true</entry>
+ <entry key="19.XmlType.NamespaceUri">http://eidas.europa.eu/attributes/naturalperson/representative</entry>
+ <entry key="19.XmlType.LocalPart">PersonIdentifierType</entry>
+ <entry key="19.XmlType.NamespacePrefix">eidas-natural</entry>
+ <entry key="19.AttributeValueMarshaller">eu.eidas.auth.commons.attribute.impl.LiteralStringAttributeValueMarshaller</entry>
+
+ <entry key="20.NameUri">http://eidas.europa.eu/attributes/naturalperson/representative/CurrentFamilyName</entry>
+ <entry key="20.FriendlyName">RepresentativeFamilyName</entry>
+ <entry key="20.PersonType">RepresentativeNaturalPerson</entry>
+ <entry key="20.Required">false</entry>
+ <entry key="20.TransliterationMandatory">true</entry>
+ <entry key="20.XmlType.NamespaceUri">http://eidas.europa.eu/attributes/naturalperson/representative</entry>
+ <entry key="20.XmlType.LocalPart">CurrentFamilyNameType</entry>
+ <entry key="20.XmlType.NamespacePrefix">eidas-reprentative-natural</entry>
+ <entry key="20.AttributeValueMarshaller">eu.eidas.auth.commons.attribute.impl.LiteralStringAttributeValueMarshaller</entry>
+
+ <entry key="21.NameUri">http://eidas.europa.eu/attributes/naturalperson/representative/CurrentGivenName</entry>
+ <entry key="21.FriendlyName">RepresentativeFirstName</entry>
+ <entry key="21.PersonType">RepresentativeNaturalPerson</entry>
+ <entry key="21.Required">false</entry>
+ <entry key="21.TransliterationMandatory">true</entry>
+ <entry key="21.XmlType.NamespaceUri">http://eidas.europa.eu/attributes/naturalperson/representative</entry>
+ <entry key="21.XmlType.LocalPart">CurrentGivenNameType</entry>
+ <entry key="21.XmlType.NamespacePrefix">eidas-reprentative-natural</entry>
+ <entry key="21.AttributeValueMarshaller">eu.eidas.auth.commons.attribute.impl.LiteralStringAttributeValueMarshaller</entry>
+
+ <entry key="22.NameUri">http://eidas.europa.eu/attributes/naturalperson/representative/DateOfBirth</entry>
+ <entry key="22.FriendlyName">RepresentativeDateOfBirth</entry>
+ <entry key="22.PersonType">RepresentativeNaturalPerson</entry>
+ <entry key="22.Required">false</entry>
+ <entry key="22.XmlType.NamespaceUri">http://eidas.europa.eu/attributes/naturalperson/representative</entry>
+ <entry key="22.XmlType.LocalPart">DateOfBirthType</entry>
+ <entry key="22.XmlType.NamespacePrefix">eidas-reprentative-natural</entry>
+ <entry key="22.AttributeValueMarshaller">eu.eidas.auth.commons.attribute.impl.DateTimeAttributeValueMarshaller</entry>
+
+ <entry key="23.NameUri">http://eidas.europa.eu/attributes/naturalperson/representative/BirthName</entry>
+ <entry key="23.FriendlyName">RepresentativeBirthName</entry>
+ <entry key="23.PersonType">RepresentativeNaturalPerson</entry>
+ <entry key="23.Required">false</entry>
+ <entry key="23.TransliterationMandatory">true</entry>
+ <entry key="23.XmlType.NamespaceUri">http://eidas.europa.eu/attributes/naturalperson/representative</entry>
+ <entry key="23.XmlType.LocalPart">BirthNameType</entry>
+ <entry key="23.XmlType.NamespacePrefix">eidas-reprentative-natural</entry>
+ <entry key="23.AttributeValueMarshaller">eu.eidas.auth.commons.attribute.impl.LiteralStringAttributeValueMarshaller</entry>
+
+ <entry key="24.NameUri">http://eidas.europa.eu/attributes/naturalperson/representative/PlaceOfBirth</entry>
+ <entry key="24.FriendlyName">RepresentativePlaceOfBirth</entry>
+ <entry key="24.PersonType">RepresentativeNaturalPerson</entry>
+ <entry key="24.Required">false</entry>
+ <entry key="24.XmlType.NamespaceUri">http://eidas.europa.eu/attributes/naturalperson/representative</entry>
+ <entry key="24.XmlType.LocalPart">PlaceOfBirthType</entry>
+ <entry key="24.XmlType.NamespacePrefix">eidas-reprentative-natural</entry>
+ <entry key="24.AttributeValueMarshaller">eu.eidas.auth.commons.attribute.impl.LiteralStringAttributeValueMarshaller</entry>
+
+ <entry key="25.NameUri">http://eidas.europa.eu/attributes/naturalperson/representative/CurrentAddress</entry>
+ <entry key="25.FriendlyName">RepresentativeCurrentAddress</entry>
+ <entry key="25.PersonType">RepresentativeNaturalPerson</entry>
+ <entry key="25.Required">false</entry>
+ <entry key="25.XmlType.NamespaceUri">http://eidas.europa.eu/attributes/naturalperson/representative</entry>
+ <entry key="25.XmlType.LocalPart">CurrentAddressType</entry>
+ <entry key="25.XmlType.NamespacePrefix">eidas-reprentative-natural</entry>
+ <entry key="25.AttributeValueMarshaller">eu.eidas.auth.commons.protocol.eidas.impl.RepvCurrentAddressAttributeValueMarshaller</entry>
+
+ <entry key="26.NameUri">http://eidas.europa.eu/attributes/naturalperson/representative/Gender</entry>
+ <entry key="26.FriendlyName">RepresentativeGender</entry>
+ <entry key="26.PersonType">RepresentativeNaturalPerson</entry>
+ <entry key="26.Required">false</entry>
+ <entry key="26.XmlType.NamespaceUri">http://eidas.europa.eu/attributes/naturalperson/representative</entry>
+ <entry key="26.XmlType.LocalPart">GenderType</entry>
+ <entry key="26.XmlType.NamespacePrefix">eidas-reprentative-natural</entry>
+ <entry key="26.AttributeValueMarshaller">eu.eidas.auth.commons.protocol.eidas.impl.GenderAttributeValueMarshaller</entry>
+
+ <entry key="27.NameUri">http://eidas.europa.eu/attributes/legalperson/representative/LegalPersonIdentifier</entry>
+ <entry key="27.FriendlyName">RepresentativeLegalPersonIdentifier</entry>
+ <entry key="27.PersonType">RepresentativeLegalPerson</entry>
+ <entry key="27.Required">false</entry>
+ <entry key="27.UniqueIdentifier">true</entry>
+ <entry key="27.XmlType.NamespaceUri">http://eidas.europa.eu/attributes/legalperson/representative</entry>
+ <entry key="27.XmlType.LocalPart">LegalPersonIdentifierType</entry>
+ <entry key="27.XmlType.NamespacePrefix">eidas-reprentative-legal</entry>
+ <entry key="27.AttributeValueMarshaller">eu.eidas.auth.commons.attribute.impl.LiteralStringAttributeValueMarshaller</entry>
+
+ <entry key="28.NameUri">http://eidas.europa.eu/attributes/legalperson/representative/LegalName</entry>
+ <entry key="28.FriendlyName">RepresentativeLegalName</entry>
+ <entry key="28.PersonType">RepresentativeLegalPerson</entry>
+ <entry key="28.Required">false</entry>
+ <entry key="28.TransliterationMandatory">true</entry>
+ <entry key="28.XmlType.NamespaceUri">http://eidas.europa.eu/attributes/legalperson/representative</entry>
+ <entry key="28.XmlType.LocalPart">LegalNameType</entry>
+ <entry key="28.XmlType.NamespacePrefix">eidas-reprentative-legal</entry>
+ <entry key="28.AttributeValueMarshaller">eu.eidas.auth.commons.attribute.impl.LiteralStringAttributeValueMarshaller</entry>
+
+ <entry key="29.NameUri">http://eidas.europa.eu/attributes/legalperson/representative/LegalPersonAddress</entry>
+ <entry key="29.FriendlyName">RepresentativeLegalAddress</entry>
+ <entry key="29.PersonType">RepresentativeLegalPerson</entry>
+ <entry key="29.Required">false</entry>
+ <entry key="29.XmlType.NamespaceUri">http://eidas.europa.eu/attributes/legalperson/representative</entry>
+ <entry key="29.XmlType.LocalPart">LegalPersonAddressType</entry>
+ <entry key="29.XmlType.NamespacePrefix">eidas-reprentative-legal</entry>
+ <entry key="29.AttributeValueMarshaller">eu.eidas.auth.commons.protocol.eidas.impl.RepvLegalAddressAttributeValueMarshaller</entry>
+
+ <entry key="30.NameUri">http://eidas.europa.eu/attributes/legalperson/representative/VATRegistrationNumber</entry>
+ <entry key="30.FriendlyName">RepresentativeVATRegistration</entry>
+ <entry key="30.PersonType">RepresentativeLegalPerson</entry>
+ <entry key="30.Required">false</entry>
+ <entry key="30.XmlType.NamespaceUri">http://eidas.europa.eu/attributes/legalperson/representative</entry>
+ <entry key="30.XmlType.LocalPart">VATRegistrationNumberType</entry>
+ <entry key="30.XmlType.NamespacePrefix">eidas-reprentative-legal</entry>
+ <entry key="30.AttributeValueMarshaller">eu.eidas.auth.commons.attribute.impl.LiteralStringAttributeValueMarshaller</entry>
+
+ <entry key="31.NameUri">http://eidas.europa.eu/attributes/legalperson/representative/TaxReference</entry>
+ <entry key="31.FriendlyName">RepresentativeTaxReference</entry>
+ <entry key="31.PersonType">RepresentativeLegalPerson</entry>
+ <entry key="31.Required">false</entry>
+ <entry key="31.XmlType.NamespaceUri">http://eidas.europa.eu/attributes/legalperson/representative</entry>
+ <entry key="31.XmlType.LocalPart">TaxReferenceType</entry>
+ <entry key="31.XmlType.NamespacePrefix">eidas-reprentative-legal</entry>
+ <entry key="31.AttributeValueMarshaller">eu.eidas.auth.commons.attribute.impl.LiteralStringAttributeValueMarshaller</entry>
+
+ <entry key="32.NameUri">http://eidas.europa.eu/attributes/legalperson/representative/D-2012-17-EUIdentifier</entry>
+ <entry key="32.FriendlyName">RepresentativeD-2012-17-EUIdentifier</entry>
+ <entry key="32.PersonType">RepresentativeLegalPerson</entry>
+ <entry key="32.Required">false</entry>
+ <entry key="32.XmlType.NamespaceUri">http://eidas.europa.eu/attributes/legalperson/representative</entry>
+ <entry key="32.XmlType.LocalPart">D-2012-17-EUIdentifierType</entry>
+ <entry key="32.XmlType.NamespacePrefix">eidas-reprentative-legal</entry>
+ <entry key="32.AttributeValueMarshaller">eu.eidas.auth.commons.attribute.impl.LiteralStringAttributeValueMarshaller</entry>
+
+ <entry key="33.NameUri">http://eidas.europa.eu/attributes/legalperson/representative/LEI</entry>
+ <entry key="33.FriendlyName">RepresentativeLEI</entry>
+ <entry key="33.PersonType">RepresentativeLegalPerson</entry>
+ <entry key="33.Required">false</entry>
+ <entry key="33.XmlType.NamespaceUri">http://eidas.europa.eu/attributes/legalperson/representative</entry>
+ <entry key="33.XmlType.LocalPart">LEIType</entry>
+ <entry key="33.XmlType.NamespacePrefix">eidas-reprentative-legal</entry>
+ <entry key="33.AttributeValueMarshaller">eu.eidas.auth.commons.attribute.impl.LiteralStringAttributeValueMarshaller</entry>
+
+ <entry key="34.NameUri">http://eidas.europa.eu/attributes/legalperson/representative/EORI</entry>
+ <entry key="34.FriendlyName">RepresentativeEORI</entry>
+ <entry key="34.PersonType">RepresentativeLegalPerson</entry>
+ <entry key="34.Required">false</entry>
+ <entry key="34.XmlType.NamespaceUri">http://eidas.europa.eu/attributes/legalperson/representative</entry>
+ <entry key="34.XmlType.LocalPart">EORIType</entry>
+ <entry key="34.XmlType.NamespacePrefix">eidas-reprentative-legal</entry>
+ <entry key="34.AttributeValueMarshaller">eu.eidas.auth.commons.attribute.impl.LiteralStringAttributeValueMarshaller</entry>
+
+ <entry key="35.NameUri">http://eidas.europa.eu/attributes/legalperson/representative/SEED</entry>
+ <entry key="35.FriendlyName">RepresentativeSEED</entry>
+ <entry key="35.PersonType">RepresentativeLegalPerson</entry>
+ <entry key="35.Required">false</entry>
+ <entry key="35.XmlType.NamespaceUri">http://eidas.europa.eu/attributes/legalperson/representative</entry>
+ <entry key="35.XmlType.LocalPart">SEEDType</entry>
+ <entry key="35.XmlType.NamespacePrefix">eidas-reprentative-legal</entry>
+ <entry key="35.AttributeValueMarshaller">eu.eidas.auth.commons.attribute.impl.LiteralStringAttributeValueMarshaller</entry>
+
+ <entry key="36.NameUri">http://eidas.europa.eu/attributes/legalperson/representative/SIC</entry>
+ <entry key="36.FriendlyName">RepresentativeSIC</entry>
+ <entry key="36.PersonType">RepresentativeLegalPerson</entry>
+ <entry key="36.Required">false</entry>
+ <entry key="36.XmlType.NamespaceUri">http://eidas.europa.eu/attributes/legalperson/representative</entry>
+ <entry key="36.XmlType.LocalPart">SICType</entry>
+ <entry key="36.XmlType.NamespacePrefix">eidas-reprentative-legal</entry>
+ <entry key="36.AttributeValueMarshaller">eu.eidas.auth.commons.attribute.impl.LiteralStringAttributeValueMarshaller</entry>
+
+ <entry key="39.NameUri">http://eidas.europa.eu/attributes/legalperson/representative/LegalPersonAddress</entry>
+ <entry key="39.FriendlyName">RepresentativeLegalAddress</entry>
+ <entry key="39.PersonType">RepresentativeLegalPerson</entry>
+ <entry key="39.Required">false</entry>
+ <entry key="39.XmlType.NamespaceUri">http://eidas.europa.eu/attributes/legalperson/representative</entry>
+ <entry key="39.XmlType.LocalPart">LegalPersonAddressType</entry>
+ <entry key="39.XmlType.NamespacePrefix">eidas-reprentative-legal</entry>
+ <entry key="39.AttributeValueMarshaller">eu.eidas.auth.commons.protocol.eidas.impl.RepvLegalAddressAttributeValueMarshaller</entry>
+
+ <entry key="40.NameUri">http://eidas.europa.eu/attributes/legalperson/representative/VATRegistrationNumber</entry>
+ <entry key="40.FriendlyName">RepresentativeVATRegistration</entry>
+ <entry key="40.PersonType">RepresentativeLegalPerson</entry>
+ <entry key="40.Required">false</entry>
+ <entry key="40.XmlType.NamespaceUri">http://eidas.europa.eu/attributes/legalperson/representative</entry>
+ <entry key="40.XmlType.LocalPart">VATRegistrationNumberType</entry>
+ <entry key="40.XmlType.NamespacePrefix">eidas-reprentative-legal</entry>
+ <entry key="40.AttributeValueMarshaller">eu.eidas.auth.commons.attribute.impl.LiteralStringAttributeValueMarshaller</entry>
+
+
+</properties>
diff --git a/modules/eidas_proxy-sevice/src/test/resources/config/idaAttributeMapping.json b/modules/eidas_proxy-sevice/src/test/resources/config/idaAttributeMapping.json
new file mode 100644
index 00000000..7e41d8f6
--- /dev/null
+++ b/modules/eidas_proxy-sevice/src/test/resources/config/idaAttributeMapping.json
@@ -0,0 +1,183 @@
+[
+ {
+ "eidasAttribute": "http://eidas.europa.eu/attributes/naturalperson/PersonIdentifier",
+ "idaAttribute": {
+ "basic": "urn:oid:1.2.40.0.10.2.1.1.149",
+ "withMandates": "urn:oid:1.2.40.0.10.2.1.1.261.98"
+ },
+ "type": {
+ "mds": true,
+ "autoIncludeWithMandates": false
+ }
+ },
+ {
+ "eidasAttribute": "http://eidas.europa.eu/attributes/naturalperson/CurrentGivenName",
+ "idaAttribute": {
+ "basic": "urn:oid:2.5.4.42",
+ "withMandates": "urn:oid:1.2.40.0.10.2.1.1.261.78"
+ },
+ "type": {
+ "mds": true,
+ "autoIncludeWithMandates": false
+ }
+ },
+ {
+ "eidasAttribute": "http://eidas.europa.eu/attributes/naturalperson/CurrentFamilyName",
+ "idaAttribute": {
+ "basic": "urn:oid:1.2.40.0.10.2.1.1.261.20",
+ "withMandates": "urn:oid:1.2.40.0.10.2.1.1.261.80"
+ },
+ "type": {
+ "mds": true,
+ "autoIncludeWithMandates": false
+ }
+ },
+ {
+ "eidasAttribute": "http://eidas.europa.eu/attributes/naturalperson/DateOfBirth",
+ "idaAttribute": {
+ "basic": "urn:oid:1.2.40.0.10.2.1.1.55",
+ "withMandates": "urn:oid:1.2.40.0.10.2.1.1.261.82"
+ },
+ "type": {
+ "mds": true,
+ "autoIncludeWithMandates": false
+ }
+ },
+ {
+ "eidasAttribute": "http://eidas.europa.eu/attributes/naturalperson/PlaceOfBirth",
+ "idaAttribute": {},
+ "type": {
+ "mds": false,
+ "autoIncludeWithMandates": false
+ }
+ },
+ {
+ "eidasAttribute": "http://eidas.europa.eu/attributes/naturalperson/BirthName",
+ "idaAttribute": {
+ "basic": "ida_birthname",
+ "withMandates": "ida_birthName_mandator"
+ },
+ "type": {
+ "mds": false,
+ "autoIncludeWithMandates": false
+ }
+ },
+ {
+ "eidasAttribute": "http://eidas.europa.eu/attributes/legalperson/LegalPersonIdentifier",
+ "idaAttribute": {
+ "withMandates": "urn:oid:1.2.40.0.10.2.1.1.261.100"
+ },
+ "addionalRequiredAttributes" : [
+ "urn:oid:1.2.40.0.10.2.1.1.149",
+ "urn:oid:2.5.4.42",
+ "urn:oid:1.2.40.0.10.2.1.1.261.20",
+ "urn:oid:1.2.40.0.10.2.1.1.55"
+ ],
+ "type": {
+ "mds": true,
+ "autoIncludeWithMandates": false
+ }
+ },
+ {
+ "eidasAttribute": "http://eidas.europa.eu/attributes/legalperson/LegalName",
+ "idaAttribute": {
+ "withMandates": "urn:oid:1.2.40.0.10.2.1.1.261.84"
+ },
+ "type": {
+ "mds": true,
+ "autoIncludeWithMandates": false
+ }
+ },
+ {
+ "eidasAttribute": "http://eidas.europa.eu/attributes/naturalperson/representative/PersonIdentifier",
+ "idaAttribute": {
+ "withMandates": "urn:oid:1.2.40.0.10.2.1.1.149"
+ },
+ "type": {
+ "mds": true,
+ "autoIncludeWithMandates": true
+ }
+ },
+ {
+ "eidasAttribute": "http://eidas.europa.eu/attributes/naturalperson/representative/CurrentFamilyName",
+ "idaAttribute": {
+ "withMandates": "urn:oid:1.2.40.0.10.2.1.1.261.20"
+ },
+ "type": {
+ "mds": true,
+ "autoIncludeWithMandates": true
+ }
+ },
+ {
+ "eidasAttribute": "http://eidas.europa.eu/attributes/naturalperson/representative/CurrentGivenName",
+ "idaAttribute": {
+ "withMandates": "urn:oid:2.5.4.42"
+ },
+ "type": {
+ "mds": true,
+ "autoIncludeWithMandates": true
+ }
+ },
+ {
+ "eidasAttribute": "http://eidas.europa.eu/attributes/naturalperson/representative/DateOfBirth",
+ "idaAttribute": {
+ "withMandates": "urn:oid:1.2.40.0.10.2.1.1.55"
+ },
+ "type": {
+ "mds": true,
+ "autoIncludeWithMandates": true
+ }
+ },
+ {
+ "eidasAttribute": "*",
+ "idaAttribute": {
+ "basic": "urn:oid:1.2.40.0.10.2.1.1.261.32",
+ "withMandates": "urn:oid:1.2.40.0.10.2.1.1.261.32"
+ },
+ "type": {
+ "mds": false,
+ "autoIncludeWithMandates": false
+ }
+ },
+ {
+ "eidasAttribute": "*",
+ "idaAttribute": {
+ "basic": "urn:oid:1.2.40.0.10.2.1.1.261.108",
+ "withMandates": "urn:oid:1.2.40.0.10.2.1.1.261.108"
+ },
+ "type": {
+ "mds": false,
+ "autoIncludeWithMandates": false
+ }
+ },
+ {
+ "eidasAttribute": "*",
+ "idaAttribute": {
+ "withMandates": "urn:oid:1.2.40.0.10.2.1.1.261.68"
+ },
+ "type": {
+ "mds": false,
+ "autoIncludeWithMandates": false
+ }
+ },
+ {
+ "eidasAttribute": "*",
+ "idaAttribute": {
+ "withMandates": "urn:oid:1.2.40.0.10.2.1.1.261.106"
+ },
+ "type": {
+ "mds": false,
+ "autoIncludeWithMandates": false
+ }
+ },
+ {
+ "eidasAttribute": "http://eidas.europa.eu/attributes/jUnit/not/exits",
+ "idaAttribute": {
+ "withMandates": "urn:oid:1.2.40.0.10.2.1.1.261.106"
+ },
+ "type": {
+ "mds": false,
+ "autoIncludeWithMandates": false
+ }
+ }
+] \ No newline at end of file
diff --git a/modules/eidas_proxy-sevice/src/test/resources/config/junit_config_1.properties b/modules/eidas_proxy-sevice/src/test/resources/config/junit_config_1.properties
new file mode 100644
index 00000000..bd4575c3
--- /dev/null
+++ b/modules/eidas_proxy-sevice/src/test/resources/config/junit_config_1.properties
@@ -0,0 +1,8 @@
+## Basic service configuration
+eidas.ms.context.url.prefix=http://localhost
+eidas.ms.context.url.request.validation=false
+
+eidas.ms.auth.eIDAS.node_v2.proxy.entityId=ownSpecificProxy
+eidas.ms.auth.eIDAS.node_v2.proxy.forward.endpoint=http://eidas.proxy/endpoint
+
+eidas.ms.auth.eIDAS.proxy.attribute.mapping.config=idaAttributeMapping.json \ No newline at end of file
diff --git a/modules/eidas_proxy-sevice/src/test/resources/spring/SpringTest-context_basic_mapConfig.xml b/modules/eidas_proxy-sevice/src/test/resources/spring/SpringTest-context_basic_mapConfig.xml
new file mode 100644
index 00000000..fe9ff441
--- /dev/null
+++ b/modules/eidas_proxy-sevice/src/test/resources/spring/SpringTest-context_basic_mapConfig.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<beans xmlns="http://www.springframework.org/schema/beans"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xmlns:context="http://www.springframework.org/schema/context"
+ xmlns:tx="http://www.springframework.org/schema/tx"
+ xmlns:aop="http://www.springframework.org/schema/aop"
+ xsi:schemaLocation="http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.1.xsd
+ http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
+ http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.1.xsd
+ http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd">
+
+ <context:annotation-config />
+
+ <bean id="dummyMapBasedConfiguration"
+ class="at.asitplus.eidas.specific.core.test.config.dummy.MsConnectorDummyConfigMap">
+ <constructor-arg value="/config/junit_config_1.properties" />
+ <property name="configRootDirSufix" value="src/test/resources/config" />
+ </bean>
+
+</beans> \ No newline at end of file
diff --git a/modules/eidas_proxy-sevice/src/test/resources/spring/SpringTest-context_basic_test.xml b/modules/eidas_proxy-sevice/src/test/resources/spring/SpringTest-context_basic_test.xml
new file mode 100644
index 00000000..0b7540f5
--- /dev/null
+++ b/modules/eidas_proxy-sevice/src/test/resources/spring/SpringTest-context_basic_test.xml
@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<beans xmlns="http://www.springframework.org/schema/beans"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xmlns:context="http://www.springframework.org/schema/context"
+ xmlns:tx="http://www.springframework.org/schema/tx"
+ xmlns:aop="http://www.springframework.org/schema/aop"
+ xsi:schemaLocation="http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.1.xsd
+ http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
+ http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.1.xsd
+ http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd">
+
+
+ <import resource="classpath:/SpringTest-context_authManager.xml" />
+ <import resource="classpath:/spring/eidas_proxy-service.beans.xml"/>
+
+ <bean id="springManagedSpecificProxyserviceCommunicationService"
+ class="at.asitplus.eidas.specific.modules.core.eidas.test.dummy.DummySpecificCommunicationService" />
+
+ <bean id="mvcGUIBuilderImpl"
+ class="at.gv.egiz.eaaf.core.impl.gui.builder.SpringMvcGuiFormBuilderImpl" />
+
+ <bean id="specificConnectorAttributesFileWithPath"
+ class="java.lang.String">
+ <constructor-arg
+ value="src/test/resources/config/eidas-attributes.xml" />
+ </bean>
+
+ <bean id="specificConnectorAdditionalAttributesFileWithPath"
+ class="java.lang.String">
+ <constructor-arg
+ value="src/test/resources/config/additional-attributes.xml" />
+ </bean>
+
+</beans> \ No newline at end of file