From 709244c42e6dfe339805a1476a70a5690b1ee4dc Mon Sep 17 00:00:00 2001 From: Thomas <> Date: Thu, 1 Dec 2022 08:21:51 +0100 Subject: feat(proxyservice): add configuration flag to disable error forwarding to eIDAS Node --- .../Handbuch_MS-eIDAS-Proxy-Service.docx | Bin 44182 -> 44443 bytes .../handbook/Handbuch_MS-Proxy-Service.pdf | Bin 421548 -> 426156 bytes infos/ms-proxyservice/readme_1.0.1.md | 47 +++---- .../msproxyservice/MsProxyServiceConstants.java | 4 +- .../protocol/EidasProxyServiceController.java | 140 +++++++++++---------- .../protocol/EidasProxyServiceControllerTest.java | 28 +++++ .../src/main/resources/application.properties | 1 + 7 files changed, 122 insertions(+), 98 deletions(-) diff --git a/infos/ms-proxyservice/Handbuch_MS-eIDAS-Proxy-Service.docx b/infos/ms-proxyservice/Handbuch_MS-eIDAS-Proxy-Service.docx index ce9b4303..af0164af 100644 Binary files a/infos/ms-proxyservice/Handbuch_MS-eIDAS-Proxy-Service.docx and b/infos/ms-proxyservice/Handbuch_MS-eIDAS-Proxy-Service.docx differ diff --git a/infos/ms-proxyservice/handbook/Handbuch_MS-Proxy-Service.pdf b/infos/ms-proxyservice/handbook/Handbuch_MS-Proxy-Service.pdf index 6bcab73b..bd875ccd 100644 Binary files a/infos/ms-proxyservice/handbook/Handbuch_MS-Proxy-Service.pdf and b/infos/ms-proxyservice/handbook/Handbuch_MS-Proxy-Service.pdf differ diff --git a/infos/ms-proxyservice/readme_1.0.1.md b/infos/ms-proxyservice/readme_1.0.1.md index 7e37e0c9..4b4bfc3a 100644 --- a/infos/ms-proxyservice/readme_1.0.1.md +++ b/infos/ms-proxyservice/readme_1.0.1.md @@ -4,7 +4,17 @@ Das MS-Proxy-Service implementiert eine Bridge zwischen dem österreichischen E- ### Änderungen in dieser Version - - Initiale Version des eIDAS MS-Proxy-Service + - SAML2 AuthnRequests ohne NameIdPolicy, da dieser Parameter aktuell vom IDA Shibboleth IDP nicht unterstützt wird + - Fehlerrückgabe an den eIDAS Node per Default deaktiviert + - Aktualisierung von Drittherstellerbibliotheken + - EAAF-Components 1.3.8 + - SpringBoot 2.5.14 + - Spring-Framework 5.3.23 + - Apache CXF 3.5.4 + - commons-text 1.10.0 + - jackson-databind 2.13.4.2 + - log4j 2.19.0 + - logback-gelf 4.0.2 @@ -15,35 +25,10 @@ Nachfolgend finden Sie die erforderlichen Schritte für das Update eines bestehe ### Ausgehend von einer bestehenden Version 1.0.0 1. Stoppen Sie die *MS-Proxy-Service* Applikation und fertigen Sie eine Sicherungskopie Ihrer Applikation inklusive Konfiguration an -2. Entpacken Sie das Releasepacket *ms_specific_proxyservice-1.0.0-dist.zip* in ein temporäres Verzeichnis welches in weiterer Folge __MsProxyServicePackage__ bezeichnet wird. +2. Entpacken Sie das Releasepacket *ms_specific_proxyservice-1.0.1-dist.zip* in ein temporäres Verzeichnis welches in weiterer Folge __MsProxyServicePackage__ bezeichnet wird. 3. Kopieren sie die Applikation __MsProxyServicePackage__/ms_proxyservice.war nach in das Applikationsverzeichnis ihres Applikationsservers 4. Die Konfiguration besteht aus einer Minimalkonfiguration [`default_config.properties`](./../config/default_config.properties) und eine in das MS-Proxy-Service integrierten Defaultkonfiguration. Die nachfolgende Aufzählung umfasst die neuen oder geänderten Konfigurationsparameter, beschreibt jedoch keine Aufteilung einer bestehenden Konfiguration in Minimal- und Defaultteil. Eine vollständige Beschreibung aller Konfigurationswerte finden Sie im Handbuch zum AT MS-Proxy-Service. -5. Update bestehender Dateien . Die nachfolgenden Dateien wurden geändert und erfordern eine Anpassung oder eine Übernahme dem Releasepacket, sofern die Anpassung nicht bereits durchgeführt wurde. Sofern die entsprechenden Datein an die bestehende Infrastruktur angepasst wurden so müssen diese Änderungen übernommen werden. - - __MsProxyServicePackage__/config/templates/error_message.html - - __MsProxyServicePackage__/config/eIDAS/igniteSpecificCommunication.xml - Hinweis: Siehe auch Update-Hinweise zur EIDAS-Node v2.5 -6. Erstellung neuer Dateien - - _KeyStore für ID Austria AuthBlock:_ Erstellen eines KeyStore mit mit öffentlichem und privaten Schlüssel welcher für die JWS Signature des technischen ID Austria AuthBlocks verwendet werden soll. -7. Neue Konfigurationsparameter - - *Allgemeine Konfiguration* - - ```eidas.ms.core.configRootDir``` - - *ID Austria Umsetzung* - - ```eidas.ms.auth.eIDAS.authblock.keystore.type``` - - ```eidas.ms.auth.eIDAS.authblock.keystore.path``` - - ```eidas.ms.auth.eIDAS.authblock.keystore.password``` - - ```eidas.ms.auth.eIDAS.authblock.key.alias``` - - ```eidas.ms.auth.eIDAS.authblock.key.password``` - - *Service-Provider Konfiguration Konfiguration* - - ```eidas.ms.sp.x.newEidMode``` -8. Gelöschte Konfigurationsparameter - - - ```authhandler.modules.bindingservice.bpk.target``` -9. Neue optionale Konfigurationsparameter - - *Allgemeine Konfiguration* - - ```eidas.ms.core.logging.level.info.errorcodes``` - - *eIDAS Node Kommunikation* - * ```eidas.ms.auth.eIDAS.node_v2.requesterId.useHashedForm``` - * ```eidas.ms.auth.eIDAS.node_v2.requesterId.lu.useStaticRequesterForAll``` - - *ID Austria Umsetzung* - - ```eidas.ms.auth.eIDAS.eid.testidentity.default``` - - ```eidas.ms.auth.eIDAS.szrclient.eidasbind.mds.inject``` +5. Neue optionale Konfigurationsparameter + - ```eidas.ms.auth.eIDAS.node_v2.proxy.forward.errors``` + + diff --git a/modules/eidas_proxy-sevice/src/main/java/at/asitplus/eidas/specific/modules/msproxyservice/MsProxyServiceConstants.java b/modules/eidas_proxy-sevice/src/main/java/at/asitplus/eidas/specific/modules/msproxyservice/MsProxyServiceConstants.java index a2a2e78f..418d2799 100644 --- a/modules/eidas_proxy-sevice/src/main/java/at/asitplus/eidas/specific/modules/msproxyservice/MsProxyServiceConstants.java +++ b/modules/eidas_proxy-sevice/src/main/java/at/asitplus/eidas/specific/modules/msproxyservice/MsProxyServiceConstants.java @@ -18,7 +18,9 @@ public class MsProxyServiceConstants { public static final String CONIG_PROPS_EIDAS_PROXY_NODE_ENTITYID = EidasConstants.CONIG_PROPS_EIDAS_NODE + ".proxy.entityId"; public static final String CONIG_PROPS_EIDAS_PROXY_NODE_FORWARD_URL = EidasConstants.CONIG_PROPS_EIDAS_NODE - + ".proxy.forward.endpoint"; + + ".proxy.forward.endpoint"; + public static final String CONIG_PROPS_EIDAS_PROXY_NODE_FORWARD_ERRORS = EidasConstants.CONIG_PROPS_EIDAS_NODE + + ".proxy.forward.errors"; public static final String CONIG_PROPS_EIDAS_PROXY_ATTIBUTE_CONFIGURATION = diff --git a/modules/eidas_proxy-sevice/src/main/java/at/asitplus/eidas/specific/modules/msproxyservice/protocol/EidasProxyServiceController.java b/modules/eidas_proxy-sevice/src/main/java/at/asitplus/eidas/specific/modules/msproxyservice/protocol/EidasProxyServiceController.java index b5f6b6d2..4de28956 100644 --- a/modules/eidas_proxy-sevice/src/main/java/at/asitplus/eidas/specific/modules/msproxyservice/protocol/EidasProxyServiceController.java +++ b/modules/eidas_proxy-sevice/src/main/java/at/asitplus/eidas/specific/modules/msproxyservice/protocol/EidasProxyServiceController.java @@ -45,6 +45,7 @@ import at.gv.egiz.eaaf.core.api.data.EaafConstants; import at.gv.egiz.eaaf.core.api.data.ExtendedPvpAttributeDefinitions.SpMandateModes; import at.gv.egiz.eaaf.core.api.idp.IModulInfo; import at.gv.egiz.eaaf.core.api.idp.ISpConfiguration; +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.idp.controller.AbstractController; @@ -99,8 +100,7 @@ public class EidasProxyServiceController extends AbstractController implements I */ @RequestMapping(value = { MsProxyServiceConstants.EIDAS_HTTP_ENDPOINT_IDP_POST, - MsProxyServiceConstants.EIDAS_HTTP_ENDPOINT_IDP_REDIRECT - }, + MsProxyServiceConstants.EIDAS_HTTP_ENDPOINT_IDP_REDIRECT }, method = { RequestMethod.POST, RequestMethod.GET }) public void receiveEidasAuthnRequest(HttpServletRequest httpReq, HttpServletResponse httpResp) throws IOException, @@ -196,42 +196,9 @@ public class EidasProxyServiceController extends AbstractController implements I @Override public boolean generateErrorMessage(Throwable e, HttpServletRequest httpReq, HttpServletResponse httpResp, IRequest pendingReq) throws Throwable { - if (pendingReq instanceof ProxyServicePendingRequest) { - try { - final ILightRequest eidasReq = ((ProxyServicePendingRequest) pendingReq).getEidasRequest(); - - // build eIDAS response - final Builder lightRespBuilder = LightResponse.builder(); - lightRespBuilder.id(UUID.randomUUID().toString()); - lightRespBuilder.inResponseToId(eidasReq.getId()); - lightRespBuilder.relayState(eidasReq.getRelayState()); - lightRespBuilder.issuer(authConfig.getBasicConfiguration( - MsProxyServiceConstants.CONIG_PROPS_EIDAS_PROXY_NODE_ENTITYID)); - lightRespBuilder.subject(UUID.randomUUID().toString()); - lightRespBuilder.subjectNameIdFormat(NameIDType.TRANSIENT); - lightRespBuilder.status(ResponseStatus.builder() - .statusCode(StatusCode.RESPONDER) - .subStatusCode(EIDASSubStatusCode.AUTHN_FAILED_URI.getValue()) - .statusMessage(StringEscapeUtils.escapeXml(e.getLocalizedMessage())) - .build()); - - // forward to eIDAS Proxy-Service - responseAction.forwardToEidasProxy(pendingReq, httpReq, httpResp, lightRespBuilder.build()); - - return true; - - } catch (ServletException | IOException | GuiBuildException e1) { - log.warn("Forward error to eIDAS Proxy-Service FAILED. Handle error localy ... ", e1); - - } - - } else { - log.error("eIDAS Proxy-Service authentication requires PendingRequest of Type: {}", - ProxyServicePendingRequest.class.getName()); - - } - - return false; + return authConfig.getBasicConfigurationBoolean( + MsProxyServiceConstants.CONIG_PROPS_EIDAS_PROXY_NODE_FORWARD_ERRORS, false) + && generateAndSendError(e, httpReq, httpResp, pendingReq); } @@ -272,17 +239,17 @@ public class EidasProxyServiceController extends AbstractController implements I .distinct() .collect(Collectors.toSet()); - if (!requiredHandlers.isEmpty()) { + if (!requiredHandlers.isEmpty()) { log.info("eIDAS requested attributes requires #{} specific attribute-hander. " - + "Starting advanced attribute-validation ... ", requiredHandlers.size()); + + "Starting advanced attribute-validation ... ", requiredHandlers.size()); for (String el : requiredHandlers) { executeAdvancedRequestValidation(el, eidasRequest); - + } - + } else { log.debug("No advanced eIDAS attribute-validation required."); - + } } @@ -302,8 +269,8 @@ public class EidasProxyServiceController extends AbstractController implements I && EidasProxyServiceUtils.isNaturalPersonRequested(eidasRequest)) { throw new EidasProxyServiceException(ERROR_08, null); - } - + } + // TODO: validate some other stuff } @@ -354,10 +321,10 @@ public class EidasProxyServiceController extends AbstractController implements I // map eIDAS attributes to national attributes buildNationalRequestedAttributes(spConfig, eidasRequest); - + // execute custom attribute-handler advancedAttributeHandler(spConfig, eidasRequest); - + return spConfig; } catch (final EidasProxyServiceException e) { @@ -368,7 +335,7 @@ public class EidasProxyServiceController extends AbstractController implements I } } - + private void advancedAttributeHandler(ServiceProviderConfiguration spConfig, ILightRequest eidasRequest) { Set requiredHandlers = eidasRequest.getRequestedAttributes().getAttributeMap().keySet().stream() .map(el -> attrRegistry.mapEidasAttributeToAttributeHandler(el.getNameUri().toString()).orElse(null)) @@ -376,44 +343,46 @@ public class EidasProxyServiceController extends AbstractController implements I .distinct() .collect(Collectors.toSet()); - if (!requiredHandlers.isEmpty()) { + if (!requiredHandlers.isEmpty()) { log.info("eIDAS requested attributes requires #{} specific attribute-hander. " - + "Starting advanced attribute-handling ... ", requiredHandlers.size()); - requiredHandlers.forEach(el -> executeAttributeHandler(el, spConfig)); - + + "Starting advanced attribute-handling ... ", requiredHandlers.size()); + requiredHandlers.forEach(el -> executeAttributeHandler(el, spConfig)); + } else { log.debug("No advanced eIDAS attribute-handling required."); - - } + + } } private void executeAttributeHandler(String handlerClass, ServiceProviderConfiguration spConfig) { try { IEidasAttributeHandler handler = applicationContext.getBean(handlerClass, IEidasAttributeHandler.class); - + log.trace("Perfom SP config post-processing by using: {}", handler.getClass().getName()); handler.performSpConfigPostprocessing(spConfig); - + } catch (Exception e) { - log.error("No custom attribute-handler implementation for: {}. Operation can NOT be performed", handlerClass, e); - - } + log.error("No custom attribute-handler implementation for: {}. Operation can NOT be performed", + handlerClass, e); + + } } - private void executeAdvancedRequestValidation(String handlerClass, ILightRequest eidasRequest) + private void executeAdvancedRequestValidation(String handlerClass, ILightRequest eidasRequest) throws EidasProxyServiceException { try { IEidasAttributeHandler handler = applicationContext.getBean(handlerClass, IEidasAttributeHandler.class); - + log.trace("Perfom request-validastion by using: {}", handler.getClass().getName()); handler.validateAuthnRequest(eidasRequest); - + } catch (BeansException e) { - log.error("No custom attribute-handler implementation for: {}. Operation can NOT be performed", handlerClass, e); - - } + log.error("No custom attribute-handler implementation for: {}. Operation can NOT be performed", + handlerClass, e); + + } } - + private void buildNationalRequestedAttributes( ServiceProviderConfiguration spConfig, ILightRequest eidasRequest) { final boolean mandatesEnabled = !SpMandateModes.NONE.equals(spConfig.getMandateMode()); @@ -552,6 +521,45 @@ public class EidasProxyServiceController extends AbstractController implements I spConfig.getMandateProfiles(), spConfig.getUniqueIdentifier()); } + } + + private boolean generateAndSendError(Throwable e, HttpServletRequest httpReq, HttpServletResponse httpResp, + IRequest pendingReq) throws EaafConfigurationException { + if (pendingReq instanceof ProxyServicePendingRequest) { + try { + final ILightRequest eidasReq = ((ProxyServicePendingRequest) pendingReq).getEidasRequest(); + + // build eIDAS response + final Builder lightRespBuilder = LightResponse.builder(); + lightRespBuilder.id(UUID.randomUUID().toString()); + lightRespBuilder.inResponseToId(eidasReq.getId()); + lightRespBuilder.relayState(eidasReq.getRelayState()); + lightRespBuilder.issuer(authConfig.getBasicConfiguration( + MsProxyServiceConstants.CONIG_PROPS_EIDAS_PROXY_NODE_ENTITYID)); + lightRespBuilder.subject(UUID.randomUUID().toString()); + lightRespBuilder.subjectNameIdFormat(NameIDType.TRANSIENT); + lightRespBuilder.status(ResponseStatus.builder() + .statusCode(StatusCode.RESPONDER) + .subStatusCode(EIDASSubStatusCode.AUTHN_FAILED_URI.getValue()) + .statusMessage(StringEscapeUtils.escapeXml(e.getLocalizedMessage())) + .build()); + + // forward to eIDAS Proxy-Service + responseAction.forwardToEidasProxy(pendingReq, httpReq, httpResp, lightRespBuilder.build()); + + return true; + + } catch (ServletException | IOException | GuiBuildException e1) { + log.warn("Forward error to eIDAS Proxy-Service FAILED. Handle error localy ... ", e1); + + } + + } else { + log.error("eIDAS Proxy-Service authentication requires PendingRequest of Type: {}", + ProxyServicePendingRequest.class.getName()); + + } + return false; } } diff --git a/modules/eidas_proxy-sevice/src/test/java/at/asitplus/eidas/specific/modules/msproxyservice/test/protocol/EidasProxyServiceControllerTest.java b/modules/eidas_proxy-sevice/src/test/java/at/asitplus/eidas/specific/modules/msproxyservice/test/protocol/EidasProxyServiceControllerTest.java index 5894ea45..c23f1d53 100644 --- a/modules/eidas_proxy-sevice/src/test/java/at/asitplus/eidas/specific/modules/msproxyservice/test/protocol/EidasProxyServiceControllerTest.java +++ b/modules/eidas_proxy-sevice/src/test/java/at/asitplus/eidas/specific/modules/msproxyservice/test/protocol/EidasProxyServiceControllerTest.java @@ -93,6 +93,7 @@ public class EidasProxyServiceControllerTest { config.putConfigValue("eidas.ms.auth.eIDAS.node_v2.proxy.forward.endpoint", "http://eidas.proxy/endpoint"); + config.putConfigValue("eidas.ms.auth.eIDAS.node_v2.proxy.forward.errors", "true"); springManagedSpecificConnectorCommunicationService = (SpecificCommunicationService) context.getBean( @@ -154,6 +155,33 @@ public class EidasProxyServiceControllerTest { } + @Test + public void generateErrorResponseWithoutForward() throws Throwable { + config.putConfigValue("eidas.ms.auth.eIDAS.node_v2.proxy.forward.errors", "false"); + + ProxyServicePendingRequest pendingReq = new ProxyServicePendingRequest(); + pendingReq.initialize(httpReq, config); + + LightRequest.Builder eidasRequestBuilder = LightRequest.builder() + .id(UUID.randomUUID().toString()) + .issuer(RandomStringUtils.randomAlphabetic(10)) + .citizenCountryCode(RandomStringUtils.randomAlphabetic(2).toUpperCase()) + .levelOfAssurance(EaafConstants.EIDAS_LOA_HIGH) + .spCountryCode(RandomStringUtils.randomAlphabetic(2).toUpperCase()) + .spType("public") + .requesterId(RandomStringUtils.randomAlphanumeric(10)) + .providerName(RandomStringUtils.randomAlphanumeric(10)); + pendingReq.setEidasRequest(eidasRequestBuilder.build()); + + + // execute test + Assert.assertFalse("wrong statusCode", controller.generateErrorMessage( + new EaafException("1000"), + httpReq, httpResp, + pendingReq)); + + } + @Test public void missingEidasToken() { EidasProxyServiceException exception = assertThrows(EidasProxyServiceException.class, diff --git a/ms_specific_proxyservice/src/main/resources/application.properties b/ms_specific_proxyservice/src/main/resources/application.properties index b81cb612..084a6963 100644 --- a/ms_specific_proxyservice/src/main/resources/application.properties +++ b/ms_specific_proxyservice/src/main/resources/application.properties @@ -66,6 +66,7 @@ eidas.ms.auth.eIDAS.proxy.attribute.mapping.config=misc/idaAttributeMapping.json #### eIDAS ms-specific Proxy-Service configuration eidas.ms.auth.eIDAS.node_v2.proxy.entityId=ownSpecificProxy #eidas.ms.auth.eIDAS.node_v2.proxy.forward.endpoint= +eidas.ms.auth.eIDAS.node_v2.proxy.forward.errors=false eidas.ms.auth.eIDAS.node_v2.forward.method=POST # Mandate configuration -- cgit v1.2.3