From fa2384985454568439dc286a6a9051fba47322ed Mon Sep 17 00:00:00 2001 From: Thomas Lenz Date: Mon, 25 Jan 2021 16:30:07 +0100 Subject: add ID Austria communication-module and additional jUnit test It's first alpha-version of eIDAS MS-specific Proxy-Service with ID Austria authentication --- .../tasks/RequestIdAustriaSystemTask.java | 209 +++++++++++++++++++++ 1 file changed, 209 insertions(+) create mode 100644 eidas_modules/authmodule_id-austria/src/main/java/at/asitplus/eidas/specific/modules/auth/idaustria/tasks/RequestIdAustriaSystemTask.java (limited to 'eidas_modules/authmodule_id-austria/src/main/java/at/asitplus/eidas/specific/modules/auth/idaustria/tasks/RequestIdAustriaSystemTask.java') diff --git a/eidas_modules/authmodule_id-austria/src/main/java/at/asitplus/eidas/specific/modules/auth/idaustria/tasks/RequestIdAustriaSystemTask.java b/eidas_modules/authmodule_id-austria/src/main/java/at/asitplus/eidas/specific/modules/auth/idaustria/tasks/RequestIdAustriaSystemTask.java new file mode 100644 index 00000000..fc46ac8b --- /dev/null +++ b/eidas_modules/authmodule_id-austria/src/main/java/at/asitplus/eidas/specific/modules/auth/idaustria/tasks/RequestIdAustriaSystemTask.java @@ -0,0 +1,209 @@ +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.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.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.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 = authConfig.getBasicConfiguration( + IdAustriaAuthConstants.CONFIG_PROPS_IDAUSTRIA_ENTITYID); + 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 requiredLoA) { + //TODO: implement LoA selection + return requiredLoA.get(0); + + } + + private List buildRequestedAttributes(IRequest pendingReq) { + final List attributs = new ArrayList<>(); + + //build attribute that contains the unique identifier of the eIDAS-Connector + final Attribute attrEidasConnectorId = PvpAttributeBuilder.buildEmptyAttribute( + ExtendedPvpAttributeDefinitions.EIDAS_CONNECTOR_UNIQUEID_NAME); + final EaafRequestedAttribute attrEidasConnectorIdReqAttr = Saml2Utils.generateReqAuthnAttributeSimple( + attrEidasConnectorId, + true, + pendingReq.getServiceProviderConfiguration().getUniqueIdentifier()); + attributs.add(attrEidasConnectorIdReqAttr); + + + // build EID sector for identification attribute + final Attribute attr = PvpAttributeBuilder.buildEmptyAttribute( + PvpAttributeDefinitions.EID_SECTOR_FOR_IDENTIFIER_NAME); + final EaafRequestedAttribute bpkTargetReqAttr = Saml2Utils.generateReqAuthnAttributeSimple( + attr, + true, + pendingReq.getServiceProviderConfiguration().getAreaSpecificTargetIdentifier()); + attributs.add(bpkTargetReqAttr); + + + // set requested LoA as attribute + final Attribute loaAttr = PvpAttributeBuilder.buildEmptyAttribute( + PvpAttributeDefinitions.EID_CITIZEN_EIDAS_QAA_LEVEL_NAME); + final EaafRequestedAttribute loaReqAttr = Saml2Utils.generateReqAuthnAttributeSimple( + loaAttr, + true, + selectHighestLoa(pendingReq.getServiceProviderConfiguration().getRequiredLoA())); + attributs.add(loaReqAttr); + + + //set ProviderName if available + String providerName = ((ProxyServicePendingRequest)pendingReq).getEidasRequest().getProviderName(); + if (StringUtils.isNotEmpty(providerName)) { + final Attribute providerNameAttr = PvpAttributeBuilder.buildEmptyAttribute( + ExtendedPvpAttributeDefinitions.SP_FRIENDLYNAME_NAME); + final EaafRequestedAttribute providerNameReqAttr = Saml2Utils.generateReqAuthnAttributeSimple( + providerNameAttr, + true, + providerName); + attributs.add(providerNameReqAttr); + + } + + + //set ProviderName if available + String requesterId = ((ProxyServicePendingRequest)pendingReq).getEidasRequest().getRequesterId(); + if (StringUtils.isNotEmpty(requesterId)) { + final Attribute requesterIdAttr = PvpAttributeBuilder.buildEmptyAttribute( + ExtendedPvpAttributeDefinitions.SP_UNIQUEID_NAME); + final EaafRequestedAttribute requesterIdReqAttr = Saml2Utils.generateReqAuthnAttributeSimple( + requesterIdAttr, + true, + requesterId); + attributs.add(requesterIdReqAttr); + + } + + return attributs; + } + +} -- cgit v1.2.3