aboutsummaryrefslogtreecommitdiff
path: root/eidas_modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/authmodule_eIDASv2/tasks
diff options
context:
space:
mode:
Diffstat (limited to 'eidas_modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/authmodule_eIDASv2/tasks')
-rw-r--r--eidas_modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/authmodule_eIDASv2/tasks/CreateIdentityLinkTask.java380
-rw-r--r--eidas_modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/authmodule_eIDASv2/tasks/GenerateAuthnRequestTask.java306
-rw-r--r--eidas_modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/authmodule_eIDASv2/tasks/ReceiveAuthnResponseTask.java97
3 files changed, 783 insertions, 0 deletions
diff --git a/eidas_modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/authmodule_eIDASv2/tasks/CreateIdentityLinkTask.java b/eidas_modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/authmodule_eIDASv2/tasks/CreateIdentityLinkTask.java
new file mode 100644
index 00000000..c5d33b73
--- /dev/null
+++ b/eidas_modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/authmodule_eIDASv2/tasks/CreateIdentityLinkTask.java
@@ -0,0 +1,380 @@
+/*******************************************************************************
+ *******************************************************************************/
+package at.asitplus.eidas.specific.modules.authmodule_eIDASv2.tasks;
+
+import java.io.InputStream;
+import java.math.BigInteger;
+import java.security.KeyFactory;
+import java.security.NoSuchAlgorithmException;
+import java.security.PublicKey;
+import java.security.interfaces.RSAPublicKey;
+import java.security.spec.InvalidKeySpecException;
+import java.security.spec.PKCS8EncodedKeySpec;
+import java.text.SimpleDateFormat;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.apache.commons.lang3.StringUtils;
+import org.joda.time.DateTime;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+import org.springframework.util.Base64Utils;
+import org.w3._2000._09.xmldsig.KeyValueType;
+import org.w3._2000._09.xmldsig.RSAKeyValueType;
+import org.w3c.dom.Element;
+import org.w3c.dom.Node;
+
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.ImmutableSet;
+
+import at.asitplus.eidas.specific.connector.MSConnectorEventCodes;
+import at.asitplus.eidas.specific.modules.authmodule_eIDASv2.Constants;
+import at.asitplus.eidas.specific.modules.authmodule_eIDASv2.exception.SZRCommunicationException;
+import at.asitplus.eidas.specific.modules.authmodule_eIDASv2.exception.eIDASAttributeException;
+import at.asitplus.eidas.specific.modules.authmodule_eIDASv2.szr.SZRClient;
+import at.asitplus.eidas.specific.modules.authmodule_eIDASv2.utils.eIDASResponseUtils;
+import at.gv.e_government.reference.namespace.persondata._20020228.PersonNameType;
+import at.gv.e_government.reference.namespace.persondata._20020228.PhysicalPersonType;
+import at.gv.egiz.eaaf.core.api.data.EAAFConstants;
+import at.gv.egiz.eaaf.core.api.data.PVPAttributeDefinitions;
+import at.gv.egiz.eaaf.core.api.idp.IConfiguration;
+import at.gv.egiz.eaaf.core.api.idp.auth.data.IIdentityLink;
+import at.gv.egiz.eaaf.core.api.idp.process.ExecutionContext;
+import at.gv.egiz.eaaf.core.exceptions.EAAFException;
+import at.gv.egiz.eaaf.core.exceptions.TaskExecutionException;
+import at.gv.egiz.eaaf.core.impl.data.Pair;
+import at.gv.egiz.eaaf.core.impl.data.Trible;
+import at.gv.egiz.eaaf.core.impl.idp.auth.builder.BPKBuilder;
+import at.gv.egiz.eaaf.core.impl.idp.auth.data.AuthProcessDataWrapper;
+import at.gv.egiz.eaaf.core.impl.idp.auth.data.SimpleIdentityLinkAssertionParser;
+import at.gv.egiz.eaaf.core.impl.idp.auth.modules.AbstractAuthServletTask;
+import at.gv.egiz.eaaf.core.impl.utils.DOMUtils;
+import at.gv.egiz.eaaf.core.impl.utils.XPathUtils;
+import eu.eidas.auth.commons.attribute.AttributeDefinition;
+import eu.eidas.auth.commons.attribute.AttributeValue;
+import eu.eidas.auth.commons.light.ILightResponse;
+import eu.eidas.auth.commons.protocol.eidas.impl.PostalAddress;
+import szrservices.IdentityLinkType;
+import szrservices.PersonInfoType;
+import szrservices.TravelDocumentType;
+
+/**
+ * @author tlenz
+ *
+ */
+@Component("CreateIdentityLinkTask")
+public class CreateIdentityLinkTask extends AbstractAuthServletTask {
+ private static final Logger log = LoggerFactory.getLogger(CreateIdentityLinkTask.class);
+
+ //@Autowired private eIDASAttributeRegistry attrRegistry;
+ @Autowired private IConfiguration basicConfig;
+ @Autowired private SZRClient szrClient;
+
+
+ /* (non-Javadoc)
+ * @see at.gv.egovernment.moa.id.process.springweb.MoaIdTask#execute(at.gv.egovernment.moa.id.process.api.ExecutionContext, javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse)
+ */
+ @Override
+ public void execute(ExecutionContext executionContext,
+ HttpServletRequest request, HttpServletResponse response)
+ throws TaskExecutionException {
+ try{
+ AuthProcessDataWrapper authProcessData = pendingReq.getSessionData(AuthProcessDataWrapper.class);
+ ILightResponse eIDASResponse = authProcessData.getGenericDataFromSession(
+ Constants.DATA_FULL_EIDAS_RESPONSE, ILightResponse.class);
+ Map<String, Object> simpleAttrMap = converteIDASAttrToSimpleMap(eIDASResponse.getAttributes().getAttributeMap());
+
+ IIdentityLink identityLink = null;
+ String bPK = null;
+
+ //extract attributes
+ Object eIdentifierObj = simpleAttrMap.get(Constants.eIDAS_ATTR_PERSONALIDENTIFIER);
+ Object familyNameObj = simpleAttrMap.get(Constants.eIDAS_ATTR_CURRENTFAMILYNAME);
+ Object givenNameObj = simpleAttrMap.get(Constants.eIDAS_ATTR_CURRENTGIVENNAME);
+ Object dateOfBirthObj = simpleAttrMap.get(Constants.eIDAS_ATTR_DATEOFBIRTH);
+
+ //check if availabe
+ if (eIdentifierObj == null || !(eIdentifierObj instanceof String))
+ throw new eIDASAttributeException(Constants.eIDAS_ATTR_PERSONALIDENTIFIER);
+
+ if (familyNameObj == null || !(familyNameObj instanceof String))
+ throw new eIDASAttributeException(Constants.eIDAS_ATTR_CURRENTFAMILYNAME);
+
+ if (givenNameObj == null || !(givenNameObj instanceof String))
+ throw new eIDASAttributeException(Constants.eIDAS_ATTR_CURRENTGIVENNAME);
+
+ if (dateOfBirthObj == null || !(dateOfBirthObj instanceof DateTime))
+ throw new eIDASAttributeException(Constants.eIDAS_ATTR_DATEOFBIRTH);
+
+ //connect SZR-Gateway
+ if(basicConfig.getBasicMOAIDConfigurationBoolean(
+ Constants.CONIG_PROPS_EIDAS_SZRCLIENT_DEBUG_USEDUMMY, false)) {
+ log.warn("SZR-Dummy IS ACTIVE! IdentityLink is NOT VALID!!!!");
+ // create fake IdL
+ // - fetch IdL template from resources
+ InputStream s = CreateIdentityLinkTask.class.getResourceAsStream("/resources/xmldata/fakeIdL_IdL_template.xml");
+ Element idlTemplate = DOMUtils.parseXmlValidating(s);
+
+ identityLink = new SimpleIdentityLinkAssertionParser(idlTemplate).parseIdentityLink();
+
+ // replace data
+ Element idlassertion = identityLink.getSamlAssertion();
+
+ // - set fake baseID;
+ Node prIdentification = XPathUtils.selectSingleNode(idlassertion, SimpleIdentityLinkAssertionParser.PERSON_IDENT_VALUE_XPATH);
+ prIdentification.getFirstChild().setNodeValue((String) eIdentifierObj);
+
+ //build personal identifier which looks like a baseID
+// String fakeBaseID = new BPKBuilder().buildBPK(eIdentifier, "baseID");
+// Logger.info("Map eIDAS eIdentifier:" + eIdentifier + " to fake baseID:" + fakeBaseID);
+// prIdentification.getFirstChild().setNodeValue(fakeBaseID);
+
+ // - set last name
+ Node prFamilyName = XPathUtils.selectSingleNode(idlassertion, SimpleIdentityLinkAssertionParser.PERSON_FAMILY_NAME_XPATH);
+ prFamilyName.getFirstChild().setNodeValue((String) familyNameObj);
+
+ // - set first name
+ Node prGivenName = XPathUtils.selectSingleNode(idlassertion, SimpleIdentityLinkAssertionParser.PERSON_GIVEN_NAME_XPATH);
+ prGivenName.getFirstChild().setNodeValue((String) givenNameObj);
+
+ // - set date of birth
+ Node prDateOfBirth = XPathUtils.selectSingleNode(idlassertion, SimpleIdentityLinkAssertionParser.PERSON_DATE_OF_BIRTH_XPATH);
+ String formatedDateOfBirth = new SimpleDateFormat("yyyy-MM-dd").format(((DateTime)dateOfBirthObj).toDate());
+ prDateOfBirth.getFirstChild().setNodeValue(formatedDateOfBirth);
+
+ identityLink = new SimpleIdentityLinkAssertionParser(idlassertion).parseIdentityLink();
+
+ Pair<String, String> bPKCalc = new BPKBuilder().generateAreaSpecificPersonIdentifier(
+ identityLink.getIdentificationValue(),
+ identityLink.getIdentificationType(),
+ pendingReq.getServiceProviderConfiguration().getAreaSpecificTargetIdentifier());
+ bPK = bPKCalc.getFirst();
+
+
+ } else {
+ //contact SZR Gateway
+ log.debug("Starting connecting SZR Gateway");
+ PersonInfoType personInfo = new PersonInfoType();
+ PersonNameType personName = new PersonNameType();
+ PhysicalPersonType naturalPerson = new PhysicalPersonType();
+ TravelDocumentType eDocument = new TravelDocumentType();
+
+ naturalPerson.setName(personName );
+ personInfo.setPerson(naturalPerson );
+ personInfo.setTravelDocument(eDocument );
+
+ //parse some eID attributes
+ String dateOfBirth = new SimpleDateFormat("yyyy-MM-dd").format(((DateTime)dateOfBirthObj).toDate());
+ Trible<String, String, String> eIdentifier =
+ eIDASResponseUtils.parseEidasPersonalIdentifier((String)eIdentifierObj);
+ String uniqueId = (String)eIdentifierObj;
+ String citizenCountry = eIdentifier.getFirst();
+
+ //person information
+ personName.setFamilyName((String)familyNameObj);
+ personName.setGivenName((String)givenNameObj);
+ naturalPerson.setDateOfBirth(dateOfBirth);
+ eDocument.setIssuingCountry(citizenCountry);
+ eDocument.setDocumentNumber(uniqueId);
+
+ //eID document information
+ eDocument.setDocumentType(basicConfig.getBasicConfiguration(
+ Constants.CONIG_PROPS_EIDAS_SZRCLIENT_PARAMS_EDOCUMENTTYPE,
+ Constants.SZR_CONSTANTS_DEFAULT_DOCUMENT_TYPE));
+
+ //TODO: that should be removed
+ eDocument.setIssueDate(basicConfig.getBasicConfiguration(
+ Constants.CONIG_PROPS_EIDAS_SZRCLIENT_PARAMS_ISSUING_DATE,
+ Constants.SZR_CONSTANTS_DEFAULT_ISSUING_DATE));
+ eDocument.setIssuingAuthority(basicConfig.getBasicConfiguration(
+ Constants.CONIG_PROPS_EIDAS_SZRCLIENT_PARAMS_ISSUING_AUTHORITY,
+ Constants.SZR_CONSTANTS_DEFAULT_ISSUING_AUTHORITY));
+
+ //TODO: keys are not available in eIDAS
+ List<KeyValueType> keyValue = dummyCodeForKeys();
+
+ /*TODO:
+ * Validate if IDL signature is valid after using this method
+ * MAYBE we had to switch to 'getIdentityLinkInRawMode' method!
+ */
+ IdentityLinkType result = szrClient.getIdentityLink(
+ personInfo,
+ keyValue,
+ basicConfig.getBasicMOAIDConfigurationBoolean(
+ Constants.CONIG_PROPS_EIDAS_SZRCLIENT_DEBUG_INSERTERNB,
+ true)
+ );
+
+ Element idlFromSZR = (Element)result.getAssertion();
+ identityLink = new SimpleIdentityLinkAssertionParser(idlFromSZR).parseIdentityLink();
+
+
+ //get bPK from SZR
+ bPK = szrClient.getBPK(
+ personInfo,
+ pendingReq.getServiceProviderConfiguration().getAreaSpecificTargetIdentifier(),
+ basicConfig.getBasicConfiguration(
+ Constants.CONIG_PROPS_EIDAS_SZRCLIENT_PARAMS_VKZ,
+ "no VKZ defined"));
+
+ }
+
+ if (identityLink == null) {
+ log.error("ERnB did not return an identity link.");
+ throw new SZRCommunicationException("ernb.00", null);
+
+ }
+ revisionsLogger.logEvent(pendingReq, MSConnectorEventCodes.SZR_IDL_RECEIVED);
+
+
+ if (bPK == null) {
+ log.error("ERnB did not return a bPK for target: " + pendingReq.getServiceProviderConfiguration().getAreaSpecificTargetIdentifier());
+ throw new SZRCommunicationException("ernb.01", null);
+
+ }
+ revisionsLogger.logEvent(pendingReq, MSConnectorEventCodes.SZR_BPK_RECEIVED);
+
+ log.debug("ERnB communication was successfull");
+
+ authProcessData.setForeigner(true);
+ authProcessData.setIdentityLink(identityLink);
+ authProcessData.setGenericDataToSession(
+ PVPAttributeDefinitions.EID_ISSUING_NATION_NAME,
+ eIDASResponseUtils.parseEidasPersonalIdentifier((String) simpleAttrMap.get(Constants.eIDAS_ATTR_PERSONALIDENTIFIER)).getFirst());
+
+ //set bPK and bPKType into auth session
+ authProcessData.setGenericDataToSession(
+ PVPAttributeDefinitions.BPK_NAME,
+ extendBPKbyPrefix(
+ bPK,
+ pendingReq.getServiceProviderConfiguration().getAreaSpecificTargetIdentifier())
+ );
+ authProcessData.setGenericDataToSession(
+ PVPAttributeDefinitions.EID_SECTOR_FOR_IDENTIFIER_NAME,
+ pendingReq.getServiceProviderConfiguration().getAreaSpecificTargetIdentifier());
+
+
+
+ //store pending-request
+ requestStoreage.storePendingRequest(pendingReq);
+
+ } catch (eIDASAttributeException e) {
+ throw new TaskExecutionException(pendingReq, "Minimum required eIDAS attributeset not found.", e);
+
+ } catch (EAAFException e) {
+ throw new TaskExecutionException(pendingReq, "IdentityLink generation for foreign person FAILED.", e);
+
+ } catch (Exception e) {
+ log.error("IdentityLink generation for foreign person FAILED.", e);
+ throw new TaskExecutionException(pendingReq, "IdentityLink generation for foreign person FAILED.", e);
+
+ }
+ }
+
+ private List<KeyValueType> dummyCodeForKeys() {
+ if (basicConfig.getBasicMOAIDConfigurationBoolean(
+ Constants.CONIG_PROPS_EIDAS_SZRCLIENT_PARAMS_KEYS_USEDUMMY,
+ false)) {
+ List<KeyValueType> keyvalueList = new ArrayList<KeyValueType>();
+ try {
+ PKCS8EncodedKeySpec spec = new PKCS8EncodedKeySpec(Constants.SZR_CONSTANTS_DEFAULT_PUBL_KEY);
+ KeyFactory kf = KeyFactory.getInstance("RSA");
+
+ PublicKey pb = kf.generatePublic(spec);
+
+ RSAPublicKey rsapb = (RSAPublicKey)pb;
+ BigInteger modulus = rsapb.getModulus();
+ BigInteger exponent = rsapb.getPublicExponent();
+
+ // set key values
+ RSAKeyValueType rsa = new RSAKeyValueType();
+ rsa.setExponent(new String(Base64Utils.encode(exponent.toByteArray())));
+ rsa.setModulus(new String(Base64Utils.encode(modulus.toByteArray())));
+
+ KeyValueType key = new KeyValueType();
+ key.setRSAKeyValue(rsa);
+
+ keyvalueList.add(key);
+
+ return keyvalueList;
+ } catch (NoSuchAlgorithmException | InvalidKeySpecException e) {
+ log.error("TestCode has an internal ERROR", e);
+
+ }
+
+ }
+
+ return null;
+
+ }
+
+ private String extendBPKbyPrefix(String bpk, String type) {
+ String bPKType = null;
+
+ if (type.startsWith(EAAFConstants.URN_PREFIX_WBPK))
+ bPKType = type.substring((EAAFConstants.URN_PREFIX_WBPK).length());
+
+ else if (type.startsWith(EAAFConstants.URN_PREFIX_CDID))
+ bPKType = type.substring((EAAFConstants.URN_PREFIX_CDID).length());
+
+ else if (type.startsWith(EAAFConstants.URN_PREFIX_EIDAS))
+ bPKType = type.substring((EAAFConstants.URN_PREFIX_EIDAS).length());
+
+
+ if (bPKType != null ) {
+ log.trace("Authenticate user with bPK/wbPK " + bpk + " and Type=" + bPKType);
+ return bPKType + ":" + bpk;
+
+ } else {
+ log.warn("Service Provider Target with: " + type + " is NOT supported. Set bPK as it is ...");
+ return bpk;
+
+ }
+
+ }
+
+ //TODO: update for complexe attributes
+ private Map<String, Object> converteIDASAttrToSimpleMap(
+ ImmutableMap<AttributeDefinition<?>, ImmutableSet<? extends AttributeValue<?>>> attributeMap) {
+ Map<String, Object> result = new HashMap<String, Object>();
+
+ for (AttributeDefinition<?> el : attributeMap.keySet()) {
+
+ final Class parameterizedType = el.getParameterizedType();
+ if ((DateTime.class).equals(parameterizedType)) {
+ DateTime attribute = eIDASResponseUtils.translateDateAttribute(el, attributeMap.get(el).asList());
+ if (attribute != null)
+ result.put(el.getFriendlyName(), attribute);
+ else
+ log.info("Ignore empty 'DateTime' attribute");
+
+ } else if ((PostalAddress.class).equals(parameterizedType)) {
+ PostalAddress addressAttribute = eIDASResponseUtils.translateAddressAttribute(el, attributeMap.get(el).asList());
+ if (addressAttribute != null)
+ result.put(el.getFriendlyName(), addressAttribute);
+ else
+ log.info("Ignore empty 'PostalAddress' attribute");
+
+ } else {
+ List<String> natPersonIdObj = eIDASResponseUtils.translateStringListAttribute(el, attributeMap.get(el).asList());
+ String stringAttr = natPersonIdObj.get(0);
+ if (StringUtils.isNotEmpty(stringAttr))
+ result.put(el.getFriendlyName(), stringAttr);
+ else
+ log.info("Ignore empty 'String' attribute");
+
+ }
+ }
+
+ return result;
+ }
+
+
+}
diff --git a/eidas_modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/authmodule_eIDASv2/tasks/GenerateAuthnRequestTask.java b/eidas_modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/authmodule_eIDASv2/tasks/GenerateAuthnRequestTask.java
new file mode 100644
index 00000000..74c98de1
--- /dev/null
+++ b/eidas_modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/authmodule_eIDASv2/tasks/GenerateAuthnRequestTask.java
@@ -0,0 +1,306 @@
+/*******************************************************************************
+ *******************************************************************************/
+package at.asitplus.eidas.specific.modules.authmodule_eIDASv2.tasks;
+
+import java.util.Map;
+import java.util.UUID;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.apache.commons.lang3.StringUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.ApplicationContext;
+import org.springframework.stereotype.Component;
+import org.springframework.web.util.UriComponentsBuilder;
+
+import com.google.common.collect.ImmutableSortedSet;
+
+import at.asitplus.eidas.specific.connector.MSConnectorEventCodes;
+import at.asitplus.eidas.specific.connector.MSeIDASNodeConstants;
+import at.asitplus.eidas.specific.connector.gui.StaticGuiBuilderConfiguration;
+import at.asitplus.eidas.specific.modules.authmodule_eIDASv2.Constants;
+import at.asitplus.eidas.specific.modules.authmodule_eIDASv2.exception.eIDASAuthenticationException;
+import at.asitplus.eidas.specific.modules.authmodule_eIDASv2.service.eIDASAttributeRegistry;
+import at.gv.egiz.eaaf.core.api.data.EAAFConstants;
+import at.gv.egiz.eaaf.core.api.gui.IGUIFormBuilder;
+import at.gv.egiz.eaaf.core.api.idp.IConfiguration;
+import at.gv.egiz.eaaf.core.api.idp.ISPConfiguration;
+import at.gv.egiz.eaaf.core.api.idp.process.ExecutionContext;
+import at.gv.egiz.eaaf.core.api.storage.ITransactionStorage;
+import at.gv.egiz.eaaf.core.exceptions.EAAFConfigurationException;
+import at.gv.egiz.eaaf.core.exceptions.TaskExecutionException;
+import at.gv.egiz.eaaf.core.impl.idp.auth.modules.AbstractAuthServletTask;
+import eu.eidas.auth.commons.EidasParameterKeys;
+import eu.eidas.auth.commons.attribute.AttributeDefinition;
+import eu.eidas.auth.commons.attribute.ImmutableAttributeMap;
+import eu.eidas.auth.commons.light.ILightRequest;
+import eu.eidas.auth.commons.light.impl.LightRequest;
+import eu.eidas.auth.commons.protocol.eidas.SpType;
+import eu.eidas.auth.commons.tx.BinaryLightToken;
+import eu.eidas.specificcommunication.BinaryLightTokenHelper;
+import eu.eidas.specificcommunication.SpecificCommunicationDefinitionBeanNames;
+import eu.eidas.specificcommunication.exception.SpecificCommunicationException;
+import eu.eidas.specificcommunication.protocol.impl.SpecificConnectorCommunicationServiceImpl;
+
+/**
+ * @author tlenz
+ *
+ */
+@Component("ConnecteIDASNodeTask")
+public class GenerateAuthnRequestTask extends AbstractAuthServletTask {
+ private static final Logger log = LoggerFactory.getLogger(GenerateAuthnRequestTask.class);
+
+ @Autowired IConfiguration basicConfig;
+ @Autowired eIDASAttributeRegistry attrRegistry;
+ @Autowired ApplicationContext context;
+ @Autowired ITransactionStorage transactionStore;
+ @Autowired IGUIFormBuilder guiBuilder;
+
+ @Override
+ public void execute(ExecutionContext executionContext,
+ HttpServletRequest request, HttpServletResponse response)
+ throws TaskExecutionException {
+
+ try{
+ //get service-provider configuration
+ ISPConfiguration spConfig = pendingReq.getServiceProviderConfiguration();
+
+ // get target, environment and validate citizen countryCode
+ String citizenCountryCode = (String) executionContext.get(MSeIDASNodeConstants.REQ_PARAM_SELECTED_COUNTRY);
+ String environment = (String) executionContext.get(MSeIDASNodeConstants.REQ_PARAM_SELECTED_ENVIRONMENT);
+
+ if (StringUtils.isEmpty(citizenCountryCode)) {
+ // illegal state; task should not have been executed without a selected country
+ throw new eIDASAuthenticationException("eidas.03", new Object[] { "" });
+
+ }
+
+ //TODO: maybe add countryCode validation before request ref. impl. eIDAS node
+ log.debug("Request eIDAS auth. for citizen of country: " + citizenCountryCode);
+ revisionsLogger.logEvent(pendingReq, MSConnectorEventCodes.COUNTRY_SELECTED, citizenCountryCode);
+
+ //build eIDAS AuthnRequest
+ LightRequest.Builder authnRequestBuilder = LightRequest.builder();
+ authnRequestBuilder.id(UUID.randomUUID().toString());
+
+
+ String issur = basicConfig.getBasicConfiguration(Constants.CONIG_PROPS_EIDAS_NODE_ENTITYID);
+ if (StringUtils.isEmpty(issur)) {
+ log.error("Found NO 'eIDAS node issuer' in configuration. Authentication NOT possible!");
+ throw new EAAFConfigurationException("config.27",
+ new Object[] {"Application config containts NO " + Constants.CONIG_PROPS_EIDAS_NODE_ENTITYID });
+
+ }
+ authnRequestBuilder.issuer(issur);
+
+
+ //TODO: set matching mode if eIDAS ref. impl. support this method
+
+
+ //TODO: update if eIDAS ref. impl. supports exact matching for non-notified LoA schemes
+ String loa = EAAFConstants.EIDAS_LOA_HIGH;
+ if (spConfig.getRequiredLoA() != null) {
+ if (spConfig.getRequiredLoA().isEmpty())
+ log.info("No eIDAS LoA requested. Use LoA HIGH as default");
+
+ else {
+ if (spConfig.getRequiredLoA().size() > 1 )
+ log.info("Currently only ONE requested LoA is supported for service provider. Use first one ... ");
+
+ loa = spConfig.getRequiredLoA().get(0);
+
+ }
+ }
+
+ log.debug("Request eIdAS node with LoA: " + loa);
+ authnRequestBuilder.levelOfAssurance(loa);
+
+ //set correct SPType for requested target sector
+ String publicSectorTargetSelector = basicConfig.getBasicConfiguration(
+ Constants.CONIG_PROPS_EIDAS_NODE_PUBLICSECTOR_TARGETS,
+ Constants.POLICY_DEFAULT_ALLOWED_TARGETS);
+ Pattern p = Pattern.compile(publicSectorTargetSelector);
+ Matcher m = p.matcher(spConfig.getAreaSpecificTargetIdentifier());
+ if (m.matches()) {
+ log.debug("Map " + spConfig.getAreaSpecificTargetIdentifier() + " to 'PublicSector'");
+ authnRequestBuilder.spType(SpType.PUBLIC.getValue());
+
+ //TODO: only for eIDAS ref. node 2.0 and 2.1 because it need 'Providername' for any SPType
+ String providerName = pendingReq.getRawData(Constants.DATA_PROVIDERNAME, String.class);
+ if (StringUtils.isNotEmpty(providerName)
+ && basicConfig.getBasicMOAIDConfigurationBoolean(
+ Constants.CONIG_PROPS_EIDAS_NODE_WORKAROUND_ADD_ALWAYS_PROVIDERNAME,
+ false)
+ )
+ authnRequestBuilder.providerName(providerName);
+
+ } else {
+ log.debug("Map " + spConfig.getAreaSpecificTargetIdentifier() + " to 'PrivateSector'");
+ authnRequestBuilder.spType(SpType.PRIVATE.getValue());
+
+ //TODO: switch to RequesterId in further version
+ //set provider name for private sector applications
+ String providerName = pendingReq.getRawData(Constants.DATA_PROVIDERNAME, String.class);
+ if (StringUtils.isNotEmpty(providerName))
+ authnRequestBuilder.providerName(providerName);
+
+ }
+
+ //set nameIDFormat
+ authnRequestBuilder.nameIdFormat(Constants.eIDAS_REQ_NAMEID_FORMAT);
+
+ //set citizen country code for foreign uses
+ authnRequestBuilder.citizenCountryCode(citizenCountryCode);
+
+ //set relay state
+ authnRequestBuilder.relayState(pendingReq.getPendingRequestId());
+
+ //build and add requested attribute set
+ ImmutableAttributeMap reqAttrMap = translateToEidasAttributes(attrRegistry.getAttributeSetFromConfiguration());
+ authnRequestBuilder.requestedAttributes(reqAttrMap);
+
+ //build request
+ LightRequest lightAuthnReq = authnRequestBuilder.build();
+
+ //put request into cache
+ BinaryLightToken token = putRequestInCommunicationCache(lightAuthnReq);
+ final String tokenBase64 = BinaryLightTokenHelper.encodeBinaryLightTokenBase64(token);
+
+ //Workaround, because eIDAS node ref. impl. does not return relayState
+ if (basicConfig.getBasicMOAIDConfigurationBoolean(
+ Constants.CONIG_PROPS_EIDAS_NODE_WORKAROUND_USEREQUESTIDASTRANSACTIONIDENTIFIER,
+ false)) {
+ log.trace("Put lightRequestId into transactionstore as session-handling backup");
+ transactionStore.put(lightAuthnReq.getId(), pendingReq.getPendingRequestId(), -1);
+
+ }
+
+ //select forward URL regarding the selected environment
+ String forwardURL = basicConfig.getBasicConfiguration(Constants.CONIG_PROPS_EIDAS_NODE_FORWARD_URL);
+ if (StringUtils.isNotEmpty(environment))
+ forwardURL = selectedForwardURLForEnvironment(environment);
+
+ if (StringUtils.isEmpty(forwardURL)) {
+ log.warn("NO ForwardURL defined in configuration. Can NOT forward to eIDAS node! Process stops");
+ throw new EAAFConfigurationException("config.08", new Object[] {Constants.CONIG_PROPS_EIDAS_NODE_FORWARD_URL});
+
+ }
+ log.debug("ForwardURL: " + forwardURL + " selected to forward eIDAS request");
+
+ if (basicConfig.getBasicConfiguration(
+ Constants.CONIG_PROPS_EIDAS_NODE_FORWARD_METHOD,
+ Constants.FORWARD_METHOD_GET
+ ).equals(Constants.FORWARD_METHOD_GET)) {
+
+ log.debug("Use http-redirect for eIDAS node forwarding ... ");
+ //send redirect
+ UriComponentsBuilder redirectUrl = UriComponentsBuilder.fromHttpUrl(forwardURL);
+ redirectUrl.queryParam(EidasParameterKeys.TOKEN.toString(), tokenBase64);
+ response.sendRedirect(redirectUrl.build().encode().toString());
+
+ } else {
+ log.debug("Use http-post for eIDAS node forwarding ... ");
+ StaticGuiBuilderConfiguration config = new StaticGuiBuilderConfiguration(
+ basicConfig,
+ pendingReq,
+ Constants.TEMPLATE_POST_FORWARD_NAME,
+ null);
+
+ config.putCustomParameter(Constants.TEMPLATE_POST_FORWARD_ENDPOINT, forwardURL);
+ config.putCustomParameter(Constants.TEMPLATE_POST_FORWARD_TOKEN_NAME,
+ EidasParameterKeys.TOKEN.toString());
+ config.putCustomParameter(Constants.TEMPLATE_POST_FORWARD_TOKEN_VALUE,
+ tokenBase64);
+
+ guiBuilder.build(response, config, "BKU-Selection form");
+
+ }
+
+ revisionsLogger.logEvent(pendingReq, MSConnectorEventCodes.EIDAS_NODE_CONNECTED, lightAuthnReq.getId());
+
+
+ } catch (eIDASAuthenticationException e) {
+ throw new TaskExecutionException(pendingReq, "eIDAS AuthnRequest generation FAILED.", e);
+
+ } catch (Exception e) {
+ log.warn("eIDAS AuthnRequest generation FAILED.", e);
+ throw new TaskExecutionException(pendingReq, e.getMessage(), e);
+
+ }
+
+ }
+
+ /**
+ * Select a forward URL from configuration for a specific environment
+ * <br><br>
+ * <b>Info: </b> This method is needed, because eIDAS Ref. Impl only supports one countrycode on each instance.
+ * In consequence, more than one eIDAS Ref. Impl nodes are required to support producation, testing, or QS stages
+ * for one country by using one ms-specific eIDAS connector
+ *
+ * @param environment Environment selector from CountrySlection page
+ * @return
+ */
+ private String selectedForwardURLForEnvironment(String environment) {
+ log.trace("Starting endpoint selection process for environment: " + environment + " ... ");
+ if (environment.equalsIgnoreCase(MSeIDASNodeConstants.REQ_PARAM_SELECTED_ENVIRONMENT_VALUE_PRODUCTION))
+ return basicConfig.getBasicConfiguration(Constants.CONIG_PROPS_EIDAS_NODE_FORWARD_URL);
+
+ else if (environment.equalsIgnoreCase(MSeIDASNodeConstants.REQ_PARAM_SELECTED_ENVIRONMENT_VALUE_QS))
+ return basicConfig.getBasicConfiguration(Constants.CONIG_PROPS_EIDAS_NODE_FORWARD_URL
+ + "." + MSeIDASNodeConstants.REQ_PARAM_SELECTED_ENVIRONMENT_VALUE_QS);
+
+ else if (environment.equalsIgnoreCase(MSeIDASNodeConstants.REQ_PARAM_SELECTED_ENVIRONMENT_VALUE_TESTING))
+ return basicConfig.getBasicConfiguration(Constants.CONIG_PROPS_EIDAS_NODE_FORWARD_URL
+ + "." + MSeIDASNodeConstants.REQ_PARAM_SELECTED_ENVIRONMENT_VALUE_TESTING);
+
+ else if (environment.equalsIgnoreCase(MSeIDASNodeConstants.REQ_PARAM_SELECTED_ENVIRONMENT_VALUE_DEVELOPMENT))
+ return basicConfig.getBasicConfiguration(Constants.CONIG_PROPS_EIDAS_NODE_FORWARD_URL
+ + "." + MSeIDASNodeConstants.REQ_PARAM_SELECTED_ENVIRONMENT_VALUE_DEVELOPMENT);
+
+ log.info("Environment selector: " + environment + " is not supported");
+ return null;
+
+ }
+
+ private ImmutableAttributeMap translateToEidasAttributes(final Map<String, Boolean> requiredAttributes) {
+ ImmutableAttributeMap.Builder builder = ImmutableAttributeMap.builder();
+ for (Map.Entry<String,Boolean> attribute : requiredAttributes.entrySet()) {
+ final String name = attribute.getKey();
+ final ImmutableSortedSet<AttributeDefinition<?>> byFriendlyName = attrRegistry.getCoreAttributeRegistry().getByFriendlyName(name);
+ if (!byFriendlyName.isEmpty()) {
+ final AttributeDefinition<?> attributeDefinition = byFriendlyName.first();
+ builder.put(AttributeDefinition.builder(attributeDefinition).required(attribute.getValue()).build());
+
+ } else
+ log.warn("Can NOT request UNKNOWN attribute: " + attribute.getKey() + " Ignore it!");
+
+ }
+
+ return builder.build();
+
+ }
+
+ private BinaryLightToken putRequestInCommunicationCache(ILightRequest iLightRequest) throws ServletException {
+ final BinaryLightToken binaryLightToken;
+ try {
+ final SpecificConnectorCommunicationServiceImpl springManagedSpecificConnectorCommunicationService =
+ (SpecificConnectorCommunicationServiceImpl) context.getBean(SpecificCommunicationDefinitionBeanNames.SPECIFIC_CONNECTOR_COMMUNICATION_SERVICE.toString());
+
+ binaryLightToken = springManagedSpecificConnectorCommunicationService.putRequest(iLightRequest);
+
+ } catch (SpecificCommunicationException e) {
+ log.error("Unable to process specific request");
+ throw new ServletException(e);
+
+ }
+
+ return binaryLightToken;
+ }
+
+}
diff --git a/eidas_modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/authmodule_eIDASv2/tasks/ReceiveAuthnResponseTask.java b/eidas_modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/authmodule_eIDASv2/tasks/ReceiveAuthnResponseTask.java
new file mode 100644
index 00000000..2970c073
--- /dev/null
+++ b/eidas_modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/authmodule_eIDASv2/tasks/ReceiveAuthnResponseTask.java
@@ -0,0 +1,97 @@
+/*******************************************************************************
+ *******************************************************************************/
+package at.asitplus.eidas.specific.modules.authmodule_eIDASv2.tasks;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.ApplicationContext;
+import org.springframework.stereotype.Component;
+
+import at.asitplus.eidas.specific.connector.MSConnectorEventCodes;
+import at.asitplus.eidas.specific.modules.authmodule_eIDASv2.Constants;
+import at.asitplus.eidas.specific.modules.authmodule_eIDASv2.exception.eIDASAuthenticationException;
+import at.asitplus.eidas.specific.modules.authmodule_eIDASv2.service.eIDASAttributeRegistry;
+import at.asitplus.eidas.specific.modules.authmodule_eIDASv2.validator.eIDASResponseValidator;
+import at.gv.egiz.eaaf.core.api.idp.IConfiguration;
+import at.gv.egiz.eaaf.core.api.idp.process.ExecutionContext;
+import at.gv.egiz.eaaf.core.exceptions.EAAFException;
+import at.gv.egiz.eaaf.core.exceptions.TaskExecutionException;
+import at.gv.egiz.eaaf.core.impl.idp.auth.data.AuthProcessDataWrapper;
+import at.gv.egiz.eaaf.core.impl.idp.auth.modules.AbstractAuthServletTask;
+import eu.eidas.auth.commons.light.ILightResponse;
+
+@Component("ReceiveResponseFromeIDASNodeTask")
+public class ReceiveAuthnResponseTask extends AbstractAuthServletTask {
+ private static final Logger log = LoggerFactory.getLogger(ReceiveAuthnResponseTask.class);
+
+ @Autowired private ApplicationContext context;
+ @Autowired private IConfiguration basicConfig;
+ @Autowired private eIDASAttributeRegistry attrRegistry;
+
+ @Override
+ public void execute(ExecutionContext executionContext, HttpServletRequest request, HttpServletResponse response) throws TaskExecutionException {
+ try{
+ ILightResponse eIDASResponse = (ILightResponse) request.getAttribute(Constants.DATA_FULL_EIDAS_RESPONSE);
+ if (eIDASResponse == null) {
+ log.warn("NO eIDAS response-message found.");
+ throw new eIDASAuthenticationException("eidas.01", null);
+
+ }
+
+ log.debug("Receive eIDAS response with RespId:" + eIDASResponse.getId() + " for ReqId:" + eIDASResponse.getInResponseToId());
+ revisionsLogger.logEvent(pendingReq, MSConnectorEventCodes.RESPONSE_FROM_EIDAS_NODE, eIDASResponse.getId());
+
+
+ //check response StatusCode
+ if (!eIDASResponse.getStatus().getStatusCode().equals(Constants.SUCCESS_URI)) {
+ log.info("Receice eIDAS Response with StatusCode:" + eIDASResponse.getStatus().getStatusCode()
+ + " Subcode:" + eIDASResponse.getStatus().getSubStatusCode() + " Msg:" + eIDASResponse.getStatus().getStatusMessage());
+ throw new eIDASAuthenticationException("eidas.02", new Object[]{eIDASResponse.getStatus().getStatusCode(), eIDASResponse.getStatus().getStatusMessage()});
+
+ }
+
+ // extract all Attributes from response
+
+
+
+ // **********************************************************
+ // ******* MS-specificresponse validation **********
+ // **********************************************************
+ String spCountry = basicConfig.getBasicConfiguration(Constants.CONIG_PROPS_EIDAS_NODE_COUNTRYCODE, "AT");
+ eIDASResponseValidator.validateResponse(pendingReq, eIDASResponse, spCountry, attrRegistry);
+
+
+ // **********************************************************
+ // ******* Store resonse infos into session object **********
+ // **********************************************************
+
+ //update MOA-Session data with received information
+ log.debug("Store eIDAS response information into pending-request.");
+ AuthProcessDataWrapper authProcessData = pendingReq.getSessionData(AuthProcessDataWrapper.class);
+ authProcessData.setQAALevel(eIDASResponse.getLevelOfAssurance());
+ authProcessData.setGenericDataToSession(Constants.DATA_FULL_EIDAS_RESPONSE, eIDASResponse);
+
+ //store MOA-session to database
+ requestStoreage.storePendingRequest(pendingReq);
+
+ revisionsLogger.logEvent(pendingReq, MSConnectorEventCodes.RESPONSE_FROM_EIDAS_NODE_VALID);
+
+ } catch (EAAFException e) {
+ revisionsLogger.logEvent(pendingReq, MSConnectorEventCodes.RESPONSE_FROM_EIDAS_NODE_NOT_VALID);
+ throw new TaskExecutionException(pendingReq, "eIDAS Response processing FAILED.", e);
+
+ } catch (Exception e) {
+ log.warn("eIDAS Response processing FAILED.", e);
+ revisionsLogger.logEvent(pendingReq, MSConnectorEventCodes.RESPONSE_FROM_EIDAS_NODE_NOT_VALID);
+ throw new TaskExecutionException(pendingReq, e.getMessage(),
+ new eIDASAuthenticationException("eidas.05", new Object[]{e.getMessage()}, e));
+
+ }
+
+ }
+
+}