features parameter will have their default
+ * values.
+ * @return returns SZR
+ */
+ @WebEndpoint(name = "SZRProduktionsumgebung")
+ public SZR getSzrProduktionsumgebung(WebServiceFeature... features) {
+ return super.getPort(SZRProduktionsumgebung, SZR.class, features);
+ }
+
+ /**
+ *Get SZR Web-Service.
+ *
+ * @return returns SZR
+ */
+ @WebEndpoint(name = "SZRTestumgebung")
+ public SZR getSzrTestumgebung() {
+ return super.getPort(SZRTestumgebung, SZR.class);
+ }
+
+ /**
+ * Get SZR Web-Service.
+ *
+ * @param features A list of {@link javax.xml.ws.WebServiceFeature} to configure
+ * on the proxy. Supported features not in the
+ * features parameter will have their default
+ * values.
+ * @return returns SZR
+ */
+ @WebEndpoint(name = "SZRTestumgebung")
+ public SZR getSzrTestumgebung(WebServiceFeature... features) {
+ return super.getPort(SZRTestumgebung, SZR.class, features);
+ }
+
+ /**
+ * Get SZR Web-Service.
+ *
+ * @return returns SZR
+ */
+ @WebEndpoint(name = "SZRBusinesspartnerTestumgebung")
+ public SZR getSzrBusinesspartnerTestumgebung() {
+ return super.getPort(SZRBusinesspartnerTestumgebung, SZR.class);
+ }
+
+ /**
+ * Get SZR Web-Service.
+ *
+ * @param features A list of {@link javax.xml.ws.WebServiceFeature} to configure
+ * on the proxy. Supported features not in the
+ * features parameter will have their default
+ * values.
+ * @return returns SZR
+ */
+ @WebEndpoint(name = "SZRBusinesspartnerTestumgebung")
+ public SZR getSzrBusinesspartnerTestumgebung(WebServiceFeature... features) {
+ return super.getPort(SZRBusinesspartnerTestumgebung, SZR.class, features);
+ }
+
+}
diff --git a/modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/tasks/CreateIdentityLinkTask.java b/modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/tasks/CreateIdentityLinkTask.java
new file mode 100644
index 00000000..6b1b96de
--- /dev/null
+++ b/modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/tasks/CreateIdentityLinkTask.java
@@ -0,0 +1,503 @@
+/*
+ * Copyright 2018 A-SIT Plus GmbH
+ * AT-specific eIDAS Connector has been developed in a cooperation between EGIZ,
+ * A-SIT Plus GmbH, A-SIT, and Graz University of Technology.
+ *
+ * Licensed under the EUPL, Version 1.2 or - as soon they will be approved by
+ * the European Commission - subsequent versions of the EUPL (the "License");
+ * You may not use this work except in compliance with the License.
+ * You may obtain a copy of the License at:
+ * https://joinup.ec.europa.eu/news/understanding-eupl-v12
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * This product combines work with different licenses. See the "NOTICE" text
+ * file for details on the various modules and licenses.
+ * The "NOTICE" text file is part of the distribution. Any derivative works
+ * that you distribute must include a readable copy of the "NOTICE" text file.
+ */
+
+package at.asitplus.eidas.specific.modules.auth.eidas.v2.tasks;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import javax.xml.parsers.ParserConfigurationException;
+
+import org.apache.commons.lang3.StringUtils;
+import org.joda.time.DateTime;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+import org.w3c.dom.Element;
+import org.w3c.dom.Node;
+import org.xml.sax.SAXException;
+
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.ImmutableSet;
+
+import at.asitplus.eidas.specific.core.MsConnectorEventCodes;
+import at.asitplus.eidas.specific.core.MsEidasNodeConstants;
+import at.asitplus.eidas.specific.modules.auth.eidas.v2.Constants;
+import at.asitplus.eidas.specific.modules.auth.eidas.v2.dao.ErnbEidData;
+import at.asitplus.eidas.specific.modules.auth.eidas.v2.exception.EidasAttributeException;
+import at.asitplus.eidas.specific.modules.auth.eidas.v2.exception.SzrCommunicationException;
+import at.asitplus.eidas.specific.modules.auth.eidas.v2.service.AuthBlockSigningService;
+import at.asitplus.eidas.specific.modules.auth.eidas.v2.service.ICcSpecificEidProcessingService;
+import at.asitplus.eidas.specific.modules.auth.eidas.v2.szr.SzrClient;
+import at.asitplus.eidas.specific.modules.auth.eidas.v2.utils.EidasResponseUtils;
+import at.gv.e_government.reference.namespace.persondata._20020228.AlternativeNameType;
+import at.gv.e_government.reference.namespace.persondata._20020228.PersonNameType;
+import at.gv.e_government.reference.namespace.persondata._20020228.PhysicalPersonType;
+import at.gv.egiz.eaaf.core.api.data.EaafConstants;
+import at.gv.egiz.eaaf.core.api.data.PvpAttributeDefinitions;
+import at.gv.egiz.eaaf.core.api.idp.IConfiguration;
+import at.gv.egiz.eaaf.core.api.idp.auth.data.IIdentityLink;
+import at.gv.egiz.eaaf.core.api.idp.process.ExecutionContext;
+import at.gv.egiz.eaaf.core.exceptions.EaafException;
+import at.gv.egiz.eaaf.core.exceptions.TaskExecutionException;
+import at.gv.egiz.eaaf.core.impl.builder.BpkBuilder;
+import at.gv.egiz.eaaf.core.impl.data.Pair;
+import at.gv.egiz.eaaf.core.impl.idp.auth.data.AuthProcessDataWrapper;
+import at.gv.egiz.eaaf.core.impl.idp.auth.data.SimpleIdentityLinkAssertionParser;
+import at.gv.egiz.eaaf.core.impl.idp.auth.modules.AbstractAuthServletTask;
+import at.gv.egiz.eaaf.core.impl.utils.DomUtils;
+import at.gv.egiz.eaaf.core.impl.utils.XPathUtils;
+import eu.eidas.auth.commons.attribute.AttributeDefinition;
+import eu.eidas.auth.commons.attribute.AttributeValue;
+import eu.eidas.auth.commons.light.ILightResponse;
+import eu.eidas.auth.commons.protocol.eidas.impl.PostalAddress;
+import lombok.Data;
+import lombok.extern.slf4j.Slf4j;
+import szrservices.IdentityLinkType;
+import szrservices.PersonInfoType;
+import szrservices.TravelDocumentType;
+
+/**
+ * Task that creates the IdentityLink for an eIDAS authenticated person.
+ *
+ * @author tlenz
+ */
+@Slf4j
+@Component("CreateIdentityLinkTask")
+public class CreateIdentityLinkTask extends AbstractAuthServletTask {
+
+ @Autowired
+ private IConfiguration basicConfig;
+ @Autowired
+ private SzrClient szrClient;
+ @Autowired
+ private ICcSpecificEidProcessingService eidPostProcessor;
+
+ @Autowired
+ private AuthBlockSigningService authBlockSigner;
+
+ private static final String EID_STATUS = "urn:eidgvat:eid.status.eidas";
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see at.gv.egovernment.moa.id.process.springweb.MoaIdTask#execute(at.gv.
+ * egovernment.moa.id.process.api.ExecutionContext,
+ * javax.servlet.http.HttpServletRequest,
+ * javax.servlet.http.HttpServletResponse)
+ */
+ @Override
+ public void execute(ExecutionContext executionContext, HttpServletRequest request, HttpServletResponse response)
+ throws TaskExecutionException {
+ try {
+ final AuthProcessDataWrapper authProcessData = pendingReq.getSessionData(AuthProcessDataWrapper.class);
+ final ILightResponse eidasResponse = authProcessData
+ .getGenericDataFromSession(Constants.DATA_FULL_EIDAS_RESPONSE, ILightResponse.class);
+
+ final Map+ * Use {@link AlgorithmIdentifiers.RSA_PSS_USING_SHA256} in case + * of a RSA based key and + * {@link AlgorithmIdentifiers.ECDSA_USING_P256_CURVE_AND_SHA256} + * in case of an ECC based key. + *
+ * + * @param keyStore KeyStore that should be used + * @param keyAlias Alias of the private key + * @param keyPassword Password to access the key + * @param payLoad PayLoad to sign + * @param addFullCertChain If true the full certificate chain will be + * added, otherwise only the + * X509CertSha256Fingerprint is added into JOSE + * header + * @param friendlyNameForLogging FriendlyName for the used KeyStore for logging + * purposes only + * @return Signed PayLoad in serialized form + * @throws EaafException In case of a key-access or key-usage error + * @throws JoseException In case of a JOSE error + */ + public static String createSignature(@Nonnull Pair+ * Use {@link AlgorithmIdentifiers.RSA_PSS_USING_SHA256} in case + * of a RSA based key and + * {@link AlgorithmIdentifiers.ECDSA_USING_P256_CURVE_AND_SHA256} + * in case of an ECC based key. + *
+ * + * @param keyStore KeyStore that should be used + * @param keyAlias Alias of the private key + * @param keyPassword Password to access the key + * @param payLoad PayLoad to sign + * @param addFullCertChain If true the full certificate chain will be + * added, otherwise only the + * X509CertSha256Fingerprint is added into JOSE + * header + * @param joseHeaders HeaderName and HeaderValue that should be set + * into JOSE header + * @param friendlyNameForLogging FriendlyName for the used KeyStore for logging + * purposes only + * @return Signed PayLoad in serialized form + * @throws EaafException In case of a key-access or key-usage error + * @throws JoseException In case of a JOSE error + */ + public static String createSignature(@Nonnull Pairtrue if mandate was used, otherwise false
+ */
+ private boolean checkIfMandateInformationIsAvailable(AssertionAttributeExtractor extractor) {
+ boolean isMandateIncluded = extractor.containsAttribute(PvpAttributeDefinitions.MANDATE_TYPE_NAME);
+ log.debug("Response from ID-Austria system contains mandate information. Switch to mandate-mode ... ");
+ return isMandateIncluded;
+
+ }
+
+ private void validateResponseAttributes(AssertionAttributeExtractor extractor)
+ throws EaafAuthenticationException {
+ final String bpkTarget = extractor.getSingleAttributeValue(
+ PvpAttributeDefinitions.EID_SECTOR_FOR_IDENTIFIER_NAME);
+ final String spTarget = pendingReq.getServiceProviderConfiguration().getAreaSpecificTargetIdentifier();
+ if (StringUtils.isNotEmpty(bpkTarget) && bpkTarget.equals(spTarget)) {
+ log.debug("Find attr: {} that matches to requested bPK target. bPK should be valid",
+ PvpAttributeDefinitions.EID_SECTOR_FOR_IDENTIFIER_FRIENDLY_NAME);
+
+ } else {
+ log.trace("Find not attr: {}. Validation bPK attribute ... ",
+ PvpAttributeDefinitions.EID_SECTOR_FOR_IDENTIFIER_FRIENDLY_NAME);
+ final String bpk = extractor.getSingleAttributeValue(PvpAttributeDefinitions.BPK_NAME);
+ final String[] split = bpk.split(":", 2);
+ if (split.length == 2) {
+ if (!spTarget.endsWith(split[0])) {
+ log.error("bPK from response: {} does not match to SP target: {}", bpk, spTarget);
+ throw new EaafAuthenticationException(IdAustriaAuthConstants.ERRORTYPE_06, null);
+
+ } else {
+ log.trace("Prefix of PVP bPK attribte matches to SP configuration. bPK looks valid");
+
+ }
+
+ } else {
+ log.warn("Find suspect bPK that has no prefix. Use it as it is ... ");
+
+ }
+ }
+ }
+
+ private void injectAuthInfosIntoSession(AuthProcessDataWrapper session,
+ String attrName, String attrValue) throws EaafStorageException, IOException {
+ log.trace("Inject attribute: {} with value: {} into AuthSession", attrName, attrValue);
+ log.debug("Inject attribute: {} into AuthSession", attrName);
+ if (PvpAttributeDefinitions.BPK_NAME.equals(attrName)) {
+ log.trace("Find bPK attribute. Extract eIDAS identifier ... ");
+ session.setGenericDataToSession(MsEidasNodeConstants.ATTR_EIDAS_PERSONAL_IDENTIFIER,
+ extractBpkFromResponse(attrValue));
+
+ } else {
+ session.setGenericDataToSession(attrName, attrValue);
+
+ }
+
+ }
+
+ private String extractBpkFromResponse(String pvpBpkAttrValue) {
+ final String[] split = pvpBpkAttrValue.split(":", 2);
+ if (split.length == 2) {
+ return split[1];
+
+ } else {
+ log.warn("PVP bPK attribute: {} has wrong format. Use it as it is.", pvpBpkAttrValue);
+ return pvpBpkAttrValue;
+
+ }
+ }
+
+ private Pairnull.
+ *
+ * @param samlResp SAML2 response
+ * @return Sub-StatusCode or null if it's not set
+ */
+ private StatusCode getSubStatusCode(Response samlResp) {
+ if (samlResp.getStatus().getStatusCode().getStatusCode() != null
+ && StringUtils.isNotEmpty(samlResp.getStatus().getStatusCode().getStatusCode().getValue())) {
+ return samlResp.getStatus().getStatusCode().getStatusCode();
+
+ }
+ return null;
+
+ }
+
+}
diff --git a/modules/authmodule_id-austria/src/main/java/at/asitplus/eidas/specific/modules/auth/idaustria/tasks/RequestIdAustriaSystemTask.java b/modules/authmodule_id-austria/src/main/java/at/asitplus/eidas/specific/modules/auth/idaustria/tasks/RequestIdAustriaSystemTask.java
new file mode 100644
index 00000000..66aadde6
--- /dev/null
+++ b/modules/authmodule_id-austria/src/main/java/at/asitplus/eidas/specific/modules/auth/idaustria/tasks/RequestIdAustriaSystemTask.java
@@ -0,0 +1,205 @@
+package at.asitplus.eidas.specific.modules.auth.idaustria.tasks;
+
+import java.security.NoSuchAlgorithmException;
+import java.text.MessageFormat;
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.apache.commons.lang3.StringUtils;
+import org.opensaml.messaging.encoder.MessageEncodingException;
+import org.opensaml.saml.saml2.core.Attribute;
+import org.opensaml.saml.saml2.metadata.EntityDescriptor;
+import org.springframework.beans.factory.annotation.Autowired;
+
+import at.asitplus.eidas.specific.core.config.ServiceProviderConfiguration;
+import at.asitplus.eidas.specific.modules.auth.idaustria.IdAustriaAuthConstants;
+import at.asitplus.eidas.specific.modules.auth.idaustria.config.IdAustriaAuthRequestBuilderConfiguration;
+import at.asitplus.eidas.specific.modules.auth.idaustria.utils.IdAustriaAuthCredentialProvider;
+import at.asitplus.eidas.specific.modules.auth.idaustria.utils.IdAustriaAuthMetadataProvider;
+import at.asitplus.eidas.specific.modules.auth.idaustria.utils.Utils;
+import at.asitplus.eidas.specific.modules.msproxyservice.protocol.ProxyServicePendingRequest;
+import at.gv.egiz.eaaf.core.api.IRequest;
+import at.gv.egiz.eaaf.core.api.data.ExtendedPvpAttributeDefinitions;
+import at.gv.egiz.eaaf.core.api.data.PvpAttributeDefinitions;
+import at.gv.egiz.eaaf.core.api.idp.process.ExecutionContext;
+import at.gv.egiz.eaaf.core.api.storage.ITransactionStorage;
+import at.gv.egiz.eaaf.core.exceptions.EaafConfigurationException;
+import at.gv.egiz.eaaf.core.exceptions.EaafException;
+import at.gv.egiz.eaaf.core.exceptions.TaskExecutionException;
+import at.gv.egiz.eaaf.core.impl.idp.auth.modules.AbstractAuthServletTask;
+import at.gv.egiz.eaaf.core.impl.utils.Random;
+import at.gv.egiz.eaaf.modules.pvp2.api.reqattr.EaafRequestedAttribute;
+import at.gv.egiz.eaaf.modules.pvp2.impl.builder.PvpAttributeBuilder;
+import at.gv.egiz.eaaf.modules.pvp2.impl.utils.Saml2Utils;
+import at.gv.egiz.eaaf.modules.pvp2.sp.exception.AuthnRequestBuildException;
+import at.gv.egiz.eaaf.modules.pvp2.sp.impl.PvpAuthnRequestBuilder;
+import lombok.extern.slf4j.Slf4j;
+import net.shibboleth.utilities.java.support.resolver.ResolverException;
+import net.shibboleth.utilities.java.support.security.impl.SecureRandomIdentifierGenerationStrategy;
+
+/**
+ * eIDAS Authentication task that generates PVP2 S-Profile request to central
+ * Austrian MS-Connector.
+ *
+ * @author tlenz
+ *
+ */
+@Slf4j
+public class RequestIdAustriaSystemTask extends AbstractAuthServletTask {
+
+ private static final String ERROR_PVP_02 = "sp.pvp2.02";
+ private static final String ERROR_PVP_13 = "sp.pvp2.13";
+
+ private static final String ERROR_MSG_1 =
+ "Requested 'ms-specific eIDAS node' {0} has no valid metadata or metadata is not found";
+ private static final String ERROR_MSG_4 =
+ "Build PVP2.1 AuthnRequest to connect 'ms-specific eIDAS node' FAILED.";
+
+ @Autowired PvpAuthnRequestBuilder authnReqBuilder;
+ @Autowired IdAustriaAuthCredentialProvider credential;
+ @Autowired IdAustriaAuthMetadataProvider metadataService;
+ @Autowired ITransactionStorage transactionStorage;
+
+ @Override
+ public void execute(ExecutionContext executionContext, HttpServletRequest request,
+ HttpServletResponse response)
+ throws TaskExecutionException {
+ try {
+ //revisionsLogger.logEvent(pendingReq, EidasAuthEventConstants.AUTHPROCESS_EIDAS_AT_CONNECTOR_SELECTED);
+
+ // get entityID for central ID Austria system
+ final String idAustriaEntityID =
+ Utils.getIdAustriaEntityId(pendingReq.getServiceProviderConfiguration(), authConfig);
+ if (StringUtils.isEmpty(idAustriaEntityID)) {
+ log.info("ID Austria authentication not possible -> NO EntityID for central central ID Austria System FOUND!");
+ throw new EaafConfigurationException(IdAustriaAuthConstants.ERRORTYPE_00,
+ new Object[] { IdAustriaAuthConstants.CONFIG_PROPS_IDAUSTRIA_ENTITYID });
+
+ }
+
+ // load IDP SAML2 entitydescriptor
+ final EntityDescriptor entityDesc = metadataService.getEntityDescriptor(idAustriaEntityID);
+ if (entityDesc == null) {
+ throw new EaafConfigurationException(IdAustriaAuthConstants.ERRORTYPE_05,
+ new Object[] { MessageFormat.format(ERROR_MSG_1, idAustriaEntityID) });
+
+ }
+
+ // setup AuthnRequestBuilder configuration
+ final IdAustriaAuthRequestBuilderConfiguration authnReqConfig =
+ new IdAustriaAuthRequestBuilderConfiguration();
+ final SecureRandomIdentifierGenerationStrategy gen =
+ new SecureRandomIdentifierGenerationStrategy();
+
+ // set basic infos
+ authnReqConfig.setRequestId(gen.generateIdentifier());
+ authnReqConfig.setIdpEntity(entityDesc);
+ authnReqConfig.setPassive(false);
+ authnReqConfig.setSignCred(credential.getMessageSigningCredential());
+ authnReqConfig.setSpEntityID(pendingReq.getAuthUrl() + IdAustriaAuthConstants.ENDPOINT_METADATA);
+
+ // set eIDAS Proxy-Service specific information for ID Austria system
+ authnReqConfig.setRequestedAttributes(buildRequestedAttributes(pendingReq));
+
+
+ /*build relayState for session synchronization, because SAML2 only allows RelayState with 80 characters
+ * but encrypted PendingRequestId is much longer.
+ */
+ String relayState = Random.nextProcessReferenceValue();
+ transactionStorage.put(relayState, pendingReq.getPendingRequestId(), -1);
+
+ // build and transmit AuthnRequest
+ authnReqBuilder.buildAuthnRequest(pendingReq, authnReqConfig, relayState, response);
+
+ //revisionsLogger.logEvent(pendingReq,
+ // EidasAuthEventConstants.AUTHPROCESS_EIDAS_AT_CONNECTOR_REQUESTED,
+ // authnReqConfig.getRequestID());
+
+ } catch (final EaafException e) {
+ throw new TaskExecutionException(pendingReq, e.getMessage(), e);
+
+ } catch (final ResolverException e) {
+ throw new TaskExecutionException(pendingReq,
+ ERROR_MSG_4,
+ new AuthnRequestBuildException(ERROR_PVP_02,
+ new Object[] { IdAustriaAuthConstants.MODULE_NAME_FOR_LOGGING }, e));
+
+ } catch (MessageEncodingException | NoSuchAlgorithmException | SecurityException e) {
+ throw new TaskExecutionException(pendingReq,
+ e.getMessage(),
+ new AuthnRequestBuildException(ERROR_PVP_13,
+ new Object[] { IdAustriaAuthConstants.MODULE_NAME_FOR_LOGGING }, e));
+
+ } catch (final Exception e) {
+ throw new TaskExecutionException(pendingReq, e.getMessage(), e);
+
+ }
+ }
+
+ private String selectHighestLoa(Listnull if no EntityId was found in configuration
+ */
+ @Nullable
+ public static String getIdAustriaEntityId(
+ ISpConfiguration spConfiguration, IConfiguration authConfig) {
+ // load from service-provider configuration
+ String msNodeEntityID = spConfiguration.getConfigurationValue(
+ IdAustriaAuthConstants.CONFIG_PROPS_APPSPECIFIC_IDAUSTRIA_NODE_URL);
+
+ if (StringUtils.isEmpty(msNodeEntityID)) {
+ msNodeEntityID = authConfig.getBasicConfiguration(
+ IdAustriaAuthConstants.CONFIG_PROPS_IDAUSTRIA_ENTITYID);
+
+ }
+
+ return msNodeEntityID;
+ }
+
+ private Utils() {
+ //hide constructor of private class
+
+ }
+
+}
diff --git a/modules/authmodule_id-austria/src/main/resources/META-INF/services/at.gv.egiz.components.spring.api.SpringResourceProvider b/modules/authmodule_id-austria/src/main/resources/META-INF/services/at.gv.egiz.components.spring.api.SpringResourceProvider
new file mode 100644
index 00000000..6bf41f6f
--- /dev/null
+++ b/modules/authmodule_id-austria/src/main/resources/META-INF/services/at.gv.egiz.components.spring.api.SpringResourceProvider
@@ -0,0 +1 @@
+at.asitplus.eidas.specific.modules.auth.idaustria.IdAustriaAuthenticationSpringResourceProvider
\ No newline at end of file
diff --git a/modules/authmodule_id-austria/src/main/resources/META-INF/services/at.gv.egiz.eaaf.core.api.idp.IAttributeBuilder b/modules/authmodule_id-austria/src/main/resources/META-INF/services/at.gv.egiz.eaaf.core.api.idp.IAttributeBuilder
new file mode 100644
index 00000000..65e9482c
--- /dev/null
+++ b/modules/authmodule_id-austria/src/main/resources/META-INF/services/at.gv.egiz.eaaf.core.api.idp.IAttributeBuilder
@@ -0,0 +1 @@
+at.asitplus.eidas.specific.modules.auth.idaustria.builder.attributes.EidasConnecorUniqueIdAttributeBuilder
diff --git a/modules/authmodule_id-austria/src/main/resources/messages/idaustria_auth_messages.properties b/modules/authmodule_id-austria/src/main/resources/messages/idaustria_auth_messages.properties
new file mode 100644
index 00000000..6de6e0dc
--- /dev/null
+++ b/modules/authmodule_id-austria/src/main/resources/messages/idaustria_auth_messages.properties
@@ -0,0 +1,10 @@
+module.idaustria.00=ID Austria authentication-module has an error in configuration. Missing: {0}
+module.idaustria.01=ID Austria authentication-module has an error in configuration: {0}. Reason: {1}
+module.idaustria.02=ID Austria authentication-module has an error in configuration. Reason: {0}
+module.idaustria.03=ID Austria authentication-module has a general error during request pre-processing. Reason: {0}
+module.idaustria.04=ID Austria authentication-module has a general error during response post-processing.
+module.idaustria.05=ID Austria authentication-module can not initialize SAML2 metadata provider for entityId: {0}. Reason: {1}
+module.idaustria.06=ID Austria authentication-module receives an invalid eIDAS bPK, which does NOT match to country-code of eIDAS Proxy-Service
+
+module.idaustria.98=ID Austria authentication-module has an internal error. Reason: {0}
+module.idaustria.99=ID Austria authentication-module has an generic internal error.
\ No newline at end of file
diff --git a/modules/authmodule_id-austria/src/main/resources/process/id_austria.Authentication.process.xml b/modules/authmodule_id-austria/src/main/resources/process/id_austria.Authentication.process.xml
new file mode 100644
index 00000000..e8a83e68
--- /dev/null
+++ b/modules/authmodule_id-austria/src/main/resources/process/id_austria.Authentication.process.xml
@@ -0,0 +1,18 @@
+
+getUniqueIdentifier()
+ *
+ * @author tlenz
+ *
+ */
+@RunWith(SpringJUnit4ClassRunner.class)
+@ContextConfiguration(locations = {
+ "/spring/SpringTest-context_basic_mapConfig.xml",
+ "/spring/SpringTest-context_basic_test.xml",
+})
+public class EidasConnecorUniqueIdAttributeBuilderTest extends AbstractAttributeBuilderTest {
+
+ private final IAttributeBuilder attrBuilder = new EidasConnecorUniqueIdAttributeBuilder();
+
+ @Test
+ public void attributeName() {
+ Assert.assertEquals("Wrong attribute name",
+ "urn:eidgvat:attributes.eidas.uniqueId", attrBuilder.getName());
+
+ }
+
+ @Test
+ public void checkEmptyAttribute() {
+ String value = attrBuilder.buildEmpty(gen);
+ Assert.assertNull("Attr. not null", value);
+
+ }
+
+
+ @Test
+ public void withAttributeValue() throws AttributeBuilderException, Exception {
+ String value = attrBuilder.build(spConfig, buildAuthData(), gen);
+ Assert.assertEquals("wrong attributeValue", spConfig.getUniqueIdentifier(), value);
+
+ }
+
+}
diff --git a/modules/authmodule_id-austria/src/test/java/at/asitplus/eidas/specific/modules/auth/idaustria/test/config/IdAustriaAuthMessageSourceTest.java b/modules/authmodule_id-austria/src/test/java/at/asitplus/eidas/specific/modules/auth/idaustria/test/config/IdAustriaAuthMessageSourceTest.java
new file mode 100644
index 00000000..2a92c01e
--- /dev/null
+++ b/modules/authmodule_id-austria/src/test/java/at/asitplus/eidas/specific/modules/auth/idaustria/test/config/IdAustriaAuthMessageSourceTest.java
@@ -0,0 +1,50 @@
+package at.asitplus.eidas.specific.modules.auth.idaustria.test.config;
+
+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.auth.idaustria.config.IdAustriaAuthMessageSource;
+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 IdAustriaAuthMessageSourceTest {
+
+ @Autowired
+ private ResourceLoader loader;
+ @Autowired(required = false)
+ private ListInjection 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.
+ * + * @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"); + attributeMap.putAll(buildAttributesWithoutMandate(authData)); + + } + } + + private ImmutableAttributeMap buildAttributesWithoutMandate(IAuthData eidAuthData) { + //TODO: throw an error in case of SZR Date with month or day = "00" + return buildAttributesWithoutMandate( + eidAuthData.getGenericData(MsEidasNodeConstants.ATTR_EIDAS_PERSONAL_IDENTIFIER, String.class), + eidAuthData.getFamilyName(), + eidAuthData.getGivenName(), + eidAuthData.getDateOfBirth()); + + } + + private ImmutableAttributeMap buildAttributesWithoutMandate(String personalIdentifier, String familyName, + String givenName, String dateOfBirth) { + final AttributeDefinition> attrDefPersonalId = attrRegistry.getCoreAttributeRegistry().getByFriendlyName( + Constants.eIDAS_ATTR_PERSONALIDENTIFIER).first(); + final AttributeDefinition> attrDefFamilyName = attrRegistry.getCoreAttributeRegistry().getByFriendlyName( + Constants.eIDAS_ATTR_CURRENTFAMILYNAME).first(); + final AttributeDefinition> attrDefGivenName = attrRegistry.getCoreAttributeRegistry().getByFriendlyName( + Constants.eIDAS_ATTR_CURRENTGIVENNAME).first(); + final AttributeDefinition> attrDefDateOfBirth = attrRegistry.getCoreAttributeRegistry().getByFriendlyName( + Constants.eIDAS_ATTR_DATEOFBIRTH).first(); + + final ImmutableAttributeMap.Builder attributeMap = + ImmutableAttributeMap.builder() + .put(attrDefPersonalId, personalIdentifier) + .put(attrDefFamilyName, familyName) + .put(attrDefGivenName, givenName) + .put(attrDefDateOfBirth, dateOfBirth); + + return attributeMap.build(); + + } + + 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; + } + + 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( + MsEidasNodeConstants.ATTR_EIDAS_JUR_MANDATOR_PERSONAL_IDENTIFIER, 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/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..4cd7ba6c --- /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.auth.eidas.v2.Constants; +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. + * @returntrue if LegalPersonIdentifier is requested, otherwise falselse
+ */
+ public static boolean isLegalPersonRequested(ILightRequest eidasRequest) {
+ return eidasRequest.getRequestedAttributes().entrySet().stream()
+ .filter(el -> el.getKey().getFriendlyName().equals(Constants.eIDAS_ATTR_LEGALPERSONIDENTIFIER))
+ .findFirst()
+ .isPresent();
+
+ }
+
+ /**
+ * Check if natural person subject is requested by eIDAS Connector.
+ *
+ * @param eidasRequest Authentication request from eIDAS Connector.
+ * @return true if PersonIdentifier is requested, otherwise falselse
+ */
+ public static boolean isNaturalPersonRequested(ILightRequest eidasRequest) {
+ return eidasRequest.getRequestedAttributes().entrySet().stream()
+ .filter(el -> el.getKey().getFriendlyName().equals(Constants.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..2055b5a9
--- /dev/null
+++ b/modules/eidas_proxy-sevice/src/main/resources/spring/eidas_proxy-service.beans.xml
@@ -0,0 +1,28 @@
+
+