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 --- .../msproxyservice/MsProxyServiceConstants.java | 12 ++ .../protocol/EidasProxyServiceController.java | 59 +++--- .../protocol/ProxyServiceAuthenticationAction.java | 200 +++++++++++++++++++-- 3 files changed, 232 insertions(+), 39 deletions(-) (limited to 'eidas_modules/eidas_proxy-sevice/src/main/java/at/asitplus/eidas') diff --git a/eidas_modules/eidas_proxy-sevice/src/main/java/at/asitplus/eidas/specific/modules/msproxyservice/MsProxyServiceConstants.java b/eidas_modules/eidas_proxy-sevice/src/main/java/at/asitplus/eidas/specific/modules/msproxyservice/MsProxyServiceConstants.java index a7c3b8e2..e5d4d33e 100644 --- a/eidas_modules/eidas_proxy-sevice/src/main/java/at/asitplus/eidas/specific/modules/msproxyservice/MsProxyServiceConstants.java +++ b/eidas_modules/eidas_proxy-sevice/src/main/java/at/asitplus/eidas/specific/modules/msproxyservice/MsProxyServiceConstants.java @@ -1,5 +1,9 @@ package at.asitplus.eidas.specific.modules.msproxyservice; +import at.asitplus.eidas.specific.modules.auth.eidas.v2.Constants; +import at.gv.egiz.eaaf.core.api.data.PvpAttributeDefinitions; +import at.gv.egiz.eaaf.core.impl.idp.auth.builder.AbstractAuthenticationDataBuilder; + /** * Constants for MS-specific eIDAS Proxy-Service. * @@ -11,7 +15,15 @@ public class MsProxyServiceConstants { //general constants public static final String TEMPLATE_SP_UNIQUE_ID = "eidasProxyAuth_from_{0}_type_{1}"; + public static final String ATTR_EIDAS_PERSONAL_IDENTIFIER = + AbstractAuthenticationDataBuilder.GENERIC_AUTHDATA_IDENTIFIER + PvpAttributeDefinitions.BPK_NAME; + //configuration constants + public static final String CONIG_PROPS_EIDAS_PROXY_NODE_ENTITYID = Constants.CONIG_PROPS_EIDAS_NODE + + ".proxy.entityId"; + public static final String CONIG_PROPS_EIDAS_PROXY_NODE_FORWARD_URL = Constants.CONIG_PROPS_EIDAS_NODE + + ".proxy.forward.endpoint"; + //http end-points public static final String EIDAS_HTTP_ENDPOINT_IDP_POST = "/eidas/light/idp/post"; diff --git a/eidas_modules/eidas_proxy-sevice/src/main/java/at/asitplus/eidas/specific/modules/msproxyservice/protocol/EidasProxyServiceController.java b/eidas_modules/eidas_proxy-sevice/src/main/java/at/asitplus/eidas/specific/modules/msproxyservice/protocol/EidasProxyServiceController.java index 47cfd3a9..aafe57e7 100644 --- a/eidas_modules/eidas_proxy-sevice/src/main/java/at/asitplus/eidas/specific/modules/msproxyservice/protocol/EidasProxyServiceController.java +++ b/eidas_modules/eidas_proxy-sevice/src/main/java/at/asitplus/eidas/specific/modules/msproxyservice/protocol/EidasProxyServiceController.java @@ -149,6 +149,32 @@ public class EidasProxyServiceController extends AbstractController implements I } + @Override + public boolean generateErrorMessage(Throwable e, HttpServletRequest request, HttpServletResponse response, + IRequest protocolRequest) throws Throwable { + + //TODO: implement error handling for eIDAS Node communication + return false; + + } + + @Override + public String getName() { + return EidasProxyServiceController.class.getName(); + + } + + @Override + public String getAuthProtocolIdentifier() { + return PROTOCOL_ID; + + } + + @Override + public boolean validate(HttpServletRequest request, HttpServletResponse response, IRequest pending) { + return true; + + } /** * Validate incoming eIDAS request. @@ -180,9 +206,12 @@ public class EidasProxyServiceController extends AbstractController implements I try { String spCountry = eidasRequest.getSpCountryCode(); Map spConfigMap = new HashMap<>(); + + //TODO: how we get the EntityId from eIDAS connector? spConfigMap.put(EaafConfigConstants.SERVICE_UNIQUEIDENTIFIER, MessageFormat.format(MsProxyServiceConstants.TEMPLATE_SP_UNIQUE_ID, spCountry, eidasRequest.getSpType())); + ServiceProviderConfiguration spConfig = new ServiceProviderConfiguration(spConfigMap, authConfig); final String ccCountry = authConfig.getBasicConfiguration(Constants.CONIG_PROPS_EIDAS_NODE_COUNTRYCODE, @@ -198,35 +227,7 @@ public class EidasProxyServiceController extends AbstractController implements I } catch (EaafException e) { throw new EidasProxyServiceException(ERROR_04, new Object[] {e.getMessage()}, e); - } - - } - - @Override - public boolean generateErrorMessage(Throwable e, HttpServletRequest request, HttpServletResponse response, - IRequest protocolRequest) throws Throwable { - - //TODO: implement error handling for eIDAS Node communication - return false; - - } - - @Override - public String getName() { - return EidasProxyServiceController.class.getName(); - - } - - @Override - public String getAuthProtocolIdentifier() { - return PROTOCOL_ID; - - } - - @Override - public boolean validate(HttpServletRequest request, HttpServletResponse response, IRequest pending) { - return true; - + } } } diff --git a/eidas_modules/eidas_proxy-sevice/src/main/java/at/asitplus/eidas/specific/modules/msproxyservice/protocol/ProxyServiceAuthenticationAction.java b/eidas_modules/eidas_proxy-sevice/src/main/java/at/asitplus/eidas/specific/modules/msproxyservice/protocol/ProxyServiceAuthenticationAction.java index 3ff35ac9..c51db460 100644 --- a/eidas_modules/eidas_proxy-sevice/src/main/java/at/asitplus/eidas/specific/modules/msproxyservice/protocol/ProxyServiceAuthenticationAction.java +++ b/eidas_modules/eidas_proxy-sevice/src/main/java/at/asitplus/eidas/specific/modules/msproxyservice/protocol/ProxyServiceAuthenticationAction.java @@ -1,18 +1,53 @@ package at.asitplus.eidas.specific.modules.msproxyservice.protocol; +import java.io.IOException; +import java.util.UUID; + +import javax.annotation.PostConstruct; +import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; +import org.apache.commons.lang3.StringUtils; +import org.opensaml.saml.saml2.core.NameIDType; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.ApplicationContext; +import org.springframework.core.io.ResourceLoader; +import org.springframework.web.util.UriComponentsBuilder; + +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.service.EidasAttributeRegistry; +import at.asitplus.eidas.specific.modules.msproxyservice.MsProxyServiceConstants; +import at.asitplus.eidas.specific.modules.msproxyservice.exception.EidasProxyServiceException; import at.gv.egiz.eaaf.core.api.IRequest; +import at.gv.egiz.eaaf.core.api.gui.ISpringMvcGuiFormBuilder; import at.gv.egiz.eaaf.core.api.idp.IAction; import at.gv.egiz.eaaf.core.api.idp.IAuthData; +import at.gv.egiz.eaaf.core.api.idp.IConfiguration; import at.gv.egiz.eaaf.core.api.idp.slo.SloInformationInterface; +import at.gv.egiz.eaaf.core.exceptions.EaafConfigurationException; import at.gv.egiz.eaaf.core.exceptions.EaafException; +import at.gv.egiz.eaaf.core.exceptions.GuiBuildException; +import at.gv.egiz.eaaf.core.impl.data.SloInformationImpl; +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.ILightResponse; +import eu.eidas.auth.commons.light.impl.LightResponse; +import eu.eidas.auth.commons.light.impl.LightResponse.Builder; +import eu.eidas.auth.commons.light.impl.ResponseStatus; +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; import lombok.extern.slf4j.Slf4j; /** * Result action of a successfully performed eIDAS Proxy-Service authentication. - * + * * @author tlenz * */ @@ -20,33 +55,178 @@ import lombok.extern.slf4j.Slf4j; public class ProxyServiceAuthenticationAction implements IAction { private static final String PROXYSERVICE_AUTH_ACTION_NAME = "MS-specific eIDAS-Proxy action"; - + + @Autowired + ApplicationContext context; + @Autowired + IConfiguration basicConfig; + @Autowired + ResourceLoader resourceLoader; + @Autowired + ISpringMvcGuiFormBuilder guiBuilder; + @Autowired + EidasAttributeRegistry attrRegistry; + @Override public SloInformationInterface processRequest(IRequest pendingReq, HttpServletRequest httpReq, HttpServletResponse httpResp, IAuthData authData) throws EaafException { if (pendingReq instanceof ProxyServicePendingRequest) { + try { + ILightRequest eidasReq = ((ProxyServicePendingRequest) pendingReq).getEidasRequest(); + + //build eIDAS response + Builder lightRespBuilder = LightResponse.builder(); + lightRespBuilder.id(UUID.randomUUID().toString()); + lightRespBuilder.inResponseToId(eidasReq.getId()); + lightRespBuilder.relayState(eidasReq.getRelayState()); + + lightRespBuilder.status(ResponseStatus.builder() + .statusCode(Constants.SUCCESS_URI) + .build()); + + //TODO: check if we can use transient subjectNameIds + lightRespBuilder.subject(UUID.randomUUID().toString()); + lightRespBuilder.subjectNameIdFormat(NameIDType.TRANSIENT); + + //TODO: + lightRespBuilder.issuer(basicConfig.getBasicConfiguration( + MsProxyServiceConstants.CONIG_PROPS_EIDAS_PROXY_NODE_ENTITYID)); + lightRespBuilder.levelOfAssurance(authData.getEidasQaaLevel()); + lightRespBuilder.attributes(buildAttributesFromAuthData(authData)); + + // put request into shared cache + final BinaryLightToken token = putResponseInCommunicationCache(lightRespBuilder.build()); + final String tokenBase64 = BinaryLightTokenHelper.encodeBinaryLightTokenBase64(token); + + // set SLO response object of EAAF framework + final SloInformationImpl sloInformation = new SloInformationImpl(); + sloInformation.setProtocolType(pendingReq.requestedModule()); + sloInformation + .setSpEntityID(pendingReq.getServiceProviderConfiguration().getUniqueIdentifier()); + + // forward to eIDAS Proxy-Service + forwardToEidasProxy(pendingReq, httpReq, httpResp, tokenBase64); + + return sloInformation; + + } catch (ServletException | IOException | GuiBuildException e) { + throw new EidasProxyServiceException("eidas.proxyservice.06", null, e); + + } - - return null; - } else { log.error("eIDAS Proxy-Service authentication requires PendingRequest of Type: {}", ProxyServicePendingRequest.class.getName()); throw new EaafException("eidas.proxyservice.99"); - - } - } + } + } + @Override - public boolean needAuthentication(IRequest req, HttpServletRequest httpReq, HttpServletResponse httpResp) { + public boolean needAuthentication(IRequest req, HttpServletRequest httpReq, HttpServletResponse httpResp) { return true; - + } @Override public String getDefaultActionName() { return PROXYSERVICE_AUTH_ACTION_NAME; + + } + + + @PostConstruct + private void checkConfiguration() { + //TODO: validate configuration on start-up } + + + private ImmutableAttributeMap buildAttributesFromAuthData(IAuthData authData) { + final AttributeDefinition attrDefPersonalId = attrRegistry.getCoreAttributeRegistry().getByFriendlyName( + Constants.eIDAS_ATTR_PERSONALIDENTIFIER).first(); + final AttributeDefinition attrDefFamilyName = attrRegistry.getCoreAttributeRegistry().getByFriendlyName( + Constants.eIDAS_ATTR_CURRENTFAMILYNAME).first(); + final AttributeDefinition attrDefGivenName = attrRegistry.getCoreAttributeRegistry().getByFriendlyName( + Constants.eIDAS_ATTR_CURRENTGIVENNAME).first(); + final AttributeDefinition attrDefDateOfBirth = attrRegistry.getCoreAttributeRegistry().getByFriendlyName( + Constants.eIDAS_ATTR_DATEOFBIRTH).first(); + + final ImmutableAttributeMap.Builder attributeMap = + ImmutableAttributeMap.builder().put(attrDefPersonalId, + authData.getGenericData(MsProxyServiceConstants.ATTR_EIDAS_PERSONAL_IDENTIFIER, String.class)) + .put(attrDefFamilyName, authData.getFamilyName()) + .put(attrDefGivenName, authData.getGivenName()) + .put(attrDefDateOfBirth, authData.getFormatedDateOfBirth()); + + return attributeMap.build(); + + } + + private BinaryLightToken putResponseInCommunicationCache(ILightResponse lightResponse) + throws ServletException { + final BinaryLightToken binaryLightToken; + try { + final SpecificCommunicationService springManagedSpecificConnectorCommunicationService = + (SpecificCommunicationService) context.getBean( + SpecificCommunicationDefinitionBeanNames.SPECIFIC_PROXYSERVICE_COMMUNICATION_SERVICE + .toString()); + + binaryLightToken = springManagedSpecificConnectorCommunicationService.putResponse(lightResponse); + + } catch (final SpecificCommunicationException e) { + log.error("Unable to process specific request"); + throw new ServletException(e); + + } + + return binaryLightToken; + } + + private void forwardToEidasProxy(IRequest pendingReq, HttpServletRequest httpReq, + HttpServletResponse httpResp, String tokenBase64) throws EaafConfigurationException, IOException, + GuiBuildException { + // select forward URL regarding the selected environment + final String forwardUrl = basicConfig.getBasicConfiguration( + MsProxyServiceConstants.CONIG_PROPS_EIDAS_PROXY_NODE_FORWARD_URL); + + 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[] { MsProxyServiceConstants.CONIG_PROPS_EIDAS_PROXY_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 + final UriComponentsBuilder redirectUrl = UriComponentsBuilder.fromHttpUrl(forwardUrl); + redirectUrl.queryParam(EidasParameterKeys.TOKEN.toString(), tokenBase64); + httpResp.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(httpReq, httpResp, config, "Forward to eIDASNode form"); + + } + + } } -- cgit v1.2.3