diff options
15 files changed, 304 insertions, 15 deletions
diff --git a/modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/Constants.java b/modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/Constants.java index c9d13eaf..70a1e69a 100644 --- a/modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/Constants.java +++ b/modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/Constants.java @@ -23,6 +23,7 @@ package at.asitplus.eidas.specific.modules.auth.eidas.v2; +import at.asitplus.eidas.specific.core.MsEidasNodeConstants; import at.asitplus.eidas.specific.modules.core.eidas.EidasConstants; import at.gv.egiz.eaaf.core.api.data.EaafConstants; @@ -33,10 +34,11 @@ public class Constants { public static final String ERRORCODE_00 = "module.eidasauth.00"; - public static final String DATA_REQUESTERID = "req_requesterId"; - public static final String DATA_PROVIDERNAME = "req_providerName"; - public static final String DATA_REQUESTED_LOA_LIST = "req_requestedLoA"; - public static final String DATA_REQUESTED_LOA_COMPERISON = "req_requestedLoAComperision"; + public static final String DATA_REQUESTERID = MsEidasNodeConstants.DATA_REQUESTERID; + public static final String DATA_PROVIDERNAME = MsEidasNodeConstants.DATA_PROVIDERNAME; + public static final String DATA_REQUESTED_LOA_LIST = MsEidasNodeConstants.DATA_REQUESTED_LOA_LIST; + public static final String DATA_REQUESTED_LOA_COMPERISON = MsEidasNodeConstants.DATA_REQUESTED_LOA_COMPERISON; + public static final String DATA_FULL_EIDAS_RESPONSE = "resp_fulleIDASResponse"; public static final String DATA_FULL_EIDAS_RESPONSE_ALTERNATIVE = "resp_fulleIDASResponseAlternative"; diff --git a/modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/tasks/AlternativeSearchTask.java b/modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/tasks/AlternativeSearchTask.java index 604a6588..6530c7b3 100644 --- a/modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/tasks/AlternativeSearchTask.java +++ b/modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/tasks/AlternativeSearchTask.java @@ -110,6 +110,9 @@ public class AlternativeSearchTask extends AbstractAuthServletTask { MatchingTaskUtils.getDetailedMatchingStatistic(pendingReq).incrementAlternativEidas(); + // store pending request before next step + requestStoreage.storePendingRequest(pendingReq); + //pre-validation of eIDAS data if (!preVerifyAlternativeEidasData(altEidasData, initialEidasData, intermediateMatchingState, executionContext)) { diff --git a/modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/tasks/ReceiveAustrianResidenceGuiResponseTask.java b/modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/tasks/ReceiveAustrianResidenceGuiResponseTask.java index ecdf8ce0..09b90a1d 100644 --- a/modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/tasks/ReceiveAustrianResidenceGuiResponseTask.java +++ b/modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/tasks/ReceiveAustrianResidenceGuiResponseTask.java @@ -54,6 +54,7 @@ import at.asitplus.eidas.specific.modules.auth.eidas.v2.service.RegisterSearchSe import at.asitplus.eidas.specific.modules.auth.eidas.v2.service.RegisterSearchService.RegisterStatusResults; import at.asitplus.eidas.specific.modules.auth.eidas.v2.utils.MatchingTaskUtils; 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.EaafStorageException; import at.gv.egiz.eaaf.core.exceptions.TaskExecutionException; import at.gv.egiz.eaaf.core.impl.idp.controller.tasks.AbstractLocaleAuthServletTask; @@ -163,11 +164,15 @@ public class ReceiveAustrianResidenceGuiResponseTask extends AbstractLocaleAuthS executionContext.put(TRANSITION_TO_GENERATE_GUI_QUERY_AUSTRIAN_RESIDENCE_TASK, false); } - + + // store pending request before next step + requestStoreage.storePendingRequest(pendingReq); + + } catch (WorkflowException e) { throw new TaskExecutionException(pendingReq, "Search with residency data failed", e); - } catch (EaafStorageException e) { + } catch (EaafException e) { log.error("Search with residency data failed", e); throw new TaskExecutionException(pendingReq, "Search with residency data failed", e); diff --git a/modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/tasks/ReceiveMobilePhoneSignatureResponseTask.java b/modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/tasks/ReceiveMobilePhoneSignatureResponseTask.java index 7db61bd0..644c1543 100644 --- a/modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/tasks/ReceiveMobilePhoneSignatureResponseTask.java +++ b/modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/tasks/ReceiveMobilePhoneSignatureResponseTask.java @@ -172,6 +172,9 @@ public class ReceiveMobilePhoneSignatureResponseTask extends AbstractAuthServlet log.info("Receive a valid assertion from IDP " + inboundMessage.getEntityID()); MatchingTaskUtils.getDetailedMatchingStatistic(pendingReq).setIdaLoginUsed(true); + // store pending request before next step + requestStoreage.storePendingRequest(pendingReq); + // load already existing information from session SimpleEidasData eidasData = MatchingTaskUtils.getInitialEidasData(pendingReq); RegisterStatusResults initialSearchResult = MatchingTaskUtils.getIntermediateMatchingResult(pendingReq); diff --git a/modules/authmodule-eIDAS-v2/src/test/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/test/tasks/AlternativeSearchTaskWithRegisterTest.java b/modules/authmodule-eIDAS-v2/src/test/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/test/tasks/AlternativeSearchTaskWithRegisterTest.java index 25a8a5b5..2506a9b6 100644 --- a/modules/authmodule-eIDAS-v2/src/test/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/test/tasks/AlternativeSearchTaskWithRegisterTest.java +++ b/modules/authmodule-eIDAS-v2/src/test/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/test/tasks/AlternativeSearchTaskWithRegisterTest.java @@ -75,6 +75,7 @@ import at.gv.bmi.namespace.zmr_su.base._20040201_.ServicePort; import at.gv.bmi.namespace.zmr_su.zmr._20040201.EidasIdentitaetAnlageType; import at.gv.bmi.namespace.zmr_su.zmr._20040201.EidasSuchdatenType; import at.gv.egiz.eaaf.core.api.IRequest; +import at.gv.egiz.eaaf.core.api.IRequestStorage; 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.EaafStorageException; @@ -105,6 +106,10 @@ public class AlternativeSearchTaskWithRegisterTest { @Autowired private IZmrClient zmrClient; @Autowired private List<CountrySpecificDetailSearchProcessor> handlers; + + @Autowired(required = true) + protected IRequestStorage requestStoreage; + private RegisterSearchService registerSearchService; private ServicePort zmrMock = null; @@ -142,6 +147,7 @@ public class AlternativeSearchTaskWithRegisterTest { registerSearchService = new RegisterSearchService(handlers, zmrClient, ernpClient); task = new AlternativeSearchTask(registerSearchService, eidPostProcessor); + task.setRequestStoreage(requestStoreage); MockHttpServletRequest httpReq = new MockHttpServletRequest("POST", "https://localhost/authhandler"); MockHttpServletResponse httpResp = new MockHttpServletResponse(); diff --git a/modules/authmodule-eIDAS-v2/src/test/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/test/tasks/ReceiveAustrianResidenceGuiResponseTaskRegisterTest.java b/modules/authmodule-eIDAS-v2/src/test/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/test/tasks/ReceiveAustrianResidenceGuiResponseTaskRegisterTest.java index 8d52baf3..8d3959f4 100644 --- a/modules/authmodule-eIDAS-v2/src/test/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/test/tasks/ReceiveAustrianResidenceGuiResponseTaskRegisterTest.java +++ b/modules/authmodule-eIDAS-v2/src/test/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/test/tasks/ReceiveAustrianResidenceGuiResponseTaskRegisterTest.java @@ -51,6 +51,7 @@ import at.asitplus.eidas.specific.modules.auth.eidas.v2.test.clients.ZmrClientTe import at.asitplus.eidas.specific.modules.auth.eidas.v2.utils.MatchingTaskUtils; import at.gv.bmi.namespace.zmr_su.base._20040201.ResponseType; import at.gv.bmi.namespace.zmr_su.base._20040201_.ServicePort; +import at.gv.egiz.eaaf.core.api.IRequestStorage; 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.EaafStorageException; @@ -70,6 +71,9 @@ public class ReceiveAustrianResidenceGuiResponseTaskRegisterTest { @Autowired protected MsConnectorDummyConfigMap authConfig; + @Autowired(required = true) + protected IRequestStorage requestStoreage; + @Autowired private RegisterSearchService registerSearchService; @@ -112,6 +116,7 @@ public class ReceiveAustrianResidenceGuiResponseTaskRegisterTest { executionContext = new ExecutionContextImpl(); task = new ReceiveAustrianResidenceGuiResponseTask(registerSearchService); + task.setRequestStoreage(requestStoreage); httpReq = new MockHttpServletRequest("POST", "https://localhost/ms_connector"); httpResp = new MockHttpServletResponse(); diff --git a/modules/authmodule-eIDAS-v2/src/test/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/test/tasks/ReceiveAustrianResidenceGuiResponseTaskTest.java b/modules/authmodule-eIDAS-v2/src/test/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/test/tasks/ReceiveAustrianResidenceGuiResponseTaskTest.java index 3bd86e63..83284455 100644 --- a/modules/authmodule-eIDAS-v2/src/test/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/test/tasks/ReceiveAustrianResidenceGuiResponseTaskTest.java +++ b/modules/authmodule-eIDAS-v2/src/test/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/test/tasks/ReceiveAustrianResidenceGuiResponseTaskTest.java @@ -41,6 +41,7 @@ import at.asitplus.eidas.specific.modules.auth.eidas.v2.service.RegisterSearchSe import at.asitplus.eidas.specific.modules.auth.eidas.v2.service.RegisterSearchService.RegisterStatusResults; import at.asitplus.eidas.specific.modules.auth.eidas.v2.tasks.ReceiveAustrianResidenceGuiResponseTask; import at.asitplus.eidas.specific.modules.auth.eidas.v2.utils.MatchingTaskUtils; +import at.gv.egiz.eaaf.core.api.IRequestStorage; import at.gv.egiz.eaaf.core.api.idp.process.ExecutionContext; import at.gv.egiz.eaaf.core.exceptions.EaafStorageException; import at.gv.egiz.eaaf.core.impl.idp.auth.data.AuthProcessDataWrapper; @@ -58,6 +59,9 @@ public class ReceiveAustrianResidenceGuiResponseTaskTest { @Autowired protected MsConnectorDummyConfigMap authConfig; + @Autowired(required = true) + protected IRequestStorage requestStoreage; + @MockBean private RegisterSearchService registerSearchService; @@ -77,7 +81,8 @@ public class ReceiveAustrianResidenceGuiResponseTaskTest { public void setUp() throws Exception { executionContext = new ExecutionContextImpl(); task = new ReceiveAustrianResidenceGuiResponseTask(registerSearchService); - + task.setRequestStoreage(requestStoreage); + httpReq = new MockHttpServletRequest("POST", "https://localhost/ms_connector"); httpResp = new MockHttpServletResponse(); RequestContextHolder.resetRequestAttributes(); diff --git a/modules/authmodule-eIDAS-v2/src/test/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/test/tasks/ReceiveOtherLoginMethodGuiResponseTaskTest.java b/modules/authmodule-eIDAS-v2/src/test/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/test/tasks/ReceiveOtherLoginMethodGuiResponseTaskTest.java index 080731d9..dfd355de 100644 --- a/modules/authmodule-eIDAS-v2/src/test/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/test/tasks/ReceiveOtherLoginMethodGuiResponseTaskTest.java +++ b/modules/authmodule-eIDAS-v2/src/test/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/test/tasks/ReceiveOtherLoginMethodGuiResponseTaskTest.java @@ -7,6 +7,8 @@ import static org.junit.Assert.assertNull; import static org.junit.Assert.assertThrows; import static org.junit.Assert.assertTrue; +import java.util.Collections; + import org.apache.commons.lang3.RandomStringUtils; import org.junit.Before; import org.junit.BeforeClass; @@ -23,14 +25,20 @@ import org.springframework.test.context.web.WebAppConfiguration; import org.springframework.web.context.request.RequestContextHolder; import org.springframework.web.context.request.ServletRequestAttributes; +import at.asitplus.eidas.specific.core.MsEidasNodeConstants; import at.asitplus.eidas.specific.core.test.config.dummy.MsConnectorDummyConfigMap; import at.asitplus.eidas.specific.modules.auth.eidas.v2.Constants; import at.asitplus.eidas.specific.modules.auth.eidas.v2.dao.SelectedLoginMethod; import at.asitplus.eidas.specific.modules.auth.eidas.v2.tasks.ReceiveOtherLoginMethodGuiResponseTask; +import at.gv.egiz.eaaf.core.api.IRequest; +import at.gv.egiz.eaaf.core.api.IRequestStorage; +import at.gv.egiz.eaaf.core.api.idp.ISpConfiguration; import at.gv.egiz.eaaf.core.exceptions.EaafException; import at.gv.egiz.eaaf.core.exceptions.TaskExecutionException; +import at.gv.egiz.eaaf.core.impl.idp.module.test.DummySpConfiguration; import at.gv.egiz.eaaf.core.impl.idp.module.test.TestRequestImpl; import at.gv.egiz.eaaf.core.impl.idp.process.ExecutionContextImpl; +import lombok.SneakyThrows; @RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration(locations = { @@ -44,6 +52,9 @@ public class ReceiveOtherLoginMethodGuiResponseTaskTest { @Autowired MsConnectorDummyConfigMap config; @Autowired + private IRequestStorage storage; + + @Autowired private ReceiveOtherLoginMethodGuiResponseTask task; private final ExecutionContextImpl executionContext = new ExecutionContextImpl(); @@ -70,22 +81,34 @@ public class ReceiveOtherLoginMethodGuiResponseTaskTest { RequestContextHolder.resetRequestAttributes(); RequestContextHolder.setRequestAttributes(new ServletRequestAttributes(httpReq, httpResp)); + ISpConfiguration spConfig = new DummySpConfiguration(Collections.emptyMap(), config); pendingReq = new TestRequestImpl(); pendingReq.setAuthUrl("https://localhost/ms_connector"); pendingReq.setPendingReqId(RandomStringUtils.randomAlphanumeric(10)); - + + pendingReq.setSpConfig(spConfig); config.putConfigValue("auth.eIDAS.matching.byaddress.enable", "false"); LocaleContextHolder.resetLocaleContext(); } @Test + @SneakyThrows public void withStopMatchingSelection() throws TaskExecutionException { -httpReq.setParameter(Constants.REQ_SELECTED_LOGIN_METHOD_PARAMETER, SelectedLoginMethod.STOP_MATCHING_PROCESS.name()); + httpReq.setParameter(Constants.REQ_SELECTED_LOGIN_METHOD_PARAMETER, SelectedLoginMethod.STOP_MATCHING_PROCESS.name()); task.execute(pendingReq, executionContext); - assertTrue("stoppedByUser", pendingReq.isAbortedByUser()); + assertTrue("stoppedByUser", pendingReq.isAbortedByUser()); + assertNotNull("matchingstate", pendingReq.getRawData(MsEidasNodeConstants.DATA_MATCHING_STATE)); + assertEquals("matchingState", MsEidasNodeConstants.MatchingStates.CANCELED_BY_USER, + pendingReq.getRawData(MsEidasNodeConstants.DATA_MATCHING_STATE)); + + IRequest storedPendingReq = storage.getPendingRequest(pendingReq.getPendingRequestId()); + assertNotNull("pendingReq not stored", storedPendingReq); + assertNotNull("matchingstate storedReq", storedPendingReq.getRawData(MsEidasNodeConstants.DATA_MATCHING_STATE)); + assertEquals("matchingState storedReq", MsEidasNodeConstants.MatchingStates.CANCELED_BY_USER, + storedPendingReq.getRawData(MsEidasNodeConstants.DATA_MATCHING_STATE)); } diff --git a/modules/authmodule_id-austria/src/main/java/at/asitplus/eidas/specific/modules/auth/idaustria/utils/IdAustriaAuthHealthCheck.java b/modules/authmodule_id-austria/src/main/java/at/asitplus/eidas/specific/modules/auth/idaustria/utils/IdAustriaAuthHealthCheck.java new file mode 100644 index 00000000..5e1d889e --- /dev/null +++ b/modules/authmodule_id-austria/src/main/java/at/asitplus/eidas/specific/modules/auth/idaustria/utils/IdAustriaAuthHealthCheck.java @@ -0,0 +1,80 @@ +package at.asitplus.eidas.specific.modules.auth.idaustria.utils; + +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.Executors; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; + +import org.apache.commons.lang3.StringUtils; +import org.opensaml.saml.saml2.metadata.EntityDescriptor; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.actuate.health.Health; +import org.springframework.boot.actuate.health.HealthIndicator; + +import at.asitplus.eidas.specific.modules.auth.idaustria.IdAustriaAuthConstants; +import at.gv.egiz.eaaf.core.api.idp.IConfiguration; +import lombok.extern.slf4j.Slf4j; +import net.shibboleth.utilities.java.support.resolver.ResolverException; + +/** + * Spring Actuator HealthCheck for ID Austria client that evaluates the current status of + * ID Austria SAML2 metadata that are loaded into MS-ProxyService. + * + * @author tlenz + * + */ +@Slf4j +public class IdAustriaAuthHealthCheck implements HealthIndicator { + + private static final int DEADLINE = 3; + + @Autowired IConfiguration authConfig; + @Autowired IdAustriaAuthMetadataProvider metadataService; + + @Override + public Health health() { + String msNodeEntityID = authConfig.getBasicConfiguration( + IdAustriaAuthConstants.CONFIG_PROPS_IDAUSTRIA_METADATAURL); + + if (StringUtils.isEmpty(msNodeEntityID)) { + log.trace("No ID Austria EntityId in configuration. Skipping tests ... "); + return Health.unknown().build(); + + } + + CompletableFuture<Health> asynchTestOperation = new CompletableFuture<>(); + Executors.newCachedThreadPool().submit(() -> runConnectionTest(asynchTestOperation, msNodeEntityID)); + try { + return asynchTestOperation.get(DEADLINE, TimeUnit.SECONDS); + + } catch (InterruptedException | ExecutionException | TimeoutException e) { + log.info("Receive no respose from Health-Check after {} seconds.", DEADLINE); + return Health.outOfService().withException(e).build(); + + } + + + } + + + private void runConnectionTest(CompletableFuture<Health> completableFuture, String entityId) { + try { + EntityDescriptor connectorMetadata = + metadataService.getEntityDescriptor(entityId); + if (connectorMetadata != null) { + completableFuture.complete(Health.up().build()); + + } else { + completableFuture.complete(Health.outOfService().withDetail("Reason", "No SAML2 metadata").build()); + + } + + } catch (ResolverException e) { + completableFuture.complete(Health.down(e).build()); + + } + + } + +} diff --git a/modules/authmodule_id-austria/src/main/resources/spring/id_austria_auth.beans.xml b/modules/authmodule_id-austria/src/main/resources/spring/id_austria_auth.beans.xml index d2d16bf9..176e5424 100644 --- a/modules/authmodule_id-austria/src/main/resources/spring/id_austria_auth.beans.xml +++ b/modules/authmodule_id-austria/src/main/resources/spring/id_austria_auth.beans.xml @@ -28,6 +28,9 @@ <bean id="idAustriaAuthMetadataProvider" class="at.asitplus.eidas.specific.modules.auth.idaustria.utils.IdAustriaAuthMetadataProvider" /> + + <bean id="idAustriaAuthMetadataHealth" + class="at.asitplus.eidas.specific.modules.auth.idaustria.utils.IdAustriaAuthHealthCheck" /> <!-- bean id="eidasAuthHealthCheck" class="at.gv.egiz.eid.authhandler.modules.auth.eidas.utils.EidasCentralAuthHealthCheck" /--> diff --git a/modules/authmodule_id-austria/src/test/java/at/asitplus/eidas/specific/modules/auth/idaustria/test/utils/IdAustriaAuthHealthCheckTest.java b/modules/authmodule_id-austria/src/test/java/at/asitplus/eidas/specific/modules/auth/idaustria/test/utils/IdAustriaAuthHealthCheckTest.java new file mode 100644 index 00000000..9856ca73 --- /dev/null +++ b/modules/authmodule_id-austria/src/test/java/at/asitplus/eidas/specific/modules/auth/idaustria/test/utils/IdAustriaAuthHealthCheckTest.java @@ -0,0 +1,130 @@ +package at.asitplus.eidas.specific.modules.auth.idaustria.test.utils; + +import java.time.Instant; +import java.time.temporal.ChronoUnit; + +import org.junit.Assert; +import org.junit.BeforeClass; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.opensaml.core.xml.config.XMLObjectProviderRegistrySupport; +import org.opensaml.core.xml.io.MarshallingException; +import org.opensaml.core.xml.io.UnmarshallingException; +import org.opensaml.core.xml.util.XMLObjectSupport; +import org.opensaml.saml.saml2.metadata.EntityDescriptor; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.actuate.health.Health; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; +import org.w3c.dom.Element; + +import at.asitplus.eidas.specific.core.test.config.dummy.MsConnectorDummyConfigMap; +import at.asitplus.eidas.specific.modules.auth.idaustria.IdAustriaAuthConstants; +import at.asitplus.eidas.specific.modules.auth.idaustria.utils.IdAustriaAuthHealthCheck; +import at.asitplus.eidas.specific.modules.auth.idaustria.utils.IdAustriaAuthMetadataProvider; +import at.gv.egiz.eaaf.modules.pvp2.api.utils.IPvp2CredentialProvider; +import at.gv.egiz.eaaf.modules.pvp2.exception.CredentialsNotAvailableException; +import at.gv.egiz.eaaf.modules.pvp2.exception.SamlSigningException; +import at.gv.egiz.eaaf.modules.pvp2.impl.opensaml.initialize.EaafOpenSaml3xInitializer; +import at.gv.egiz.eaaf.modules.pvp2.impl.utils.Saml2Utils; +import net.shibboleth.utilities.java.support.resolver.ResolverException; +import net.shibboleth.utilities.java.support.xml.SerializeSupport; +import net.shibboleth.utilities.java.support.xml.XMLParserException; +import okhttp3.HttpUrl; +import okhttp3.mockwebserver.MockResponse; +import okhttp3.mockwebserver.MockWebServer; + +@RunWith(SpringJUnit4ClassRunner.class) +@ContextConfiguration(locations = { + "/spring/SpringTest-context_basic_test.xml", + "/spring/SpringTest-context_basic_mapConfig.xml" +}) +public class IdAustriaAuthHealthCheckTest { + + @Autowired private IdAustriaAuthHealthCheck toCheck; + @Autowired protected MsConnectorDummyConfigMap config; + @Autowired private IPvp2CredentialProvider credentialProvider; + @Autowired IdAustriaAuthMetadataProvider provider; + + private static MockWebServer mockWebServer; + private static HttpUrl mockServerUrl; + + /** + * JUnit class initializer. + * + * @throws Exception In case of an OpenSAML3 initialization error + */ + @BeforeClass + public static void classInitializer() throws Exception { + EaafOpenSaml3xInitializer.eaafInitialize(); + + mockWebServer = new MockWebServer(); + mockServerUrl = mockWebServer.url("/sp/metadata"); + + } + + @Test + public void notActive() { + //set-up test + config.putConfigValue(IdAustriaAuthConstants.CONFIG_PROPS_IDAUSTRIA_METADATAURL, + null); + + //perform check + Health status = toCheck.health(); + + //evaluate status + Assert.assertEquals("wrong status", Health.unknown().build().getStatus(), status.getStatus()); + + } + + @Test + public void success() throws SamlSigningException, CredentialsNotAvailableException, + XMLParserException, UnmarshallingException, MarshallingException { + + //set-up test + config.putConfigValue(IdAustriaAuthConstants.CONFIG_PROPS_IDAUSTRIA_METADATAURL, + mockServerUrl.url().toString()); + injectValidHttpMetadata(mockServerUrl.url().toString()); + + //perform check + Health status = toCheck.health(); + + //evaluate status + Assert.assertEquals("wrong status", Health.up().build().getStatus(), status.getStatus()); + + } + + @Test + public void invalid() throws SamlSigningException, CredentialsNotAvailableException, + XMLParserException, UnmarshallingException, MarshallingException, ResolverException { + //set-up test + provider.clear(); + config.putConfigValue(IdAustriaAuthConstants.CONFIG_PROPS_IDAUSTRIA_METADATAURL, + "http://localhost:1234/junit/metadata"); + + //perform check + Health status = toCheck.health(); + + //evaluate status + Assert.assertEquals("wrong status", Health.outOfService().build().getStatus(), status.getStatus()); + + } + + private String injectValidHttpMetadata(String dynEntityId) throws XMLParserException, + UnmarshallingException, MarshallingException, SamlSigningException, CredentialsNotAvailableException { + final EntityDescriptor metadata = (EntityDescriptor) XMLObjectSupport.unmarshallFromInputStream( + XMLObjectProviderRegistrySupport.getParserPool(), + IdAustriaAuthHealthCheckTest.class.getResourceAsStream("/data/idp_metadata_no_sig.xml")); + metadata.setValidUntil(Instant.now().plus(1, ChronoUnit.DAYS)); + metadata.setSignature(null); + metadata.setEntityID(dynEntityId); + Saml2Utils.signSamlObject(metadata, credentialProvider.getMetaDataSigningCredential(), true); + final Element metadataElement = XMLObjectSupport.marshall(metadata); + mockWebServer.enqueue(new MockResponse().setResponseCode(200) + .setBody(SerializeSupport.nodeToString(metadataElement)) + .setHeader("Content-Type", "text/html;charset=utf-8")); + return dynEntityId; + +} + +} diff --git a/ms_specific_connector/src/main/java/at/asitplus/eidas/specific/core/logger/AdvancedStatisicLogger.java b/ms_specific_connector/src/main/java/at/asitplus/eidas/specific/core/logger/AdvancedStatisicLogger.java index 538048ca..cfa93286 100644 --- a/ms_specific_connector/src/main/java/at/asitplus/eidas/specific/core/logger/AdvancedStatisicLogger.java +++ b/ms_specific_connector/src/main/java/at/asitplus/eidas/specific/core/logger/AdvancedStatisicLogger.java @@ -62,9 +62,11 @@ public class AdvancedStatisicLogger implements IStatisticLogger { entry.setSuccess(SuccessEntry.builder() .spSector(protocolRequest.getServiceProviderConfiguration().getAreaSpecificTargetIdentifier()) .citizenCountryCode(authData.getCiticenCountryCode()) + .build()); + entry.setMatching(MatchingDetails.builder() .matchingMethod(extractMatchingState(protocolRequest)) - .matchingDetails(extractMatchingDetails(protocolRequest)) - .build()); + .matchingDetails(extractMatchingDetails(protocolRequest)) + .build()); writeEntryToLog(entry); } @@ -79,6 +81,10 @@ public class AdvancedStatisicLogger implements IStatisticLogger { public void logErrorOperation(Throwable throwable, IRequest errorRequest) { final StatisticLogEntry entry = buildCoreEntry(errorRequest); entry.setError(new ErrorEntry(messageService.getResponseErrorCode(throwable), throwable.getMessage())); + entry.setMatching(MatchingDetails.builder() + .matchingMethod(extractMatchingState(errorRequest)) + .matchingDetails(extractMatchingDetails(errorRequest)) + .build()); writeEntryToLog(entry); } @@ -161,6 +167,9 @@ public class AdvancedStatisicLogger implements IStatisticLogger { @JsonProperty("error") private ErrorEntry error; + + @JsonProperty("idenityMatching") + private MatchingDetails matching; } @@ -175,15 +184,23 @@ public class AdvancedStatisicLogger implements IStatisticLogger { @JsonProperty("ccc") private final String citizenCountryCode; + + } + + @Getter + @Setter + @Builder + @JsonInclude(Include.NON_NULL) + private static class MatchingDetails { @JsonProperty("finalMatchingMethod") private final String matchingMethod; @JsonProperty("matchingProcessDetails") private final DetailedMatchtingStatistic matchingDetails; - + } - + @Getter @Setter @RequiredArgsConstructor diff --git a/ms_specific_connector/src/main/resources/application.properties b/ms_specific_connector/src/main/resources/application.properties index 2ff13ff4..64367880 100644 --- a/ms_specific_connector/src/main/resources/application.properties +++ b/ms_specific_connector/src/main/resources/application.properties @@ -17,6 +17,10 @@ spring.boot.admin.client.enabled=false ############################################################################# ## SpringBoot Actuator management.endpoints.web.exposure.include=health,info +management.endpoint.health.group.public.include=IgniteClusterState,eidasNodeMetadata,saml2MetadataGeneration,idAustriaClientMetadataHealthCheck +management.endpoint.health.group.public.show-components=always +management.endpoint.health.group.public.show-details=always + ############################################################################# ## Common parts of MS-speccific eIDAS application configuration diff --git a/ms_specific_proxyservice/src/main/resources/application.properties b/ms_specific_proxyservice/src/main/resources/application.properties index a3df8f90..b81cb612 100644 --- a/ms_specific_proxyservice/src/main/resources/application.properties +++ b/ms_specific_proxyservice/src/main/resources/application.properties @@ -18,6 +18,9 @@ spring.boot.admin.client.enabled=false ############################################################################# ## SpringBoot Actuator management.endpoints.web.exposure.include=health,info +management.endpoint.health.group.public.include=IgniteClusterState,eidasNodeMetadata,idAustriaAuthMetadataHealth +management.endpoint.health.group.public.show-components=always +management.endpoint.health.group.public.show-details=always ############################################################################# ## Common parts of MS-speccific eIDAS application configuration @@ -25,7 +25,7 @@ <!-- ===================================================================== --> <egiz-spring-api>0.3</egiz-spring-api> <egiz-eventlog-slf4jBackend>0.4</egiz-eventlog-slf4jBackend> - <eaaf-core.version>1.3.7</eaaf-core.version> + <eaaf-core.version>1.3.8-SNAPSHOT</eaaf-core.version> <spring-boot-starter-web.version>2.5.14</spring-boot-starter-web.version> <spring-boot-admin-starter-client.version>2.7.4</spring-boot-admin-starter-client.version> |