aboutsummaryrefslogtreecommitdiff
path: root/eidas_modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/tasks
diff options
context:
space:
mode:
Diffstat (limited to 'eidas_modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/tasks')
-rw-r--r--eidas_modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/tasks/CreateIdentityLinkTask.java406
-rw-r--r--eidas_modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/tasks/GenerateAuthnRequestTask.java288
-rw-r--r--eidas_modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/tasks/ReceiveAuthnResponseTask.java126
3 files changed, 820 insertions, 0 deletions
diff --git a/eidas_modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/tasks/CreateIdentityLinkTask.java b/eidas_modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/tasks/CreateIdentityLinkTask.java
new file mode 100644
index 00000000..8f49d57d
--- /dev/null
+++ b/eidas_modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/tasks/CreateIdentityLinkTask.java
@@ -0,0 +1,406 @@
+/*
+ * 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.InputStream;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.apache.commons.lang3.StringUtils;
+import org.joda.time.DateTime;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+import org.w3c.dom.Element;
+import org.w3c.dom.Node;
+
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.ImmutableSet;
+
+import at.asitplus.eidas.specific.connector.MsConnectorEventCodes;
+import at.asitplus.eidas.specific.connector.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.SzrCommunicationException;
+import at.asitplus.eidas.specific.modules.auth.eidas.v2.exception.EidasAttributeException;
+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.data.Pair;
+import at.gv.egiz.eaaf.core.impl.idp.auth.builder.BpkBuilder;
+import at.gv.egiz.eaaf.core.impl.idp.auth.data.AuthProcessDataWrapper;
+import at.gv.egiz.eaaf.core.impl.idp.auth.data.SimpleIdentityLinkAssertionParser;
+import at.gv.egiz.eaaf.core.impl.idp.auth.modules.AbstractAuthServletTask;
+import at.gv.egiz.eaaf.core.impl.utils.DomUtils;
+import at.gv.egiz.eaaf.core.impl.utils.XPathUtils;
+import eu.eidas.auth.commons.attribute.AttributeDefinition;
+import eu.eidas.auth.commons.attribute.AttributeValue;
+import eu.eidas.auth.commons.light.ILightResponse;
+import eu.eidas.auth.commons.protocol.eidas.impl.PostalAddress;
+import szrservices.IdentityLinkType;
+import szrservices.PersonInfoType;
+import szrservices.TravelDocumentType;
+
+/**
+ * Task that creates the IdentityLink for an eIDAS authenticated person.
+ *
+ * @author tlenz
+ *
+ */
+@Component("CreateIdentityLinkTask")
+public class CreateIdentityLinkTask extends AbstractAuthServletTask {
+ private static final Logger log = LoggerFactory.getLogger(CreateIdentityLinkTask.class);
+
+ @Autowired
+ private IConfiguration basicConfig;
+ @Autowired
+ private SzrClient szrClient;
+ @Autowired
+ private ICcSpecificEidProcessingService eidPostProcessor;
+
+ /*
+ * (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<String, Object> simpleAttrMap = convertEidasAttrToSimpleMap(eidasResponse.getAttributes()
+ .getAttributeMap());
+
+ IIdentityLink identityLink = null;
+ String bpk = null;
+
+ // post-process eIDAS attributes
+ final ErnbEidData eidData = eidPostProcessor.postProcess(simpleAttrMap);
+
+ // write MDS into technical log and revision log
+ writeMdsLogInformation(eidData);
+
+ // connect SZR-Gateway
+ if (basicConfig.getBasicConfigurationBoolean(
+ Constants.CONIG_PROPS_EIDAS_SZRCLIENT_DEBUG_USEDUMMY, false)) {
+ log.warn("SZR-Dummy IS ACTIVE! IdentityLink is NOT VALID!!!!");
+ // create fake IdL
+ // - fetch IdL template from resources
+ final InputStream s = CreateIdentityLinkTask.class.getResourceAsStream(
+ "/resources/xmldata/fakeIdL_IdL_template.xml");
+ final Element idlTemplate = DomUtils.parseXmlValidating(s);
+
+ identityLink = new SimpleIdentityLinkAssertionParser(idlTemplate).parseIdentityLink();
+
+ // replace data
+ final Element idlassertion = identityLink.getSamlAssertion();
+
+ // - set fake baseID;
+ final Node prIdentification = XPathUtils.selectSingleNode(idlassertion,
+ SimpleIdentityLinkAssertionParser.PERSON_IDENT_VALUE_XPATH);
+ prIdentification.getFirstChild().setNodeValue(eidData.getPseudonym());
+
+ // - set last name
+ final Node prFamilyName = XPathUtils.selectSingleNode(idlassertion,
+ SimpleIdentityLinkAssertionParser.PERSON_FAMILY_NAME_XPATH);
+ prFamilyName.getFirstChild().setNodeValue(eidData.getFamilyName());
+
+ // - set first name
+ final Node prGivenName = XPathUtils.selectSingleNode(idlassertion,
+ SimpleIdentityLinkAssertionParser.PERSON_GIVEN_NAME_XPATH);
+ prGivenName.getFirstChild().setNodeValue(eidData.getGivenName());
+
+ // - set date of birth
+ final Node prDateOfBirth = XPathUtils.selectSingleNode(idlassertion,
+ SimpleIdentityLinkAssertionParser.PERSON_DATE_OF_BIRTH_XPATH);
+
+ prDateOfBirth.getFirstChild().setNodeValue(eidData.getFormatedDateOfBirth());
+
+ identityLink = new SimpleIdentityLinkAssertionParser(idlassertion).parseIdentityLink();
+
+ new BpkBuilder();
+ final Pair<String, String> bpkCalc = BpkBuilder.generateAreaSpecificPersonIdentifier(
+ identityLink.getIdentificationValue(),
+ identityLink.getIdentificationType(),
+ pendingReq.getServiceProviderConfiguration().getAreaSpecificTargetIdentifier());
+ bpk = bpkCalc.getFirst();
+
+ } else {
+ // contact SZR Gateway
+ log.debug("Starting connecting SZR Gateway");
+ final PersonInfoType personInfo = new PersonInfoType();
+ final PersonNameType personName = new PersonNameType();
+ final PhysicalPersonType naturalPerson = new PhysicalPersonType();
+ final TravelDocumentType eDocument = new TravelDocumentType();
+
+ naturalPerson.setName(personName);
+ personInfo.setPerson(naturalPerson);
+ personInfo.setTravelDocument(eDocument);
+
+ // person information
+ personName.setFamilyName(eidData.getFamilyName());
+ personName.setGivenName(eidData.getGivenName());
+ naturalPerson.setDateOfBirth(eidData.getFormatedDateOfBirth());
+ eDocument.setIssuingCountry(eidData.getCitizenCountryCode());
+ eDocument.setDocumentNumber(eidData.getPseudonym());
+
+ // eID document information
+ eDocument.setDocumentType(basicConfig.getBasicConfiguration(
+ Constants.CONIG_PROPS_EIDAS_SZRCLIENT_PARAMS_EDOCUMENTTYPE,
+ Constants.SZR_CONSTANTS_DEFAULT_DOCUMENT_TYPE));
+
+ // set PlaceOfBirth if available
+ if (eidData.getPlaceOfBirth() != null) {
+ log.trace("Find 'PlaceOfBirth' attribute: " + eidData.getPlaceOfBirth());
+ if (basicConfig.getBasicConfigurationBoolean(
+ Constants.CONIG_PROPS_EIDAS_SZRCLIENT_PARAMS_SETPLACEOFBIRTHIFAVAILABLE,
+ true)) {
+ naturalPerson.setPlaceOfBirth(eidData.getPlaceOfBirth());
+ log.trace("Adding 'PlaceOfBirth' to ERnB request ... ");
+
+ }
+ }
+
+ // set BirthName if available
+ if (eidData.getBirthName() != null) {
+ log.trace("Find 'BirthName' attribute: " + eidData.getBirthName());
+ if (basicConfig.getBasicConfigurationBoolean(
+ Constants.CONIG_PROPS_EIDAS_SZRCLIENT_PARAMS_SETBIRTHNAMEIFAVAILABLE,
+ true)) {
+ final AlternativeNameType alternativeName = new AlternativeNameType();
+ naturalPerson.setAlternativeName(alternativeName);
+ alternativeName.setFamilyName(eidData.getBirthName());
+ log.trace("Adding 'BirthName' to ERnB request ... ");
+
+ }
+ }
+
+ final IdentityLinkType result = szrClient.getIdentityLinkInRawMode(personInfo);
+
+ final Element idlFromSzr = (Element) result.getAssertion();
+ identityLink = new SimpleIdentityLinkAssertionParser(idlFromSzr).parseIdentityLink();
+
+ // write ERnB inputdata into revisionlog
+ if (basicConfig.getBasicConfigurationBoolean(
+ Constants.CONIG_PROPS_EIDAS_SZRCLIENT_WORKAROUND_REVISIONLOGDATASTORE_ACTIVE, false)) {
+ revisionsLogger.logEvent(pendingReq,
+ MsConnectorEventCodes.SZR_ERNB_EIDAS_RAW_ID,
+ (String) simpleAttrMap.get(Constants.eIDAS_ATTR_PERSONALIDENTIFIER));
+ revisionsLogger.logEvent(pendingReq,
+ MsConnectorEventCodes.SZR_ERNB_EIDAS_ERNB_ID, eidData.getPseudonym());
+
+ }
+
+ // get bPK from SZR
+ if (basicConfig.getBasicConfigurationBoolean(
+ Constants.CONIG_PROPS_EIDAS_SZRCLIENT_DEBUG_USESRZFORBPKGENERATION, true)) {
+ bpk = szrClient.getBpk(
+ personInfo,
+ pendingReq.getServiceProviderConfiguration().getAreaSpecificTargetIdentifier(),
+ basicConfig.getBasicConfiguration(
+ Constants.CONIG_PROPS_EIDAS_SZRCLIENT_PARAMS_VKZ,
+ "no VKZ defined"));
+
+ } else {
+ log.debug("Calculating bPK from baseId ... ");
+ new BpkBuilder();
+ final Pair<String, String> bpkCalc = BpkBuilder.generateAreaSpecificPersonIdentifier(
+ identityLink.getIdentificationValue(),
+ identityLink.getIdentificationType(),
+ pendingReq.getServiceProviderConfiguration().getAreaSpecificTargetIdentifier());
+ bpk = bpkCalc.getFirst();
+
+ }
+
+ }
+
+ if (identityLink == null) {
+ log.error("ERnB did not return an identity link.");
+ throw new SzrCommunicationException("ernb.00", null);
+
+ }
+ revisionsLogger.logEvent(pendingReq, MsConnectorEventCodes.SZR_IDL_RECEIVED,
+ identityLink.getSamlAssertion().getAttribute(SimpleIdentityLinkAssertionParser.ASSERTIONID));
+
+ if (bpk == null) {
+ log.error("ERnB did not return a bPK for target: " + pendingReq.getServiceProviderConfiguration()
+ .getAreaSpecificTargetIdentifier());
+ throw new SzrCommunicationException("ernb.01", null);
+
+ }
+ revisionsLogger.logEvent(pendingReq, MsConnectorEventCodes.SZR_BPK_RECEIVED);
+
+ log.debug("ERnB communication was successfull");
+
+ authProcessData.setForeigner(true);
+ authProcessData.setIdentityLink(identityLink);
+ authProcessData.setGenericDataToSession(
+ PvpAttributeDefinitions.EID_ISSUING_NATION_NAME,
+ EidasResponseUtils.parseEidasPersonalIdentifier((String) simpleAttrMap.get(
+ Constants.eIDAS_ATTR_PERSONALIDENTIFIER)).getFirst());
+
+ // set bPK and bPKType into auth session
+ authProcessData.setGenericDataToSession(
+ PvpAttributeDefinitions.BPK_NAME,
+ extendBpkByPrefix(
+ bpk,
+ pendingReq.getServiceProviderConfiguration().getAreaSpecificTargetIdentifier()));
+ authProcessData.setGenericDataToSession(
+ PvpAttributeDefinitions.EID_SECTOR_FOR_IDENTIFIER_NAME,
+ pendingReq.getServiceProviderConfiguration().getAreaSpecificTargetIdentifier());
+
+ // store pending-request
+ requestStoreage.storePendingRequest(pendingReq);
+
+ } catch (final EidasAttributeException e) {
+ throw new TaskExecutionException(pendingReq, "Minimum required eIDAS attributeset not found.", e);
+
+ } catch (final EaafException e) {
+ throw new TaskExecutionException(pendingReq, "IdentityLink generation for foreign person FAILED.", e);
+
+ } catch (final Exception e) {
+ log.error("IdentityLink generation for foreign person FAILED.", e);
+ throw new TaskExecutionException(pendingReq, "IdentityLink generation for foreign person FAILED.", e);
+
+ }
+ }
+
+ private String extendBpkByPrefix(String bpk, String type) {
+ String bpkType = null;
+
+ if (type.startsWith(EaafConstants.URN_PREFIX_WBPK)) {
+ bpkType = type.substring(EaafConstants.URN_PREFIX_WBPK.length());
+ } else if (type.startsWith(EaafConstants.URN_PREFIX_CDID)) {
+ bpkType = type.substring(EaafConstants.URN_PREFIX_CDID.length());
+ } else if (type.startsWith(EaafConstants.URN_PREFIX_EIDAS)) {
+ bpkType = type.substring(EaafConstants.URN_PREFIX_EIDAS.length());
+ }
+
+ if (bpkType != null) {
+ log.trace("Authenticate user with bPK/wbPK " + bpk + " and Type=" + bpkType);
+ return bpkType + ":" + bpk;
+
+ } else {
+ log.warn("Service Provider Target with: " + type + " is NOT supported. Set bPK as it is ...");
+ return bpk;
+
+ }
+
+ }
+
+ private Map<String, Object> convertEidasAttrToSimpleMap(
+ ImmutableMap<AttributeDefinition<?>, ImmutableSet<? extends AttributeValue<?>>> attributeMap) {
+ final Map<String, Object> result = new HashMap<>();
+
+ for (final AttributeDefinition<?> el : attributeMap.keySet()) {
+
+ final Class parameterizedType = el.getParameterizedType();
+ if (DateTime.class.equals(parameterizedType)) {
+ final DateTime attribute = EidasResponseUtils.translateDateAttribute(el, attributeMap.get(el)
+ .asList());
+ if (attribute != null) {
+ result.put(el.getFriendlyName(), attribute);
+ log.trace("Find attr '" + el.getFriendlyName() + "' with value: " + attribute.toString());
+
+ } else {
+ log.info("Ignore empty 'DateTime' attribute");
+ }
+
+ } else if (PostalAddress.class.equals(parameterizedType)) {
+ final PostalAddress addressAttribute = EidasResponseUtils.translateAddressAttribute(el, attributeMap
+ .get(el).asList());
+ if (addressAttribute != null) {
+ result.put(el.getFriendlyName(), addressAttribute);
+ log.trace("Find attr '" + el.getFriendlyName() + "' with value: " + addressAttribute.toString());
+
+ } else {
+ log.info("Ignore empty 'PostalAddress' attribute");
+ }
+
+ } else {
+ final List<String> natPersonIdObj = EidasResponseUtils.translateStringListAttribute(el, attributeMap
+ .get(el).asList());
+ final String stringAttr = natPersonIdObj.get(0);
+ if (StringUtils.isNotEmpty(stringAttr)) {
+ result.put(el.getFriendlyName(), stringAttr);
+ log.trace("Find attr '" + el.getFriendlyName() + "' with value: " + stringAttr);
+
+ } else {
+ log.info("Ignore empty 'String' attribute");
+ }
+
+ }
+ }
+
+ log.debug("Receive #" + result.size() + " attributes with names: " + result.keySet().toString());
+
+ return result;
+ }
+
+ private void writeMdsLogInformation(ErnbEidData eidData) {
+ // log MDS and country code into technical log
+ if (basicConfig.getBasicConfigurationBoolean(
+ MsEidasNodeConstants.PROP_CONFIG_TECHNICALLOG_WRITE_MDS_INTO_TECH_LOG, false)) {
+ log.info("eIDAS Auth. for user: "
+ + eidData.getGivenName() + " "
+ + eidData.getFamilyName() + " "
+ + eidData.getFormatedDateOfBirth() + " "
+ + "from " + eidData.getCitizenCountryCode());
+ }
+
+ // log MDS and country code into revision log
+ if (basicConfig.getBasicConfigurationBoolean(
+ MsEidasNodeConstants.PROP_CONFIG_REVISIONLOG_WRITE_MDS_INTO_REVISION_LOG, false)) {
+ revisionsLogger.logEvent(pendingReq, MsConnectorEventCodes.RESPONSE_FROM_EIDAS_MDSDATA,
+ "{" + eidData.getGivenName() + ","
+ + eidData.getFamilyName() + ","
+ + eidData.getFormatedDateOfBirth() + ","
+ + eidData.getCitizenCountryCode() + "}");
+ }
+
+ }
+
+}
diff --git a/eidas_modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/tasks/GenerateAuthnRequestTask.java b/eidas_modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/tasks/GenerateAuthnRequestTask.java
new file mode 100644
index 00000000..da849c8f
--- /dev/null
+++ b/eidas_modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/tasks/GenerateAuthnRequestTask.java
@@ -0,0 +1,288 @@
+/*
+ * 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.util.UUID;
+
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.apache.commons.lang3.StringUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.ApplicationContext;
+import org.springframework.stereotype.Component;
+import org.springframework.web.util.UriComponentsBuilder;
+
+import at.asitplus.eidas.specific.connector.MsConnectorEventCodes;
+import at.asitplus.eidas.specific.connector.MsEidasNodeConstants;
+import at.asitplus.eidas.specific.connector.gui.StaticGuiBuilderConfiguration;
+import at.asitplus.eidas.specific.modules.auth.eidas.v2.Constants;
+import at.asitplus.eidas.specific.modules.auth.eidas.v2.exception.EidasSAuthenticationException;
+import at.asitplus.eidas.specific.modules.auth.eidas.v2.service.ICcSpecificEidProcessingService;
+import at.gv.egiz.eaaf.core.api.data.EaafConstants;
+import at.gv.egiz.eaaf.core.api.gui.ISpringMvcGuiFormBuilder;
+import at.gv.egiz.eaaf.core.api.idp.IConfiguration;
+import at.gv.egiz.eaaf.core.api.idp.ISpConfiguration;
+import at.gv.egiz.eaaf.core.api.idp.process.ExecutionContext;
+import at.gv.egiz.eaaf.core.api.storage.ITransactionStorage;
+import at.gv.egiz.eaaf.core.exceptions.EaafConfigurationException;
+import at.gv.egiz.eaaf.core.exceptions.TaskExecutionException;
+import at.gv.egiz.eaaf.core.impl.idp.auth.modules.AbstractAuthServletTask;
+import eu.eidas.auth.commons.EidasParameterKeys;
+import eu.eidas.auth.commons.light.ILightRequest;
+import eu.eidas.auth.commons.light.impl.LightRequest;
+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;
+
+/**
+ * Authentication-process task that generates the Authn. Request to eIDAS Node.
+ *
+ * @author tlenz
+ *
+ */
+@Component("ConnecteIDASNodeTask")
+public class GenerateAuthnRequestTask extends AbstractAuthServletTask {
+ private static final Logger log = LoggerFactory.getLogger(GenerateAuthnRequestTask.class);
+
+ @Autowired
+ IConfiguration basicConfig;
+ @Autowired
+ ApplicationContext context;
+ @Autowired
+ ITransactionStorage transactionStore;
+ @Autowired
+ ISpringMvcGuiFormBuilder guiBuilder;
+ @Autowired
+ ICcSpecificEidProcessingService ccSpecificProcessing;
+
+ @Override
+ public void execute(ExecutionContext executionContext,
+ HttpServletRequest request, HttpServletResponse response)
+ throws TaskExecutionException {
+
+ try {
+ // get service-provider configuration
+ final ISpConfiguration spConfig = pendingReq.getServiceProviderConfiguration();
+
+ // get target, environment and validate citizen countryCode
+ final String citizenCountryCode = (String) executionContext.get(
+ MsEidasNodeConstants.REQ_PARAM_SELECTED_COUNTRY);
+ final String environment = (String) executionContext.get(
+ MsEidasNodeConstants.REQ_PARAM_SELECTED_ENVIRONMENT);
+
+ if (StringUtils.isEmpty(citizenCountryCode)) {
+ // illegal state; task should not have been executed without a selected country
+ throw new EidasSAuthenticationException("eidas.03", new Object[] { "" });
+
+ }
+
+ // TODO: maybe add countryCode validation before request ref. impl. eIDAS node
+ log.info("Request eIDAS auth. for citizen of country: " + citizenCountryCode);
+ revisionsLogger.logEvent(pendingReq, MsConnectorEventCodes.COUNTRY_SELECTED, citizenCountryCode);
+
+ // build eIDAS AuthnRequest
+ final LightRequest.Builder authnRequestBuilder = LightRequest.builder();
+ authnRequestBuilder.id(UUID.randomUUID().toString());
+
+ final String issur = basicConfig.getBasicConfiguration(Constants.CONIG_PROPS_EIDAS_NODE_ENTITYID);
+ if (StringUtils.isEmpty(issur)) {
+ log.error("Found NO 'eIDAS node issuer' in configuration. Authentication NOT possible!");
+ throw new EaafConfigurationException("config.27",
+ new Object[] { "Application config containts NO " + Constants.CONIG_PROPS_EIDAS_NODE_ENTITYID });
+
+ }
+ authnRequestBuilder.issuer(issur);
+
+ // TODO: set matching mode if eIDAS ref. impl. support this method
+
+ // TODO: update if eIDAS ref. impl. supports exact matching for non-notified LoA
+ // schemes
+ String loa = EaafConstants.EIDAS_LOA_HIGH;
+ if (spConfig.getRequiredLoA() != null) {
+ if (spConfig.getRequiredLoA().isEmpty()) {
+ log.info("No eIDAS LoA requested. Use LoA HIGH as default");
+ } else {
+ if (spConfig.getRequiredLoA().size() > 1) {
+ log.info(
+ "Currently only ONE requested LoA is supported for service provider. Use first one ... ");
+ }
+
+ loa = spConfig.getRequiredLoA().get(0);
+
+ }
+ }
+
+ log.debug("Request eIdAS node with LoA: " + loa);
+ authnRequestBuilder.levelOfAssurance(loa);
+
+ // set nameIDFormat
+ authnRequestBuilder.nameIdFormat(Constants.eIDAS_REQ_NAMEID_FORMAT);
+
+ // set citizen country code for foreign uses
+ authnRequestBuilder.citizenCountryCode(citizenCountryCode);
+
+ // set relay state
+ /*
+ * TODO: SecureToken PendingRequestId generates a validation exception in
+ * eIDASNode because eIDASNode implements limit on size for RelayState
+ * (80characaters)
+ */
+ // authnRequestBuilder.relayState(pendingReq.getPendingRequestId());
+
+ // Add country-specific informations into eIDAS request
+ ccSpecificProcessing.preProcess(citizenCountryCode, pendingReq, authnRequestBuilder);
+
+ // build request
+ final LightRequest lightAuthnReq = authnRequestBuilder.build();
+
+ // put request into Hazelcast cache
+ final BinaryLightToken token = putRequestInCommunicationCache(lightAuthnReq);
+ final String tokenBase64 = BinaryLightTokenHelper.encodeBinaryLightTokenBase64(token);
+
+ // Workaround, because eIDAS node ref. impl. does not return relayState
+ if (basicConfig.getBasicConfigurationBoolean(
+ Constants.CONIG_PROPS_EIDAS_NODE_WORKAROUND_USEREQUESTIDASTRANSACTIONIDENTIFIER,
+ false)) {
+ log.trace("Put lightRequestId into transactionstore as session-handling backup");
+ transactionStore.put(lightAuthnReq.getId(), pendingReq.getPendingRequestId(), -1);
+
+ }
+
+ // select forward URL regarding the selected environment
+ String forwardUrl = basicConfig.getBasicConfiguration(Constants.CONIG_PROPS_EIDAS_NODE_FORWARD_URL);
+ if (StringUtils.isNotEmpty(environment)) {
+ forwardUrl = selectedForwardUrlForEnvironment(environment);
+ }
+
+ if (StringUtils.isEmpty(forwardUrl)) {
+ log.warn("NO ForwardURL defined in configuration. Can NOT forward to eIDAS node! Process stops");
+ throw new EaafConfigurationException("config.08", new Object[] {
+ environment == null ? Constants.CONIG_PROPS_EIDAS_NODE_FORWARD_URL
+ : Constants.CONIG_PROPS_EIDAS_NODE_FORWARD_URL + "." + environment
+ });
+
+ }
+ log.debug("ForwardURL: " + forwardUrl + " selected to forward eIDAS request");
+
+ if (basicConfig.getBasicConfiguration(
+ Constants.CONIG_PROPS_EIDAS_NODE_FORWARD_METHOD,
+ Constants.FORWARD_METHOD_GET).equals(Constants.FORWARD_METHOD_GET)) {
+
+ log.debug("Use http-redirect for eIDAS node forwarding ... ");
+ // send redirect
+ final UriComponentsBuilder redirectUrl = UriComponentsBuilder.fromHttpUrl(forwardUrl);
+ redirectUrl.queryParam(EidasParameterKeys.TOKEN.toString(), tokenBase64);
+ response.sendRedirect(redirectUrl.build().encode().toString());
+
+ } else {
+ log.debug("Use http-post for eIDAS node forwarding ... ");
+ final StaticGuiBuilderConfiguration config = new StaticGuiBuilderConfiguration(
+ basicConfig,
+ pendingReq,
+ Constants.TEMPLATE_POST_FORWARD_NAME,
+ null,
+ resourceLoader);
+
+ config.putCustomParameter(null, Constants.TEMPLATE_POST_FORWARD_ENDPOINT, forwardUrl);
+ config.putCustomParameter(null, Constants.TEMPLATE_POST_FORWARD_TOKEN_NAME,
+ EidasParameterKeys.TOKEN.toString());
+ config.putCustomParameter(null, Constants.TEMPLATE_POST_FORWARD_TOKEN_VALUE,
+ tokenBase64);
+
+ guiBuilder.build(request, response, config, "Forward to eIDASNode form");
+
+ }
+
+ revisionsLogger.logEvent(pendingReq, MsConnectorEventCodes.EIDAS_NODE_CONNECTED, lightAuthnReq.getId());
+
+ } catch (final EidasSAuthenticationException e) {
+ throw new TaskExecutionException(pendingReq, "eIDAS AuthnRequest generation FAILED.", e);
+
+ } catch (final Exception e) {
+ log.warn("eIDAS AuthnRequest generation FAILED.", e);
+ throw new TaskExecutionException(pendingReq, e.getMessage(), e);
+
+ }
+
+ }
+
+ /**
+ * Select a forward URL from configuration for a specific environment <br>
+ * <br>
+ * <b>Info: </b> This method is needed, because eIDAS Ref. Impl only supports
+ * one countrycode on each instance. In consequence, more than one eIDAS Ref.
+ * Impl nodes are required to support producation, testing, or QS stages for one
+ * country by using one ms-specific eIDAS connector
+ *
+ * @param environment Environment selector from CountrySlection page
+ * @return
+ */
+ private String selectedForwardUrlForEnvironment(String environment) {
+ log.trace("Starting endpoint selection process for environment: " + environment + " ... ");
+ if (environment.equalsIgnoreCase(MsEidasNodeConstants.REQ_PARAM_SELECTED_ENVIRONMENT_VALUE_PRODUCTION)) {
+ return basicConfig.getBasicConfiguration(Constants.CONIG_PROPS_EIDAS_NODE_FORWARD_URL);
+ } else if (environment.equalsIgnoreCase(MsEidasNodeConstants.REQ_PARAM_SELECTED_ENVIRONMENT_VALUE_QS)) {
+ return basicConfig.getBasicConfiguration(Constants.CONIG_PROPS_EIDAS_NODE_FORWARD_URL
+ + "." + MsEidasNodeConstants.REQ_PARAM_SELECTED_ENVIRONMENT_VALUE_QS);
+ } else if (environment.equalsIgnoreCase(
+ MsEidasNodeConstants.REQ_PARAM_SELECTED_ENVIRONMENT_VALUE_TESTING)) {
+ return basicConfig.getBasicConfiguration(Constants.CONIG_PROPS_EIDAS_NODE_FORWARD_URL
+ + "." + MsEidasNodeConstants.REQ_PARAM_SELECTED_ENVIRONMENT_VALUE_TESTING);
+ } else if (environment.equalsIgnoreCase(
+ MsEidasNodeConstants.REQ_PARAM_SELECTED_ENVIRONMENT_VALUE_DEVELOPMENT)) {
+ return basicConfig.getBasicConfiguration(Constants.CONIG_PROPS_EIDAS_NODE_FORWARD_URL
+ + "." + MsEidasNodeConstants.REQ_PARAM_SELECTED_ENVIRONMENT_VALUE_DEVELOPMENT);
+ }
+
+ log.info("Environment selector: " + environment + " is not supported");
+ return null;
+
+ }
+
+ private BinaryLightToken putRequestInCommunicationCache(ILightRequest lightRequest)
+ throws ServletException {
+ final BinaryLightToken binaryLightToken;
+ try {
+ final SpecificCommunicationService springManagedSpecificConnectorCommunicationService =
+ (SpecificCommunicationService) context.getBean(
+ SpecificCommunicationDefinitionBeanNames.SPECIFIC_CONNECTOR_COMMUNICATION_SERVICE.toString());
+
+ binaryLightToken = springManagedSpecificConnectorCommunicationService.putRequest(lightRequest);
+
+ } catch (final SpecificCommunicationException e) {
+ log.error("Unable to process specific request");
+ throw new ServletException(e);
+
+ }
+
+ return binaryLightToken;
+ }
+
+}
diff --git a/eidas_modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/tasks/ReceiveAuthnResponseTask.java b/eidas_modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/tasks/ReceiveAuthnResponseTask.java
new file mode 100644
index 00000000..60049323
--- /dev/null
+++ b/eidas_modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/tasks/ReceiveAuthnResponseTask.java
@@ -0,0 +1,126 @@
+/*
+ * 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 javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+
+import at.asitplus.eidas.specific.connector.MsConnectorEventCodes;
+import at.asitplus.eidas.specific.connector.MsEidasNodeConstants;
+import at.asitplus.eidas.specific.modules.auth.eidas.v2.Constants;
+import at.asitplus.eidas.specific.modules.auth.eidas.v2.exception.EidasSAuthenticationException;
+import at.asitplus.eidas.specific.modules.auth.eidas.v2.service.EidasAttributeRegistry;
+import at.asitplus.eidas.specific.modules.auth.eidas.v2.validator.EidasResponseValidator;
+import at.gv.egiz.eaaf.core.api.idp.IConfiguration;
+import at.gv.egiz.eaaf.core.api.idp.process.ExecutionContext;
+import at.gv.egiz.eaaf.core.exceptions.EaafException;
+import at.gv.egiz.eaaf.core.exceptions.TaskExecutionException;
+import at.gv.egiz.eaaf.core.impl.idp.auth.data.AuthProcessDataWrapper;
+import at.gv.egiz.eaaf.core.impl.idp.auth.modules.AbstractAuthServletTask;
+import eu.eidas.auth.commons.light.ILightResponse;
+
+@Component("ReceiveResponseFromeIDASNodeTask")
+public class ReceiveAuthnResponseTask extends AbstractAuthServletTask {
+ private static final Logger log = LoggerFactory.getLogger(ReceiveAuthnResponseTask.class);
+
+ @Autowired
+ private IConfiguration basicConfig;
+ @Autowired
+ private EidasAttributeRegistry attrRegistry;
+
+ @Override
+ public void execute(ExecutionContext executionContext, HttpServletRequest request,
+ HttpServletResponse response) throws TaskExecutionException {
+ try {
+ final ILightResponse eidasResponse = (ILightResponse) request.getAttribute(
+ Constants.DATA_FULL_EIDAS_RESPONSE);
+ if (eidasResponse == null) {
+ log.warn("NO eIDAS response-message found.");
+ throw new EidasSAuthenticationException("eidas.01", null);
+
+ }
+
+ log.debug("Receive eIDAS response with RespId:" + eidasResponse.getId() + " for ReqId:" + eidasResponse
+ .getInResponseToId());
+ log.trace("Full eIDAS-Resp: " + eidasResponse.toString());
+ revisionsLogger.logEvent(pendingReq, MsConnectorEventCodes.RESPONSE_FROM_EIDAS_NODE, eidasResponse
+ .getId());
+
+ // check response StatusCode
+ if (!eidasResponse.getStatus().getStatusCode().equals(Constants.SUCCESS_URI)) {
+ log.info("Receice eIDAS Response with StatusCode:" + eidasResponse.getStatus().getStatusCode()
+ + " Subcode:" + eidasResponse.getStatus().getSubStatusCode() + " Msg:" + eidasResponse.getStatus()
+ .getStatusMessage());
+ throw new EidasSAuthenticationException("eidas.02", new Object[] { eidasResponse.getStatus()
+ .getStatusCode(), eidasResponse.getStatus().getStatusMessage() });
+
+ }
+
+ // extract all Attributes from response
+
+ // **********************************************************
+ // ******* MS-specificresponse validation **********
+ // **********************************************************
+ final String spCountry = basicConfig.getBasicConfiguration(Constants.CONIG_PROPS_EIDAS_NODE_COUNTRYCODE,
+ "AT");
+ final String citizenCountryCode = (String) executionContext.get(
+ MsEidasNodeConstants.REQ_PARAM_SELECTED_COUNTRY);
+ EidasResponseValidator.validateResponse(pendingReq, eidasResponse, spCountry, citizenCountryCode,
+ attrRegistry);
+
+ // **********************************************************
+ // ******* Store resonse infos into session object **********
+ // **********************************************************
+
+ // update MOA-Session data with received information
+ log.debug("Store eIDAS response information into pending-request.");
+ final AuthProcessDataWrapper authProcessData = pendingReq.getSessionData(AuthProcessDataWrapper.class);
+ authProcessData.setQaaLevel(eidasResponse.getLevelOfAssurance());
+ authProcessData.setGenericDataToSession(Constants.DATA_FULL_EIDAS_RESPONSE, eidasResponse);
+
+ // store MOA-session to database
+ requestStoreage.storePendingRequest(pendingReq);
+
+ revisionsLogger.logEvent(pendingReq, MsConnectorEventCodes.RESPONSE_FROM_EIDAS_NODE_VALID);
+
+ } catch (final EaafException e) {
+ revisionsLogger.logEvent(pendingReq, MsConnectorEventCodes.RESPONSE_FROM_EIDAS_NODE_NOT_VALID);
+ throw new TaskExecutionException(pendingReq, "eIDAS Response processing FAILED.", e);
+
+ } catch (final Exception e) {
+ log.warn("eIDAS Response processing FAILED.", e);
+ revisionsLogger.logEvent(pendingReq, MsConnectorEventCodes.RESPONSE_FROM_EIDAS_NODE_NOT_VALID);
+ throw new TaskExecutionException(pendingReq, e.getMessage(),
+ new EidasSAuthenticationException("eidas.05", new Object[] { e.getMessage() }, e));
+
+ }
+
+ }
+
+}