diff options
Diffstat (limited to 'modules/authmodule_id-austria/src/main/java/at/asitplus/eidas/specific/modules/auth/idaustria/tasks')
2 files changed, 598 insertions, 0 deletions
diff --git a/modules/authmodule_id-austria/src/main/java/at/asitplus/eidas/specific/modules/auth/idaustria/tasks/ReceiveFromIdAustriaSystemTask.java b/modules/authmodule_id-austria/src/main/java/at/asitplus/eidas/specific/modules/auth/idaustria/tasks/ReceiveFromIdAustriaSystemTask.java new file mode 100644 index 00000000..e486b851 --- /dev/null +++ b/modules/authmodule_id-austria/src/main/java/at/asitplus/eidas/specific/modules/auth/idaustria/tasks/ReceiveFromIdAustriaSystemTask.java @@ -0,0 +1,393 @@ +package at.asitplus.eidas.specific.modules.auth.idaustria.tasks; + +import java.io.IOException; +import java.util.Set; + +import javax.naming.ConfigurationException; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import javax.xml.transform.TransformerException; + +import org.apache.commons.lang3.StringUtils; +import org.opensaml.core.xml.io.MarshallingException; +import org.opensaml.messaging.decoder.MessageDecodingException; +import org.opensaml.saml.saml2.core.Response; +import org.opensaml.saml.saml2.core.StatusCode; +import org.opensaml.saml.saml2.metadata.IDPSSODescriptor; +import org.springframework.beans.factory.annotation.Autowired; + +import at.asitplus.eidas.specific.core.MsEidasNodeConstants; +import at.asitplus.eidas.specific.modules.auth.idaustria.IdAustriaAuthConstants; +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.gv.egiz.eaaf.core.api.data.PvpAttributeDefinitions; +import at.gv.egiz.eaaf.core.api.idp.process.ExecutionContext; +import at.gv.egiz.eaaf.core.exceptions.EaafAuthenticationException; +import at.gv.egiz.eaaf.core.exceptions.EaafBuilderException; +import at.gv.egiz.eaaf.core.exceptions.EaafException; +import at.gv.egiz.eaaf.core.exceptions.EaafStorageException; +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.data.AuthProcessDataWrapper; +import at.gv.egiz.eaaf.core.impl.idp.auth.modules.AbstractAuthServletTask; +import at.gv.egiz.eaaf.modules.pvp2.api.binding.IDecoder; +import at.gv.egiz.eaaf.modules.pvp2.exception.CredentialsNotAvailableException; +import at.gv.egiz.eaaf.modules.pvp2.exception.SamlAssertionValidationExeption; +import at.gv.egiz.eaaf.modules.pvp2.exception.SamlSigningException; +import at.gv.egiz.eaaf.modules.pvp2.impl.binding.PostBinding; +import at.gv.egiz.eaaf.modules.pvp2.impl.binding.RedirectBinding; +import at.gv.egiz.eaaf.modules.pvp2.impl.message.InboundMessage; +import at.gv.egiz.eaaf.modules.pvp2.impl.message.PvpSProfileResponse; +import at.gv.egiz.eaaf.modules.pvp2.impl.utils.Saml2Utils; +import at.gv.egiz.eaaf.modules.pvp2.impl.validation.EaafUriCompare; +import at.gv.egiz.eaaf.modules.pvp2.impl.validation.TrustEngineFactory; +import at.gv.egiz.eaaf.modules.pvp2.impl.verification.SamlVerificationEngine; +import at.gv.egiz.eaaf.modules.pvp2.sp.exception.AssertionValidationExeption; +import at.gv.egiz.eaaf.modules.pvp2.sp.exception.AuthnResponseValidationException; +import at.gv.egiz.eaaf.modules.pvp2.sp.impl.utils.AssertionAttributeExtractor; +import lombok.extern.slf4j.Slf4j; + +/** + * ID Austria authentication task that receives the SAML2 response from ID + * Austria system. + * + * @author tlenz + * + */ +@Slf4j +public class ReceiveFromIdAustriaSystemTask extends AbstractAuthServletTask { + + private static final String ERROR_PVP_03 = "sp.pvp2.03"; + private static final String ERROR_PVP_05 = "sp.pvp2.05"; + private static final String ERROR_PVP_06 = "sp.pvp2.06"; + private static final String ERROR_PVP_08 = "sp.pvp2.08"; + private static final String ERROR_PVP_10 = "sp.pvp2.10"; + private static final String ERROR_PVP_11 = "sp.pvp2.11"; + private static final String ERROR_PVP_12 = "sp.pvp2.12"; + + private static final String ERROR_MSG_00 = + "Receive INVALID PVP Response from federated IDP"; + private static final String ERROR_MSG_01 = + "Processing PVP response from 'ms-specific eIDAS node' FAILED."; + private static final String ERROR_MSG_02 = + "PVP response decrytion FAILED. No credential found."; + private static final String ERROR_MSG_03 = + "PVP response validation FAILED."; + + @Autowired + private SamlVerificationEngine samlVerificationEngine; + @Autowired + private IdAustriaAuthCredentialProvider credentialProvider; + @Autowired(required = true) + IdAustriaAuthMetadataProvider metadataProvider; + + /* + * (non-Javadoc) + * + * @see + * at.gv.egovernment.moa.id.auth.modules.AbstractAuthServletTask#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 { + InboundMessage msg = null; + + try { + + IDecoder decoder = null; + EaafUriCompare comperator = null; + // select Response Binding + if (request.getMethod().equalsIgnoreCase("POST")) { + decoder = new PostBinding(); + comperator = new EaafUriCompare(pendingReq.getAuthUrl() + IdAustriaAuthConstants.ENDPOINT_POST); + log.trace("Receive PVP Response from 'ID Austria', by using POST-Binding."); + + } else if (request.getMethod().equalsIgnoreCase("GET")) { + decoder = new RedirectBinding(); + comperator = new EaafUriCompare(pendingReq.getAuthUrl() + + IdAustriaAuthConstants.ENDPOINT_REDIRECT); + log.trace("Receive PVP Response from 'ID Austria', by using Redirect-Binding."); + + } else { + log.warn("Receive PVP Response, but Binding (" + + request.getMethod() + ") is not supported."); + throw new AuthnResponseValidationException(ERROR_PVP_03, new Object[] { + IdAustriaAuthConstants.MODULE_NAME_FOR_LOGGING }); + + } + + // decode PVP response object + msg = (InboundMessage) decoder.decode( + request, response, metadataProvider, IDPSSODescriptor.DEFAULT_ELEMENT_NAME, + comperator); + + // validate response signature + if (!msg.isVerified()) { + samlVerificationEngine.verify(msg, + TrustEngineFactory.getSignatureKnownKeysTrustEngine(metadataProvider)); + msg.setVerified(true); + + } + + // validate assertion + final Pair<PvpSProfileResponse, Boolean> processedMsg = + preProcessAuthResponse((PvpSProfileResponse) msg); + + // check if SAML2 response contains user-stop decision + if (processedMsg.getSecond()) { + stopProcessFromUserDecision(executionContext, request, response); + + } else { + // validate entityId of response + final String idAustriaEntityID = + Utils.getIdAustriaEntityId(pendingReq.getServiceProviderConfiguration(), authConfig); + final String respEntityId = msg.getEntityID(); + if (!idAustriaEntityID.equals(respEntityId)) { + log.warn("Response Issuer is not a 'ID Austria System'. Stopping eIDAS authentication ..."); + throw new AuthnResponseValidationException(ERROR_PVP_08, + new Object[] { IdAustriaAuthConstants.MODULE_NAME_FOR_LOGGING, + msg.getEntityID() }); + + } + + // initialize Attribute extractor + final AssertionAttributeExtractor extractor = + new AssertionAttributeExtractor(processedMsg.getFirst().getResponse()); + + getAuthDataFromInterfederation(extractor); + + // set NeedConsent to false, because user gives consont during authentication + pendingReq.setNeedUserConsent(false); + + // store pending-request + requestStoreage.storePendingRequest(pendingReq); + + // write log entries + // revisionsLogger.logEvent(pendingReq, + // EidasAuthEventConstants.AUTHPROCESS_EIDAS_AT_CONNECTOR_MDS_VALID); + log.info("Receive a valid assertion from IDP " + msg.getEntityID()); + + } + + } catch (final AuthnResponseValidationException e) { + throw new TaskExecutionException(pendingReq, ERROR_MSG_03, e); + + } catch (MessageDecodingException | SecurityException | SamlSigningException e) { + final String samlRequest = request.getParameter("SAMLRequest"); + log.debug("Receive INVALID PVP Response from 'ID Austria System': {}", + samlRequest, null, e); + throw new TaskExecutionException(pendingReq, ERROR_MSG_00, + new AuthnResponseValidationException(ERROR_PVP_11, + new Object[] { IdAustriaAuthConstants.MODULE_NAME_FOR_LOGGING }, e)); + + } catch (IOException | MarshallingException | TransformerException e) { + log.debug("Processing PVP response from 'ID Austria System' FAILED.", e); + throw new TaskExecutionException(pendingReq, ERROR_MSG_01, + new AuthnResponseValidationException(ERROR_PVP_12, + new Object[] { IdAustriaAuthConstants.MODULE_NAME_FOR_LOGGING, e.getMessage() }, + e)); + + } catch (final CredentialsNotAvailableException e) { + log.debug("PVP response decrytion FAILED. No credential found.", e); + throw new TaskExecutionException(pendingReq, ERROR_MSG_02, + new AuthnResponseValidationException(ERROR_PVP_10, + new Object[] { IdAustriaAuthConstants.MODULE_NAME_FOR_LOGGING }, e)); + + } catch (final Exception e) { + log.debug("PVP response validation FAILED. Msg:" + e.getMessage(), e); + throw new TaskExecutionException(pendingReq, ERROR_MSG_03, + new AuthnResponseValidationException(ERROR_PVP_12, + new Object[] { IdAustriaAuthConstants.MODULE_NAME_FOR_LOGGING, e.getMessage() }, e)); + + } + + } + + private void getAuthDataFromInterfederation(AssertionAttributeExtractor extractor) + throws EaafBuilderException, ConfigurationException { + + final Set<String> requiredEidasNodeAttributes = + IdAustriaAuthConstants.DEFAULT_REQUIRED_PVP_ATTRIBUTE_NAMES; + try { + // check if all attributes are include + if (!extractor.containsAllRequiredAttributes() + || !extractor.containsAllRequiredAttributes( + requiredEidasNodeAttributes)) { + log.warn("PVP Response from 'ID Austria System' contains not all requested attributes."); + throw new AssertionValidationExeption(ERROR_PVP_06, new Object[] { + IdAustriaAuthConstants.MODULE_NAME_FOR_LOGGING }); + + } + + // copy attributes into MOASession + final AuthProcessDataWrapper session = pendingReq.getSessionData( + AuthProcessDataWrapper.class); + + // validate response attributes + validateResponseAttributes(extractor); + + // inject all attributes into session + final Set<String> includedAttrNames = extractor.getAllIncludeAttributeNames(); + for (final String attrName : includedAttrNames) { + injectAuthInfosIntoSession(session, attrName, + extractor.getSingleAttributeValue(attrName)); + + } + + // set foreigner flag + session.setForeigner(false); + + // mark it as ID Austria process, because we have no baseId + session.setEidProcess(true); + + // set IssuerInstant from Assertion + session.setIssueInstant(extractor.getAssertionIssuingDate()); + + // set mandate flag + session.setUseMandates(checkIfMandateInformationIsAvailable(extractor)); + + + } catch (final EaafException | IOException e) { + throw new EaafBuilderException(ERROR_PVP_06, null, e.getMessage(), e); + + } + } + + + /** + * Check if mandate information is available. + * + * @param extractor Assertion from ID Austria system. + * @return <code>true</code> if mandate was used, otherwise <code>false</code> + */ + 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 Pair<PvpSProfileResponse, Boolean> preProcessAuthResponse(PvpSProfileResponse msg) + throws IOException, MarshallingException, TransformerException, + CredentialsNotAvailableException, AuthnResponseValidationException, SamlAssertionValidationExeption { + log.debug("Start PVP-2x assertion processing... "); + final Response samlResp = (Response) msg.getResponse(); + + // check SAML2 response status-code + if (samlResp.getStatus().getStatusCode().getValue().equals(StatusCode.SUCCESS)) { + // validate PVP 2.1 assertion + samlVerificationEngine.validateAssertion(samlResp, + credentialProvider.getMessageEncryptionCredential(), + pendingReq.getAuthUrl() + IdAustriaAuthConstants.ENDPOINT_METADATA, + IdAustriaAuthConstants.MODULE_NAME_FOR_LOGGING); + + msg.setSamlMessage(Saml2Utils.asDomDocument(samlResp).getDocumentElement()); + // revisionsLogger.logEvent(pendingReq, + // EidasAuthEventConstants.AUTHPROCESS_EIDAS_AT_CONNECTOR_RECEIVED, + // samlResp.getID()); + return Pair.newInstance(msg, false); + + } else { + log.info("Receive StatusCode " + samlResp.getStatus().getStatusCode().getValue() + + " from 'ms-specific eIDAS node'."); + final StatusCode subStatusCode = getSubStatusCode(samlResp); + if (subStatusCode != null + && IdAustriaAuthConstants.SAML2_STATUSCODE_USERSTOP.equals(subStatusCode.getValue())) { + log.info("Find 'User-Stop operation' in SAML2 response. Stopping authentication process ... "); + return Pair.newInstance(msg, true); + + } + + // revisionsLogger.logEvent(pendingReq, + // EidasAuthEventConstants.AUTHPROCESS_EIDAS_AT_CONNECTOR_RECEIVED_ERROR); + throw new AuthnResponseValidationException(ERROR_PVP_05, + new Object[] { IdAustriaAuthConstants.MODULE_NAME_FOR_LOGGING, + samlResp.getIssuer().getValue(), + samlResp.getStatus().getStatusCode().getValue(), + samlResp.getStatus().getStatusMessage().getValue() }); + + } + + } + + /** + * Get SAML2 Sub-StatusCode if not <code>null</code>. + * + * @param samlResp SAML2 response + * @return Sub-StatusCode or <code>null</code> 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(List<String> requiredLoA) { + //TODO: implement LoA selection + return requiredLoA.get(0); + + } + + private List<EaafRequestedAttribute> buildRequestedAttributes(IRequest pendingReq) { + final List<EaafRequestedAttribute> attributs = new ArrayList<>(); + + //build attribute that contains the unique identifier of the eIDAS-Connector + injectAttribute(attributs, ExtendedPvpAttributeDefinitions.EIDAS_CONNECTOR_UNIQUEID_NAME, + pendingReq.getServiceProviderConfiguration().getUniqueIdentifier()); + + // build EID sector for identification attribute + injectAttribute(attributs, PvpAttributeDefinitions.EID_SECTOR_FOR_IDENTIFIER_NAME, + pendingReq.getServiceProviderConfiguration().getAreaSpecificTargetIdentifier()); + + // set requested LoA as attribute + injectAttribute(attributs, PvpAttributeDefinitions.EID_CITIZEN_EIDAS_QAA_LEVEL_NAME, + selectHighestLoa(pendingReq.getServiceProviderConfiguration().getRequiredLoA())); + + //set ProviderName if available + String providerName = ((ProxyServicePendingRequest)pendingReq).getEidasRequest().getProviderName(); + if (StringUtils.isNotEmpty(providerName)) { + injectAttribute(attributs, ExtendedPvpAttributeDefinitions.SP_FRIENDLYNAME_NAME, providerName); + + } + + //set ProviderName if available + String requesterId = ((ProxyServicePendingRequest)pendingReq).getEidasRequest().getRequesterId(); + if (StringUtils.isNotEmpty(requesterId)) { + injectAttribute(attributs, ExtendedPvpAttributeDefinitions.SP_UNIQUEID_NAME, requesterId); + + } + + //set mandate profiles + List<String> mandateProfiles = + pendingReq.getServiceProviderConfiguration(ServiceProviderConfiguration.class).getMandateProfiles(); + if (mandateProfiles != null && !mandateProfiles.isEmpty()) { + log.debug("Set mandate-profiles attribute into ID-Austria request"); + injectAttribute(attributs, ExtendedPvpAttributeDefinitions.SP_USED_MANDATE_PROFILES_NAME, + StringUtils.join(mandateProfiles, ",")); + + } + + // inject mandate mode attribute + injectAttribute(attributs, ExtendedPvpAttributeDefinitions.SP_USED_MANDATE_TYPE_NAME, + pendingReq.getServiceProviderConfiguration(ServiceProviderConfiguration.class).getMandateMode().getMode()); + + + return attributs; + } + + private void injectAttribute(List<EaafRequestedAttribute> attributs, String attributeName, String attributeValue) { + final Attribute requesterIdAttr = PvpAttributeBuilder.buildEmptyAttribute(attributeName); + final EaafRequestedAttribute requesterIdReqAttr = Saml2Utils.generateReqAuthnAttributeSimple( + requesterIdAttr, + true, + attributeValue); + attributs.add(requesterIdReqAttr); + + } + +} |