From 7bf7c3c03fd3a1efeaf3f8e3dd75922e2f5f9921 Mon Sep 17 00:00:00 2001 From: Thomas <> Date: Tue, 8 Mar 2022 19:06:10 +0100 Subject: refactor(core): move all project libs into sub-project 'modules' --- .../checks/spotbugs-exclude.xml | 44 + modules/authmodule-eIDAS-v2/pom.xml | 295 +++++++ .../specific/modules/auth/eidas/v2/Constants.java | 192 +++++ .../eidas/v2/EidasAuthenticationModulImpl.java | 87 ++ .../EidasAuthenticationSpringResourceProvider.java | 52 ++ .../modules/auth/eidas/v2/EidasSignalServlet.java | 161 ++++ .../modules/auth/eidas/v2/dao/ErnbEidData.java | 115 +++ .../v2/exception/EidPostProcessingException.java | 40 + .../v2/exception/EidasAttributeException.java | 34 + .../exception/EidasSAuthenticationException.java | 41 + .../v2/exception/EidasValidationException.java | 34 + .../eidas/v2/exception/SqliteServiceException.java | 40 + .../v2/exception/SzrCommunicationException.java | 38 + .../eidas/v2/handler/AbstractEidProcessor.java | 425 ++++++++++ .../auth/eidas/v2/handler/DeEidProcessor.java | 113 +++ .../auth/eidas/v2/handler/GenericEidProcessor.java | 61 ++ .../eidas/v2/handler/INationalEidProcessor.java | 81 ++ .../auth/eidas/v2/handler/LuEidProcessor.java | 61 ++ .../auth/eidas/v2/handler/NlEidProcessor.java | 54 ++ .../eidas/v2/service/AuthBlockSigningService.java | 211 +++++ .../v2/service/CcSpecificEidProcessingService.java | 135 +++ .../eidas/v2/service/EidasAttributeRegistry.java | 180 ++++ .../auth/eidas/v2/service/EidasDataStore.java | 363 ++++++++ .../service/ICcSpecificEidProcessingService.java | 61 ++ .../modules/auth/eidas/v2/szr/SzrClient.java | 522 ++++++++++++ .../modules/auth/eidas/v2/szr/SzrService.java | 164 ++++ .../eidas/v2/tasks/CreateIdentityLinkTask.java | 503 +++++++++++ .../eidas/v2/tasks/GenerateAuthnRequestTask.java | 255 ++++++ .../eidas/v2/tasks/ReceiveAuthnResponseTask.java | 130 +++ .../auth/eidas/v2/utils/EidasResponseUtils.java | 179 ++++ .../modules/auth/eidas/v2/utils/JoseUtils.java | 305 +++++++ .../auth/eidas/v2/utils/LoggingHandler.java | 72 ++ .../eidas/v2/validator/EidasResponseValidator.java | 175 ++++ ...iz.components.spring.api.SpringResourceProvider | 1 + .../resources/eIDAS.Authentication.process.xml | 29 + .../main/resources/eIDAS/additional-attributes.xml | 42 + .../src/main/resources/eIDAS/eidas-attributes.xml | 379 +++++++++ .../src/main/resources/eidas_v2_auth.beans.xml | 100 +++ .../resources/xmldata/fakeIdL_IdL_template.xml | 122 +++ .../src/main/resources/szr_client/SZR-1.1.WSDL | 939 +++++++++++++++++++++ .../src/main/resources/szr_client/SZR-1.WSDL | 901 ++++++++++++++++++++ .../src/main/resources/szr_client/SZR_v4.0.wsdl | 441 ++++++++++ .../src/main/resources/szr_client/pvp1.xsd | 133 +++ .../src/main/resources/szr_client/pvp19.xsd | 133 +++ .../src/main/resources/szr_client/szr.xsd | 388 +++++++++ .../src/main/resources/szr_client/szr_ecdsa.xsd | 30 + .../main/resources/szr_client/szr_persondata.xsd | 54 ++ .../src/main/resources/szr_client/szr_pvp_sec.xsd | 10 + .../main/resources/szr_client/szr_v4.0-schemas.xml | 54 ++ .../main/resources/szr_client/szr_v4.0-wsdl.xml | 10 + .../src/main/resources/szr_client/szr_v4.0.xsd | 443 ++++++++++ .../src/main/resources/szr_client/szr_xmldsig.xsd | 31 + .../resources/templates/eidas_node_forward.html | 36 + .../test/EidasAuthSpringResourceProviderTest.java | 56 ++ .../v2/test/EidasAuthenticationModulImplTest.java | 121 +++ .../auth/eidas/v2/test/EidasDataStoreTest.java | 118 +++ .../auth/eidas/v2/test/EidasSignalServletTest.java | 244 ++++++ .../modules/auth/eidas/v2/test/SzrClientTest.java | 439 ++++++++++ .../eidas/v2/test/SzrClientTestProduction.java | 236 ++++++ .../dummy/DummySpecificCommunicationService.java | 66 ++ .../tasks/CreateIdentityLinkTaskEidNewTest.java | 491 +++++++++++ .../v2/test/tasks/CreateIdentityLinkTaskTest.java | 464 ++++++++++ .../test/tasks/GenerateAuthnRequestTaskTest.java | 637 ++++++++++++++ .../test/tasks/ReceiveEidasResponseTaskTest.java | 223 +++++ .../auth/eidas/v2/test/utils/JoseUtilsTest.java | 139 +++ .../EidasAttributePostProcessingTest.java | 460 ++++++++++ .../EidasRequestPreProcessingFirstTest.java | 193 +++++ .../EidasRequestPreProcessingSecondTest.java | 157 ++++ .../validation/EidasResponseValidatorTest.java | 333 ++++++++ .../SpringTest-context_basic_mapConfig.xml | 20 + .../SpringTest-context_basic_realConfig.xml | 25 + .../resources/SpringTest-context_basic_test.xml | 73 ++ .../resources/SpringTest-context_tasks_test.xml | 67 ++ .../resources/config/additional-attributes.xml | 39 + .../src/test/resources/config/eidas-attributes.xml | 376 +++++++++ .../resources/config/junit_config_1.properties | 117 +++ .../resources/config/junit_config_2.properties | 114 +++ .../resources/config/junit_config_3.properties | 118 +++ .../resources/config/junit_config_4.properties | 114 +++ .../config/junit_config_de_attributes.properties | 116 +++ .../src/test/resources/data/junit.jks | Bin 0 -> 5738 bytes .../test/resources/data/szr/signed_eidasBind.jws | 1 + .../data/szr/szr_resp_error_travelerdocexists.xml | 6 + .../test/resources/data/szr/szr_resp_valid_1.xml | 50 ++ .../test/resources/data/szr/szr_resp_valid_2.xml | 50 ++ .../src/test/resources/keystore/teststore.jks | Bin 0 -> 2028 bytes .../checks/spotbugs-exclude.xml | 29 + modules/authmodule_id-austria/pom.xml | 171 ++++ .../auth/idaustria/IdAustriaAuthConstants.java | 123 +++ ...ustriaAuthenticationSpringResourceProvider.java | 56 ++ ...IdAustriaEidasProxyAuthenticationModulImpl.java | 91 ++ .../EidasConnecorUniqueIdAttributeBuilder.java | 52 ++ .../config/IdAustriaAuthMessageSource.java | 22 + .../config/IdAustriaAuthMetadataConfiguration.java | 462 ++++++++++ .../IdAustriaAuthRequestBuilderConfiguration.java | 307 +++++++ .../IdAustriaAuthMetadataController.java | 150 ++++ .../controller/IdAustriaAuthSignalController.java | 94 +++ .../tasks/ReceiveFromIdAustriaSystemTask.java | 393 +++++++++ .../tasks/RequestIdAustriaSystemTask.java | 205 +++++ .../utils/IdAustriaAuthCredentialProvider.java | 130 +++ .../utils/IdAustriaAuthMetadataProvider.java | 168 ++++ .../modules/auth/idaustria/utils/Utils.java | 44 + ...iz.components.spring.api.SpringResourceProvider | 1 + .../at.gv.egiz.eaaf.core.api.idp.IAttributeBuilder | 1 + .../messages/idaustria_auth_messages.properties | 10 + .../process/id_austria.Authentication.process.xml | 18 + .../resources/spring/id_austria_auth.beans.xml | 36 + .../resources/spring/id_austria_task.beans.xml | 23 + .../IdAustriaAuthSpringResourceProviderTest.java | 56 ++ ...striaEidasProxyAuthenticationModulImplTest.java | 102 +++ .../EidasConnecorUniqueIdAttributeBuilderTest.java | 54 ++ .../config/IdAustriaAuthMessageSourceTest.java | 50 ++ .../IdAustriaAuthMetadataControllerFirstTest.java | 186 ++++ .../IdAustriaAuthSignalControllerTest.java | 200 +++++ .../test/task/ReceiveAuthnResponseTaskTest.java | 792 +++++++++++++++++ .../test/task/RequestIdAustriaSystemTaskTest.java | 455 ++++++++++ .../utils/IdAustriaAuthCredentialProviderTest.java | 413 +++++++++ .../IdAustriaAuthMetadataProviderFirstTest.java | 236 ++++++ .../IdAustriaAuthMetadataProviderSecondTest.java | 65 ++ .../src/test/resources/config/junit.jks | Bin 0 -> 3980 bytes .../resources/config/junit_config_1.properties | 44 + .../src/test/resources/config/junit_test.jks | Bin 0 -> 8410 bytes .../resources/config/junit_test_no_trust_certs.jks | Bin 0 -> 4818 bytes .../src/test/resources/config/pvp.jks | Bin 0 -> 4833 bytes .../src/test/resources/config/pvp.p12 | Bin 0 -> 5494 bytes .../src/test/resources/data/Response_with_EID.xml | 49 ++ .../data/Response_with_EID_bpk_without_prefix.xml | 49 ++ .../resources/data/Response_with_EID_minimum.xml | 43 + .../Response_with_EID_with_eid_sector_attr.xml | 52 ++ .../data/Response_with_EID_with_mandate_jur.xml | 63 ++ .../data/Response_with_EID_with_mandate_nat.xml | 66 ++ .../data/Response_with_EID_wrong_data.xml | 46 + .../Response_with_wrong_destination_endpoint.xml | 52 ++ .../Response_without_sig_classpath_entityid.xml | 52 ++ .../data/Response_without_sig_with_error.xml | 46 + ...sponse_without_sig_with_error_empty_subcode.xml | 46 + .../Response_without_sig_with_error_userstop.xml | 46 + ...onse_without_sig_with_error_without_subcode.xml | 45 + .../src/test/resources/data/eidas_node_siging.crt | 21 + .../data/idp_metadata_classpath_entity.xml | 146 ++++ .../test/resources/data/idp_metadata_no_sig.xml | 46 + .../test/resources/data/idp_metadata_no_sig2.xml | 46 + .../resources/data/idp_metadata_sig_notvalid.xml | 84 ++ .../data/idp_metadata_sig_valid_wrong_alg.xml | 74 ++ .../resources/data/junit_keystore_metadata.crt | 11 + .../test/resources/data/junit_keystore_signing.crt | 18 + .../src/test/resources/data/moa_sig_signing.crt | 27 + .../resources/data/pvp_postbinding_template.html | 3 + .../src/test/resources/data/sp_metadata_junit.xml | 66 ++ .../spring/SpringTest-context_basic_mapConfig.xml | 20 + .../spring/SpringTest-context_basic_test.xml | 32 + .../resources/spring/SpringTest-context_lazy.xml | 24 + .../core_common_lib/checks/spotbugs-exclude.xml | 20 + modules/core_common_lib/pom.xml | 106 +++ .../eidas/specific/core/MsConnectorEventCodes.java | 52 ++ .../eidas/specific/core/MsEidasNodeConstants.java | 229 +++++ .../core/config/BasicConfigurationProvider.java | 155 ++++ .../core/config/ServiceProviderConfiguration.java | 171 ++++ .../SpringBootBasicConfigurationProvider.java | 122 +++ .../core/gui/DefaultVelocityGuiBuilderImpl.java | 77 ++ .../core/gui/GuiBuilderConfigurationFactory.java | 69 ++ .../core/gui/StaticGuiBuilderConfiguration.java | 148 ++++ .../src/main/resources/common_gui.beans.xml | 60 ++ .../core/test/config/BasicConfigProviderTest.java | 156 ++++ .../config/ServiceProviderConfigurationTest.java | 54 ++ .../SpringBootBasicConfigurationProviderTest.java | 148 ++++ .../config/dummy/MsConnectorDummyConfigMap.java | 120 +++ .../dummy/MsConnectorDummySpConfiguration.java | 28 + .../SpringTest-context_basic_realConfig.xml | 25 + .../resources/config/junit_config_1.properties | 124 +++ .../core_common_webapp/checks/spotbugs-exclude.xml | 12 + modules/core_common_webapp/pom.xml | 136 +++ .../specific/core/SpringContextCloseHandler.java | 170 ++++ .../specific/core/auth/AuthenticationManager.java | 60 ++ .../core/builder/AuthenticationDataBuilder.java | 255 ++++++ .../core/config/StaticResourceConfiguration.java | 220 +++++ .../health/EidasNodeMetadataHealthIndicator.java | 69 ++ .../core/health/IgniteClusterHealthIndicator.java | 52 ++ .../WebFrontEndSecurityInterceptor.java | 90 ++ .../eidas/specific/core/logger/RevisionLogger.java | 110 +++ .../specific/core/logger/StatisticLogger.java | 141 ++++ .../eidas/specific/core/mapper/LoALevelMapper.java | 60 ++ .../core/provider/StatusMessageProvider.java | 182 ++++ .../core/storage/CacheWithEidasBackend.java | 35 + .../EidasCacheTransactionStoreDecorator.java | 180 ++++ .../storage/SimpleInMemoryTransactionStorage.java | 169 ++++ .../core/storage/TransactionStoreElement.java | 70 ++ .../main/resources/specific_eIDAS_core.beans.xml | 61 ++ .../specific_eIDAS_core_storage.beans.xml | 39 + ...sNodeMetadataHealthIndicatorNoEndpointTest.java | 70 ++ .../EidasNodeMetadataHealthIndicatorTest.java | 102 +++ .../test/utils/AuthenticationDataBuilderTest.java | 635 ++++++++++++++ .../config/junit_config_1_springboot.properties | 113 +++ .../config/junit_config_2_springboot.properties | 113 +++ .../resources/config/junit_config_3.properties | 148 ++++ .../src/test/resources/config/log4j.properties | 54 ++ .../src/test/resources/data/metadata_valid.xml | 106 +++ .../src/test/resources/data/test_idl_1.xml | 46 + .../spring/SpringTest-context_basic_test.xml | 22 + .../spring/SpringTest-context_healthcheck.xml | 22 + .../spring/SpringTest-context_simple_storage.xml | 15 + .../resources/spring/SpringTest_core.beans.xml | 70 ++ .../spring/SpringTest_core_config.beans.xml | 25 + .../eidas_proxy-sevice/checks/spotbugs-exclude.xml | 20 + modules/eidas_proxy-sevice/pom.xml | 184 ++++ .../msproxyservice/EidasProxyMessageSource.java | 22 + .../msproxyservice/MsProxyServiceConstants.java | 54 ++ .../MsProxyServiceSpringResourceProvider.java | 52 ++ .../exception/EidasProxyServiceException.java | 19 + .../protocol/EidasProxyServiceController.java | 443 ++++++++++ .../protocol/ProxyServiceAuthenticationAction.java | 374 ++++++++ .../protocol/ProxyServicePendingRequest.java | 28 + .../utils/EidasProxyServiceUtils.java | 45 + ...iz.components.spring.api.SpringResourceProvider | 1 + .../messages/eidasproxy_messages.properties | 14 + .../resources/spring/eidas_proxy-service.beans.xml | 28 + .../test/EidasProxyMessageSourceTest.java | 50 ++ .../MsProxyServiceSpringResourceProviderTest.java | 56 ++ .../protocol/EidasProxyServiceControllerTest.java | 666 +++++++++++++++ .../ProxyServiceAuthenticationActionTest.java | 637 ++++++++++++++ .../resources/config/additional-attributes.xml | 39 + .../src/test/resources/config/eidas-attributes.xml | 376 +++++++++ .../resources/config/junit_config_1.properties | 6 + .../spring/SpringTest-context_basic_mapConfig.xml | 20 + .../spring/SpringTest-context_basic_test.xml | 42 + modules/pom.xml | 23 + 226 files changed, 30389 insertions(+) create mode 100644 modules/authmodule-eIDAS-v2/checks/spotbugs-exclude.xml create mode 100644 modules/authmodule-eIDAS-v2/pom.xml create mode 100644 modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/Constants.java create mode 100644 modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/EidasAuthenticationModulImpl.java create mode 100644 modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/EidasAuthenticationSpringResourceProvider.java create mode 100644 modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/EidasSignalServlet.java create mode 100644 modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/dao/ErnbEidData.java create mode 100644 modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/exception/EidPostProcessingException.java create mode 100644 modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/exception/EidasAttributeException.java create mode 100644 modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/exception/EidasSAuthenticationException.java create mode 100644 modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/exception/EidasValidationException.java create mode 100644 modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/exception/SqliteServiceException.java create mode 100644 modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/exception/SzrCommunicationException.java create mode 100644 modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/handler/AbstractEidProcessor.java create mode 100644 modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/handler/DeEidProcessor.java create mode 100644 modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/handler/GenericEidProcessor.java create mode 100644 modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/handler/INationalEidProcessor.java create mode 100644 modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/handler/LuEidProcessor.java create mode 100644 modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/handler/NlEidProcessor.java create mode 100644 modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/service/AuthBlockSigningService.java create mode 100644 modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/service/CcSpecificEidProcessingService.java create mode 100644 modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/service/EidasAttributeRegistry.java create mode 100644 modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/service/EidasDataStore.java create mode 100644 modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/service/ICcSpecificEidProcessingService.java create mode 100644 modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/szr/SzrClient.java create mode 100644 modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/szr/SzrService.java create mode 100644 modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/tasks/CreateIdentityLinkTask.java create mode 100644 modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/tasks/GenerateAuthnRequestTask.java create mode 100644 modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/tasks/ReceiveAuthnResponseTask.java create mode 100644 modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/utils/EidasResponseUtils.java create mode 100644 modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/utils/JoseUtils.java create mode 100644 modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/utils/LoggingHandler.java create mode 100644 modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/validator/EidasResponseValidator.java create mode 100644 modules/authmodule-eIDAS-v2/src/main/resources/META-INF/services/at.gv.egiz.components.spring.api.SpringResourceProvider create mode 100644 modules/authmodule-eIDAS-v2/src/main/resources/eIDAS.Authentication.process.xml create mode 100644 modules/authmodule-eIDAS-v2/src/main/resources/eIDAS/additional-attributes.xml create mode 100644 modules/authmodule-eIDAS-v2/src/main/resources/eIDAS/eidas-attributes.xml create mode 100644 modules/authmodule-eIDAS-v2/src/main/resources/eidas_v2_auth.beans.xml create mode 100644 modules/authmodule-eIDAS-v2/src/main/resources/resources/xmldata/fakeIdL_IdL_template.xml create mode 100644 modules/authmodule-eIDAS-v2/src/main/resources/szr_client/SZR-1.1.WSDL create mode 100644 modules/authmodule-eIDAS-v2/src/main/resources/szr_client/SZR-1.WSDL create mode 100644 modules/authmodule-eIDAS-v2/src/main/resources/szr_client/SZR_v4.0.wsdl create mode 100644 modules/authmodule-eIDAS-v2/src/main/resources/szr_client/pvp1.xsd create mode 100644 modules/authmodule-eIDAS-v2/src/main/resources/szr_client/pvp19.xsd create mode 100644 modules/authmodule-eIDAS-v2/src/main/resources/szr_client/szr.xsd create mode 100644 modules/authmodule-eIDAS-v2/src/main/resources/szr_client/szr_ecdsa.xsd create mode 100644 modules/authmodule-eIDAS-v2/src/main/resources/szr_client/szr_persondata.xsd create mode 100644 modules/authmodule-eIDAS-v2/src/main/resources/szr_client/szr_pvp_sec.xsd create mode 100644 modules/authmodule-eIDAS-v2/src/main/resources/szr_client/szr_v4.0-schemas.xml create mode 100644 modules/authmodule-eIDAS-v2/src/main/resources/szr_client/szr_v4.0-wsdl.xml create mode 100644 modules/authmodule-eIDAS-v2/src/main/resources/szr_client/szr_v4.0.xsd create mode 100644 modules/authmodule-eIDAS-v2/src/main/resources/szr_client/szr_xmldsig.xsd create mode 100644 modules/authmodule-eIDAS-v2/src/main/resources/templates/eidas_node_forward.html create mode 100644 modules/authmodule-eIDAS-v2/src/test/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/test/EidasAuthSpringResourceProviderTest.java create mode 100644 modules/authmodule-eIDAS-v2/src/test/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/test/EidasAuthenticationModulImplTest.java create mode 100644 modules/authmodule-eIDAS-v2/src/test/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/test/EidasDataStoreTest.java create mode 100644 modules/authmodule-eIDAS-v2/src/test/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/test/EidasSignalServletTest.java create mode 100644 modules/authmodule-eIDAS-v2/src/test/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/test/SzrClientTest.java create mode 100644 modules/authmodule-eIDAS-v2/src/test/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/test/SzrClientTestProduction.java create mode 100644 modules/authmodule-eIDAS-v2/src/test/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/test/dummy/DummySpecificCommunicationService.java create mode 100644 modules/authmodule-eIDAS-v2/src/test/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/test/tasks/CreateIdentityLinkTaskEidNewTest.java create mode 100644 modules/authmodule-eIDAS-v2/src/test/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/test/tasks/CreateIdentityLinkTaskTest.java create mode 100644 modules/authmodule-eIDAS-v2/src/test/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/test/tasks/GenerateAuthnRequestTaskTest.java create mode 100644 modules/authmodule-eIDAS-v2/src/test/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/test/tasks/ReceiveEidasResponseTaskTest.java create mode 100644 modules/authmodule-eIDAS-v2/src/test/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/test/utils/JoseUtilsTest.java create mode 100644 modules/authmodule-eIDAS-v2/src/test/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/test/validation/EidasAttributePostProcessingTest.java create mode 100644 modules/authmodule-eIDAS-v2/src/test/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/test/validation/EidasRequestPreProcessingFirstTest.java create mode 100644 modules/authmodule-eIDAS-v2/src/test/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/test/validation/EidasRequestPreProcessingSecondTest.java create mode 100644 modules/authmodule-eIDAS-v2/src/test/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/test/validation/EidasResponseValidatorTest.java create mode 100644 modules/authmodule-eIDAS-v2/src/test/resources/SpringTest-context_basic_mapConfig.xml create mode 100644 modules/authmodule-eIDAS-v2/src/test/resources/SpringTest-context_basic_realConfig.xml create mode 100644 modules/authmodule-eIDAS-v2/src/test/resources/SpringTest-context_basic_test.xml create mode 100644 modules/authmodule-eIDAS-v2/src/test/resources/SpringTest-context_tasks_test.xml create mode 100644 modules/authmodule-eIDAS-v2/src/test/resources/config/additional-attributes.xml create mode 100644 modules/authmodule-eIDAS-v2/src/test/resources/config/eidas-attributes.xml create mode 100644 modules/authmodule-eIDAS-v2/src/test/resources/config/junit_config_1.properties create mode 100644 modules/authmodule-eIDAS-v2/src/test/resources/config/junit_config_2.properties create mode 100644 modules/authmodule-eIDAS-v2/src/test/resources/config/junit_config_3.properties create mode 100644 modules/authmodule-eIDAS-v2/src/test/resources/config/junit_config_4.properties create mode 100644 modules/authmodule-eIDAS-v2/src/test/resources/config/junit_config_de_attributes.properties create mode 100644 modules/authmodule-eIDAS-v2/src/test/resources/data/junit.jks create mode 100644 modules/authmodule-eIDAS-v2/src/test/resources/data/szr/signed_eidasBind.jws create mode 100644 modules/authmodule-eIDAS-v2/src/test/resources/data/szr/szr_resp_error_travelerdocexists.xml create mode 100644 modules/authmodule-eIDAS-v2/src/test/resources/data/szr/szr_resp_valid_1.xml create mode 100644 modules/authmodule-eIDAS-v2/src/test/resources/data/szr/szr_resp_valid_2.xml create mode 100644 modules/authmodule-eIDAS-v2/src/test/resources/keystore/teststore.jks create mode 100644 modules/authmodule_id-austria/checks/spotbugs-exclude.xml create mode 100644 modules/authmodule_id-austria/pom.xml create mode 100644 modules/authmodule_id-austria/src/main/java/at/asitplus/eidas/specific/modules/auth/idaustria/IdAustriaAuthConstants.java create mode 100644 modules/authmodule_id-austria/src/main/java/at/asitplus/eidas/specific/modules/auth/idaustria/IdAustriaAuthenticationSpringResourceProvider.java create mode 100644 modules/authmodule_id-austria/src/main/java/at/asitplus/eidas/specific/modules/auth/idaustria/IdAustriaEidasProxyAuthenticationModulImpl.java create mode 100644 modules/authmodule_id-austria/src/main/java/at/asitplus/eidas/specific/modules/auth/idaustria/builder/attributes/EidasConnecorUniqueIdAttributeBuilder.java create mode 100644 modules/authmodule_id-austria/src/main/java/at/asitplus/eidas/specific/modules/auth/idaustria/config/IdAustriaAuthMessageSource.java create mode 100644 modules/authmodule_id-austria/src/main/java/at/asitplus/eidas/specific/modules/auth/idaustria/config/IdAustriaAuthMetadataConfiguration.java create mode 100644 modules/authmodule_id-austria/src/main/java/at/asitplus/eidas/specific/modules/auth/idaustria/config/IdAustriaAuthRequestBuilderConfiguration.java create mode 100644 modules/authmodule_id-austria/src/main/java/at/asitplus/eidas/specific/modules/auth/idaustria/controller/IdAustriaAuthMetadataController.java create mode 100644 modules/authmodule_id-austria/src/main/java/at/asitplus/eidas/specific/modules/auth/idaustria/controller/IdAustriaAuthSignalController.java create mode 100644 modules/authmodule_id-austria/src/main/java/at/asitplus/eidas/specific/modules/auth/idaustria/tasks/ReceiveFromIdAustriaSystemTask.java create mode 100644 modules/authmodule_id-austria/src/main/java/at/asitplus/eidas/specific/modules/auth/idaustria/tasks/RequestIdAustriaSystemTask.java create mode 100644 modules/authmodule_id-austria/src/main/java/at/asitplus/eidas/specific/modules/auth/idaustria/utils/IdAustriaAuthCredentialProvider.java create mode 100644 modules/authmodule_id-austria/src/main/java/at/asitplus/eidas/specific/modules/auth/idaustria/utils/IdAustriaAuthMetadataProvider.java create mode 100644 modules/authmodule_id-austria/src/main/java/at/asitplus/eidas/specific/modules/auth/idaustria/utils/Utils.java create mode 100644 modules/authmodule_id-austria/src/main/resources/META-INF/services/at.gv.egiz.components.spring.api.SpringResourceProvider create mode 100644 modules/authmodule_id-austria/src/main/resources/META-INF/services/at.gv.egiz.eaaf.core.api.idp.IAttributeBuilder create mode 100644 modules/authmodule_id-austria/src/main/resources/messages/idaustria_auth_messages.properties create mode 100644 modules/authmodule_id-austria/src/main/resources/process/id_austria.Authentication.process.xml create mode 100644 modules/authmodule_id-austria/src/main/resources/spring/id_austria_auth.beans.xml create mode 100644 modules/authmodule_id-austria/src/main/resources/spring/id_austria_task.beans.xml create mode 100644 modules/authmodule_id-austria/src/test/java/at/asitplus/eidas/specific/modules/auth/idaustria/test/IdAustriaAuthSpringResourceProviderTest.java create mode 100644 modules/authmodule_id-austria/src/test/java/at/asitplus/eidas/specific/modules/auth/idaustria/test/IdAustriaEidasProxyAuthenticationModulImplTest.java create mode 100644 modules/authmodule_id-austria/src/test/java/at/asitplus/eidas/specific/modules/auth/idaustria/test/builder/attributes/EidasConnecorUniqueIdAttributeBuilderTest.java create mode 100644 modules/authmodule_id-austria/src/test/java/at/asitplus/eidas/specific/modules/auth/idaustria/test/config/IdAustriaAuthMessageSourceTest.java create mode 100644 modules/authmodule_id-austria/src/test/java/at/asitplus/eidas/specific/modules/auth/idaustria/test/controller/IdAustriaAuthMetadataControllerFirstTest.java create mode 100644 modules/authmodule_id-austria/src/test/java/at/asitplus/eidas/specific/modules/auth/idaustria/test/controller/IdAustriaAuthSignalControllerTest.java create mode 100644 modules/authmodule_id-austria/src/test/java/at/asitplus/eidas/specific/modules/auth/idaustria/test/task/ReceiveAuthnResponseTaskTest.java create mode 100644 modules/authmodule_id-austria/src/test/java/at/asitplus/eidas/specific/modules/auth/idaustria/test/task/RequestIdAustriaSystemTaskTest.java create mode 100644 modules/authmodule_id-austria/src/test/java/at/asitplus/eidas/specific/modules/auth/idaustria/test/utils/IdAustriaAuthCredentialProviderTest.java create mode 100644 modules/authmodule_id-austria/src/test/java/at/asitplus/eidas/specific/modules/auth/idaustria/test/utils/IdAustriaAuthMetadataProviderFirstTest.java create mode 100644 modules/authmodule_id-austria/src/test/java/at/asitplus/eidas/specific/modules/auth/idaustria/test/utils/IdAustriaAuthMetadataProviderSecondTest.java create mode 100644 modules/authmodule_id-austria/src/test/resources/config/junit.jks create mode 100644 modules/authmodule_id-austria/src/test/resources/config/junit_config_1.properties create mode 100644 modules/authmodule_id-austria/src/test/resources/config/junit_test.jks create mode 100644 modules/authmodule_id-austria/src/test/resources/config/junit_test_no_trust_certs.jks create mode 100644 modules/authmodule_id-austria/src/test/resources/config/pvp.jks create mode 100644 modules/authmodule_id-austria/src/test/resources/config/pvp.p12 create mode 100644 modules/authmodule_id-austria/src/test/resources/data/Response_with_EID.xml create mode 100644 modules/authmodule_id-austria/src/test/resources/data/Response_with_EID_bpk_without_prefix.xml create mode 100644 modules/authmodule_id-austria/src/test/resources/data/Response_with_EID_minimum.xml create mode 100644 modules/authmodule_id-austria/src/test/resources/data/Response_with_EID_with_eid_sector_attr.xml create mode 100644 modules/authmodule_id-austria/src/test/resources/data/Response_with_EID_with_mandate_jur.xml create mode 100644 modules/authmodule_id-austria/src/test/resources/data/Response_with_EID_with_mandate_nat.xml create mode 100644 modules/authmodule_id-austria/src/test/resources/data/Response_with_EID_wrong_data.xml create mode 100644 modules/authmodule_id-austria/src/test/resources/data/Response_with_wrong_destination_endpoint.xml create mode 100644 modules/authmodule_id-austria/src/test/resources/data/Response_without_sig_classpath_entityid.xml create mode 100644 modules/authmodule_id-austria/src/test/resources/data/Response_without_sig_with_error.xml create mode 100644 modules/authmodule_id-austria/src/test/resources/data/Response_without_sig_with_error_empty_subcode.xml create mode 100644 modules/authmodule_id-austria/src/test/resources/data/Response_without_sig_with_error_userstop.xml create mode 100644 modules/authmodule_id-austria/src/test/resources/data/Response_without_sig_with_error_without_subcode.xml create mode 100644 modules/authmodule_id-austria/src/test/resources/data/eidas_node_siging.crt create mode 100644 modules/authmodule_id-austria/src/test/resources/data/idp_metadata_classpath_entity.xml create mode 100644 modules/authmodule_id-austria/src/test/resources/data/idp_metadata_no_sig.xml create mode 100644 modules/authmodule_id-austria/src/test/resources/data/idp_metadata_no_sig2.xml create mode 100644 modules/authmodule_id-austria/src/test/resources/data/idp_metadata_sig_notvalid.xml create mode 100644 modules/authmodule_id-austria/src/test/resources/data/idp_metadata_sig_valid_wrong_alg.xml create mode 100644 modules/authmodule_id-austria/src/test/resources/data/junit_keystore_metadata.crt create mode 100644 modules/authmodule_id-austria/src/test/resources/data/junit_keystore_signing.crt create mode 100644 modules/authmodule_id-austria/src/test/resources/data/moa_sig_signing.crt create mode 100644 modules/authmodule_id-austria/src/test/resources/data/pvp_postbinding_template.html create mode 100644 modules/authmodule_id-austria/src/test/resources/data/sp_metadata_junit.xml create mode 100644 modules/authmodule_id-austria/src/test/resources/spring/SpringTest-context_basic_mapConfig.xml create mode 100644 modules/authmodule_id-austria/src/test/resources/spring/SpringTest-context_basic_test.xml create mode 100644 modules/authmodule_id-austria/src/test/resources/spring/SpringTest-context_lazy.xml create mode 100644 modules/core_common_lib/checks/spotbugs-exclude.xml create mode 100644 modules/core_common_lib/pom.xml create mode 100644 modules/core_common_lib/src/main/java/at/asitplus/eidas/specific/core/MsConnectorEventCodes.java create mode 100644 modules/core_common_lib/src/main/java/at/asitplus/eidas/specific/core/MsEidasNodeConstants.java create mode 100644 modules/core_common_lib/src/main/java/at/asitplus/eidas/specific/core/config/BasicConfigurationProvider.java create mode 100644 modules/core_common_lib/src/main/java/at/asitplus/eidas/specific/core/config/ServiceProviderConfiguration.java create mode 100644 modules/core_common_lib/src/main/java/at/asitplus/eidas/specific/core/config/SpringBootBasicConfigurationProvider.java create mode 100644 modules/core_common_lib/src/main/java/at/asitplus/eidas/specific/core/gui/DefaultVelocityGuiBuilderImpl.java create mode 100644 modules/core_common_lib/src/main/java/at/asitplus/eidas/specific/core/gui/GuiBuilderConfigurationFactory.java create mode 100644 modules/core_common_lib/src/main/java/at/asitplus/eidas/specific/core/gui/StaticGuiBuilderConfiguration.java create mode 100644 modules/core_common_lib/src/main/resources/common_gui.beans.xml create mode 100644 modules/core_common_lib/src/test/java/at/asitplus/eidas/specific/core/test/config/BasicConfigProviderTest.java create mode 100644 modules/core_common_lib/src/test/java/at/asitplus/eidas/specific/core/test/config/ServiceProviderConfigurationTest.java create mode 100644 modules/core_common_lib/src/test/java/at/asitplus/eidas/specific/core/test/config/SpringBootBasicConfigurationProviderTest.java create mode 100644 modules/core_common_lib/src/test/java/at/asitplus/eidas/specific/core/test/config/dummy/MsConnectorDummyConfigMap.java create mode 100644 modules/core_common_lib/src/test/java/at/asitplus/eidas/specific/core/test/config/dummy/MsConnectorDummySpConfiguration.java create mode 100644 modules/core_common_lib/src/test/resources/SpringTest-context_basic_realConfig.xml create mode 100644 modules/core_common_lib/src/test/resources/config/junit_config_1.properties create mode 100644 modules/core_common_webapp/checks/spotbugs-exclude.xml create mode 100644 modules/core_common_webapp/pom.xml create mode 100644 modules/core_common_webapp/src/main/java/at/asitplus/eidas/specific/core/SpringContextCloseHandler.java create mode 100644 modules/core_common_webapp/src/main/java/at/asitplus/eidas/specific/core/auth/AuthenticationManager.java create mode 100644 modules/core_common_webapp/src/main/java/at/asitplus/eidas/specific/core/builder/AuthenticationDataBuilder.java create mode 100644 modules/core_common_webapp/src/main/java/at/asitplus/eidas/specific/core/config/StaticResourceConfiguration.java create mode 100644 modules/core_common_webapp/src/main/java/at/asitplus/eidas/specific/core/health/EidasNodeMetadataHealthIndicator.java create mode 100644 modules/core_common_webapp/src/main/java/at/asitplus/eidas/specific/core/health/IgniteClusterHealthIndicator.java create mode 100644 modules/core_common_webapp/src/main/java/at/asitplus/eidas/specific/core/interceptor/WebFrontEndSecurityInterceptor.java create mode 100644 modules/core_common_webapp/src/main/java/at/asitplus/eidas/specific/core/logger/RevisionLogger.java create mode 100644 modules/core_common_webapp/src/main/java/at/asitplus/eidas/specific/core/logger/StatisticLogger.java create mode 100644 modules/core_common_webapp/src/main/java/at/asitplus/eidas/specific/core/mapper/LoALevelMapper.java create mode 100644 modules/core_common_webapp/src/main/java/at/asitplus/eidas/specific/core/provider/StatusMessageProvider.java create mode 100644 modules/core_common_webapp/src/main/java/at/asitplus/eidas/specific/core/storage/CacheWithEidasBackend.java create mode 100644 modules/core_common_webapp/src/main/java/at/asitplus/eidas/specific/core/storage/EidasCacheTransactionStoreDecorator.java create mode 100644 modules/core_common_webapp/src/main/java/at/asitplus/eidas/specific/core/storage/SimpleInMemoryTransactionStorage.java create mode 100644 modules/core_common_webapp/src/main/java/at/asitplus/eidas/specific/core/storage/TransactionStoreElement.java create mode 100644 modules/core_common_webapp/src/main/resources/specific_eIDAS_core.beans.xml create mode 100644 modules/core_common_webapp/src/main/resources/specific_eIDAS_core_storage.beans.xml create mode 100644 modules/core_common_webapp/src/test/java/at/asitplus/eidas/specific/core/test/health/EidasNodeMetadataHealthIndicatorNoEndpointTest.java create mode 100644 modules/core_common_webapp/src/test/java/at/asitplus/eidas/specific/core/test/health/EidasNodeMetadataHealthIndicatorTest.java create mode 100644 modules/core_common_webapp/src/test/java/at/asitplus/eidas/specific/core/test/utils/AuthenticationDataBuilderTest.java create mode 100644 modules/core_common_webapp/src/test/resources/config/junit_config_1_springboot.properties create mode 100644 modules/core_common_webapp/src/test/resources/config/junit_config_2_springboot.properties create mode 100644 modules/core_common_webapp/src/test/resources/config/junit_config_3.properties create mode 100644 modules/core_common_webapp/src/test/resources/config/log4j.properties create mode 100644 modules/core_common_webapp/src/test/resources/data/metadata_valid.xml create mode 100644 modules/core_common_webapp/src/test/resources/data/test_idl_1.xml create mode 100644 modules/core_common_webapp/src/test/resources/spring/SpringTest-context_basic_test.xml create mode 100644 modules/core_common_webapp/src/test/resources/spring/SpringTest-context_healthcheck.xml create mode 100644 modules/core_common_webapp/src/test/resources/spring/SpringTest-context_simple_storage.xml create mode 100644 modules/core_common_webapp/src/test/resources/spring/SpringTest_core.beans.xml create mode 100644 modules/core_common_webapp/src/test/resources/spring/SpringTest_core_config.beans.xml create mode 100644 modules/eidas_proxy-sevice/checks/spotbugs-exclude.xml create mode 100644 modules/eidas_proxy-sevice/pom.xml create mode 100644 modules/eidas_proxy-sevice/src/main/java/at/asitplus/eidas/specific/modules/msproxyservice/EidasProxyMessageSource.java create mode 100644 modules/eidas_proxy-sevice/src/main/java/at/asitplus/eidas/specific/modules/msproxyservice/MsProxyServiceConstants.java create mode 100644 modules/eidas_proxy-sevice/src/main/java/at/asitplus/eidas/specific/modules/msproxyservice/MsProxyServiceSpringResourceProvider.java create mode 100644 modules/eidas_proxy-sevice/src/main/java/at/asitplus/eidas/specific/modules/msproxyservice/exception/EidasProxyServiceException.java create mode 100644 modules/eidas_proxy-sevice/src/main/java/at/asitplus/eidas/specific/modules/msproxyservice/protocol/EidasProxyServiceController.java create mode 100644 modules/eidas_proxy-sevice/src/main/java/at/asitplus/eidas/specific/modules/msproxyservice/protocol/ProxyServiceAuthenticationAction.java create mode 100644 modules/eidas_proxy-sevice/src/main/java/at/asitplus/eidas/specific/modules/msproxyservice/protocol/ProxyServicePendingRequest.java create mode 100644 modules/eidas_proxy-sevice/src/main/java/at/asitplus/eidas/specific/modules/msproxyservice/utils/EidasProxyServiceUtils.java create mode 100644 modules/eidas_proxy-sevice/src/main/resources/META-INF/services/at.gv.egiz.components.spring.api.SpringResourceProvider create mode 100644 modules/eidas_proxy-sevice/src/main/resources/messages/eidasproxy_messages.properties create mode 100644 modules/eidas_proxy-sevice/src/main/resources/spring/eidas_proxy-service.beans.xml create mode 100644 modules/eidas_proxy-sevice/src/test/java/at/asitplus/eidas/specific/modules/auth/idaustria/test/EidasProxyMessageSourceTest.java create mode 100644 modules/eidas_proxy-sevice/src/test/java/at/asitplus/eidas/specific/modules/auth/idaustria/test/MsProxyServiceSpringResourceProviderTest.java create mode 100644 modules/eidas_proxy-sevice/src/test/java/at/asitplus/eidas/specific/modules/auth/idaustria/test/protocol/EidasProxyServiceControllerTest.java create mode 100644 modules/eidas_proxy-sevice/src/test/java/at/asitplus/eidas/specific/modules/auth/idaustria/test/protocol/ProxyServiceAuthenticationActionTest.java create mode 100644 modules/eidas_proxy-sevice/src/test/resources/config/additional-attributes.xml create mode 100644 modules/eidas_proxy-sevice/src/test/resources/config/eidas-attributes.xml create mode 100644 modules/eidas_proxy-sevice/src/test/resources/config/junit_config_1.properties create mode 100644 modules/eidas_proxy-sevice/src/test/resources/spring/SpringTest-context_basic_mapConfig.xml create mode 100644 modules/eidas_proxy-sevice/src/test/resources/spring/SpringTest-context_basic_test.xml create mode 100644 modules/pom.xml (limited to 'modules') diff --git a/modules/authmodule-eIDAS-v2/checks/spotbugs-exclude.xml b/modules/authmodule-eIDAS-v2/checks/spotbugs-exclude.xml new file mode 100644 index 00000000..d961b4d6 --- /dev/null +++ b/modules/authmodule-eIDAS-v2/checks/spotbugs-exclude.xml @@ -0,0 +1,44 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/modules/authmodule-eIDAS-v2/pom.xml b/modules/authmodule-eIDAS-v2/pom.xml new file mode 100644 index 00000000..f16edb2d --- /dev/null +++ b/modules/authmodule-eIDAS-v2/pom.xml @@ -0,0 +1,295 @@ + + + 4.0.0 + + at.asitplus.eidas.ms_specific + modules + 1.2.4-SNAPSHOT + + at.asitplus.eidas.ms_specific.modules + authmodule-eIDAS-v2 + eIDAS v2 authentication module + eIDAS module based on eIDAS node reference implementation v2.x + + + + default + + true + + + + egiz-commons + https://apps.egiz.gv.at/maven/ + + true + + + + eIDASNode-local + local + file:${basedir}/../../repository + + + + + + + + at.gv.egiz.components + egiz-spring-api + + + at.asitplus.eidas.ms_specific + core_common_lib + + + at.gv.egiz.eaaf + eaaf-core + + + + + eu.eidas + eidas-commons + + + log4j + log4j + + + log4j-over-slf4j + org.slf4j + + + + + + eu.eidas + eidas-light-commons + + + + eu.eidas + eidas-specific-communication-definition + + + + eu.eidas + eidas-jcache-ignite-specific-communication + + + + + org.apache.commons + commons-lang3 + + + com.google.guava + guava + + + joda-time + joda-time + + + org.apache.commons + commons-text + + + org.springframework + spring-webmvc + + + org.apache.cxf + cxf-core + + + org.apache.cxf + cxf-rt-frontend-jaxws + + + org.apache.cxf + cxf-rt-transports-http + + + com.fasterxml.jackson.datatype + jackson-datatype-jsr310 + + + + org.bitbucket.b_c + jose4j + + + + javax.servlet + javax.servlet-api + provided + + + + + junit + junit + test + + + org.springframework + spring-test + test + + + + at.asitplus.eidas.ms_specific + core_common_lib + test + test-jar + + + + at.gv.egiz.eaaf + eaaf_core_utils + test + test-jar + + + at.gv.egiz.eaaf + eaaf-core + test + test-jar + + + + com.github.skjolber + mockito-soap-cxf + test + + + + org.powermock + powermock-module-junit4 + test + + + org.powermock + powermock-api-mockito2 + test + + + + + + + + src/main/resources + + + target/generated-sources/cxf + + + + + + org.apache.maven.plugins + maven-compiler-plugin + + 1.8 + 1.8 + + + + org.apache.cxf + cxf-codegen-plugin + + + xerces + xercesImpl + 2.8.1 + + + com.sun.xml.bind + jaxb-impl + 2.2.5 + + + com.sun.xml.bind + jaxb-xjc + 2.2.5 + + + + + generate-sources + generate-sources + + ${project.build.directory}/generated/cxf + + + ${basedir}/src/main/resources/szr_client/SZR_v4.0.wsdl + + -verbose + + + + + + wsdl2java + + + + + + + com.github.spotbugs + spotbugs-maven-plugin + ${spotbugs-maven-plugin.version} + + checks/spotbugs-exclude.xml + + + + + org.jacoco + jacoco-maven-plugin + + + post-unit-check + test + + check + report + + + true + + **/at/gv/e_government/reference/namespace/persondata/_20020228/* + **/org/w3/_2000/_09/* + **/org/w3/_2001/_04/* + **/szrservices/* + **/generated/cxf/* + + + + + + + + + maven-surefire-plugin + + 1 + + + + org.apache.maven.surefire + surefire-junit47 + ${surefire.version} + + + + + + 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 new file mode 100644 index 00000000..a554bf57 --- /dev/null +++ b/modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/Constants.java @@ -0,0 +1,192 @@ +/* + * Copyright 2018 A-SIT Plus GmbH + * AT-specific eIDAS Connector has been developed in a cooperation between EGIZ, + * A-SIT Plus GmbH, A-SIT, and Graz University of Technology. + * + * Licensed under the EUPL, Version 1.2 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "License"); + * You may not use this work except in compliance with the License. + * You may obtain a copy of the License at: + * https://joinup.ec.europa.eu/news/understanding-eupl-v12 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. +*/ + +package at.asitplus.eidas.specific.modules.auth.eidas.v2; + +import at.gv.egiz.eaaf.core.api.data.EaafConstants; + +public class Constants { + + 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_FULL_EIDAS_RESPONSE = "resp_fulleIDASResponse"; + + // templates for post-binding forwarding + public static final String TEMPLATE_POST_FORWARD_NAME = "eidas_node_forward.html"; + public static final String TEMPLATE_POST_FORWARD_ENDPOINT = "endPoint"; + public static final String TEMPLATE_POST_FORWARD_TOKEN_NAME = "tokenName"; + public static final String TEMPLATE_POST_FORWARD_TOKEN_VALUE = "tokenValue"; + + // configuration properties + public static final String CONIG_PROPS_EIDAS_PREFIX = "auth.eIDAS"; + public static final String CONIG_PROPS_EIDAS_IS_TEST_IDENTITY = CONIG_PROPS_EIDAS_PREFIX + + ".eid.testidentity.default"; + public static final String CONIG_PROPS_EIDAS_NODE = CONIG_PROPS_EIDAS_PREFIX + ".node_v2"; + public static final String CONIG_PROPS_EIDAS_NODE_COUNTRYCODE = CONIG_PROPS_EIDAS_NODE + ".countrycode"; + public static final String CONIG_PROPS_EIDAS_NODE_PUBLICSECTOR_TARGETS = CONIG_PROPS_EIDAS_NODE + + ".publicSectorTargets"; + public static final String CONIG_PROPS_EIDAS_NODE_ENTITYID = CONIG_PROPS_EIDAS_NODE + ".entityId"; + public static final String CONIG_PROPS_EIDAS_CONNECTOR_NODE_FORWARD_URL = CONIG_PROPS_EIDAS_NODE + + ".forward.endpoint"; + + public static final String CONIG_PROPS_EIDAS_NODE_FORWARD_METHOD = CONIG_PROPS_EIDAS_NODE + + ".forward.method"; + public static final String CONIG_PROPS_EIDAS_NODE_ATTRIBUTES_REQUESTED_DEFAULT_ONLYNATURAL = + CONIG_PROPS_EIDAS_NODE + ".attributes.requested.onlynatural"; + public static final String CONIG_PROPS_EIDAS_NODE_ATTRIBUTES_REQUESTED_CC_SPECIFIC_ONLYNATURAL = + CONIG_PROPS_EIDAS_NODE + ".attributes.requested.{0}.onlynatural"; + public static final String CONIG_PROPS_EIDAS_NODE_ATTRIBUTES_REQUESTED_REPRESENTATION = + CONIG_PROPS_EIDAS_NODE + ".attributes.requested.representation"; + + public static final String CONIG_PROPS_EIDAS_NODE_REQUESTERID_USE_HASHED_VERSION = + CONIG_PROPS_EIDAS_NODE + ".requesterId.useHashedForm"; + public static final String CONIG_PROPS_EIDAS_NODE_WORKAROUND_USE_STATIC_REQUESTERID_FOR_LUX = + CONIG_PROPS_EIDAS_NODE + ".requesterId.lu.useStaticRequesterForAll"; + + public static final String CONIG_PROPS_EIDAS_NODE_WORKAROUND_ADD_ALWAYS_PROVIDERNAME = + CONIG_PROPS_EIDAS_NODE + ".workarounds.addAlwaysProviderName"; + public static final String CONIG_PROPS_EIDAS_NODE_WORKAROUND_USEREQUESTIDASTRANSACTIONIDENTIFIER = + CONIG_PROPS_EIDAS_NODE + ".workarounds.useRequestIdAsTransactionIdentifier"; + + public static final String CONFIG_PROP_EIDAS_NODE_NAMEIDFORMAT = + CONIG_PROPS_EIDAS_NODE + ".requested.nameIdFormat"; + + public static final String CONIG_PROPS_EIDAS_NODE_STATIC_PROVIDERNAME_FOR_PUBLIC_SP = CONIG_PROPS_EIDAS_NODE + + ".staticProviderNameForPublicSPs"; + public static final String DEFAULT_PROPS_EIDAS_NODE_STATIC_PROVIDERNAME_FOR_PUBLIC_SP = "Austria"; + + public static final String FORWARD_METHOD_POST = "POST"; + public static final String FORWARD_METHOD_GET = "GET"; + + public static final String CONIG_PROPS_EIDAS_SZRCLIENT = CONIG_PROPS_EIDAS_PREFIX + ".szrclient"; + public static final String CONIG_PROPS_EIDAS_SZRCLIENT_USETESTSERVICE = CONIG_PROPS_EIDAS_SZRCLIENT + + ".useTestService"; + public static final String CONIG_PROPS_EIDAS_SZRCLIENT_DEBUG_TRACEMESSAGES = CONIG_PROPS_EIDAS_SZRCLIENT + + ".debug.logfullmessages"; + public static final String CONIG_PROPS_EIDAS_SZRCLIENT_DEBUG_USEDUMMY = CONIG_PROPS_EIDAS_SZRCLIENT + + ".debug.useDummySolution"; + public static final String CONIG_PROPS_EIDAS_SZRCLIENT_SET_MDS_TO_EIDASBIND = CONIG_PROPS_EIDAS_SZRCLIENT + + ".eidasbind.mds.inject"; + public static final String CONIG_PROPS_EIDAS_SZRCLIENT_TIMEOUT_CONNECTION = CONIG_PROPS_EIDAS_SZRCLIENT + + ".timeout.connection"; + public static final String CONIG_PROPS_EIDAS_SZRCLIENT_TIMEOUT_RESPONSE = CONIG_PROPS_EIDAS_SZRCLIENT + + ".timeout.response"; + public static final String CONIG_PROPS_EIDAS_SZRCLIENT_ENDPOINT_PROD = CONIG_PROPS_EIDAS_SZRCLIENT + + ".endpoint.prod"; + public static final String CONIG_PROPS_EIDAS_SZRCLIENT_ENDPOINT_TEST = CONIG_PROPS_EIDAS_SZRCLIENT + + ".endpoint.test"; + public static final String CONIG_PROPS_EIDAS_SZRCLIENT_SSL_KEYSTORE_PATH = CONIG_PROPS_EIDAS_SZRCLIENT + + ".ssl.keyStore.path"; + public static final String CONIG_PROPS_EIDAS_SZRCLIENT_SSL_KEYSTORE_PASSWORD = CONIG_PROPS_EIDAS_SZRCLIENT + + ".ssl.keyStore.password"; + public static final String CONIG_PROPS_EIDAS_SZRCLIENT_SSL_TRUSTSTORE_PATH = CONIG_PROPS_EIDAS_SZRCLIENT + + ".ssl.trustStore.path"; + public static final String CONIG_PROPS_EIDAS_SZRCLIENT_SSL_TRUSTSTORE_PASSWORD = CONIG_PROPS_EIDAS_SZRCLIENT + + ".ssl.trustStore.password"; + + public static final String CONIG_PROPS_EIDAS_SZRCLIENT_PARAMS_EDOCUMENTTYPE = CONIG_PROPS_EIDAS_SZRCLIENT + + ".params.documenttype"; + public static final String CONIG_PROPS_EIDAS_SZRCLIENT_PARAMS_VKZ = CONIG_PROPS_EIDAS_SZRCLIENT + + ".params.vkz"; + public static final String CONIG_PROPS_EIDAS_SZRCLIENT_PARAMS_ISSUING_DATE = CONIG_PROPS_EIDAS_SZRCLIENT + + ".params.issuingdate"; + public static final String CONIG_PROPS_EIDAS_SZRCLIENT_PARAMS_ISSUING_AUTHORITY = + CONIG_PROPS_EIDAS_SZRCLIENT + ".params.issuingauthority"; + public static final String CONIG_PROPS_EIDAS_SZRCLIENT_PARAMS_KEYS_USEDUMMY = CONIG_PROPS_EIDAS_SZRCLIENT + + ".params.usedummykeys"; + public static final String CONIG_PROPS_EIDAS_SZRCLIENT_DEBUG_USESRZFORBPKGENERATION = + CONIG_PROPS_EIDAS_SZRCLIENT + ".params.useSZRForbPKCalculation"; + public static final String CONIG_PROPS_EIDAS_SZRCLIENT_PARAMS_SETPLACEOFBIRTHIFAVAILABLE = + CONIG_PROPS_EIDAS_SZRCLIENT + ".params.setPlaceOfBirthIfAvailable"; + public static final String CONIG_PROPS_EIDAS_SZRCLIENT_PARAMS_SETBIRTHNAMEIFAVAILABLE = + CONIG_PROPS_EIDAS_SZRCLIENT + ".params.setBirthNameIfAvailable"; + + public static final String CONIG_PROPS_EIDAS_SZRCLIENT_WORKAROUND_REVISIONLOGDATASTORE_ACTIVE = + CONIG_PROPS_EIDAS_SZRCLIENT + ".revisionlog.eidmapping.active"; + + public static final String DEFAULT_MS_NODE_COUNTRY_CODE = "AT"; + + @Deprecated + public static final String CONIG_PROPS_EIDAS_SZRCLIENT_WORKAROUND_SQLLITEDATASTORE_URL = + CONIG_PROPS_EIDAS_SZRCLIENT + ".workarounds.datastore.sqlite.url"; + @Deprecated + public static final String CONIG_PROPS_EIDAS_SZRCLIENT_WORKAROUND_SQLLITEDATASTORE_ACTIVE = + CONIG_PROPS_EIDAS_SZRCLIENT + ".workarounds.datastore.sqlite.active"; + + // http endpoint descriptions + public static final String eIDAS_HTTP_ENDPOINT_SP_POST = "/eidas/light/sp/post"; + public static final String eIDAS_HTTP_ENDPOINT_SP_REDIRECT = "/eidas/light/sp/redirect"; + public static final String eIDAS_HTTP_ENDPOINT_IDP_COLLEAGUEREQUEST = "/eidas/light/ColleagueRequest"; + public static final String eIDAS_HTTP_ENDPOINT_METADATA = "/eidas/light/metadata"; + + // eIDAS request parameters + public static final String eIDAS_REQ_NAMEID_FORMAT = "urn:oasis:names:tc:SAML:2.0:nameid-format:persistent"; + + // eIDAS attribute names + public static final String eIDAS_ATTR_PERSONALIDENTIFIER = "PersonIdentifier"; + public static final String eIDAS_ATTR_DATEOFBIRTH = "DateOfBirth"; + public static final String eIDAS_ATTR_CURRENTGIVENNAME = "FirstName"; + public static final String eIDAS_ATTR_CURRENTFAMILYNAME = "FamilyName"; + public static final String eIDAS_ATTR_PLACEOFBIRTH = "PlaceOfBirth"; + public static final String eIDAS_ATTR_BIRTHNAME = "BirthName"; + public static final String eIDAS_ATTR_CURRENTADDRESS = "CurrentAddress"; + + public static final String eIDAS_ATTR_LEGALPERSONIDENTIFIER = "LegalPersonIdentifier"; + public static final String eIDAS_ATTR_LEGALNAME = "LegalName"; + + public static final String eIDAS_ATTR_REPRESENTATIVE_PERSONALIDENTIFIER = "RepresentativePersonIdentifier"; + public static final String eIDAS_ATTR_REPRESENTATIVE_DATEOFBIRTH = "RepresentativeDateOfBirth"; + public static final String eIDAS_ATTR_REPRESENTATIVE_CURRENTGIVENNAME = "RepresentativeFirstName"; + public static final String eIDAS_ATTR_REPRESENTATIVE_CURRENTFAMILYNAME = "RepresentativeFamilyName"; + + + public static final String eIDAS_REQ_PARAM_SECTOR_PUBLIC = "public"; + public static final String eIDAS_REQ_PARAM_SECTOR_PRIVATE = "private"; + + public static final String POLICY_DEFAULT_ALLOWED_TARGETS = + EaafConstants.URN_PREFIX_CDID.replaceAll("\\.", "\\\\.").replaceAll("\\+", "\\\\+") + ".*"; + + // SAML2 Constants + public static final String SUCCESS_URI = "urn:oasis:names:tc:SAML:2.0:status:Success"; + public static final String ERROR_URI = "urn:oasis:names:tc:SAML:2.0:status:Responder"; + + public static final String HTTP_CLIENT_DEFAULT_TIMEOUT_CONNECTION = "30"; // seconds + public static final String HTTP_CLIENT_DEFAULT_TIMEOUT_RESPONSE = "60"; // seconds + + public static final String SZR_SCHEMA_LOCATIONS = + "urn:SZRServices" + " " + "/szr_client/szr.xsd"; + + // Default values for SZR communication + public static final String SZR_CONSTANTS_DEFAULT_DOCUMENT_TYPE = "ELEKTR_DOKUMENT"; + + // TODO remove!!! + public static final String SZR_CONSTANTS_DEFAULT_ISSUING_DATE = "2014-01-01"; + public static final String SZR_CONSTANTS_DEFAULT_ISSUING_AUTHORITY = "ms-specific eIDAS-Node for AT"; + public static final String SZR_CONSTANTS_DEFAULT_PUBKEY_EXPONENT = "AQAB"; + public static final String SZR_CONSTANTS_DEFAULT_PUBKEY_MODULUS = + "AJZyj/+sdCMDRq9RkvbFcgSTVn/OfS8EUE81ddwP8MNuJ1kd1SWBUJPaQX2JLJHrL54mkOhrkhH2M/zcuOTu8nW9TOEg" + + "XGjrRB/0HpiYKpV+VDJViyyc/GacNLxN4Anw4pima6gHYaJIw9hQkL/nuO2hyh8PGJd7rxeFXJmbLy+X"; + +} diff --git a/modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/EidasAuthenticationModulImpl.java b/modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/EidasAuthenticationModulImpl.java new file mode 100644 index 00000000..85f0873e --- /dev/null +++ b/modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/EidasAuthenticationModulImpl.java @@ -0,0 +1,87 @@ +/* + * Copyright 2018 A-SIT Plus GmbH + * AT-specific eIDAS Connector has been developed in a cooperation between EGIZ, + * A-SIT Plus GmbH, A-SIT, and Graz University of Technology. + * + * Licensed under the EUPL, Version 1.2 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "License"); + * You may not use this work except in compliance with the License. + * You may obtain a copy of the License at: + * https://joinup.ec.europa.eu/news/understanding-eupl-v12 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. +*/ + +package at.asitplus.eidas.specific.modules.auth.eidas.v2; + +import java.io.Serializable; + +import org.apache.commons.lang3.StringUtils; + +import at.asitplus.eidas.specific.core.MsEidasNodeConstants; +import at.gv.egiz.eaaf.core.api.IRequest; +import at.gv.egiz.eaaf.core.api.idp.auth.modules.AuthModule; +import at.gv.egiz.eaaf.core.api.idp.process.ExecutionContext; + +/** + * eIDAS authentication-process selector. + * + * @author tlenz + * + */ +public class EidasAuthenticationModulImpl implements AuthModule { + + private int priority = 1; + + @Override + public int getPriority() { + return priority; + } + + /** + * Sets the priority of this module. Default value is {@code 0}. + * + * @param priority The priority. + */ + public void setPriority(int priority) { + this.priority = priority; + } + + /* + * (non-Javadoc) + * + * @see at.gv.egovernment.moa.id.auth.modules.AuthModule#selectProcess(at.gv. + * egovernment.moa.id.process.api.ExecutionContext) + */ + @Override + public String selectProcess(ExecutionContext context, IRequest pendingReq) { + Serializable flagObj = context.get(MsEidasNodeConstants.REQ_PARAM_SELECTED_COUNTRY); + if (flagObj != null && flagObj instanceof String + && StringUtils.isNotBlank((String) context.get(MsEidasNodeConstants.REQ_PARAM_SELECTED_COUNTRY))) { + return "eIDASAuthentication_v2"; + } else { + return null; + } + + } + + /* + * (non-Javadoc) + * + * @see at.gv.egovernment.moa.id.auth.modules.AuthModule#getProcessDefinitions() + */ + @Override + public String[] getProcessDefinitions() { + return new String[] { "classpath:eIDAS.Authentication.process.xml" }; + } + +} diff --git a/modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/EidasAuthenticationSpringResourceProvider.java b/modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/EidasAuthenticationSpringResourceProvider.java new file mode 100644 index 00000000..535e4f97 --- /dev/null +++ b/modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/EidasAuthenticationSpringResourceProvider.java @@ -0,0 +1,52 @@ +/* + * Copyright 2018 A-SIT Plus GmbH + * AT-specific eIDAS Connector has been developed in a cooperation between EGIZ, + * A-SIT Plus GmbH, A-SIT, and Graz University of Technology. + * + * Licensed under the EUPL, Version 1.2 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "License"); + * You may not use this work except in compliance with the License. + * You may obtain a copy of the License at: + * https://joinup.ec.europa.eu/news/understanding-eupl-v12 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. +*/ + +package at.asitplus.eidas.specific.modules.auth.eidas.v2; + +import org.springframework.core.io.ClassPathResource; +import org.springframework.core.io.Resource; + +import at.gv.egiz.components.spring.api.SpringResourceProvider; + +public class EidasAuthenticationSpringResourceProvider implements SpringResourceProvider { + + @Override + public String getName() { + return "Auth. module for eIDAS Ref. Impl. v2.x"; + } + + @Override + public String[] getPackagesToScan() { + // TODO Auto-generated method stub + return null; + } + + @Override + public Resource[] getResourcesToLoad() { + final ClassPathResource eidasAuthConfig = new ClassPathResource("/eidas_v2_auth.beans.xml", + EidasAuthenticationSpringResourceProvider.class); + + return new Resource[] { eidasAuthConfig }; + } + +} diff --git a/modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/EidasSignalServlet.java b/modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/EidasSignalServlet.java new file mode 100644 index 00000000..d3cac80c --- /dev/null +++ b/modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/EidasSignalServlet.java @@ -0,0 +1,161 @@ +/* + * Copyright 2018 A-SIT Plus GmbH + * AT-specific eIDAS Connector has been developed in a cooperation between EGIZ, + * A-SIT Plus GmbH, A-SIT, and Graz University of Technology. + * + * Licensed under the EUPL, Version 1.2 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "License"); + * You may not use this work except in compliance with the License. + * You may obtain a copy of the License at: + * https://joinup.ec.europa.eu/news/understanding-eupl-v12 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. +*/ + +package at.asitplus.eidas.specific.modules.auth.eidas.v2; + +import java.io.IOException; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.apache.commons.lang3.StringUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.ApplicationContext; +import org.springframework.stereotype.Controller; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; + +import com.google.common.collect.ImmutableSortedSet; + +import at.asitplus.eidas.specific.modules.auth.eidas.v2.exception.EidasSAuthenticationException; +import at.asitplus.eidas.specific.modules.auth.eidas.v2.service.EidasAttributeRegistry; +import at.gv.egiz.eaaf.core.exceptions.EaafException; +import at.gv.egiz.eaaf.core.impl.idp.controller.AbstractProcessEngineSignalController; +import eu.eidas.auth.commons.EidasParameterKeys; +import eu.eidas.auth.commons.light.ILightResponse; +import eu.eidas.specificcommunication.SpecificCommunicationDefinitionBeanNames; +import eu.eidas.specificcommunication.exception.SpecificCommunicationException; +import eu.eidas.specificcommunication.protocol.SpecificCommunicationService; + +/** + * Controler implementation for eIDAS Node communication. + * + * @author tlenz + * + */ +@Controller +public class EidasSignalServlet extends AbstractProcessEngineSignalController { + + private static final Logger log = LoggerFactory.getLogger(EidasSignalServlet.class); + @Autowired + private ApplicationContext context; + @Autowired + private EidasAttributeRegistry attrRegistry; + + /** + * eIDAS Node communication end-point implementation. + * + */ + public EidasSignalServlet() { + super(); + log.debug("Registering servlet {} with mappings '{}' and '{}'.", + getClass().getName(), Constants.eIDAS_HTTP_ENDPOINT_SP_POST, + Constants.eIDAS_HTTP_ENDPOINT_SP_REDIRECT); + + } + + @RequestMapping(value = { + Constants.eIDAS_HTTP_ENDPOINT_SP_POST, + Constants.eIDAS_HTTP_ENDPOINT_SP_REDIRECT + }, + method = { RequestMethod.POST, RequestMethod.GET }) + public void restoreEidasAuthProcess(HttpServletRequest req, HttpServletResponse resp) throws IOException, + EaafException { + signalProcessManagement(req, resp); + } + + /** + * Protocol specific implementation to get the pending-requestID from http + * request object. + * + * @param request The http Servlet-Request object + * @return The Pending-request id + * + */ + @Override + public String getPendingRequestId(HttpServletRequest request) { + // String sessionId = super.getPendingRequestId(request); + + try { + // get token from Request + final String tokenBase64 = request.getParameter(EidasParameterKeys.TOKEN.toString()); + if (StringUtils.isEmpty(tokenBase64)) { + log.warn("NO eIDAS message token found."); + throw new EidasSAuthenticationException("eidas.04", null); + + } + log.trace("Receive eIDAS-node token: " + tokenBase64 + " Starting transaction-restore process ... "); + + final SpecificCommunicationService specificConnectorCommunicationService = + (SpecificCommunicationService) context.getBean( + SpecificCommunicationDefinitionBeanNames.SPECIFIC_CONNECTOR_COMMUNICATION_SERVICE.toString()); + final ILightResponse eidasResponse = specificConnectorCommunicationService.getAndRemoveResponse( + tokenBase64, + ImmutableSortedSet.copyOf(attrRegistry.getCoreAttributeRegistry().getAttributes())); + + String pendingReqId = null; + if (StringUtils.isEmpty(eidasResponse.getRelayState())) { + log.debug("eIDAS Node returns no RelayState. "); + + if (authConfig.getBasicConfigurationBoolean( + Constants.CONIG_PROPS_EIDAS_NODE_WORKAROUND_USEREQUESTIDASTRANSACTIONIDENTIFIER, + false)) { + log.trace("Use lightRequestId to recover session ... "); + pendingReqId = transactionStorage.get(eidasResponse.getInResponseToId(), String.class); + if (StringUtils.isNotEmpty(pendingReqId)) { + log.debug("Restoring session with lightRequestId ... "); + transactionStorage.remove(eidasResponse.getInResponseToId()); + + } + } + + } else { + log.debug("Find transaction identifier in SAML2 'RelayState': " + eidasResponse.getRelayState()); + pendingReqId = eidasResponse.getRelayState(); + + } + + if (StringUtils.isNotEmpty(pendingReqId)) { + request.setAttribute(Constants.DATA_FULL_EIDAS_RESPONSE, eidasResponse); + return pendingReqId; + + } + + log.info("NO transaction identifier found! Stopping process ...."); + log.trace("FullResponse: " + eidasResponse.toString()); + + } catch (final SpecificCommunicationException e) { + log.warn("Can NOT load eIDAS Response from cache.", e); + log.debug("eIDAS response token was: " + request.getParameter(EidasParameterKeys.TOKEN.toString())); + + } catch (final Exception e) { + log.warn("Unable to retrieve moa session id.", e); + + } + + return null; + } + +} diff --git a/modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/dao/ErnbEidData.java b/modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/dao/ErnbEidData.java new file mode 100644 index 00000000..6c7eeb6b --- /dev/null +++ b/modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/dao/ErnbEidData.java @@ -0,0 +1,115 @@ +/* + * Copyright 2018 A-SIT Plus GmbH + * AT-specific eIDAS Connector has been developed in a cooperation between EGIZ, + * A-SIT Plus GmbH, A-SIT, and Graz University of Technology. + * + * Licensed under the EUPL, Version 1.2 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "License"); + * You may not use this work except in compliance with the License. + * You may obtain a copy of the License at: + * https://joinup.ec.europa.eu/news/understanding-eupl-v12 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. +*/ + +package at.asitplus.eidas.specific.modules.auth.eidas.v2.dao; + +import java.text.SimpleDateFormat; + +import org.joda.time.DateTime; + +import at.gv.e_government.reference.namespace.persondata._20020228.PostalAddressType; + +public class ErnbEidData { + + private String citizenCountryCode = null; + + // MDS + private String pseudonym = null; + private String givenName = null; + private String familyName = null; + private DateTime dateOfBirth = null; + + // additional attributes + private String placeOfBirth = null; + private String birthName = null; + private PostalAddressType address = null; + + public String getCitizenCountryCode() { + return citizenCountryCode; + } + + public void setCitizenCountryCode(String citizenCountryCode) { + this.citizenCountryCode = citizenCountryCode; + } + + public String getPseudonym() { + return pseudonym; + } + + public void setPseudonym(String pseudonym) { + this.pseudonym = pseudonym; + } + + public String getGivenName() { + return givenName; + } + + public void setGivenName(String givenName) { + this.givenName = givenName; + } + + public String getFamilyName() { + return familyName; + } + + public void setFamilyName(String familyName) { + this.familyName = familyName; + } + + public DateTime getDateOfBirth() { + return dateOfBirth; + } + + public void setDateOfBirth(DateTime dateOfBirth) { + this.dateOfBirth = dateOfBirth; + } + + public String getPlaceOfBirth() { + return placeOfBirth; + } + + public void setPlaceOfBirth(String placeOfBirth) { + this.placeOfBirth = placeOfBirth; + } + + public String getBirthName() { + return birthName; + } + + public void setBirthName(String birthName) { + this.birthName = birthName; + } + + public PostalAddressType getAddress() { + return address; + } + + public void setAddress(PostalAddressType address) { + this.address = address; + } + + public String getFormatedDateOfBirth() { + return new SimpleDateFormat("yyyy-MM-dd").format(dateOfBirth.toDate()); + } + +} diff --git a/modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/exception/EidPostProcessingException.java b/modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/exception/EidPostProcessingException.java new file mode 100644 index 00000000..f4c0be67 --- /dev/null +++ b/modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/exception/EidPostProcessingException.java @@ -0,0 +1,40 @@ +/* + * Copyright 2018 A-SIT Plus GmbH + * AT-specific eIDAS Connector has been developed in a cooperation between EGIZ, + * A-SIT Plus GmbH, A-SIT, and Graz University of Technology. + * + * Licensed under the EUPL, Version 1.2 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "License"); + * You may not use this work except in compliance with the License. + * You may obtain a copy of the License at: + * https://joinup.ec.europa.eu/news/understanding-eupl-v12 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. +*/ + +package at.asitplus.eidas.specific.modules.auth.eidas.v2.exception; + +public class EidPostProcessingException extends EidasSAuthenticationException { + + private static final long serialVersionUID = 6780652273831172456L; + + public EidPostProcessingException(String internalMsgId, Object[] params) { + super(internalMsgId, params); + + } + + public EidPostProcessingException(String internalMsgId, Object[] params, Throwable e) { + super(internalMsgId, params, e); + + } + +} diff --git a/modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/exception/EidasAttributeException.java b/modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/exception/EidasAttributeException.java new file mode 100644 index 00000000..49736d58 --- /dev/null +++ b/modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/exception/EidasAttributeException.java @@ -0,0 +1,34 @@ +/* + * Copyright 2018 A-SIT Plus GmbH + * AT-specific eIDAS Connector has been developed in a cooperation between EGIZ, + * A-SIT Plus GmbH, A-SIT, and Graz University of Technology. + * + * Licensed under the EUPL, Version 1.2 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "License"); + * You may not use this work except in compliance with the License. + * You may obtain a copy of the License at: + * https://joinup.ec.europa.eu/news/understanding-eupl-v12 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. +*/ + +package at.asitplus.eidas.specific.modules.auth.eidas.v2.exception; + +public class EidasAttributeException extends EidasSAuthenticationException { + private static final long serialVersionUID = 1L; + + public EidasAttributeException(String attrbuteName) { + super("eidas.00", new Object[] { attrbuteName }); + + } + +} diff --git a/modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/exception/EidasSAuthenticationException.java b/modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/exception/EidasSAuthenticationException.java new file mode 100644 index 00000000..8ff218e3 --- /dev/null +++ b/modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/exception/EidasSAuthenticationException.java @@ -0,0 +1,41 @@ +/* + * Copyright 2018 A-SIT Plus GmbH + * AT-specific eIDAS Connector has been developed in a cooperation between EGIZ, + * A-SIT Plus GmbH, A-SIT, and Graz University of Technology. + * + * Licensed under the EUPL, Version 1.2 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "License"); + * You may not use this work except in compliance with the License. + * You may obtain a copy of the License at: + * https://joinup.ec.europa.eu/news/understanding-eupl-v12 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. +*/ + +package at.asitplus.eidas.specific.modules.auth.eidas.v2.exception; + +import at.gv.egiz.eaaf.core.exceptions.EaafAuthenticationException; + +public class EidasSAuthenticationException extends EaafAuthenticationException { + + + private static final long serialVersionUID = 1L; + + public EidasSAuthenticationException(String internalMsgId, Object[] params) { + super(internalMsgId, params); + } + + public EidasSAuthenticationException(String internalMsgId, Object[] params, Throwable e) { + super(internalMsgId, params, e); + } + +} diff --git a/modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/exception/EidasValidationException.java b/modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/exception/EidasValidationException.java new file mode 100644 index 00000000..2988dd6f --- /dev/null +++ b/modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/exception/EidasValidationException.java @@ -0,0 +1,34 @@ +/* + * Copyright 2018 A-SIT Plus GmbH + * AT-specific eIDAS Connector has been developed in a cooperation between EGIZ, + * A-SIT Plus GmbH, A-SIT, and Graz University of Technology. + * + * Licensed under the EUPL, Version 1.2 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "License"); + * You may not use this work except in compliance with the License. + * You may obtain a copy of the License at: + * https://joinup.ec.europa.eu/news/understanding-eupl-v12 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. +*/ + +package at.asitplus.eidas.specific.modules.auth.eidas.v2.exception; + +public class EidasValidationException extends EidasSAuthenticationException { + + private static final long serialVersionUID = 1L; + + public EidasValidationException(String internalMsgId, Object[] params) { + super(internalMsgId, params); + } + +} diff --git a/modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/exception/SqliteServiceException.java b/modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/exception/SqliteServiceException.java new file mode 100644 index 00000000..d48abec9 --- /dev/null +++ b/modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/exception/SqliteServiceException.java @@ -0,0 +1,40 @@ +/* + * Copyright 2018 A-SIT Plus GmbH + * AT-specific eIDAS Connector has been developed in a cooperation between EGIZ, + * A-SIT Plus GmbH, A-SIT, and Graz University of Technology. + * + * Licensed under the EUPL, Version 1.2 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "License"); + * You may not use this work except in compliance with the License. + * You may obtain a copy of the License at: + * https://joinup.ec.europa.eu/news/understanding-eupl-v12 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. +*/ + +package at.asitplus.eidas.specific.modules.auth.eidas.v2.exception; + +public class SqliteServiceException extends EidasSAuthenticationException { + + private static final long serialVersionUID = 2278259367925102676L; + + public SqliteServiceException(String internalMsgId, Object[] params, Throwable e) { + super(internalMsgId, params, e); + + } + + public SqliteServiceException(String internalMsgId, Object[] params) { + super(internalMsgId, params); + + } + +} diff --git a/modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/exception/SzrCommunicationException.java b/modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/exception/SzrCommunicationException.java new file mode 100644 index 00000000..c736cadb --- /dev/null +++ b/modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/exception/SzrCommunicationException.java @@ -0,0 +1,38 @@ +/* + * Copyright 2018 A-SIT Plus GmbH + * AT-specific eIDAS Connector has been developed in a cooperation between EGIZ, + * A-SIT Plus GmbH, A-SIT, and Graz University of Technology. + * + * Licensed under the EUPL, Version 1.2 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "License"); + * You may not use this work except in compliance with the License. + * You may obtain a copy of the License at: + * https://joinup.ec.europa.eu/news/understanding-eupl-v12 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. +*/ + +package at.asitplus.eidas.specific.modules.auth.eidas.v2.exception; + +public class SzrCommunicationException extends EidasSAuthenticationException { + + private static final long serialVersionUID = 1L; + + public SzrCommunicationException(String internalMsgId, Object[] params) { + super(internalMsgId, params); + } + + public SzrCommunicationException(String internalMsgId, Object[] params, Throwable e) { + super(internalMsgId, params, e); + } + +} diff --git a/modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/handler/AbstractEidProcessor.java b/modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/handler/AbstractEidProcessor.java new file mode 100644 index 00000000..4a3218e9 --- /dev/null +++ b/modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/handler/AbstractEidProcessor.java @@ -0,0 +1,425 @@ +/* + * Copyright 2018 A-SIT Plus GmbH + * AT-specific eIDAS Connector has been developed in a cooperation between EGIZ, + * A-SIT Plus GmbH, A-SIT, and Graz University of Technology. + * + * Licensed under the EUPL, Version 1.2 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "License"); + * You may not use this work except in compliance with the License. + * You may obtain a copy of the License at: + * https://joinup.ec.europa.eu/news/understanding-eupl-v12 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + */ + +package at.asitplus.eidas.specific.modules.auth.eidas.v2.handler; + +import java.nio.charset.StandardCharsets; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; +import java.util.Arrays; +import java.util.Base64; +import java.util.Map; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import org.apache.commons.lang3.StringUtils; +import org.joda.time.DateTime; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.lang.NonNull; + +import com.google.common.collect.ImmutableSortedSet; + +import at.asitplus.eidas.specific.modules.auth.eidas.v2.Constants; +import at.asitplus.eidas.specific.modules.auth.eidas.v2.dao.ErnbEidData; +import at.asitplus.eidas.specific.modules.auth.eidas.v2.exception.EidPostProcessingException; +import at.asitplus.eidas.specific.modules.auth.eidas.v2.exception.EidasAttributeException; +import at.asitplus.eidas.specific.modules.auth.eidas.v2.service.EidasAttributeRegistry; +import at.asitplus.eidas.specific.modules.auth.eidas.v2.utils.EidasResponseUtils; +import at.gv.e_government.reference.namespace.persondata._20020228.PostalAddressType; +import at.gv.egiz.eaaf.core.api.IRequest; +import at.gv.egiz.eaaf.core.api.data.EaafConstants; +import at.gv.egiz.eaaf.core.api.idp.IConfigurationWithSP; +import at.gv.egiz.eaaf.core.api.idp.ISpConfiguration; +import at.gv.egiz.eaaf.core.impl.data.Triple; +import eu.eidas.auth.commons.attribute.AttributeDefinition; +import eu.eidas.auth.commons.attribute.ImmutableAttributeMap; +import eu.eidas.auth.commons.light.impl.LightRequest.Builder; +import eu.eidas.auth.commons.protocol.eidas.SpType; +import eu.eidas.auth.commons.protocol.eidas.impl.PostalAddress; + +public abstract class AbstractEidProcessor implements INationalEidProcessor { + private static final Logger log = LoggerFactory.getLogger(AbstractEidProcessor.class); + + @Autowired + protected EidasAttributeRegistry attrRegistry; + @Autowired + protected IConfigurationWithSP basicConfig; + + @Override + public final void preProcess(IRequest pendingReq, Builder authnRequestBuilder) { + + buildLevelOfAssurance(pendingReq.getServiceProviderConfiguration(), authnRequestBuilder); + buildProviderNameAndRequesterIdAttribute(pendingReq, authnRequestBuilder); + buildRequestedAttributes(authnRequestBuilder); + + } + + + @Override + public final ErnbEidData postProcess(Map eidasAttrMap) throws EidPostProcessingException, + EidasAttributeException { + final ErnbEidData result = new ErnbEidData(); + + final Object eIdentifierObj = eidasAttrMap.get(Constants.eIDAS_ATTR_PERSONALIDENTIFIER); + final Triple eIdentifier = + EidasResponseUtils.parseEidasPersonalIdentifier((String) eIdentifierObj); + result.setCitizenCountryCode(eIdentifier.getFirst()); + + // MDS attributes + result.setPseudonym(processPseudonym(eidasAttrMap.get(Constants.eIDAS_ATTR_PERSONALIDENTIFIER))); + result.setFamilyName(processFamilyName(eidasAttrMap.get(Constants.eIDAS_ATTR_CURRENTFAMILYNAME))); + result.setGivenName(processGivenName(eidasAttrMap.get(Constants.eIDAS_ATTR_CURRENTGIVENNAME))); + result.setDateOfBirth(processDateOfBirth(eidasAttrMap.get(Constants.eIDAS_ATTR_DATEOFBIRTH))); + + // additional attributes + result.setPlaceOfBirth(processPlaceOfBirth(eidasAttrMap.get(Constants.eIDAS_ATTR_PLACEOFBIRTH))); + result.setBirthName(processBirthName(eidasAttrMap.get(Constants.eIDAS_ATTR_BIRTHNAME))); + result.setAddress(processAddress(eidasAttrMap.get(Constants.eIDAS_ATTR_CURRENTADDRESS))); + + return result; + + } + + + /** + * Get a Map of country-specific requested attributes. + * + * @return + */ + @NonNull + protected abstract Map getCountrySpecificRequestedAttributes(); + + /** + * Post-Process the eIDAS CurrentAddress attribute. + * + * @param currentAddressObj eIDAS current address information + * @return current address or null if no attribute is available + * @throws EidPostProcessingException if post-processing fails + * @throws EidasAttributeException if eIDAS attribute is of a wrong type + */ + protected PostalAddressType processAddress(Object currentAddressObj) throws EidPostProcessingException, + EidasAttributeException { + + if (currentAddressObj != null) { + if (currentAddressObj instanceof PostalAddress) { + final PostalAddressType result = new PostalAddressType(); + result.setPostalCode(((PostalAddress) currentAddressObj).getPostCode()); + result.setMunicipality(((PostalAddress) currentAddressObj).getPostName()); + + // TODO: add more mappings + + return result; + + } else { + log.warn("eIDAS attr: " + Constants.eIDAS_ATTR_CURRENTADDRESS + " is of WRONG type"); + throw new EidasAttributeException(Constants.eIDAS_ATTR_CURRENTADDRESS); + + } + + } else { + log.debug("NO '" + Constants.eIDAS_ATTR_CURRENTADDRESS + "' attribute. Post-Processing skipped ... "); + } + + return null; + + } + + /** + * Post-Process the eIDAS BirthName attribute. + * + * @param birthNameObj eIDAS birthname information + * @return birthName or null if no attribute is available + * @throws EidPostProcessingException if post-processing fails + * @throws EidasAttributeException if eIDAS attribute is of a wrong type + */ + protected String processBirthName(Object birthNameObj) throws EidPostProcessingException, + EidasAttributeException { + if (birthNameObj != null) { + if (birthNameObj instanceof String) { + return (String) birthNameObj; + + } else { + log.warn("eIDAS attr: " + Constants.eIDAS_ATTR_BIRTHNAME + " is of WRONG type"); + throw new EidasAttributeException(Constants.eIDAS_ATTR_BIRTHNAME); + + } + + } else { + log.debug("NO '" + Constants.eIDAS_ATTR_BIRTHNAME + "' attribute. Post-Processing skipped ... "); + } + + return null; + + } + + /** + * Post-Process the eIDAS PlaceOfBirth attribute. + * + * @param placeOfBirthObj eIDAS Place-of-Birth information + * @return place of Birth or null if no attribute is available + * @throws EidPostProcessingException if post-processing fails + * @throws EidasAttributeException if eIDAS attribute is of a wrong type + */ + protected String processPlaceOfBirth(Object placeOfBirthObj) throws EidPostProcessingException, + EidasAttributeException { + if (placeOfBirthObj != null) { + if (placeOfBirthObj instanceof String) { + return (String) placeOfBirthObj; + + } else { + log.warn("eIDAS attr: " + Constants.eIDAS_ATTR_PLACEOFBIRTH + " is of WRONG type"); + throw new EidasAttributeException(Constants.eIDAS_ATTR_PLACEOFBIRTH); + + } + + } else { + log.debug("NO '" + Constants.eIDAS_ATTR_PLACEOFBIRTH + "' attribute. Post-Processing skipped ... "); + } + + return null; + + } + + /** + * Post-Process the eIDAS DateOfBirth attribute. + * + * @param dateOfBirthObj eIDAS date-of-birth attribute information + * @return formated user's date-of-birth + * @throws EidasAttributeException if NO attribute is available + * @throws EidPostProcessingException if post-processing fails + */ + protected DateTime processDateOfBirth(Object dateOfBirthObj) throws EidPostProcessingException, + EidasAttributeException { + if (dateOfBirthObj == null || !(dateOfBirthObj instanceof DateTime)) { + throw new EidasAttributeException(Constants.eIDAS_ATTR_DATEOFBIRTH); + } + + return (DateTime) dateOfBirthObj; + + } + + /** + * Post-Process the eIDAS GivenName attribute. + * + * @param givenNameObj eIDAS givenName attribute information + * @return formated user's givenname + * @throws EidasAttributeException if NO attribute is available + * @throws EidPostProcessingException if post-processing fails + */ + protected String processGivenName(Object givenNameObj) throws EidPostProcessingException, + EidasAttributeException { + if (givenNameObj == null || !(givenNameObj instanceof String)) { + throw new EidasAttributeException(Constants.eIDAS_ATTR_CURRENTGIVENNAME); + } + + return (String) givenNameObj; + + } + + /** + * Post-Process the eIDAS FamilyName attribute. + * + * @param familyNameObj eIDAS familyName attribute information + * @return formated user's familyname + * @throws EidasAttributeException if NO attribute is available + * @throws EidPostProcessingException if post-processing fails + */ + protected String processFamilyName(Object familyNameObj) throws EidPostProcessingException, + EidasAttributeException { + if (familyNameObj == null || !(familyNameObj instanceof String)) { + throw new EidasAttributeException(Constants.eIDAS_ATTR_CURRENTFAMILYNAME); + } + + return (String) familyNameObj; + + } + + /** + * Post-Process the eIDAS pseudonym to ERnB unique identifier. + * + * @param personalIdObj eIDAS PersonalIdentifierAttribute + * @return Unique personal identifier without country-code information + * @throws EidasAttributeException if NO attribute is available + * @throws EidPostProcessingException if post-processing fails + */ + protected String processPseudonym(Object personalIdObj) throws EidPostProcessingException, + EidasAttributeException { + if (personalIdObj == null || !(personalIdObj instanceof String)) { + throw new EidasAttributeException(Constants.eIDAS_ATTR_PERSONALIDENTIFIER); + } + + final Triple eIdentifier = + EidasResponseUtils.parseEidasPersonalIdentifier((String) personalIdObj); + + return eIdentifier.getThird(); + + } + + /** + * Set ProviderName and RequestId into eIDAS AuthnRequest. + * + * @param pendingReq Current pendingRequest + * @param authnRequestBuilder AuthnRequest builder + */ + protected void buildProviderNameAndRequesterIdAttribute(IRequest pendingReq, Builder authnRequestBuilder) { + final ISpConfiguration spConfig = pendingReq.getServiceProviderConfiguration(); + + // set correct SPType for requested target sector + final String publicSectorTargetSelector = basicConfig.getBasicConfiguration( + Constants.CONIG_PROPS_EIDAS_NODE_PUBLICSECTOR_TARGETS, + Constants.POLICY_DEFAULT_ALLOWED_TARGETS); + final Pattern p = Pattern.compile(publicSectorTargetSelector); + final Matcher m = p.matcher(spConfig.getAreaSpecificTargetIdentifier()); + if (m.matches()) { + log.debug("Map " + spConfig.getAreaSpecificTargetIdentifier() + " to 'PublicSector'"); + authnRequestBuilder.spType(SpType.PUBLIC.getValue()); + + final String providerName = pendingReq.getRawData(Constants.DATA_PROVIDERNAME, String.class); + if (basicConfig.getBasicConfigurationBoolean( + Constants.CONIG_PROPS_EIDAS_NODE_WORKAROUND_ADD_ALWAYS_PROVIDERNAME, + false)) { + //TODO: only for eIDAS ref. node 2.0 and 2.1 because it need 'Providername' for + if (StringUtils.isNotEmpty(providerName)) { + log.debug("Set 'providername' to: {}", providerName); + authnRequestBuilder.providerName(providerName); + + } else { + authnRequestBuilder.providerName(basicConfig.getBasicConfiguration( + Constants.CONIG_PROPS_EIDAS_NODE_STATIC_PROVIDERNAME_FOR_PUBLIC_SP, + Constants.DEFAULT_PROPS_EIDAS_NODE_STATIC_PROVIDERNAME_FOR_PUBLIC_SP)); + + } + } + + } else { + log.debug("Map " + spConfig.getAreaSpecificTargetIdentifier() + " to 'PrivateSector'"); + authnRequestBuilder.spType(SpType.PRIVATE.getValue()); + + // TODO: switch to RequesterId in further version + // set provider name for private sector applications + final String providerName = pendingReq.getRawData(Constants.DATA_PROVIDERNAME, String.class); + if (StringUtils.isNotEmpty(providerName)) { + authnRequestBuilder.providerName(providerName); + + } + + authnRequestBuilder.requesterId( + generateRequesterId(pendingReq.getRawData(Constants.DATA_REQUESTERID, String.class))); + + } + } + + /** + * Build LoA based on Service-Provider configuration. + * + * @param spConfig Current SP configuration + * @param authnRequestBuilder AuthnRequest builder + */ + protected void buildLevelOfAssurance(ISpConfiguration spConfig, Builder authnRequestBuilder) { + // TODO: set matching mode if eIDAS ref. impl. support this method + + // TODO: update if eIDAS ref. impl. supports exact matching for non-notified LoA + // schemes + String loa = EaafConstants.EIDAS_LOA_HIGH; + if (spConfig.getRequiredLoA() != null) { + if (spConfig.getRequiredLoA().isEmpty()) { + log.info("No eIDAS LoA requested. Use LoA HIGH as default"); + } else { + if (spConfig.getRequiredLoA().size() > 1) { + log.info( + "Currently only ONE requested LoA is supported for service provider. Use first one ... "); + } + + loa = spConfig.getRequiredLoA().get(0); + + } + } + + log.debug("Request eIdAS node with LoA: " + loa); + authnRequestBuilder.levelsOfAssuranceValues(Arrays.asList(loa)); + + } + + private String generateRequesterId(String requesterId) { + if (requesterId != null && basicConfig.getBasicConfigurationBoolean( + Constants.CONIG_PROPS_EIDAS_NODE_REQUESTERID_USE_HASHED_VERSION, true)) { + try { + log.trace("Building hashed 'requesterId' for private SP ... "); + MessageDigest digest = MessageDigest.getInstance("SHA-256"); + String encodedRequesterId = Base64.getEncoder().encodeToString( + digest.digest(requesterId.getBytes(StandardCharsets.UTF_8))); + log.debug("Set 'requesterId' for: {} to: {}", requesterId, encodedRequesterId); + return encodedRequesterId; + + } catch (NoSuchAlgorithmException e) { + log.error("Can NOT generate hashed 'requesterId' from: {}. Use it as it is", requesterId, e); + + } + + } + + return requesterId; + + } + + + private void buildRequestedAttributes(Builder authnRequestBuilder) { + // build and add requested attribute set + final Map ccSpecificReqAttr = getCountrySpecificRequestedAttributes(); + log.debug("Get #{} country-specific requested attributes", ccSpecificReqAttr.size()); + + final Map mdsReqAttr = attrRegistry.getDefaultAttributeSetFromConfiguration(); + log.trace("Get #{} default requested attributes", mdsReqAttr.size()); + + // put it together + ccSpecificReqAttr.putAll(mdsReqAttr); + + // convert it to eIDAS attributes + final ImmutableAttributeMap reqAttrMap = translateToEidasAttributes(ccSpecificReqAttr); + authnRequestBuilder.requestedAttributes(reqAttrMap); + + } + + private ImmutableAttributeMap translateToEidasAttributes(final Map requiredAttributes) { + final ImmutableAttributeMap.Builder builder = ImmutableAttributeMap.builder(); + for (final Map.Entry attribute : requiredAttributes.entrySet()) { + final String name = attribute.getKey(); + final ImmutableSortedSet> byFriendlyName = attrRegistry + .getCoreAttributeRegistry().getByFriendlyName(name); + if (!byFriendlyName.isEmpty()) { + final AttributeDefinition attributeDefinition = byFriendlyName.first(); + builder.put(AttributeDefinition.builder(attributeDefinition).required(attribute.getValue()).build()); + + } else { + log.warn("Can NOT request UNKNOWN attribute: " + attribute.getKey() + " Ignore it!"); + } + + } + + return builder.build(); + + } + +} diff --git a/modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/handler/DeEidProcessor.java b/modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/handler/DeEidProcessor.java new file mode 100644 index 00000000..6dc08181 --- /dev/null +++ b/modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/handler/DeEidProcessor.java @@ -0,0 +1,113 @@ +/* + * Copyright 2018 A-SIT Plus GmbH + * AT-specific eIDAS Connector has been developed in a cooperation between EGIZ, + * A-SIT Plus GmbH, A-SIT, and Graz University of Technology. + * + * Licensed under the EUPL, Version 1.2 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "License"); + * You may not use this work except in compliance with the License. + * You may obtain a copy of the License at: + * https://joinup.ec.europa.eu/news/understanding-eupl-v12 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. +*/ + +package at.asitplus.eidas.specific.modules.auth.eidas.v2.handler; + +import java.io.UnsupportedEncodingException; +import java.util.Base64; +import java.util.Map; + +import org.apache.commons.codec.DecoderException; +import org.apache.commons.codec.binary.Hex; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import at.asitplus.eidas.specific.modules.auth.eidas.v2.Constants; +import at.asitplus.eidas.specific.modules.auth.eidas.v2.exception.EidPostProcessingException; +import at.asitplus.eidas.specific.modules.auth.eidas.v2.exception.EidasAttributeException; +import at.asitplus.eidas.specific.modules.auth.eidas.v2.utils.EidasResponseUtils; +import at.gv.egiz.eaaf.core.impl.data.Triple; + + +public class DeEidProcessor extends AbstractEidProcessor { + private static final Logger log = LoggerFactory.getLogger(DeEidProcessor.class); + private static final String canHandleCC = "DE"; + + private int priority = 1; + + @Override + public int getPriority() { + return priority; + } + + @Override + public boolean canHandle(String countryCode) { + return countryCode != null && countryCode.equalsIgnoreCase(canHandleCC); + + } + + public void setPriority(int priority) { + this.priority = priority; + } + + @Override + public String getName() { + return "DE-PostProcessor"; + + } + + @Override + protected String processPseudonym(Object uniqeIdentifierObj) throws EidPostProcessingException, + EidasAttributeException { + if (uniqeIdentifierObj == null || !(uniqeIdentifierObj instanceof String)) { + throw new EidasAttributeException(Constants.eIDAS_ATTR_PERSONALIDENTIFIER); + } + + final Triple eIdentifier = + EidasResponseUtils.parseEidasPersonalIdentifier((String) uniqeIdentifierObj); + + log.trace(getName() + " starts processing of attribute: " + Constants.eIDAS_ATTR_PERSONALIDENTIFIER); + final String result = convertDeIdentifier(eIdentifier.getThird()); + log.debug(getName() + " finished processing of attribute: " + Constants.eIDAS_ATTR_PERSONALIDENTIFIER); + + return result; + + } + + private String convertDeIdentifier(String hexEncodedDeIdentifier) throws EidPostProcessingException { + if (hexEncodedDeIdentifier.length() != 64) { + throw new EidPostProcessingException("ernb.03", new Object[] { + "Input has wrong length, expected 64 chars" }); + } + + byte[] data; + try { + data = Hex.decodeHex(hexEncodedDeIdentifier); + final byte[] encoded = Base64.getEncoder().encode(data); + return new String(encoded, "UTF-8"); + + } catch (final DecoderException | UnsupportedEncodingException e) { + throw new EidPostProcessingException("ernb.03", null, e); + + } + + + } + + @Override + protected Map getCountrySpecificRequestedAttributes() { + return attrRegistry.getAttributeSetFromConfiguration(canHandleCC); + + } + +} diff --git a/modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/handler/GenericEidProcessor.java b/modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/handler/GenericEidProcessor.java new file mode 100644 index 00000000..69949435 --- /dev/null +++ b/modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/handler/GenericEidProcessor.java @@ -0,0 +1,61 @@ +/* + * Copyright 2018 A-SIT Plus GmbH + * AT-specific eIDAS Connector has been developed in a cooperation between EGIZ, + * A-SIT Plus GmbH, A-SIT, and Graz University of Technology. + * + * Licensed under the EUPL, Version 1.2 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "License"); + * You may not use this work except in compliance with the License. + * You may obtain a copy of the License at: + * https://joinup.ec.europa.eu/news/understanding-eupl-v12 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. +*/ + +package at.asitplus.eidas.specific.modules.auth.eidas.v2.handler; + +import java.util.HashMap; +import java.util.Map; + +public class GenericEidProcessor extends AbstractEidProcessor { + + private int priority = 0; + + @Override + public int getPriority() { + return priority; + + } + + @Override + public boolean canHandle(String countryCode) { + return true; + + } + + public void setPriority(int priority) { + this.priority = priority; + } + + @Override + public String getName() { + return "Default-PostProcessor"; + + } + + @Override + protected Map getCountrySpecificRequestedAttributes() { + return new HashMap<>(); + + } + +} diff --git a/modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/handler/INationalEidProcessor.java b/modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/handler/INationalEidProcessor.java new file mode 100644 index 00000000..577efbcd --- /dev/null +++ b/modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/handler/INationalEidProcessor.java @@ -0,0 +1,81 @@ +/* + * Copyright 2018 A-SIT Plus GmbH + * AT-specific eIDAS Connector has been developed in a cooperation between EGIZ, + * A-SIT Plus GmbH, A-SIT, and Graz University of Technology. + * + * Licensed under the EUPL, Version 1.2 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "License"); + * You may not use this work except in compliance with the License. + * You may obtain a copy of the License at: + * https://joinup.ec.europa.eu/news/understanding-eupl-v12 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + */ + +package at.asitplus.eidas.specific.modules.auth.eidas.v2.handler; + +import java.util.Map; + +import at.asitplus.eidas.specific.modules.auth.eidas.v2.dao.ErnbEidData; +import at.asitplus.eidas.specific.modules.auth.eidas.v2.exception.EidasAttributeException; +import at.asitplus.eidas.specific.modules.auth.eidas.v2.exception.EidPostProcessingException; +import at.gv.egiz.eaaf.core.api.IRequest; +import eu.eidas.auth.commons.light.ILightRequest; +import eu.eidas.auth.commons.light.impl.LightRequest.Builder; + +public interface INationalEidProcessor { + + /** + * Get a friendlyName of this post-processor implementation. + * + * @return + */ + String getName(); + + /** + * Get the priority of this eID Post-Processor
+ * If more than one Post-Processor implementations can handle the eID data, the + * post-processor with the highest priority are selected. The Default-Processor + * has priority '0' + * + * @return Priority of this handler + */ + int getPriority(); + + /** + * Check if this postProcessor is sensitive for a specific country. + * + * @param countryCode of the eID data that should be processed + * @return true if this implementation can handle the country, otherwise false + * + */ + boolean canHandle(String countryCode); + + /** + * Post-Process eIDAS eID data into national format. + * + * @param eidasAttrMap Map of eIDAS attributes in format friendlyName and + * attribute + * @throws EidPostProcessingException In case of a post-processing error + * @throws EidasAttributeException In case of an invalid eIDAS attribute + */ + ErnbEidData postProcess(Map eidasAttrMap) throws EidPostProcessingException, + EidasAttributeException; + + /** + * Pre-Process eIDAS Request to national requirements. + * + * @param pendingReq current pending request + * @param authnRequestBuilder eIDAS {@link ILightRequest} builder + */ + void preProcess(IRequest pendingReq, Builder authnRequestBuilder); +} diff --git a/modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/handler/LuEidProcessor.java b/modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/handler/LuEidProcessor.java new file mode 100644 index 00000000..8402457f --- /dev/null +++ b/modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/handler/LuEidProcessor.java @@ -0,0 +1,61 @@ +package at.asitplus.eidas.specific.modules.auth.eidas.v2.handler; + +import java.util.HashMap; +import java.util.Map; + +import at.asitplus.eidas.specific.modules.auth.eidas.v2.Constants; +import at.gv.egiz.eaaf.core.api.IRequest; +import eu.eidas.auth.commons.light.impl.LightRequest.Builder; +import lombok.Getter; +import lombok.Setter; +import lombok.extern.slf4j.Slf4j; + +@Slf4j +public class LuEidProcessor extends AbstractEidProcessor { + + + + private static final String canHandleCC = "LU"; + + @Getter + @Setter + private int priority = 1; + + @Override + public String getName() { + return "LU-PostProcessor"; + + } + + @Override + public boolean canHandle(String countryCode) { + return countryCode != null && countryCode.equalsIgnoreCase(canHandleCC); + + } + + @Override + protected void buildProviderNameAndRequesterIdAttribute(IRequest pendingReq, Builder authnRequestBuilder) { + super.buildProviderNameAndRequesterIdAttribute(pendingReq, authnRequestBuilder); + if (basicConfig.getBasicConfigurationBoolean( + Constants.CONIG_PROPS_EIDAS_NODE_WORKAROUND_USE_STATIC_REQUESTERID_FOR_LUX, true)) { + String staticName = basicConfig.getBasicConfiguration( + Constants.CONIG_PROPS_EIDAS_NODE_STATIC_PROVIDERNAME_FOR_PUBLIC_SP, + Constants.DEFAULT_PROPS_EIDAS_NODE_STATIC_PROVIDERNAME_FOR_PUBLIC_SP); + authnRequestBuilder.providerName(staticName); + authnRequestBuilder.requesterId(staticName); + log.debug("Use static name: {} as 'providerName' and 'RequesterId' for all 'LU' requests ", staticName); + + } else { + log.info("Static 'providerName' and 'RequesterId' for country: LU is deactivated"); + + } + + } + + @Override + protected Map getCountrySpecificRequestedAttributes() { + return new HashMap<>(); + + } + +} diff --git a/modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/handler/NlEidProcessor.java b/modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/handler/NlEidProcessor.java new file mode 100644 index 00000000..2dd22927 --- /dev/null +++ b/modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/handler/NlEidProcessor.java @@ -0,0 +1,54 @@ +package at.asitplus.eidas.specific.modules.auth.eidas.v2.handler; + +import java.util.Arrays; +import java.util.HashMap; +import java.util.Map; + +import at.gv.egiz.eaaf.core.api.data.EaafConstants; +import at.gv.egiz.eaaf.core.api.idp.ISpConfiguration; +import eu.eidas.auth.commons.light.impl.LightRequest.Builder; +import lombok.Getter; +import lombok.Setter; +import lombok.extern.slf4j.Slf4j; + +@Slf4j +public class NlEidProcessor extends AbstractEidProcessor { + + + + private static final String canHandleCC = "NL"; + + @Getter + @Setter + private int priority = 1; + + @Override + public String getName() { + return "NL-PostProcessor"; + + } + + @Override + public boolean canHandle(String countryCode) { + return countryCode != null && countryCode.equalsIgnoreCase(canHandleCC); + + } + + protected void buildLevelOfAssurance(ISpConfiguration spConfig, Builder authnRequestBuilder) { + super.buildLevelOfAssurance(spConfig, authnRequestBuilder); + + //check requested level + if (authnRequestBuilder.build().getLevelOfAssurance().equals(EaafConstants.EIDAS_LOA_LOW)) { + log.debug("Upgrade LoA to {}, because NL needs it as minimum.", EaafConstants.EIDAS_LOA_SUBSTANTIAL); + authnRequestBuilder.levelsOfAssuranceValues(Arrays.asList(EaafConstants.EIDAS_LOA_SUBSTANTIAL)); + + } + } + + @Override + protected Map getCountrySpecificRequestedAttributes() { + return new HashMap<>(); + + } + +} diff --git a/modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/service/AuthBlockSigningService.java b/modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/service/AuthBlockSigningService.java new file mode 100644 index 00000000..098e76ce --- /dev/null +++ b/modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/service/AuthBlockSigningService.java @@ -0,0 +1,211 @@ +package at.asitplus.eidas.specific.modules.auth.eidas.v2.service; + +import java.security.Key; +import java.security.KeyStore; +import java.security.KeyStoreException; +import java.security.Provider; +import java.security.cert.X509Certificate; +import java.time.LocalDateTime; +import java.time.ZoneOffset; +import java.time.temporal.ChronoUnit; +import java.util.Base64; +import java.util.UUID; + +import javax.annotation.PostConstruct; + +import org.apache.commons.lang3.StringUtils; +import org.jose4j.lang.JoseException; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import com.fasterxml.jackson.annotation.JsonFormat; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.annotation.JsonDeserialize; +import com.fasterxml.jackson.databind.annotation.JsonSerialize; +import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateTimeDeserializer; +import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateTimeSerializer; + +import at.asitplus.eidas.specific.core.MsEidasNodeConstants; +import at.asitplus.eidas.specific.modules.auth.eidas.v2.utils.JoseUtils; +import at.gv.egiz.eaaf.core.api.IRequest; +import at.gv.egiz.eaaf.core.api.idp.IConfiguration; +import at.gv.egiz.eaaf.core.exception.EaafKeyAccessException; +import at.gv.egiz.eaaf.core.exceptions.EaafConfigurationException; +import at.gv.egiz.eaaf.core.exceptions.EaafException; +import at.gv.egiz.eaaf.core.impl.credential.EaafKeyStoreFactory; +import at.gv.egiz.eaaf.core.impl.credential.EaafKeyStoreUtils; +import at.gv.egiz.eaaf.core.impl.credential.KeyStoreConfiguration; +import at.gv.egiz.eaaf.core.impl.data.Pair; +import lombok.Data; +import lombok.extern.slf4j.Slf4j; + +/** + * Service to build and sign AuthBlock's for E-ID system. + * + * @author tlenz + * + */ +@Slf4j +@Service("authBlockSigningService") +public class AuthBlockSigningService { + + private static final String KEYSTORE_FRIENDLYNAME = "AuthBlock_Signing"; + + private static ObjectMapper mapper = new ObjectMapper(); + + @Autowired + IConfiguration basicConfig; + + @Autowired + EaafKeyStoreFactory keyStoreFactory; + + + private Pair keyStore; + + /** + * Build and sign an AuthBlock for E-ID system. + * + * @param pendingReq data that should be added into AuthBlock + * @return serialized JWS + * @throws JsonProcessingException In case of a AuthBlock generation error + * @throws JoseException In case of a JWS signing error + * @throws EaafException In case of a KeyStore or Key error + */ + public String buildSignedAuthBlock(IRequest pendingReq) + throws JsonProcessingException, EaafException, JoseException { + + //TODO: set Challenge to SAML2 requestId to create link between authentication request and authBlock + + // build AuthBlock + EidasAuchBlock authBlock = new EidasAuchBlock(); + authBlock.setChallenge(UUID.randomUUID().toString()); + authBlock.setTimestamp(LocalDateTime.now(ZoneOffset.UTC).truncatedTo(ChronoUnit.SECONDS)); + authBlock.setUniqueId(pendingReq.getRawData(MsEidasNodeConstants.DATA_REQUESTERID, String.class)); + authBlock.setPiiTransactionId(pendingReq.getUniquePiiTransactionIdentifier()); + + //set Binding PublicKey if available + Object bindingPubKey = pendingReq.getRawData(MsEidasNodeConstants.EID_BINDING_PUBLIC_KEY_NAME); + if (bindingPubKey instanceof String) { + authBlock.setBindingPublicKey((String) bindingPubKey); + + } + + String jwsPayload = mapper.writeValueAsString(authBlock); + log.debug("Building and sign authBlock with data: {}", jwsPayload); + + //sign JWS + return JoseUtils + .createSignature(keyStore, getKeyAlias(), getKeyPassword(), jwsPayload, false, + KEYSTORE_FRIENDLYNAME); + } + + + /** + * Get the Base64 encoded PublicKey that is used to sign the AuthBlock. + * + * @return Base64 encoded PublicKey + * @throws EaafKeyAccessException In case of an unknown or invalid key + */ + public String getBase64EncodedPublicKey() throws EaafKeyAccessException { + Pair keyPair = EaafKeyStoreUtils.getPrivateKeyAndCertificates( + keyStore.getFirst(), getKeyAlias(), getKeyPassword(), true, KEYSTORE_FRIENDLYNAME); + return Base64.getEncoder().encodeToString(keyPair.getSecond()[0].getPublicKey().getEncoded()); + + } + + @PostConstruct + private void initialize() throws KeyStoreException, EaafException { + log.debug("Initializing AuthBlock signing service ... "); + // read Connector wide config data TODO connector wide! + String keyStoreName = basicConfig + .getBasicConfiguration(MsEidasNodeConstants.PROP_CONFIG_AUTHBLOCK_KEYSTORE_NAME); + String keyStorePw = basicConfig + .getBasicConfiguration(MsEidasNodeConstants.PROP_CONFIG_AUTHBLOCK_KEYSTORE_PASSWORD); + String keyStorePath = basicConfig + .getBasicConfiguration(MsEidasNodeConstants.PROP_CONFIG_AUTHBLOCK_KEYSTORE_PATH); + String keyStoreType = basicConfig + .getBasicConfiguration(MsEidasNodeConstants.PROP_CONFIG_AUTHBLOCK_KEYSTORE_TYPE); + + + //build new KeyStore configuration + KeyStoreConfiguration keyStoreConfiguration = new KeyStoreConfiguration(); + keyStoreConfiguration.setFriendlyName(KEYSTORE_FRIENDLYNAME); + + keyStoreConfiguration.setSoftKeyStoreFilePath(keyStorePath); + keyStoreConfiguration.setSoftKeyStorePassword(keyStorePw); + keyStoreConfiguration.setKeyStoreType(KeyStoreConfiguration.KeyStoreType.fromString(keyStoreType)); + keyStoreConfiguration.setKeyStoreName(keyStoreName); + + //validate KeyStore configuration + keyStoreConfiguration.validate(); + + //validate key alias + if (StringUtils.isEmpty(getKeyAlias())) { + throw new EaafConfigurationException("config.08", + new Object[] {MsEidasNodeConstants.PROP_CONFIG_AUTHBLOCK_KEY_ALIAS}); + + } + + //build new KeyStore based on configuration + keyStore = keyStoreFactory.buildNewKeyStore(keyStoreConfiguration); + + //check if Key is accessible + EaafKeyStoreUtils.getPrivateKeyAndCertificates( + keyStore.getFirst(), getKeyAlias(), getKeyPassword(), true, KEYSTORE_FRIENDLYNAME); + + log.info("AuthBlock signing-service successful initialized"); + + } + + private char[] getKeyPassword() { + final String value = basicConfig.getBasicConfiguration(MsEidasNodeConstants.PROP_CONFIG_AUTHBLOCK_KEY_PASSWORD); + if (value != null) { + return value.trim().toCharArray(); + } + + return null; + + } + + + private String getKeyAlias() { + return basicConfig + .getBasicConfiguration(MsEidasNodeConstants.PROP_CONFIG_AUTHBLOCK_KEY_ALIAS); + + } + + /** + * Technical AuthBlock for eIDAS Authentication. + * + * @author tlenz + * + */ + @Data + @JsonInclude(JsonInclude.Include.NON_NULL) + private static class EidasAuchBlock { + + @JsonProperty("challenge") + private String challenge; + + @JsonProperty("timestamp") + @JsonSerialize(using = LocalDateTimeSerializer.class) + @JsonDeserialize(using = LocalDateTimeDeserializer.class) + @JsonFormat(pattern = "yyyy-MM-dd'T'HH:mm:ss.SSS'Z'", timezone = "UTC") + private LocalDateTime timestamp; + + @JsonProperty("appId") + private String uniqueId; + + @JsonProperty("piiTransactionId") + private String piiTransactionId; + + @JsonProperty("bindingPublicKey") + private String bindingPublicKey; + + } + + +} diff --git a/modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/service/CcSpecificEidProcessingService.java b/modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/service/CcSpecificEidProcessingService.java new file mode 100644 index 00000000..230d6052 --- /dev/null +++ b/modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/service/CcSpecificEidProcessingService.java @@ -0,0 +1,135 @@ +/* + * Copyright 2018 A-SIT Plus GmbH + * AT-specific eIDAS Connector has been developed in a cooperation between EGIZ, + * A-SIT Plus GmbH, A-SIT, and Graz University of Technology. + * + * Licensed under the EUPL, Version 1.2 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "License"); + * You may not use this work except in compliance with the License. + * You may obtain a copy of the License at: + * https://joinup.ec.europa.eu/news/understanding-eupl-v12 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. +*/ + +package at.asitplus.eidas.specific.modules.auth.eidas.v2.service; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; + +import javax.annotation.PostConstruct; + +import org.apache.commons.lang3.StringUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.ApplicationContext; +import org.springframework.stereotype.Service; + +import at.asitplus.eidas.specific.modules.auth.eidas.v2.Constants; +import at.asitplus.eidas.specific.modules.auth.eidas.v2.dao.ErnbEidData; +import at.asitplus.eidas.specific.modules.auth.eidas.v2.exception.EidPostProcessingException; +import at.asitplus.eidas.specific.modules.auth.eidas.v2.exception.EidasAttributeException; +import at.asitplus.eidas.specific.modules.auth.eidas.v2.handler.INationalEidProcessor; +import at.asitplus.eidas.specific.modules.auth.eidas.v2.utils.EidasResponseUtils; +import at.gv.egiz.eaaf.core.api.IRequest; +import at.gv.egiz.eaaf.core.impl.data.Triple; +import eu.eidas.auth.commons.light.impl.LightRequest.Builder; + +@Service +public class CcSpecificEidProcessingService implements ICcSpecificEidProcessingService { + private static final Logger log = LoggerFactory.getLogger(CcSpecificEidProcessingService.class); + + @Autowired + private ApplicationContext context; + + private final List handlers = new ArrayList<>(); + + @PostConstruct + private void initialize() { + log.debug("Initialize eID PostProcessing-Service ... "); + final Map postProcessors = context.getBeansOfType( + INationalEidProcessor.class); + final Iterator> iterator = postProcessors.entrySet().iterator(); + while (iterator.hasNext()) { + final Entry el = iterator.next(); + log.debug("Find eID-PostProcessor with name: " + el.getKey()); + handlers.add(el.getValue()); + + } + + log.trace("Sorting eID-PostProcessors on priority ... "); + Collections.sort(handlers, (thisAuthModule, otherAuthModule) -> { + final int thisOrder = thisAuthModule.getPriority(); + final int otherOrder = otherAuthModule.getPriority(); + return thisOrder < otherOrder ? 1 : thisOrder == otherOrder ? 0 : -1; + }); + + log.info("# " + handlers.size() + " eID PostProcessing services are registrated"); + + } + + @Override + public void preProcess(String selectedCitizenCountry, IRequest pendingReq, Builder authnRequestBuilder) + throws EidPostProcessingException { + if (StringUtils.isEmpty(selectedCitizenCountry)) { + log.info("No CountryCode for eID Pre-Processor. Default Pre-Processor will be used"); + } + + for (final INationalEidProcessor el : handlers) { + if (el.canHandle(selectedCitizenCountry)) { + log.debug("Pre-Process eIDAS request for " + selectedCitizenCountry + " by using: " + el.getName()); + el.preProcess(pendingReq, authnRequestBuilder); + return; + + } + } + + log.error("NO eID PostProcessor FOUND. Looks like a depentency problem!"); + throw new EidPostProcessingException("internal.00", null); + + } + + @Override + public ErnbEidData postProcess(Map eidasAttrMap) throws EidPostProcessingException, + EidasAttributeException { + // extract citizen country from eIDAS unique identifier + final Object eIdentifierObj = eidasAttrMap.get(Constants.eIDAS_ATTR_PERSONALIDENTIFIER); + if (eIdentifierObj == null || !(eIdentifierObj instanceof String)) { + throw new EidasAttributeException(Constants.eIDAS_ATTR_PERSONALIDENTIFIER); + } + + final Triple eIdentifier = + EidasResponseUtils.parseEidasPersonalIdentifier((String) eIdentifierObj); + final String citizenCountry = eIdentifier.getFirst(); + + if (StringUtils.isEmpty(citizenCountry)) { + log.info("No CountryCode for eID PostProcessor. Default-PostProcessor will be used"); + } + + for (final INationalEidProcessor el : handlers) { + if (el.canHandle(citizenCountry)) { + log.debug("Post-Process eIDAS eID from " + citizenCountry + " by using: " + el.getName()); + return el.postProcess(eidasAttrMap); + + } + } + + log.error("NO eID PostProcessor FOUND. Looks like a depentency problem!"); + throw new EidPostProcessingException("internal.00", null); + } + +} diff --git a/modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/service/EidasAttributeRegistry.java b/modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/service/EidasAttributeRegistry.java new file mode 100644 index 00000000..e73491ab --- /dev/null +++ b/modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/service/EidasAttributeRegistry.java @@ -0,0 +1,180 @@ +/* + * Copyright 2018 A-SIT Plus GmbH + * AT-specific eIDAS Connector has been developed in a cooperation between EGIZ, + * A-SIT Plus GmbH, A-SIT, and Graz University of Technology. + * + * Licensed under the EUPL, Version 1.2 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "License"); + * You may not use this work except in compliance with the License. + * You may obtain a copy of the License at: + * https://joinup.ec.europa.eu/news/understanding-eupl-v12 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. +*/ + +package at.asitplus.eidas.specific.modules.auth.eidas.v2.service; + +import java.io.File; +import java.text.MessageFormat; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import javax.annotation.PostConstruct; + +import org.apache.commons.lang3.StringUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.lang.NonNull; +import org.springframework.stereotype.Service; + +import at.asitplus.eidas.specific.modules.auth.eidas.v2.Constants; +import at.gv.egiz.eaaf.core.api.idp.IConfigurationWithSP; +import at.gv.egiz.eaaf.core.exceptions.EaafConfigurationException; +import at.gv.egiz.eaaf.core.impl.utils.KeyValueUtils; +import eu.eidas.auth.commons.attribute.AttributeRegistries; +import eu.eidas.auth.commons.attribute.AttributeRegistry; + +@Service("attributeRegistry") +public class EidasAttributeRegistry { + private static final Logger log = LoggerFactory.getLogger(EidasAttributeRegistry.class); + @Autowired + private IConfigurationWithSP basicConfig; + + private AttributeRegistry coreAttributeRegistry; + + private String eidasAttributesFile; + private String additionalAttributesFile; + + @PostConstruct + private void initialize() throws RuntimeException { + try { + if (eidasAttributesFile.isEmpty()) { + log.error("Basic eIDAS addribute definition NOT defined"); + throw new EaafConfigurationException("config.30", + new Object[] { "eidas-attributes.xml" }); + + } + + boolean additionalAttrAvailabe = false; + if (!additionalAttributesFile.isEmpty()) { + final File file = new File(additionalAttributesFile); + if (file.exists()) { + additionalAttrAvailabe = true; + } + + } + + if (!additionalAttrAvailabe) { + log.info("Start eIDAS ref. impl. Core without additional eIDAS attribute definitions ... "); + coreAttributeRegistry = AttributeRegistries.fromFiles(eidasAttributesFile, null); + + } else { + // load attribute definitions + log.info("Start eIDAS ref. impl. Core with additional eIDAS attribute definitions ... "); + coreAttributeRegistry = AttributeRegistries.fromFiles(eidasAttributesFile, null, + additionalAttributesFile); + + } + + } catch (final Throwable e) { + log.error("Can NOT initialize eIDAS attribute definition.", e); + throw new RuntimeException("Can NOT initialize eIDAS attribute definition.", e); + + } + } + + public AttributeRegistry getCoreAttributeRegistry() { + return coreAttributeRegistry; + } + + /** + * Get Map of attributes that are requested by default. + * + * @return Map of AttributeIdentifier, isRequired flag + */ + @NonNull + public Map getDefaultAttributeSetFromConfiguration() { + /* + * TODO: select set for representation if mandates should be used. It's an open + * task in respect to requested eIDAS attributes and isRequired flag, because + * there can be a decision problem in case of natural or legal person + * representation! From an Austrian use-case point of view, an Austrian service + * provider can support mandates for natural and legal persons at the same time. + * However, we CAN NOT request attributes for natural AND legal persons on the + * same time, because it's not possible to represent both simultaneously. + */ + final Map configAttributes = + basicConfig.getBasicConfigurationWithPrefix( + Constants.CONIG_PROPS_EIDAS_NODE_ATTRIBUTES_REQUESTED_DEFAULT_ONLYNATURAL); + return processAttributeInfosFromConfig(configAttributes); + + } + + /** + * Get a Map of attributes that are additionally requested for a specific country. + * + * @param countryCode Country Code + * @return Map of AttributeIdentifier, isRequired flag + */ + @NonNull + public Map getAttributeSetFromConfiguration(String countryCode) { + + /* + * TODO: select set for representation if mandates should be used. It's an open + * task in respect to requested eIDAS attributes and isRequired flag, because + * there can be a decision problem in case of natural or legal person + * representation! From an Austrian use-case point of view, an Austrian service + * provider can support mandates for natural and legal persons at the same time. + * However, we CAN NOT request attributes for natural AND legal persons on the + * same time, because it's not possible to represent both simultaneously. + */ + final Map configAttributes = + basicConfig.getBasicConfigurationWithPrefix( + MessageFormat.format( + Constants.CONIG_PROPS_EIDAS_NODE_ATTRIBUTES_REQUESTED_CC_SPECIFIC_ONLYNATURAL, + countryCode.toLowerCase())); + return processAttributeInfosFromConfig(configAttributes); + + } + + private Map processAttributeInfosFromConfig(Map configAttributes) { + + final Map result = new HashMap<>(); + for (final String el : configAttributes.values()) { + if (StringUtils.isNotEmpty(el.trim())) { + final List attrDef = KeyValueUtils.getListOfCsvValues(el.trim()); + boolean isRequired = false; + if (attrDef.size() == 2) { + isRequired = Boolean.parseBoolean(attrDef.get(1)); + } + + result.put(attrDef.get(0), isRequired); + + } + } + + log.trace("Load #" + result.size() + " requested attributes from configuration"); + return result; + + } + + public void setEidasAttributesFile(String eidasAttributesFile) { + this.eidasAttributesFile = eidasAttributesFile; + } + + public void setAdditionalAttributesFile(String additionalAttributesFile) { + this.additionalAttributesFile = additionalAttributesFile; + } + +} diff --git a/modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/service/EidasDataStore.java b/modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/service/EidasDataStore.java new file mode 100644 index 00000000..549aa65c --- /dev/null +++ b/modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/service/EidasDataStore.java @@ -0,0 +1,363 @@ +/* + * Copyright 2018 A-SIT Plus GmbH AT-specific eIDAS Connector has been developed + * in a cooperation between EGIZ, A-SIT Plus GmbH, A-SIT, and Graz University of + * Technology. + * + * Licensed under the EUPL, Version 1.2 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "License"); + * You may not use this work except in compliance with the License. You may + * obtain a copy of the License at: + * https://joinup.ec.europa.eu/news/understanding-eupl-v12 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" basis, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. The "NOTICE" text file + * is part of the distribution. Any derivative works that you distribute must + * include a readable copy of the "NOTICE" text file. + */ + +package at.asitplus.eidas.specific.modules.auth.eidas.v2.service; + +//import java.io.File; +//import java.io.IOException; +//import java.sql.Connection; +//import java.sql.DriverManager; +//import java.sql.PreparedStatement; +//import java.sql.ResultSet; +//import java.sql.SQLException; +//import java.sql.Statement; +//import java.time.Instant; +//import java.util.Properties; +// +//import javax.annotation.PostConstruct; +// +//import org.slf4j.Logger; +//import org.slf4j.LoggerFactory; +//import org.springframework.beans.factory.annotation.Autowired; +//import org.springframework.stereotype.Component; +//import org.sqlite.SQLiteConfig; +//import org.sqlite.SQLiteConfig.LockingMode; +//import org.sqlite.SQLiteConfig.SynchronousMode; +//import org.sqlite.SQLiteErrorCode; +// +//import at.asitplus.eidas.specific.modules.auth.eidas.v2.Constants; +//import at.asitplus.eidas.specific.modules.auth.eidas.v2.DAO.eIDASPersonalIdStoreDAO; +//import at.asitplus.eidas.specific.modules.auth.eidas.v2.exception.SQLiteServiceException; +//import at.gv.egiz.eaaf.core.api.idp.IConfiguration; +//import at.gv.egiz.eaaf.core.impl.data.Pair; +//import at.gv.egiz.eaaf.core.impl.data.Trible; +// +//@Component +//@Deprecated +//public class EidasDataStore { +// +// private static final String SQLITE_JDBC_DRIVER_CLASS = "org.sqlite.JDBC"; +// private static final String SQLITE_CONNECTION_PARAM = "jdbc:sqlite:%s"; +// private static final boolean sleep = true; +// private static final int howLongToSleepOnBusyLock_ = 100; +// +// private static final Logger log = LoggerFactory.getLogger(EidasDataStore.class); +// +// @Autowired +// private IConfiguration basicConfig; +// +// private String connectionUrl; +// private Connection conn = null; +// +// @PostConstruct +// private void initialize() throws SQLiteServiceException { +// try { +// final String sqlLiteDbUrl = basicConfig.getBasicConfiguration( +// Constants.CONIG_PROPS_EIDAS_SZRCLIENT_WORKAROUND_SQLLITEDATASTORE_URL, +// basicConfig.getConfigurationRootDirectory().toString() + "/sqlite/database.db" +// +// ); +// +// log.info("Use SQLite database with URL: " + sqlLiteDbUrl); +// +// // check if SQLite lib is in Classpath +// Class.forName(SQLITE_JDBC_DRIVER_CLASS); +// +// // open DB connection +// boolean isNewFileCreated = false; +// +// // open file or create file if not already exists +// final File dbFile = new File(sqlLiteDbUrl); +// if (!dbFile.exists()) { +// log.info("SQLite database does not exist. Creating new database file ... "); +// dbFile.createNewFile(); +// isNewFileCreated = true; +// +// } +// +// // open database connection +// connectionUrl = String.format(SQLITE_CONNECTION_PARAM, dbFile.getPath()); +// +// // create DB scheme if new DB file was created +// if (isNewFileCreated) { +// executeUpdate(startConnection().createStatement(), eIDASPersonalIdStoreDAO.CREATE); +// log.debug("SQLite db scheme created"); +// +// } +// +// } catch (final ClassNotFoundException e) { +// log.warn("Can NOT initialize SQLite database for temporarly identity mapping. ", e); +// throw new SQLiteServiceException("internal.05", new Object[] { e.getMessage() }, e); +// +// } catch (SQLException | IOException e) { +// log.warn("Can NOT initialize SQLite database for temporarly identity mapping. ", e); +// throw new SQLiteServiceException("internal.05", new Object[] { e.getMessage() }, e); +// +// } +// +// } +// +// /** +// * Store a mapping entry with eIDAS personal identifier (source country / +// * destination country / personal identifier) and the identifier that is used +// * for ERnB communication. +// * +// * @param transactionId Id of this authentication transaction +// * @param eidasId eIDAS personal identifier without country prefixes +// * @param ernbId personal identifier that is used to request the ERnB +// * @throws SQLiteServiceException In case of a database error +// */ +// public void storeNationalId(String transactionId, Trible eidasId, String ernbId) +// throws SQLiteServiceException { +// try { +// final PreparedStatement preStatment = startConnection().prepareStatement( +// eIDASPersonalIdStoreDAO.INSERT, +// Statement.RETURN_GENERATED_KEYS); +// +// for (int i = 1; i <= eIDASPersonalIdStoreDAO.TABLE_COLS.size(); i++) { +// final Pair col = eIDASPersonalIdStoreDAO.TABLE_COLS.get(i - 1); +// if (col.getFirst().equals(eIDASPersonalIdStoreDAO.COLS.timestamp.name())) { +// preStatment.setDate(i, new java.sql.Date(Instant.now().toEpochMilli())); +// } else if (col.getFirst().equals(eIDASPersonalIdStoreDAO.COLS.transactionId.name())) { +// preStatment.setString(i, transactionId); +// } else if (col.getFirst().equals(eIDASPersonalIdStoreDAO.COLS.eidasId.name())) { +// preStatment.setString(i, eidasId.getThird()); +// } else if (col.getFirst().equals(eIDASPersonalIdStoreDAO.COLS.eidasSourceCountry.name())) { +// preStatment.setString(i, eidasId.getFirst()); +// } else if (col.getFirst().equals(eIDASPersonalIdStoreDAO.COLS.eidasDestinationCountry.name())) { +// preStatment.setString(i, eidasId.getSecond()); +// } else if (col.getFirst().equals(eIDASPersonalIdStoreDAO.COLS.ernbId.name())) { +// preStatment.setString(i, ernbId); +// } else { +// log.warn("SQLite table:" + eIDASPersonalIdStoreDAO.NAME + " contains no col with name:" + col +// .getFirst()); +// } +// +// } +// +// // execute SQL query +// final int sqlResult = preStatment.executeUpdate(); +// +// if (sqlResult != 1) { +// log.warn("SQLite query execution FAILED!"); +// throw new SQLiteServiceException("internal.06", new Object[] { "Queryresult is '-1'" }); +// +// } +// +// } catch (SQLiteServiceException | SQLException e) { +// log.warn("SQLite query execution FAILED!", e); +// throw new SQLiteServiceException("internal.05", new Object[] { e.getMessage() }, e); +// +// } +// +// } +// +// /** +// * Get the ERnB related national identifier from mapping database. +// * +// * @param eidasId eIDAS related identifier +// * @return Mapped ERnB identifier +// * @throws SQLiteServiceException In case of a database error +// */ +// public String getErnbNationalId(Trible eidasId) throws SQLiteServiceException { +// try { +// final PreparedStatement preStatment = startConnection().prepareStatement( +// eIDASPersonalIdStoreDAO.SELECT_BY_EIDAS_RAW_ID, +// Statement.RETURN_GENERATED_KEYS); +// +// preStatment.setString(1, eidasId.getThird()); +// preStatment.setString(2, eidasId.getFirst()); +// +// final ResultSet rs = preStatment.executeQuery(); +// +// if (!rs.next()) { +// return null; +// } else { +// return rs.getString(eIDASPersonalIdStoreDAO.COLS.ernbId.name()); +// } +// +// } catch (SQLiteServiceException | SQLException e) { +// log.warn("SQLite query execution FAILED!", e); +// throw new SQLiteServiceException("internal.05", new Object[] { e.getMessage() }, e); +// +// } +// +// } +// +// /** +// * Get the eIDAS identifier from an ERnB identifier. +// * +// * @param ernbId ERnB specific identifier +// * @return eIDAS unqiue identifier +// * @throws SQLiteServiceException In case of a database error +// */ +// public String getEidasRawNationalId(String ernbId) throws SQLiteServiceException { +// try { +// final PreparedStatement preStatment = startConnection().prepareStatement( +// eIDASPersonalIdStoreDAO.SELECT_BY_ERNB_ID, +// Statement.RETURN_GENERATED_KEYS); +// +// preStatment.setString(1, ernbId); +// +// final ResultSet rs = preStatment.executeQuery(); +// +// if (!rs.next()) { +// return null; +// } else { +// return rs.getString(eIDASPersonalIdStoreDAO.COLS.eidasId.name()); +// } +// +// } catch (SQLiteServiceException | SQLException e) { +// log.warn("SQLite query execution FAILED!", e); +// throw new SQLiteServiceException("internal.05", new Object[] { e.getMessage() }, e); +// +// } +// +// } +// +// private Connection startConnection() throws SQLiteServiceException { +// int i = howLongToSleepOnBusyLock_; +// +// while (true) { +// try { +// if (conn == null) { +// log.info("Initializing SQLite database with URL: " + connectionUrl + " ... "); +// conn = DriverManager.getConnection(connectionUrl, getConnectionProperties()); +// +// } else { +// if (!conn.isValid(10)) { +// log.info("SQLite connection is not valid any more --> restarting connection ..."); +// conn.close(); +// conn = DriverManager.getConnection(connectionUrl, getConnectionProperties()); +// } +// } +// +// log.info("SQLite database connected"); +// return conn; +// +// } catch (final SQLException e) { +// final String msg = e.getLocalizedMessage(); +// if (isBusyLocked(e)) { +// log.warn(msg, e); +// try { +// if (sleep) { +// Thread.sleep(i++); +// } +// +// } catch (final InterruptedException e1) { +// throw new SQLiteServiceException("internal.05", new Object[] { e1.getMessage() }, e1); +// +// } +// continue; +// +// } +// throw new SQLiteServiceException("internal.05", new Object[] { e.getMessage() }, e); +// +// } +// } +// } +// +// /* +// * SQLite query code +// */ +// +// protected Properties getConnectionProperties() { +// final SQLiteConfig config = new SQLiteConfig(); +// config.enforceForeignKeys(true); +// config.setCacheSize(8000); +// config.setLockingMode(LockingMode.NORMAL); +// config.setSharedCache(false); +// config.setReadUncommited(true); +// config.setSynchronous(SynchronousMode.NORMAL); +// return config.toProperties(); +// +// } +// +// private int executeUpdate(Statement statement, String sql) throws SQLiteServiceException { +// final int i = 10; +// +// int rc = -1; +// while (true) { +// try { +// rc = statement.executeUpdate(sql); +// break; +// +// } catch (final SQLException e) { +// try { +// if (executeUpdateError(e, i)) { +// continue; +// } else { +// throw new SQLiteServiceException("internal.06", +// new Object[] { e.getMessage() }, e); +// } +// +// } catch (final SQLiteServiceException e1) { +// log.warn("\n" + sql + "\n" + e1.getMessage()); +// throw e1; +// +// } +// } +// } +// +// return rc; +// +// } +// +// private boolean isBusyLocked(SQLException e) { +// final int eC = e.getErrorCode(); +// +// if (eC == SQLiteErrorCode.SQLITE_LOCKED.code +// || eC == SQLiteErrorCode.SQLITE_BUSY.code) { +// log.trace("SQLite db is busy looked"); +// return true; +// +// } +// +// final String msg = e.getMessage(); +// if (msg.contains("[SQLITE_LOCKED]") || msg.contains("[SQLITE_BUSY]")) { +// log.trace("SQLite db is busy looked"); +// return true; +// } +// +// return false; +// } +// +// private boolean executeUpdateError(SQLException e, int theadSleepCounter) throws SQLiteServiceException { +// if (isBusyLocked(e)) { +// try { +// if (sleep) { +// Thread.sleep(theadSleepCounter++); +// } +// +// } catch (final InterruptedException e1) { +// throw new SQLiteServiceException("internal.05", new Object[] { e1.getMessage() }, e1); +// +// } +// +// return true; +// } +// +// return false; +// +// } +//} diff --git a/modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/service/ICcSpecificEidProcessingService.java b/modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/service/ICcSpecificEidProcessingService.java new file mode 100644 index 00000000..ebbc15e4 --- /dev/null +++ b/modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/service/ICcSpecificEidProcessingService.java @@ -0,0 +1,61 @@ +/* + * Copyright 2018 A-SIT Plus GmbH + * AT-specific eIDAS Connector has been developed in a cooperation between EGIZ, + * A-SIT Plus GmbH, A-SIT, and Graz University of Technology. + * + * Licensed under the EUPL, Version 1.2 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "License"); + * You may not use this work except in compliance with the License. + * You may obtain a copy of the License at: + * https://joinup.ec.europa.eu/news/understanding-eupl-v12 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + */ + +package at.asitplus.eidas.specific.modules.auth.eidas.v2.service; + +import java.util.Map; + +import at.asitplus.eidas.specific.modules.auth.eidas.v2.dao.ErnbEidData; +import at.asitplus.eidas.specific.modules.auth.eidas.v2.exception.EidasAttributeException; +import at.asitplus.eidas.specific.modules.auth.eidas.v2.exception.EidPostProcessingException; +import at.gv.egiz.eaaf.core.api.IRequest; +import eu.eidas.auth.commons.light.ILightRequest; +import eu.eidas.auth.commons.light.impl.LightRequest.Builder; + +public interface ICcSpecificEidProcessingService { + + /** + * Post-process eIDAS eID attributes into national format. + * + * @param eidasAttrMap Map of eIDAS attributes in format friendlyName and + * attribute + * + * @return eID attributes for SZR request + * @throws EidPostProcessingException In case of a post-processing error + * @throws EidasAttributeException In case of an invalid eIDAS attribute value + */ + ErnbEidData postProcess(Map eidasAttrMap) throws EidPostProcessingException, + EidasAttributeException; + + /** + * Pre Process eIDAS request into national requirements. + * + * @param selectedCC Citizen Country from selection + * @param pendingReq current pending request + * @param authnRequestBuilder eIDAS {@link ILightRequest} builder + * @throws EidPostProcessingException In case of a pre-processing error + */ + void preProcess(String selectedCC, IRequest pendingReq, Builder authnRequestBuilder) + throws EidPostProcessingException; + +} diff --git a/modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/szr/SzrClient.java b/modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/szr/SzrClient.java new file mode 100644 index 00000000..1f5837d6 --- /dev/null +++ b/modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/szr/SzrClient.java @@ -0,0 +1,522 @@ +/* + * Copyright 2018 A-SIT Plus GmbH + * AT-specific eIDAS Connector has been developed in a cooperation between EGIZ, + * A-SIT Plus GmbH, A-SIT, and Graz University of Technology. + * + * Licensed under the EUPL, Version 1.2 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "License"); + * You may not use this work except in compliance with the License. + * You may obtain a copy of the License at: + * https://joinup.ec.europa.eu/news/understanding-eupl-v12 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + */ + +package at.asitplus.eidas.specific.modules.auth.eidas.v2.szr; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.net.URL; +import java.security.KeyManagementException; +import java.security.KeyStore; +import java.security.KeyStoreException; +import java.security.NoSuchAlgorithmException; +import java.security.SecureRandom; +import java.security.UnrecoverableKeyException; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import javax.annotation.PostConstruct; +import javax.net.ssl.KeyManager; +import javax.net.ssl.KeyManagerFactory; +import javax.net.ssl.SSLContext; +import javax.net.ssl.TrustManager; +import javax.net.ssl.TrustManagerFactory; +import javax.xml.XMLConstants; +import javax.xml.bind.JAXBContext; +import javax.xml.bind.Marshaller; +import javax.xml.namespace.QName; +import javax.xml.transform.Source; +import javax.xml.transform.Transformer; +import javax.xml.transform.TransformerException; +import javax.xml.transform.TransformerFactory; +import javax.xml.transform.stream.StreamResult; +import javax.xml.transform.stream.StreamSource; +import javax.xml.ws.BindingProvider; +import javax.xml.ws.Dispatch; +import javax.xml.ws.handler.Handler; + +import org.apache.commons.lang3.StringUtils; +import org.apache.cxf.configuration.jsse.TLSClientParameters; +import org.apache.cxf.endpoint.Client; +import org.apache.cxf.frontend.ClientProxy; +import org.apache.cxf.jaxws.DispatchImpl; +import org.apache.cxf.transport.http.HTTPConduit; +import org.apache.cxf.transports.http.configuration.HTTPClientPolicy; +import org.apache.xpath.XPathAPI; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.w3c.dom.Document; +import org.w3c.dom.Element; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; + +import at.asitplus.eidas.specific.modules.auth.eidas.v2.Constants; +import at.asitplus.eidas.specific.modules.auth.eidas.v2.dao.ErnbEidData; +import at.asitplus.eidas.specific.modules.auth.eidas.v2.exception.SzrCommunicationException; +import at.asitplus.eidas.specific.modules.auth.eidas.v2.utils.LoggingHandler; +import at.gv.egiz.eaaf.core.api.data.PvpAttributeDefinitions; +import at.gv.egiz.eaaf.core.api.data.XmlNamespaceConstants; +import at.gv.egiz.eaaf.core.api.idp.IConfiguration; +import at.gv.egiz.eaaf.core.impl.utils.DomUtils; +import at.gv.egiz.eaaf.core.impl.utils.FileUtils; +import at.gv.egiz.eaaf.core.impl.utils.KeyStoreUtils; +import szrservices.GetBPK; +import szrservices.GetBPKResponse; +import szrservices.GetIdentityLinkEidas; +import szrservices.GetIdentityLinkEidasResponse; +import szrservices.IdentityLinkType; +import szrservices.JwsHeaderParam; +import szrservices.ObjectFactory; +import szrservices.PersonInfoType; +import szrservices.SZR; +import szrservices.SZRException_Exception; +import szrservices.SignContent; +import szrservices.SignContentEntry; +import szrservices.SignContentResponseType; + + +@Service("SZRClientForeIDAS") +public class SzrClient { + private static final Logger log = LoggerFactory.getLogger(SzrClient.class); + + private static final String CLIENT_DEFAULT = "DefaultClient"; + private static final String CLIENT_RAW = "RawClient"; + + private static final String ATTR_NAME_VSZ = "urn:eidgvat:attributes.vsz.value"; + private static final String ATTR_NAME_PUBKEYS = "urn:eidgvat:attributes.user.pubkeys"; + private static final String ATTR_NAME_STATUS = "urn:eidgvat:attributes.eid.status"; + private static final String KEY_BC_BIND = "bcBindReq"; + private static final String JOSE_HEADER_USERCERTPINNING_TYPE = "urn:at.gv.eid:bindtype"; + private static final String JOSE_HEADER_USERCERTPINNING_EIDASBIND = "urn:at.gv.eid:eidasBind"; + public static final String ATTR_NAME_MDS = "urn:eidgvat:mds"; + + @Autowired + private IConfiguration basicConfig; + + // client for anything, without identitylink + private SZR szr = null; + + // RAW client is needed for identitylink + private Dispatch dispatch = null; + + private SzrService szrService = null; + private String szrUrl = null; + private QName qname = null; + + final ObjectMapper mapper = new ObjectMapper(); + + /** + * Get IdentityLink of a person. + * + * @param personInfo Person identification information + * @return IdentityLink + * @throws SzrCommunicationException In case of a SZR error + */ + public IdentityLinkType getIdentityLinkInRawMode(PersonInfoType personInfo) + throws SzrCommunicationException { + try { + final GetIdentityLinkEidas getIdl = new GetIdentityLinkEidas(); + getIdl.setPersonInfo(personInfo); + + final JAXBContext jaxbContext = JAXBContext.newInstance(ObjectFactory.class); + final Marshaller jaxbMarshaller = jaxbContext.createMarshaller(); + + final ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); + jaxbMarshaller.marshal(getIdl, outputStream); + outputStream.flush(); + + final Source source = new StreamSource(new ByteArrayInputStream(outputStream.toByteArray())); + outputStream.close(); + + log.trace("Requesting SZR ... "); + final Source response = dispatch.invoke(source); + log.trace("Receive RAW response from SZR"); + + final byte[] szrResponse = sourceToByteArray(response); + final GetIdentityLinkEidasResponse jaxbElement = (GetIdentityLinkEidasResponse) jaxbContext + .createUnmarshaller().unmarshal(new ByteArrayInputStream(szrResponse)); + + // build response + log.trace(new String(szrResponse, "UTF-8")); + + // ok, we have success + final Document doc = DomUtils.parseDocument( + new ByteArrayInputStream(szrResponse), + true, + XmlNamespaceConstants.ALL_SCHEMA_LOCATIONS + " " + Constants.SZR_SCHEMA_LOCATIONS, + null, null); + final String xpathExpression = "//saml:Assertion"; + final Element nsNode = doc.createElementNS("urn:oasis:names:tc:SAML:1.0:assertion", "saml:NSNode"); + + log.trace("Selecting signed doc " + xpathExpression); + final Element documentNode = (Element) XPathAPI.selectSingleNode(doc, + xpathExpression, nsNode); + log.trace("Signed document: " + DomUtils.serializeNode(documentNode)); + + final IdentityLinkType idl = new IdentityLinkType(); + idl.setAssertion(documentNode); + idl.setPersonInfo(jaxbElement.getGetIdentityLinkReturn().getPersonInfo()); + + return idl; + + } catch (final Exception e) { + log.warn("SZR communication FAILED. Reason: " + e.getMessage(), e); + throw new SzrCommunicationException("ernb.02", new Object[]{e.getMessage()}, e); + + } + + } + + /** + * Get bPK of person. + * + * @param personInfo Person identification information + * @param target requested bPK target + * @param vkz Verfahrenskennzeichen + * @return bPK for this person + * @throws SzrCommunicationException In case of a SZR error + */ + public List getBpk(PersonInfoType personInfo, String target, String vkz) + throws SzrCommunicationException { + try { + final GetBPK parameters = new GetBPK(); + parameters.setPersonInfo(personInfo); + parameters.getBereichsKennung().add(target); + parameters.setVKZ(vkz); + final GetBPKResponse result = this.szr.getBPK(parameters); + + return result.getGetBPKReturn(); + + } catch (final SZRException_Exception e) { + log.warn("SZR communication FAILED. Reason: " + e.getMessage(), e); + throw new SzrCommunicationException("ernb.02", new Object[]{e.getMessage()}, e); + + } + + } + + /** + * Request a encryped baseId from SRZ. + * + * @param personInfo Minimum dataset of person + * @return encrypted baseId + * @throws SzrCommunicationException In case of a SZR error + */ + public String getEncryptedStammzahl(final PersonInfoType personInfo) + throws SzrCommunicationException { + + final String resp; + try { + resp = this.szr.getStammzahlEncrypted(personInfo, true); + } catch (SZRException_Exception e) { + throw new SzrCommunicationException("ernb.02", new Object[]{e.getMessage()}, e); + } + + if (StringUtils.isEmpty(resp)) { + throw new SzrCommunicationException("ernb.01", new Object[]{"Stammzahl response empty"}); // TODO error handling + } + + return resp; + + } + + /** + * Sign an eidasBind data-structure that combines vsz with user's pubKey and E-ID status. + * + * @param vsz encryped baseId + * @param bindingPubKey binding PublikKey as PKCS1# (ASN.1) container + * @param eidStatus Status of the E-ID + * @param eidData eID information that was used for ERnP registration + * @return bPK for this person + * @throws SzrCommunicationException In case of a SZR error + */ + public String getEidsaBind(final String vsz, final String bindingPubKey, final String eidStatus, + ErnbEidData eidData)throws SzrCommunicationException { + + final Map eidsaBindMap = new HashMap<>(); + eidsaBindMap.put(ATTR_NAME_VSZ, vsz); + eidsaBindMap.put(ATTR_NAME_STATUS, eidStatus); + eidsaBindMap.put(ATTR_NAME_PUBKEYS, Arrays.asList(bindingPubKey)); + eidsaBindMap.put(PvpAttributeDefinitions.EID_ISSUING_NATION_NAME, eidData.getCitizenCountryCode()); + injectMdsIfAvailableAndActive(eidsaBindMap, eidData); + + try { + final String serializedEidasBind = mapper.writeValueAsString(eidsaBindMap); + final SignContent req = new SignContent(); + final SignContentEntry eidasBindInfo = new SignContentEntry(); + eidasBindInfo.setKey(KEY_BC_BIND); + eidasBindInfo.setValue(serializedEidasBind); + req.getIn().add(eidasBindInfo); + req.setAppendCert(false); + final JwsHeaderParam eidasBindJoseHeader = new JwsHeaderParam(); + eidasBindJoseHeader.setKey(JOSE_HEADER_USERCERTPINNING_TYPE); + eidasBindJoseHeader.setValue(JOSE_HEADER_USERCERTPINNING_EIDASBIND); + req.getJWSHeaderParam().add(eidasBindJoseHeader); + + log.trace("Requesting SZR to sign bcBind datastructure ... "); + final SignContentResponseType resp = szr.signContent(req.isAppendCert(), req.getJWSHeaderParam(), req.getIn()); + log.trace("Receive SZR response on bcBind siging operation "); + + if (resp == null || resp.getOut() == null + || resp.getOut().isEmpty() + || StringUtils.isEmpty(resp.getOut().get(0).getValue())) { + throw new SzrCommunicationException("ernb.01", new Object[]{"BcBind response empty"}); + } + + return resp.getOut().get(0).getValue(); + + } catch (final JsonProcessingException | SZRException_Exception e) { + log.warn("Requesting bcBind by using SZR FAILED. Reason: {}", e.getMessage(), null, e); + throw new SzrCommunicationException("ernb.02", + new Object[]{e.getMessage()}, e); + } + } + + @PostConstruct + private void initialize() { + log.info("Starting SZR-Client initialization .... "); + final URL url = SzrClient.class.getResource("/szr_client/SZR_v4.0.wsdl"); + + final boolean useTestSzr = basicConfig.getBasicConfigurationBoolean( + Constants.CONIG_PROPS_EIDAS_SZRCLIENT_USETESTSERVICE, + true); + + if (useTestSzr) { + log.debug("Initializing SZR test environment configuration."); + qname = SzrService.SZRTestumgebung; + szrService = new SzrService(url, new QName("urn:SZRServices", "SZRService")); + szr = szrService.getSzrTestumgebung(); + szrUrl = basicConfig.getBasicConfiguration(Constants.CONIG_PROPS_EIDAS_SZRCLIENT_ENDPOINT_TEST); + + } else { + log.debug("Initializing SZR productive configuration."); + qname = SzrService.SZRProduktionsumgebung; + szrService = new SzrService(url, new QName("urn:SZRServices", "SZRService")); + szr = szrService.getSzrProduktionsumgebung(); + szrUrl = basicConfig.getBasicConfiguration(Constants.CONIG_PROPS_EIDAS_SZRCLIENT_ENDPOINT_PROD); + + } + + // create raw client; + dispatch = szrService.createDispatch(qname, Source.class, javax.xml.ws.Service.Mode.PAYLOAD); + + if (StringUtils.isEmpty(szrUrl)) { + log.error("No SZR service-URL found. SZR-Client initalisiation failed."); + throw new RuntimeException("No SZR service URL found. SZR-Client initalisiation failed."); + + } + + // check if Clients can be initialized + if (szr == null) { + log.error("SZR " + CLIENT_DEFAULT + " is 'NULL'. Something goes wrong"); + throw new RuntimeException("SZR " + CLIENT_DEFAULT + " is 'NULL'. Something goes wrong"); + + } + if (dispatch == null) { + log.error("SZR " + CLIENT_RAW + " is 'NULL'. Something goes wrong"); + throw new RuntimeException("SZR " + CLIENT_RAW + " is 'NULL'. Something goes wrong"); + + } + + // inject handler + log.info("Use SZR service-URL: " + szrUrl); + injectBindingProvider((BindingProvider) szr, CLIENT_DEFAULT); + injectBindingProvider(dispatch, CLIENT_RAW); + + // inject http parameters and SSL context + log.debug("Inject HTTP client settings ... "); + injectHttpClient(szr, CLIENT_DEFAULT); + injectHttpClient(dispatch, CLIENT_RAW); + + log.info("SZR-Client initialization successfull"); + } + + private void injectHttpClient(Object raw, String clientType) { + // extract client from implementation + Client client = null; + if (raw instanceof DispatchImpl) { + client = ((DispatchImpl) raw).getClient(); + } else if (raw instanceof Client) { + client = ClientProxy.getClient(raw); + } else { + throw new RuntimeException("SOAP Client for SZR connection is of UNSUPPORTED type: " + raw.getClass() + .getName()); + } + + // set basic connection policies + final HTTPConduit http = (HTTPConduit) client.getConduit(); + + // set timeout policy + final HTTPClientPolicy httpClientPolicy = new HTTPClientPolicy(); + httpClientPolicy.setConnectionTimeout( + Integer.parseInt(basicConfig.getBasicConfiguration( + Constants.CONIG_PROPS_EIDAS_SZRCLIENT_TIMEOUT_CONNECTION, + Constants.HTTP_CLIENT_DEFAULT_TIMEOUT_CONNECTION)) * 1000); + httpClientPolicy.setReceiveTimeout( + Integer.parseInt(basicConfig.getBasicConfiguration( + Constants.CONIG_PROPS_EIDAS_SZRCLIENT_TIMEOUT_RESPONSE, + Constants.HTTP_CLIENT_DEFAULT_TIMEOUT_RESPONSE)) * 1000); + http.setClient(httpClientPolicy); + + // inject SSL context in case of https + if (szrUrl.toLowerCase().startsWith("https")) { + log.debug("Adding SSLContext to client: " + clientType + " ... "); + final TLSClientParameters tlsParams = new TLSClientParameters(); + tlsParams.setSSLSocketFactory(createSslContext(clientType).getSocketFactory()); + http.setTlsClientParameters(tlsParams); + log.info("SSLContext initialized for client: " + clientType); + + } + + } + + private void injectBindingProvider(BindingProvider bindingProvider, String clientType) { + final Map requestContext = bindingProvider.getRequestContext(); + requestContext.put(BindingProvider.ENDPOINT_ADDRESS_PROPERTY, szrUrl); + + log.trace("Adding JAX-WS request/response trace handler to client: " + clientType); + List handlerList = bindingProvider.getBinding().getHandlerChain(); + if (handlerList == null) { + handlerList = new ArrayList<>(); + bindingProvider.getBinding().setHandlerChain(handlerList); + + } + + // add logging handler to trace messages if required + if (basicConfig.getBasicConfigurationBoolean( + Constants.CONIG_PROPS_EIDAS_SZRCLIENT_DEBUG_TRACEMESSAGES, + false)) { + final LoggingHandler loggingHandler = new LoggingHandler(); + handlerList.add(loggingHandler); + + } + bindingProvider.getBinding().setHandlerChain(handlerList); + } + + private SSLContext createSslContext(String clientType) { + try { + final SSLContext context = SSLContext.getInstance("TLS"); + + // initialize key-mangager for SSL client-authentication + KeyManager[] keyManager = null; + final String keyStorePath = basicConfig.getBasicConfiguration( + Constants.CONIG_PROPS_EIDAS_SZRCLIENT_SSL_KEYSTORE_PATH); + final String keyStorePassword = basicConfig.getBasicConfiguration( + Constants.CONIG_PROPS_EIDAS_SZRCLIENT_SSL_KEYSTORE_PASSWORD); + if (StringUtils.isNotEmpty(keyStorePath)) { + log.trace("Find keyStore path: " + keyStorePath + " Injecting SSL client certificate ... "); + try { + final KeyStore keyStore = KeyStoreUtils.loadKeyStore( + FileUtils.makeAbsoluteUrl(keyStorePath, basicConfig.getConfigurationRootDirectory()), + keyStorePassword); + + final KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509"); + kmf.init(keyStore, keyStorePassword.toCharArray()); + keyManager = kmf.getKeyManagers(); + log.debug("SSL client certificate injected to client: " + clientType); + + } catch (KeyStoreException | IOException | UnrecoverableKeyException e) { + log.error("Can NOT load SSL client certificate from path: " + keyStorePath); + throw new RuntimeException("Can NOT load SSL client certificate from path: " + keyStorePath, e); + + } + } else { + log.debug( + "No KeyStore for SSL Client Auth. found. Initializing SSLContext without authentication ... "); + + } + + // initialize SSL TrustStore + TrustManager[] trustManager = null; + final String trustStorePath = basicConfig.getBasicConfiguration( + Constants.CONIG_PROPS_EIDAS_SZRCLIENT_SSL_TRUSTSTORE_PATH); + final String trustStorePassword = basicConfig.getBasicConfiguration( + Constants.CONIG_PROPS_EIDAS_SZRCLIENT_SSL_TRUSTSTORE_PASSWORD); + if (StringUtils.isNotEmpty(trustStorePath)) { + log.trace("Find trustStore path: " + trustStorePath + " Injecting SSL TrustStore ... "); + try { + final KeyStore trustStore = KeyStoreUtils.loadKeyStore( + FileUtils.makeAbsoluteUrl(trustStorePath, basicConfig.getConfigurationRootDirectory()), + trustStorePassword); + + final TrustManagerFactory tmf = TrustManagerFactory.getInstance("SunX509"); + tmf.init(trustStore); + trustManager = tmf.getTrustManagers(); + log.debug("SSL TrustStore injected to client: " + clientType); + + } catch (KeyStoreException | IOException e) { + log.error("Can NOT open SSL TrustStore from path: " + trustStorePath); + throw new RuntimeException("Can NOT open SSL TrustStore from path: " + trustStorePath, e); + + } + + } else { + log.debug("No custom SSL TrustStore found. Initializing SSLContext with JVM default truststore ... "); + + } + + context.init(keyManager, trustManager, new SecureRandom()); + return context; + + } catch (NoSuchAlgorithmException | KeyManagementException e) { + log.error("SSLContext initialization FAILED.", e); + throw new RuntimeException("SSLContext initialization FAILED.", e); + + } + + } + + private void injectMdsIfAvailableAndActive(Map eidsaBindMap, ErnbEidData eidData) { + if (basicConfig.getBasicConfigurationBoolean( + Constants.CONIG_PROPS_EIDAS_SZRCLIENT_SET_MDS_TO_EIDASBIND, false)) { + log.info("Injecting MDS into eidasBind ... "); + final Map mds = new HashMap<>(); + mds.put(PvpAttributeDefinitions.PRINCIPAL_NAME_NAME, eidData.getFamilyName()); + mds.put(PvpAttributeDefinitions.GIVEN_NAME_NAME, eidData.getGivenName()); + mds.put(PvpAttributeDefinitions.BIRTHDATE_NAME, eidData.getFormatedDateOfBirth()); + eidsaBindMap.put(ATTR_NAME_MDS, mds); + + } + } + + private byte[] sourceToByteArray(Source result) throws TransformerException { + final TransformerFactory factory = TransformerFactory.newInstance(); + factory.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true); + final Transformer transformer = factory.newTransformer(); + transformer.setOutputProperty("omit-xml-declaration", "yes"); + transformer.setOutputProperty("method", "xml"); + final ByteArrayOutputStream out = new ByteArrayOutputStream(); + final StreamResult streamResult = new StreamResult(); + streamResult.setOutputStream(out); + transformer.transform(result, streamResult); + return out.toByteArray(); + } + +} diff --git a/modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/szr/SzrService.java b/modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/szr/SzrService.java new file mode 100644 index 00000000..dde868b1 --- /dev/null +++ b/modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/szr/SzrService.java @@ -0,0 +1,164 @@ +/* + * Copyright 2018 A-SIT Plus GmbH + * AT-specific eIDAS Connector has been developed in a cooperation between EGIZ, + * A-SIT Plus GmbH, A-SIT, and Graz University of Technology. + * + * Licensed under the EUPL, Version 1.2 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "License"); + * You may not use this work except in compliance with the License. + * You may obtain a copy of the License at: + * https://joinup.ec.europa.eu/news/understanding-eupl-v12 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. +*/ + +package at.asitplus.eidas.specific.modules.auth.eidas.v2.szr; + +import java.net.URL; + +import javax.xml.namespace.QName; +import javax.xml.ws.Service; +import javax.xml.ws.WebEndpoint; +import javax.xml.ws.WebServiceClient; +import javax.xml.ws.WebServiceFeature; + +import szrservices.SZR; + +/** + * This class was generated by Apache CXF 3.1.16 2018-07-10T09:36:01.466+02:00 + * Generated source version: 3.1.16 + * + */ +@WebServiceClient(name = "SZRService", + wsdlLocation = "./src/main/resources/szr_client/SZR-1.WSDL", + targetNamespace = "urn:SZRServices") +public class SzrService extends Service { + + public static final URL WSDL_LOCATION; + + public static final QName SERVICE = new QName("urn:SZRServices", "SZRService"); + public static final QName SZRProduktionsumgebung = new QName("urn:SZRServices", "SZRProduktionsumgebung"); + public static final QName SZRTestumgebung = new QName("urn:SZRServices", "SZRTestumgebung"); + public static final QName SZRBusinesspartnerTestumgebung = new QName("urn:SZRServices", + "SZRBusinesspartnerTestumgebung"); + + static { + URL url = SzrService.class.getResource("./src/main/resources/szr_client/SZR-1.WSDL"); + if (url == null) { + url = SzrService.class.getClassLoader().getResource("/szr_client/SZR-1.WSDL"); + } + if (url == null) { + java.util.logging.Logger.getLogger(SzrService.class.getName()) + .log(java.util.logging.Level.INFO, + "Can not initialize the default wsdl from {0}", "/szr_client/SZR-1.WSDL"); + } + WSDL_LOCATION = url; + + } + + public SzrService(URL wsdlLocation) { + super(wsdlLocation, SERVICE); + } + + public SzrService(URL wsdlLocation, QName serviceName) { + super(wsdlLocation, serviceName); + } + + public SzrService() { + super(WSDL_LOCATION, SERVICE); + } + + public SzrService(WebServiceFeature... features) { + super(WSDL_LOCATION, SERVICE, features); + } + + public SzrService(URL wsdlLocation, WebServiceFeature... features) { + super(wsdlLocation, SERVICE, features); + } + + public SzrService(URL wsdlLocation, QName serviceName, WebServiceFeature... features) { + super(wsdlLocation, serviceName, features); + } + + /** + * Get SZR Web-Service. + * + * @return returns SZR + */ + @WebEndpoint(name = "SZRProduktionsumgebung") + public SZR getSzrProduktionsumgebung() { + return super.getPort(SZRProduktionsumgebung, SZR.class); + } + + /** + * Get SZR Web-Service. + * + * @param features A list of {@link javax.xml.ws.WebServiceFeature} to configure + * on the proxy. Supported features not in the + * features parameter will have their default + * values. + * @return returns SZR + */ + @WebEndpoint(name = "SZRProduktionsumgebung") + public SZR getSzrProduktionsumgebung(WebServiceFeature... features) { + return super.getPort(SZRProduktionsumgebung, SZR.class, features); + } + + /** + *Get SZR Web-Service. + * + * @return returns SZR + */ + @WebEndpoint(name = "SZRTestumgebung") + public SZR getSzrTestumgebung() { + return super.getPort(SZRTestumgebung, SZR.class); + } + + /** + * Get SZR Web-Service. + * + * @param features A list of {@link javax.xml.ws.WebServiceFeature} to configure + * on the proxy. Supported features not in the + * features parameter will have their default + * values. + * @return returns SZR + */ + @WebEndpoint(name = "SZRTestumgebung") + public SZR getSzrTestumgebung(WebServiceFeature... features) { + return super.getPort(SZRTestumgebung, SZR.class, features); + } + + /** + * Get SZR Web-Service. + * + * @return returns SZR + */ + @WebEndpoint(name = "SZRBusinesspartnerTestumgebung") + public SZR getSzrBusinesspartnerTestumgebung() { + return super.getPort(SZRBusinesspartnerTestumgebung, SZR.class); + } + + /** + * Get SZR Web-Service. + * + * @param features A list of {@link javax.xml.ws.WebServiceFeature} to configure + * on the proxy. Supported features not in the + * features parameter will have their default + * values. + * @return returns SZR + */ + @WebEndpoint(name = "SZRBusinesspartnerTestumgebung") + public SZR getSzrBusinesspartnerTestumgebung(WebServiceFeature... features) { + return super.getPort(SZRBusinesspartnerTestumgebung, SZR.class, features); + } + +} diff --git a/modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/tasks/CreateIdentityLinkTask.java b/modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/tasks/CreateIdentityLinkTask.java new file mode 100644 index 00000000..6b1b96de --- /dev/null +++ b/modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/tasks/CreateIdentityLinkTask.java @@ -0,0 +1,503 @@ +/* + * Copyright 2018 A-SIT Plus GmbH + * AT-specific eIDAS Connector has been developed in a cooperation between EGIZ, + * A-SIT Plus GmbH, A-SIT, and Graz University of Technology. + * + * Licensed under the EUPL, Version 1.2 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "License"); + * You may not use this work except in compliance with the License. + * You may obtain a copy of the License at: + * https://joinup.ec.europa.eu/news/understanding-eupl-v12 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + */ + +package at.asitplus.eidas.specific.modules.auth.eidas.v2.tasks; + +import java.io.IOException; +import java.io.InputStream; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import javax.xml.parsers.ParserConfigurationException; + +import org.apache.commons.lang3.StringUtils; +import org.joda.time.DateTime; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; +import org.w3c.dom.Element; +import org.w3c.dom.Node; +import org.xml.sax.SAXException; + +import com.google.common.collect.ImmutableMap; +import com.google.common.collect.ImmutableSet; + +import at.asitplus.eidas.specific.core.MsConnectorEventCodes; +import at.asitplus.eidas.specific.core.MsEidasNodeConstants; +import at.asitplus.eidas.specific.modules.auth.eidas.v2.Constants; +import at.asitplus.eidas.specific.modules.auth.eidas.v2.dao.ErnbEidData; +import at.asitplus.eidas.specific.modules.auth.eidas.v2.exception.EidasAttributeException; +import at.asitplus.eidas.specific.modules.auth.eidas.v2.exception.SzrCommunicationException; +import at.asitplus.eidas.specific.modules.auth.eidas.v2.service.AuthBlockSigningService; +import at.asitplus.eidas.specific.modules.auth.eidas.v2.service.ICcSpecificEidProcessingService; +import at.asitplus.eidas.specific.modules.auth.eidas.v2.szr.SzrClient; +import at.asitplus.eidas.specific.modules.auth.eidas.v2.utils.EidasResponseUtils; +import at.gv.e_government.reference.namespace.persondata._20020228.AlternativeNameType; +import at.gv.e_government.reference.namespace.persondata._20020228.PersonNameType; +import at.gv.e_government.reference.namespace.persondata._20020228.PhysicalPersonType; +import at.gv.egiz.eaaf.core.api.data.EaafConstants; +import at.gv.egiz.eaaf.core.api.data.PvpAttributeDefinitions; +import at.gv.egiz.eaaf.core.api.idp.IConfiguration; +import at.gv.egiz.eaaf.core.api.idp.auth.data.IIdentityLink; +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.TaskExecutionException; +import at.gv.egiz.eaaf.core.impl.builder.BpkBuilder; +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.data.SimpleIdentityLinkAssertionParser; +import at.gv.egiz.eaaf.core.impl.idp.auth.modules.AbstractAuthServletTask; +import at.gv.egiz.eaaf.core.impl.utils.DomUtils; +import at.gv.egiz.eaaf.core.impl.utils.XPathUtils; +import eu.eidas.auth.commons.attribute.AttributeDefinition; +import eu.eidas.auth.commons.attribute.AttributeValue; +import eu.eidas.auth.commons.light.ILightResponse; +import eu.eidas.auth.commons.protocol.eidas.impl.PostalAddress; +import lombok.Data; +import lombok.extern.slf4j.Slf4j; +import szrservices.IdentityLinkType; +import szrservices.PersonInfoType; +import szrservices.TravelDocumentType; + +/** + * Task that creates the IdentityLink for an eIDAS authenticated person. + * + * @author tlenz + */ +@Slf4j +@Component("CreateIdentityLinkTask") +public class CreateIdentityLinkTask extends AbstractAuthServletTask { + + @Autowired + private IConfiguration basicConfig; + @Autowired + private SzrClient szrClient; + @Autowired + private ICcSpecificEidProcessingService eidPostProcessor; + + @Autowired + private AuthBlockSigningService authBlockSigner; + + private static final String EID_STATUS = "urn:eidgvat:eid.status.eidas"; + + /* + * (non-Javadoc) + * + * @see at.gv.egovernment.moa.id.process.springweb.MoaIdTask#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 { + try { + final AuthProcessDataWrapper authProcessData = pendingReq.getSessionData(AuthProcessDataWrapper.class); + final ILightResponse eidasResponse = authProcessData + .getGenericDataFromSession(Constants.DATA_FULL_EIDAS_RESPONSE, ILightResponse.class); + + final Map simpleAttrMap = convertEidasAttrToSimpleMap( + eidasResponse.getAttributes().getAttributeMap()); + + // post-process eIDAS attributes + final ErnbEidData eidData = eidPostProcessor.postProcess(simpleAttrMap); + + // write MDS into technical log and revision log + writeMdsLogInformation(eidData); + + //build IdentityLink or VSZ and eidasBind + if (basicConfig.getBasicConfigurationBoolean(Constants.CONIG_PROPS_EIDAS_SZRCLIENT_DEBUG_USEDUMMY, false)) { + SzrResultHolder idlResult = createDummyIdentityLinkForTestDeployment(eidData); + //inject personal-data into session + authProcessData.setIdentityLink(idlResult.getIdentityLink()); + + // set bPK and bPKType into auth session + authProcessData.setGenericDataToSession(PvpAttributeDefinitions.BPK_NAME, extendBpkByPrefix( + idlResult.getBpK(), pendingReq.getServiceProviderConfiguration().getAreaSpecificTargetIdentifier())); + authProcessData.setGenericDataToSession(PvpAttributeDefinitions.EID_SECTOR_FOR_IDENTIFIER_NAME, + pendingReq.getServiceProviderConfiguration() + .getAreaSpecificTargetIdentifier()); + + } else { + //build SZR request from eIDAS data + final PersonInfoType personInfo = generateSzrRequest(eidData); + + //request SZR based on IDL or E-ID mode + if (pendingReq.getServiceProviderConfiguration() + .isConfigurationValue(MsEidasNodeConstants.PROP_CONFIG_SP_NEW_EID_MODE, false)) { + + // get encrypted baseId + String vsz = szrClient.getEncryptedStammzahl(personInfo); + + //write revision-Log entry and extended infos personal-identifier mapping + revisionsLogger.logEvent(pendingReq, MsConnectorEventCodes.SZR_VSZ_RECEIVED); + writeExtendedRevisionLogEntry(simpleAttrMap, eidData); + + + // get eIDAS bind + String signedEidasBind = szrClient.getEidsaBind(vsz, + authBlockSigner.getBase64EncodedPublicKey(), + EID_STATUS, eidData); + revisionsLogger.logEvent(pendingReq, MsConnectorEventCodes.SZR_EIDASBIND_RECEIVED); + authProcessData.setGenericDataToSession(MsEidasNodeConstants.AUTH_DATA_EIDAS_BIND, signedEidasBind); + + //get signed AuthBlock + String jwsSignature = authBlockSigner.buildSignedAuthBlock(pendingReq); + revisionsLogger.logEvent(pendingReq, MsConnectorEventCodes.TECH_AUCHBLOCK_CREATED); + authProcessData.setGenericDataToSession(MsEidasNodeConstants.AUTH_DATA_SZR_AUTHBLOCK, jwsSignature); + + //inject personal-data into session + authProcessData.setEidProcess(true); + + } else { + //request SZR + SzrResultHolder idlResult = requestSzrForIdentityLink(personInfo); + + //write revision-Log entry for personal-identifier mapping + writeExtendedRevisionLogEntry(simpleAttrMap, eidData); + + //check result-data and write revision-log based on current state + checkStateAndWriteRevisionLog(idlResult); + + //inject personal-data into session + authProcessData.setIdentityLink(idlResult.getIdentityLink()); + authProcessData.setEidProcess(false); + + // set bPK and bPKType into auth session + authProcessData.setGenericDataToSession(PvpAttributeDefinitions.BPK_NAME, extendBpkByPrefix( + idlResult.getBpK(), pendingReq.getServiceProviderConfiguration().getAreaSpecificTargetIdentifier())); + authProcessData.setGenericDataToSession(PvpAttributeDefinitions.EID_SECTOR_FOR_IDENTIFIER_NAME, + pendingReq.getServiceProviderConfiguration() + .getAreaSpecificTargetIdentifier()); + + } + } + + //add generic info's into session + authProcessData.setForeigner(true); + authProcessData.setGenericDataToSession(PvpAttributeDefinitions.EID_ISSUING_NATION_NAME, EidasResponseUtils + .parseEidasPersonalIdentifier((String) simpleAttrMap.get(Constants.eIDAS_ATTR_PERSONALIDENTIFIER)) + .getFirst()); + authProcessData.setQaaLevel(eidasResponse.getLevelOfAssurance()); + + // store pending-request + requestStoreage.storePendingRequest(pendingReq); + + + } catch (final EidasAttributeException e) { + throw new TaskExecutionException(pendingReq, "Minimum required eIDAS attributeset not found.", e); + + } catch (final EaafException e) { + throw new TaskExecutionException(pendingReq, "IdentityLink generation for foreign person FAILED.", e); + + } catch (final Exception e) { + log.error("IdentityLink generation for foreign person FAILED.", e); + throw new TaskExecutionException(pendingReq, "IdentityLink generation for foreign person FAILED.", e); + + } + } + + private void writeExtendedRevisionLogEntry(Map simpleAttrMap, ErnbEidData eidData) { + // write ERnB input-data into revision-log + if (basicConfig.getBasicConfigurationBoolean( + Constants.CONIG_PROPS_EIDAS_SZRCLIENT_WORKAROUND_REVISIONLOGDATASTORE_ACTIVE, false)) { + revisionsLogger.logEvent(pendingReq, MsConnectorEventCodes.SZR_ERNB_EIDAS_RAW_ID, + (String) simpleAttrMap.get(Constants.eIDAS_ATTR_PERSONALIDENTIFIER)); + revisionsLogger.logEvent(pendingReq, MsConnectorEventCodes.SZR_ERNB_EIDAS_ERNB_ID, eidData.getPseudonym()); + + } + } + + private PersonInfoType generateSzrRequest(ErnbEidData eidData) { + log.debug("Starting connecting SZR Gateway"); + final PersonInfoType personInfo = new PersonInfoType(); + final PersonNameType personName = new PersonNameType(); + final PhysicalPersonType naturalPerson = new PhysicalPersonType(); + final TravelDocumentType eDocument = new TravelDocumentType(); + + naturalPerson.setName(personName); + personInfo.setPerson(naturalPerson); + personInfo.setTravelDocument(eDocument); + + // person information + personName.setFamilyName(eidData.getFamilyName()); + personName.setGivenName(eidData.getGivenName()); + naturalPerson.setDateOfBirth(eidData.getFormatedDateOfBirth()); + eDocument.setIssuingCountry(eidData.getCitizenCountryCode()); + eDocument.setDocumentNumber(eidData.getPseudonym()); + + // eID document information + eDocument.setDocumentType(basicConfig + .getBasicConfiguration(Constants.CONIG_PROPS_EIDAS_SZRCLIENT_PARAMS_EDOCUMENTTYPE, + Constants.SZR_CONSTANTS_DEFAULT_DOCUMENT_TYPE)); + + // set PlaceOfBirth if available + if (eidData.getPlaceOfBirth() != null) { + log.trace("Find 'PlaceOfBirth' attribute: " + eidData.getPlaceOfBirth()); + if (basicConfig + .getBasicConfigurationBoolean(Constants.CONIG_PROPS_EIDAS_SZRCLIENT_PARAMS_SETPLACEOFBIRTHIFAVAILABLE, + true)) { + naturalPerson.setPlaceOfBirth(eidData.getPlaceOfBirth()); + log.trace("Adding 'PlaceOfBirth' to ERnB request ... "); + + } + } + + // set BirthName if available + if (eidData.getBirthName() != null) { + log.trace("Find 'BirthName' attribute: " + eidData.getBirthName()); + if (basicConfig + .getBasicConfigurationBoolean(Constants.CONIG_PROPS_EIDAS_SZRCLIENT_PARAMS_SETBIRTHNAMEIFAVAILABLE, + true)) { + final AlternativeNameType alternativeName = new AlternativeNameType(); + naturalPerson.setAlternativeName(alternativeName); + alternativeName.setFamilyName(eidData.getBirthName()); + log.trace("Adding 'BirthName' to ERnB request ... "); + + } + } + + return personInfo; + + } + + private SzrResultHolder requestSzrForIdentityLink(PersonInfoType personInfo) + throws SzrCommunicationException, EaafException { + //request IdentityLink from SZR + final IdentityLinkType result = szrClient.getIdentityLinkInRawMode(personInfo); + + final Element idlFromSzr = (Element) result.getAssertion(); + IIdentityLink identityLink = new SimpleIdentityLinkAssertionParser(idlFromSzr).parseIdentityLink(); + + // get bPK from SZR + String bpk = null; + if (basicConfig + .getBasicConfigurationBoolean(Constants.CONIG_PROPS_EIDAS_SZRCLIENT_DEBUG_USESRZFORBPKGENERATION, true)) { + List bpkList = szrClient + .getBpk(personInfo, pendingReq.getServiceProviderConfiguration().getAreaSpecificTargetIdentifier(), + basicConfig + .getBasicConfiguration(Constants.CONIG_PROPS_EIDAS_SZRCLIENT_PARAMS_VKZ, "no VKZ defined")); + if (!bpkList.isEmpty()) { + bpk = bpkList.get(0); + + } + + + } else { + log.debug("Calculating bPK from baseId ... "); + new BpkBuilder(); + final Pair bpkCalc = BpkBuilder + .generateAreaSpecificPersonIdentifier(identityLink.getIdentificationValue(), + identityLink.getIdentificationType(), + pendingReq.getServiceProviderConfiguration() + .getAreaSpecificTargetIdentifier()); + bpk = bpkCalc.getFirst(); + + } + + return new SzrResultHolder(identityLink, bpk); + + } + + private void checkStateAndWriteRevisionLog(SzrResultHolder idlResult) throws SzrCommunicationException { + // write some infos into revision log + if (idlResult.getIdentityLink() == null) { + log.error("ERnB did not return an identity link."); + throw new SzrCommunicationException("ernb.00", null); + + } + revisionsLogger.logEvent(pendingReq, + MsConnectorEventCodes.SZR_IDL_RECEIVED, + idlResult.getIdentityLink().getSamlAssertion() + .getAttribute(SimpleIdentityLinkAssertionParser.ASSERTIONID)); + + if (idlResult.getBpK() == null) { + log.error("ERnB did not return a bPK for target: " + pendingReq.getServiceProviderConfiguration() + .getAreaSpecificTargetIdentifier()); + throw new SzrCommunicationException("ernb.01", null); + + } + revisionsLogger.logEvent(pendingReq, MsConnectorEventCodes.SZR_BPK_RECEIVED); + log.debug("ERnB communication was successfull"); + + } + + private String extendBpkByPrefix(String bpk, String type) { + String bpkType = null; + + if (type.startsWith(EaafConstants.URN_PREFIX_WBPK)) { + bpkType = type.substring(EaafConstants.URN_PREFIX_WBPK.length()); + } else if (type.startsWith(EaafConstants.URN_PREFIX_CDID)) { + bpkType = type.substring(EaafConstants.URN_PREFIX_CDID.length()); + } else if (type.startsWith(EaafConstants.URN_PREFIX_EIDAS)) { + bpkType = type.substring(EaafConstants.URN_PREFIX_EIDAS.length()); + } + + if (bpkType != null) { + log.trace("Authenticate user with bPK/wbPK " + bpk + " and Type=" + bpkType); + return bpkType + ":" + bpk; + + } else { + log.warn("Service Provider Target with: " + type + " is NOT supported. Set bPK as it is ..."); + return bpk; + + } + + } + + private Map convertEidasAttrToSimpleMap( + ImmutableMap, ImmutableSet>> attributeMap) { + final Map result = new HashMap<>(); + + for (final AttributeDefinition el : attributeMap.keySet()) { + + final Class parameterizedType = el.getParameterizedType(); + if (DateTime.class.equals(parameterizedType)) { + final DateTime attribute = EidasResponseUtils.translateDateAttribute(el, attributeMap.get(el).asList()); + if (attribute != null) { + result.put(el.getFriendlyName(), attribute); + log.trace("Find attr '" + el.getFriendlyName() + "' with value: " + attribute.toString()); + + } else { + log.info("Ignore empty 'DateTime' attribute"); + } + + } else if (PostalAddress.class.equals(parameterizedType)) { + final PostalAddress addressAttribute = EidasResponseUtils + .translateAddressAttribute(el, attributeMap.get(el).asList()); + if (addressAttribute != null) { + result.put(el.getFriendlyName(), addressAttribute); + log.trace("Find attr '" + el.getFriendlyName() + "' with value: " + addressAttribute.toString()); + + } else { + log.info("Ignore empty 'PostalAddress' attribute"); + } + + } else { + final List natPersonIdObj = EidasResponseUtils + .translateStringListAttribute(el, attributeMap.get(el)); + final String stringAttr = natPersonIdObj.get(0); + if (StringUtils.isNotEmpty(stringAttr)) { + result.put(el.getFriendlyName(), stringAttr); + log.trace("Find attr '" + el.getFriendlyName() + "' with value: " + stringAttr); + + } else { + log.info("Ignore empty 'String' attribute"); + } + + } + } + + log.debug("Receive #" + result.size() + " attributes with names: " + result.keySet().toString()); + + return result; + } + + private void writeMdsLogInformation(ErnbEidData eidData) { + // log MDS and country code into technical log + if (basicConfig + .getBasicConfigurationBoolean(MsEidasNodeConstants.PROP_CONFIG_TECHNICALLOG_WRITE_MDS_INTO_TECH_LOG, false)) { + log.info("eIDAS Auth. for user: " + eidData.getGivenName() + " " + eidData.getFamilyName() + " " + eidData + .getFormatedDateOfBirth() + " " + "from " + eidData.getCitizenCountryCode()); + } + + // log MDS and country code into revision log + if (basicConfig + .getBasicConfigurationBoolean(MsEidasNodeConstants.PROP_CONFIG_REVISIONLOG_WRITE_MDS_INTO_REVISION_LOG, + false)) { + revisionsLogger.logEvent(pendingReq, MsConnectorEventCodes.RESPONSE_FROM_EIDAS_MDSDATA, + "{" + eidData.getGivenName() + "," + eidData.getFamilyName() + "," + eidData + .getFormatedDateOfBirth() + "," + eidData.getCitizenCountryCode() + "}"); + } + + } + + @Data + private static class SzrResultHolder { + final IIdentityLink identityLink; + final String bpK; + + } + + /** + * Build a dummy IdentityLink and a dummy bPK based on eIDAS information. + * + *

+ * FOR LOCAL TESTING ONLY!!! + * + * @param eidData Information from eIDAS response + * @return IdentityLink and bPK + * @throws ParserConfigurationException In case of an IDL processing error + * @throws SAXException In case of an IDL processing error + * @throws IOException In case of an IDL processing error + * @throws EaafException In case of a bPK generation error + */ + private SzrResultHolder createDummyIdentityLinkForTestDeployment(ErnbEidData eidData) + throws ParserConfigurationException, SAXException, IOException, EaafException { + log.warn("SZR-Dummy IS ACTIVE! IdentityLink is NOT VALID!!!!"); + // create fake IdL + // - fetch IdL template from resources + final InputStream s = CreateIdentityLinkTask.class + .getResourceAsStream("/resources/xmldata/fakeIdL_IdL_template.xml"); + final Element idlTemplate = DomUtils.parseXmlValidating(s); + + IIdentityLink identityLink = new SimpleIdentityLinkAssertionParser(idlTemplate).parseIdentityLink(); + + // replace data + final Element idlassertion = identityLink.getSamlAssertion(); + + // - set fake baseID; + final Node prIdentification = XPathUtils + .selectSingleNode(idlassertion, SimpleIdentityLinkAssertionParser.PERSON_IDENT_VALUE_XPATH); + prIdentification.getFirstChild().setNodeValue(eidData.getPseudonym()); + + // - set last name + final Node prFamilyName = XPathUtils + .selectSingleNode(idlassertion, SimpleIdentityLinkAssertionParser.PERSON_FAMILY_NAME_XPATH); + prFamilyName.getFirstChild().setNodeValue(eidData.getFamilyName()); + + // - set first name + final Node prGivenName = XPathUtils + .selectSingleNode(idlassertion, SimpleIdentityLinkAssertionParser.PERSON_GIVEN_NAME_XPATH); + prGivenName.getFirstChild().setNodeValue(eidData.getGivenName()); + + // - set date of birth + final Node prDateOfBirth = XPathUtils + .selectSingleNode(idlassertion, SimpleIdentityLinkAssertionParser.PERSON_DATE_OF_BIRTH_XPATH); + + prDateOfBirth.getFirstChild().setNodeValue(eidData.getFormatedDateOfBirth()); + + identityLink = new SimpleIdentityLinkAssertionParser(idlassertion).parseIdentityLink(); + + final Pair bpkCalc = BpkBuilder + .generateAreaSpecificPersonIdentifier(identityLink.getIdentificationValue(), + identityLink.getIdentificationType(), + pendingReq.getServiceProviderConfiguration() + .getAreaSpecificTargetIdentifier()); + return new SzrResultHolder(identityLink, bpkCalc.getFirst()); + + } + +} diff --git a/modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/tasks/GenerateAuthnRequestTask.java b/modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/tasks/GenerateAuthnRequestTask.java new file mode 100644 index 00000000..b43c1bc2 --- /dev/null +++ b/modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/tasks/GenerateAuthnRequestTask.java @@ -0,0 +1,255 @@ +/* + * Copyright 2018 A-SIT Plus GmbH + * AT-specific eIDAS Connector has been developed in a cooperation between EGIZ, + * A-SIT Plus GmbH, A-SIT, and Graz University of Technology. + * + * Licensed under the EUPL, Version 1.2 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "License"); + * You may not use this work except in compliance with the License. + * You may obtain a copy of the License at: + * https://joinup.ec.europa.eu/news/understanding-eupl-v12 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. +*/ + +package at.asitplus.eidas.specific.modules.auth.eidas.v2.tasks; + +import java.util.UUID; + +import javax.servlet.ServletException; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.apache.commons.lang3.StringUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.ApplicationContext; +import org.springframework.stereotype.Component; +import org.springframework.web.util.UriComponentsBuilder; + +import at.asitplus.eidas.specific.core.MsConnectorEventCodes; +import at.asitplus.eidas.specific.core.MsEidasNodeConstants; +import at.asitplus.eidas.specific.core.gui.StaticGuiBuilderConfiguration; +import at.asitplus.eidas.specific.modules.auth.eidas.v2.Constants; +import at.asitplus.eidas.specific.modules.auth.eidas.v2.exception.EidasSAuthenticationException; +import at.asitplus.eidas.specific.modules.auth.eidas.v2.service.ICcSpecificEidProcessingService; +import at.gv.egiz.eaaf.core.api.gui.ISpringMvcGuiFormBuilder; +import at.gv.egiz.eaaf.core.api.idp.IConfiguration; +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.TaskExecutionException; +import at.gv.egiz.eaaf.core.impl.idp.auth.modules.AbstractAuthServletTask; +import eu.eidas.auth.commons.EidasParameterKeys; +import eu.eidas.auth.commons.light.ILightRequest; +import eu.eidas.auth.commons.light.impl.LightRequest; +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; + +/** + * Authentication-process task that generates the Authn. Request to eIDAS Node. + * + * @author tlenz + * + */ +@Slf4j +@Component("ConnecteIDASNodeTask") +public class GenerateAuthnRequestTask extends AbstractAuthServletTask { + + @Autowired + IConfiguration basicConfig; + @Autowired + ApplicationContext context; + @Autowired + ITransactionStorage transactionStore; + @Autowired + ISpringMvcGuiFormBuilder guiBuilder; + @Autowired + ICcSpecificEidProcessingService ccSpecificProcessing; + + @Override + public void execute(ExecutionContext executionContext, + HttpServletRequest request, HttpServletResponse response) + throws TaskExecutionException { + + try { + // get target, environment and validate citizen countryCode + final String citizenCountryCode = (String) executionContext.get( + MsEidasNodeConstants.REQ_PARAM_SELECTED_COUNTRY); + final String environment = (String) executionContext.get( + MsEidasNodeConstants.REQ_PARAM_SELECTED_ENVIRONMENT); + + if (StringUtils.isEmpty(citizenCountryCode)) { + // illegal state; task should not have been executed without a selected country + throw new EidasSAuthenticationException("eidas.03", new Object[] { "" }); + + } + + // TODO: maybe add countryCode validation before request ref. impl. eIDAS node + log.info("Request eIDAS auth. for citizen of country: " + citizenCountryCode); + revisionsLogger.logEvent(pendingReq, MsConnectorEventCodes.COUNTRY_SELECTED, citizenCountryCode); + + // build eIDAS AuthnRequest + final LightRequest.Builder authnRequestBuilder = LightRequest.builder(); + authnRequestBuilder.id(UUID.randomUUID().toString()); + + // set nameIDFormat + authnRequestBuilder.nameIdFormat( + authConfig.getBasicConfiguration(Constants.CONFIG_PROP_EIDAS_NODE_NAMEIDFORMAT)); + + // set citizen country code for foreign uses + authnRequestBuilder.citizenCountryCode(citizenCountryCode); + + //set Issuer + final String issur = basicConfig.getBasicConfiguration(Constants.CONIG_PROPS_EIDAS_NODE_ENTITYID); + if (StringUtils.isEmpty(issur)) { + log.error("Found NO 'eIDAS node issuer' in configuration. Authentication NOT possible!"); + throw new EaafConfigurationException("config.27", + new Object[] { "Application config containts NO " + Constants.CONIG_PROPS_EIDAS_NODE_ENTITYID }); + + } + authnRequestBuilder.issuer(issur); + + + // Add country-specific informations into eIDAS request + ccSpecificProcessing.preProcess(citizenCountryCode, pendingReq, authnRequestBuilder); + + // build request + final LightRequest lightAuthnReq = authnRequestBuilder.build(); + + // put request into Hazelcast cache + final BinaryLightToken token = putRequestInCommunicationCache(lightAuthnReq); + final String tokenBase64 = BinaryLightTokenHelper.encodeBinaryLightTokenBase64(token); + + // Workaround, because eIDAS node ref. impl. does not return relayState + if (basicConfig.getBasicConfigurationBoolean( + Constants.CONIG_PROPS_EIDAS_NODE_WORKAROUND_USEREQUESTIDASTRANSACTIONIDENTIFIER, + false)) { + log.trace("Put lightRequestId into transactionstore as session-handling backup"); + transactionStore.put(lightAuthnReq.getId(), pendingReq.getPendingRequestId(), -1); + + } + + // select forward URL regarding the selected environment + String forwardUrl = basicConfig.getBasicConfiguration(Constants.CONIG_PROPS_EIDAS_CONNECTOR_NODE_FORWARD_URL); + if (StringUtils.isNotEmpty(environment)) { + forwardUrl = selectedForwardUrlForEnvironment(environment); + } + + 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[] { + environment == null ? Constants.CONIG_PROPS_EIDAS_CONNECTOR_NODE_FORWARD_URL + : Constants.CONIG_PROPS_EIDAS_CONNECTOR_NODE_FORWARD_URL + "." + environment + }); + + } + 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); + response.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(request, response, config, "Forward to eIDASNode form"); + + } + + revisionsLogger.logEvent(pendingReq, MsConnectorEventCodes.EIDAS_NODE_CONNECTED, lightAuthnReq.getId()); + + } catch (final EidasSAuthenticationException e) { + throw new TaskExecutionException(pendingReq, "eIDAS AuthnRequest generation FAILED.", e); + + } catch (final Exception e) { + log.warn("eIDAS AuthnRequest generation FAILED.", e); + throw new TaskExecutionException(pendingReq, e.getMessage(), e); + + } + + } + + /** + * Select a forward URL from configuration for a specific environment
+ *
+ * Info: This method is needed, because eIDAS Ref. Impl only supports + * one countrycode on each instance. In consequence, more than one eIDAS Ref. + * Impl nodes are required to support producation, testing, or QS stages for one + * country by using one ms-specific eIDAS connector + * + * @param environment Environment selector from CountrySlection page + * @return + */ + private String selectedForwardUrlForEnvironment(String environment) { + log.trace("Starting endpoint selection process for environment: " + environment + " ... "); + if (environment.equalsIgnoreCase(MsEidasNodeConstants.REQ_PARAM_SELECTED_ENVIRONMENT_VALUE_PRODUCTION)) { + return basicConfig.getBasicConfiguration(Constants.CONIG_PROPS_EIDAS_CONNECTOR_NODE_FORWARD_URL); + } else if (environment.equalsIgnoreCase(MsEidasNodeConstants.REQ_PARAM_SELECTED_ENVIRONMENT_VALUE_QS)) { + return basicConfig.getBasicConfiguration(Constants.CONIG_PROPS_EIDAS_CONNECTOR_NODE_FORWARD_URL + + "." + MsEidasNodeConstants.REQ_PARAM_SELECTED_ENVIRONMENT_VALUE_QS); + } else if (environment.equalsIgnoreCase( + MsEidasNodeConstants.REQ_PARAM_SELECTED_ENVIRONMENT_VALUE_TESTING)) { + return basicConfig.getBasicConfiguration(Constants.CONIG_PROPS_EIDAS_CONNECTOR_NODE_FORWARD_URL + + "." + MsEidasNodeConstants.REQ_PARAM_SELECTED_ENVIRONMENT_VALUE_TESTING); + } else if (environment.equalsIgnoreCase( + MsEidasNodeConstants.REQ_PARAM_SELECTED_ENVIRONMENT_VALUE_DEVELOPMENT)) { + return basicConfig.getBasicConfiguration(Constants.CONIG_PROPS_EIDAS_CONNECTOR_NODE_FORWARD_URL + + "." + MsEidasNodeConstants.REQ_PARAM_SELECTED_ENVIRONMENT_VALUE_DEVELOPMENT); + } + + log.info("Environment selector: " + environment + " is not supported"); + return null; + + } + + private BinaryLightToken putRequestInCommunicationCache(ILightRequest lightRequest) + throws ServletException { + final BinaryLightToken binaryLightToken; + try { + final SpecificCommunicationService springManagedSpecificConnectorCommunicationService = + (SpecificCommunicationService) context.getBean( + SpecificCommunicationDefinitionBeanNames.SPECIFIC_CONNECTOR_COMMUNICATION_SERVICE.toString()); + + binaryLightToken = springManagedSpecificConnectorCommunicationService.putRequest(lightRequest); + + } catch (final SpecificCommunicationException e) { + log.error("Unable to process specific request"); + throw new ServletException(e); + + } + + return binaryLightToken; + } + +} diff --git a/modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/tasks/ReceiveAuthnResponseTask.java b/modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/tasks/ReceiveAuthnResponseTask.java new file mode 100644 index 00000000..8d5df99f --- /dev/null +++ b/modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/tasks/ReceiveAuthnResponseTask.java @@ -0,0 +1,130 @@ +/* + * Copyright 2018 A-SIT Plus GmbH + * AT-specific eIDAS Connector has been developed in a cooperation between EGIZ, + * A-SIT Plus GmbH, A-SIT, and Graz University of Technology. + * + * Licensed under the EUPL, Version 1.2 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "License"); + * You may not use this work except in compliance with the License. + * You may obtain a copy of the License at: + * https://joinup.ec.europa.eu/news/understanding-eupl-v12 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. +*/ + +package at.asitplus.eidas.specific.modules.auth.eidas.v2.tasks; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import at.asitplus.eidas.specific.core.MsConnectorEventCodes; +import at.asitplus.eidas.specific.core.MsEidasNodeConstants; +import at.asitplus.eidas.specific.modules.auth.eidas.v2.Constants; +import at.asitplus.eidas.specific.modules.auth.eidas.v2.exception.EidasSAuthenticationException; +import at.asitplus.eidas.specific.modules.auth.eidas.v2.service.EidasAttributeRegistry; +import at.asitplus.eidas.specific.modules.auth.eidas.v2.validator.EidasResponseValidator; +import at.gv.egiz.eaaf.core.api.idp.IConfiguration; +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.TaskExecutionException; +import at.gv.egiz.eaaf.core.impl.idp.auth.data.EidAuthProcessDataWrapper; +import at.gv.egiz.eaaf.core.impl.idp.auth.modules.AbstractAuthServletTask; +import eu.eidas.auth.commons.light.ILightResponse; +import lombok.extern.slf4j.Slf4j; + +@Slf4j +@Component("ReceiveResponseFromeIDASNodeTask") +public class ReceiveAuthnResponseTask extends AbstractAuthServletTask { + + @Autowired + private IConfiguration basicConfig; + @Autowired + private EidasAttributeRegistry attrRegistry; + + @Override + public void execute(ExecutionContext executionContext, HttpServletRequest request, + HttpServletResponse response) throws TaskExecutionException { + try { + final ILightResponse eidasResponse = (ILightResponse) request.getAttribute( + Constants.DATA_FULL_EIDAS_RESPONSE); + if (eidasResponse == null) { + log.warn("NO eIDAS response-message found."); + throw new EidasSAuthenticationException("eidas.01", null); + + } + + log.debug("Receive eIDAS response with RespId:" + eidasResponse.getId() + " for ReqId:" + eidasResponse + .getInResponseToId()); + log.trace("Full eIDAS-Resp: " + eidasResponse.toString()); + revisionsLogger.logEvent(pendingReq, MsConnectorEventCodes.RESPONSE_FROM_EIDAS_NODE, eidasResponse + .getId()); + + // check response StatusCode + if (!eidasResponse.getStatus().getStatusCode().equals(Constants.SUCCESS_URI)) { + log.info("Receice eIDAS Response with StatusCode:" + eidasResponse.getStatus().getStatusCode() + + " Subcode:" + eidasResponse.getStatus().getSubStatusCode() + " Msg:" + eidasResponse.getStatus() + .getStatusMessage()); + throw new EidasSAuthenticationException("eidas.02", new Object[] { eidasResponse.getStatus() + .getStatusCode(), eidasResponse.getStatus().getStatusMessage() }); + + } + + // extract all Attributes from response + + // ********************************************************** + // ******* MS-specificresponse validation ********** + // ********************************************************** + final String spCountry = basicConfig.getBasicConfiguration(Constants.CONIG_PROPS_EIDAS_NODE_COUNTRYCODE, + Constants.DEFAULT_MS_NODE_COUNTRY_CODE); + final String citizenCountryCode = (String) executionContext.get( + MsEidasNodeConstants.REQ_PARAM_SELECTED_COUNTRY); + EidasResponseValidator.validateResponse(pendingReq, eidasResponse, spCountry, citizenCountryCode, + attrRegistry); + + // ********************************************************** + // ******* Store resonse infos into session object ********** + // ********************************************************** + + // update MOA-Session data with received information + log.debug("Store eIDAS response information into pending-request."); + final EidAuthProcessDataWrapper authProcessData = pendingReq.getSessionData(EidAuthProcessDataWrapper.class); + authProcessData.setQaaLevel(eidasResponse.getLevelOfAssurance()); + authProcessData.setGenericDataToSession(Constants.DATA_FULL_EIDAS_RESPONSE, eidasResponse); + + + //inject set flag to inject + authProcessData.setTestIdentity( + basicConfig.getBasicConfigurationBoolean(Constants.CONIG_PROPS_EIDAS_IS_TEST_IDENTITY, false)); + + // store MOA-session to database + requestStoreage.storePendingRequest(pendingReq); + + revisionsLogger.logEvent(pendingReq, MsConnectorEventCodes.RESPONSE_FROM_EIDAS_NODE_VALID); + + } catch (final EaafException e) { + revisionsLogger.logEvent(pendingReq, MsConnectorEventCodes.RESPONSE_FROM_EIDAS_NODE_NOT_VALID); + throw new TaskExecutionException(pendingReq, "eIDAS Response processing FAILED.", e); + + } catch (final Exception e) { + log.warn("eIDAS Response processing FAILED.", e); + revisionsLogger.logEvent(pendingReq, MsConnectorEventCodes.RESPONSE_FROM_EIDAS_NODE_NOT_VALID); + throw new TaskExecutionException(pendingReq, e.getMessage(), + new EidasSAuthenticationException("eidas.05", new Object[] { e.getMessage() }, e)); + + } + + } + +} diff --git a/modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/utils/EidasResponseUtils.java b/modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/utils/EidasResponseUtils.java new file mode 100644 index 00000000..c8c5a069 --- /dev/null +++ b/modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/utils/EidasResponseUtils.java @@ -0,0 +1,179 @@ +/* + * Copyright 2018 A-SIT Plus GmbH + * AT-specific eIDAS Connector has been developed in a cooperation between EGIZ, + * A-SIT Plus GmbH, A-SIT, and Graz University of Technology. + * + * Licensed under the EUPL, Version 1.2 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "License"); + * You may not use this work except in compliance with the License. + * You may obtain a copy of the License at: + * https://joinup.ec.europa.eu/news/understanding-eupl-v12 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. +*/ + +package at.asitplus.eidas.specific.modules.auth.eidas.v2.utils; + +import java.util.ArrayList; +import java.util.List; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import javax.annotation.Nullable; + +import org.apache.commons.lang3.StringUtils; +import org.joda.time.DateTime; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableSet; + +import at.asitplus.eidas.specific.modules.auth.eidas.v2.Constants; +import at.gv.egiz.eaaf.core.impl.data.Triple; +import eu.eidas.auth.commons.attribute.AttributeDefinition; +import eu.eidas.auth.commons.attribute.AttributeValue; +import eu.eidas.auth.commons.attribute.AttributeValueMarshaller; +import eu.eidas.auth.commons.attribute.AttributeValueMarshallingException; +import eu.eidas.auth.commons.attribute.AttributeValueTransliterator; +import eu.eidas.auth.commons.protocol.eidas.impl.PostalAddress; + +public class EidasResponseUtils { + private static final Logger log = LoggerFactory.getLogger(EidasResponseUtils.class); + + public static final String PERSONALIDENIFIER_VALIDATION_PATTERN = "^[A-Z,a-z]{2}/[A-Z,a-z]{2}/.*"; + + /** + * Validate a eIDAS PersonalIdentifier attribute value This validation is done + * according to eIDAS SAML Attribute Profile - Section 2.2.3 Unique Identifier + * + * @param uniqueID eIDAS attribute value of a unique identifier + * @return true if the uniqueID matches to eIDAS to Unique Identifier + * specification, otherwise false + */ + public static boolean validateEidasPersonalIdentifier(String uniqueID) { + final Pattern pattern = Pattern.compile(PERSONALIDENIFIER_VALIDATION_PATTERN); + final Matcher matcher = pattern.matcher(uniqueID); + return matcher.matches(); + + } + + /** + * Parse an eIDAS PersonalIdentifier attribute value into it components. This + * processing is done according to eIDAS SAML Attribute Profile - Section 2.2.3 + * Unique Identifier + * + * @param uniqueID eIDAS attribute value of a unique identifier + * @return {@link Trible} that contains:
+ * First : citizen country
+ * Second: destination country
+ * Third : unique identifier
+ * or null if the attribute value has a wrong format + */ + public static Triple parseEidasPersonalIdentifier(String uniqueID) { + if (!validateEidasPersonalIdentifier(uniqueID)) { + log.error("eIDAS attribute value for {} looks wrong formated. Value: {}", + Constants.eIDAS_ATTR_PERSONALIDENTIFIER, uniqueID); + return null; + + } + return Triple.newInstance(uniqueID.substring(0, 2), uniqueID.substring(3, 5), uniqueID.substring(6)); + + } + + /** + * Get eIDAS attribute-values from eIDAS Node attributes. + * + * @param attributeDefinition eIDAS attribute definition + * @param attributeValues Attributes from eIDAS response + * @return Set of attribute values. If more then one value than the first value contains the 'Latin' value. + */ + // TODO: check possible problem with nonLatinCharacters + public static List translateStringListAttribute(AttributeDefinition attributeDefinition, + ImmutableSet> attributeValues) { + final List stringListAttribute = new ArrayList<>(); + if (attributeValues != null) { + final AttributeValueMarshaller attributeValueMarshaller = attributeDefinition + .getAttributeValueMarshaller(); + for (final AttributeValue attributeValue : attributeValues.asList()) { + String valueString = null; + try { + valueString = attributeValueMarshaller.marshal((AttributeValue) attributeValue); + + log.trace("Find attr: {} with value: {} nonLatinFlag: {} needTransliteration: {}", + attributeDefinition.getFriendlyName(), attributeValue.toString(), + attributeValue.isNonLatinScriptAlternateVersion(), + AttributeValueTransliterator.needsTransliteration(valueString)); + + // if (attributeValue.isNonLatinScriptAlternateVersion()) { + if (!AttributeValueTransliterator.needsTransliteration(valueString)) { + stringListAttribute.add(0, valueString); + + } else { + log.trace("Find 'needsTransliteration' flag. Setting this value at last list element ... "); + stringListAttribute.add(valueString); + + } + + } catch (final AttributeValueMarshallingException e) { + throw new IllegalStateException(e); + + } + } + + log.trace("Extract values: {} for attr: {}", + StringUtils.join(stringListAttribute, ","), attributeDefinition.getFriendlyName()); + + } else { + log.info("Can not extract infos from 'null' attribute value"); + + } + + return stringListAttribute; + + } + + /** + * Convert eIDAS DateTime attribute to Java Object. + * + * @param attributeDefinition eIDAS attribute definition. + * @param attributeValues eIDAS attribute value + * @return + */ + @Nullable + public static DateTime translateDateAttribute(AttributeDefinition attributeDefinition, + ImmutableList> attributeValues) { + if (attributeValues.size() != 0) { + final AttributeValue firstAttributeValue = attributeValues.get(0); + return (DateTime) firstAttributeValue.getValue(); + + } + + return null; + } + + /** + * Concert eIDAS Address attribute to Java object. + * + * @param attributeDefinition eIDAS attribute definition + * @param attributeValues eIDAS attribute value + * @return + */ + @Nullable + public static PostalAddress translateAddressAttribute(AttributeDefinition attributeDefinition, + ImmutableList> attributeValues) { + final AttributeValue firstAttributeValue = attributeValues.get(0); + return (PostalAddress) firstAttributeValue.getValue(); + + } + +} diff --git a/modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/utils/JoseUtils.java b/modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/utils/JoseUtils.java new file mode 100644 index 00000000..e81c4c92 --- /dev/null +++ b/modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/utils/JoseUtils.java @@ -0,0 +1,305 @@ +package at.asitplus.eidas.specific.modules.auth.eidas.v2.utils; + +import at.gv.egiz.eaaf.core.exception.EaafKeyUsageException; +import at.gv.egiz.eaaf.core.exceptions.EaafException; +import at.gv.egiz.eaaf.core.impl.credential.EaafKeyStoreUtils; +import at.gv.egiz.eaaf.core.impl.data.Pair; +import at.gv.egiz.eaaf.core.impl.utils.X509Utils; +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; +import org.jose4j.jca.ProviderContext; +import org.jose4j.jwa.AlgorithmConstraints; +import org.jose4j.jws.AlgorithmIdentifiers; +import org.jose4j.jws.JsonWebSignature; +import org.jose4j.jwx.Headers; +import org.jose4j.jwx.JsonWebStructure; +import org.jose4j.keys.resolvers.X509VerificationKeyResolver; +import org.jose4j.lang.JoseException; +import org.springframework.util.Base64Utils; + +import javax.annotation.Nonnull; +import java.io.IOException; +import java.security.Key; +import java.security.KeyStore; +import java.security.Provider; +import java.security.cert.CertificateEncodingException; +import java.security.cert.X509Certificate; +import java.security.interfaces.ECPrivateKey; +import java.security.interfaces.RSAPrivateKey; +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; + +/** + * {@link JoseUtils} provides static methods JWS and JWE processing. + * + * @author tlenz + * + */ +@Slf4j +public class JoseUtils { + + /** + * Create a JWS signature. + * + *

+ * Use {@link AlgorithmIdentifiers.RSA_PSS_USING_SHA256} in case + * of a RSA based key and + * {@link AlgorithmIdentifiers.ECDSA_USING_P256_CURVE_AND_SHA256} + * in case of an ECC based key. + *

+ * + * @param keyStore KeyStore that should be used + * @param keyAlias Alias of the private key + * @param keyPassword Password to access the key + * @param payLoad PayLoad to sign + * @param addFullCertChain If true the full certificate chain will be + * added, otherwise only the + * X509CertSha256Fingerprint is added into JOSE + * header + * @param friendlyNameForLogging FriendlyName for the used KeyStore for logging + * purposes only + * @return Signed PayLoad in serialized form + * @throws EaafException In case of a key-access or key-usage error + * @throws JoseException In case of a JOSE error + */ + public static String createSignature(@Nonnull Pair keyStore, + @Nonnull final String keyAlias, @Nonnull final char[] keyPassword, + @Nonnull final String payLoad, boolean addFullCertChain, + @Nonnull String friendlyNameForLogging) throws EaafException, JoseException { + return createSignature(keyStore, keyAlias, keyPassword, payLoad, addFullCertChain, Collections.emptyMap(), + AlgorithmIdentifiers.RSA_PSS_USING_SHA256, AlgorithmIdentifiers.ECDSA_USING_P256_CURVE_AND_SHA256, + friendlyNameForLogging); + + } + + /** + * Create a JWS signature. + * + *

+ * Use {@link AlgorithmIdentifiers.RSA_PSS_USING_SHA256} in case + * of a RSA based key and + * {@link AlgorithmIdentifiers.ECDSA_USING_P256_CURVE_AND_SHA256} + * in case of an ECC based key. + *

+ * + * @param keyStore KeyStore that should be used + * @param keyAlias Alias of the private key + * @param keyPassword Password to access the key + * @param payLoad PayLoad to sign + * @param addFullCertChain If true the full certificate chain will be + * added, otherwise only the + * X509CertSha256Fingerprint is added into JOSE + * header + * @param joseHeaders HeaderName and HeaderValue that should be set + * into JOSE header + * @param friendlyNameForLogging FriendlyName for the used KeyStore for logging + * purposes only + * @return Signed PayLoad in serialized form + * @throws EaafException In case of a key-access or key-usage error + * @throws JoseException In case of a JOSE error + */ + public static String createSignature(@Nonnull Pair keyStore, + @Nonnull final String keyAlias, @Nonnull final char[] keyPassword, + @Nonnull final String payLoad, boolean addFullCertChain, + @Nonnull final Map joseHeaders, + @Nonnull String friendlyNameForLogging) throws EaafException, JoseException { + return createSignature(keyStore, keyAlias, keyPassword, payLoad, addFullCertChain, joseHeaders, + AlgorithmIdentifiers.RSA_PSS_USING_SHA256, AlgorithmIdentifiers.ECDSA_USING_P256_CURVE_AND_SHA256, + friendlyNameForLogging); + + } + + /** + * Create a JWS signature. + * + * @param keyStore KeyStore that should be used + * @param keyAlias Alias of the private key + * @param keyPassword Password to access the key + * @param payLoad PayLoad to sign + * @param addFullCertChain If true the full certificate chain will be + * added, otherwise only the + * X509CertSha256Fingerprint is added into JOSE + * header + * @param joseHeaders HeaderName and HeaderValue that should be set + * into JOSE header + * @param rsaAlgToUse Signing algorithm that should be used in case + * of a signing key based on RSA + * @param eccAlgToUse Signing algorithm that should be used in case + * of a signing key based on ECC + * @param friendlyNameForLogging FriendlyName for the used KeyStore for logging + * purposes only + * @return Signed PayLoad in serialized form + * @throws EaafException In case of a key-access or key-usage error + * @throws JoseException In case of a JOSE error + */ + public static String createSignature(@Nonnull Pair keyStore, + @Nonnull final String keyAlias, @Nonnull final char[] keyPassword, + @Nonnull final String payLoad, boolean addFullCertChain, + @Nonnull final Map joseHeaders, + @Nonnull final String rsaAlgToUse, @Nonnull final String eccAlgToUse, + @Nonnull String friendlyNameForLogging) throws EaafException, JoseException { + + final JsonWebSignature jws = new JsonWebSignature(); + + // set payload + jws.setPayload(payLoad); + + // set JOSE headers + for (final Entry el : joseHeaders.entrySet()) { + log.trace("Set JOSE header: {} with value: {} into JWS", el.getKey(), el.getValue()); + jws.setHeader(el.getKey(), el.getValue()); + + } + + // set signing information + final Pair signingCred = EaafKeyStoreUtils.getPrivateKeyAndCertificates( + keyStore.getFirst(), keyAlias, keyPassword, true, friendlyNameForLogging); + jws.setKey(signingCred.getFirst()); + jws.setAlgorithmHeaderValue(getKeyOperationAlgorithmFromCredential( + jws.getKey(), rsaAlgToUse, eccAlgToUse, friendlyNameForLogging)); + + // set special provider if required + if (keyStore.getSecond() != null) { + log.trace("Injecting special Java Security Provider: {}", keyStore.getSecond().getName()); + final ProviderContext providerCtx = new ProviderContext(); + providerCtx.getSuppliedKeyProviderContext().setSignatureProvider( + keyStore.getSecond().getName()); + jws.setProviderContext(providerCtx); + + } + + if (addFullCertChain) { + jws.setCertificateChainHeaderValue(signingCred.getSecond()); + + } + + jws.setX509CertSha256ThumbprintHeaderValue(signingCred.getSecond()[0]); + + return jws.getCompactSerialization(); + + } + + /** + * Verify a JOSE signature. + * + * @param serializedContent Serialized content that should be verified + * @param trustedCerts Trusted certificates that should be used for + * verification + * @param constraints {@link AlgorithmConstraints} for verification + * @return {@link JwsResult} object + * @throws JoseException In case of a signature verification error + * @throws IOException In case of a general error + */ + public static JwsResult validateSignature(@Nonnull final String serializedContent, + @Nonnull final List trustedCerts, @Nonnull final AlgorithmConstraints constraints) + throws JoseException, IOException { + final JsonWebSignature jws = new JsonWebSignature(); + // set payload + jws.setCompactSerialization(serializedContent); + + // set security constrains + jws.setAlgorithmConstraints(constraints); + + // load signinc certs + Key selectedKey = null; + final List x5cCerts = jws.getCertificateChainHeaderValue(); + final String x5t256 = jws.getX509CertSha256ThumbprintHeaderValue(); + if (x5cCerts != null) { + log.debug("Found x509 certificate in JOSE header ... "); + log.trace("Sorting received X509 certificates ... "); + final List sortedX5cCerts = X509Utils.sortCertificates(x5cCerts); + + if (trustedCerts.contains(sortedX5cCerts.get(0))) { + selectedKey = sortedX5cCerts.get(0).getPublicKey(); + + } else { + log.info("Can NOT find JOSE certificate in truststore."); + if (log.isDebugEnabled()) { + try { + log.debug("Cert: {}", Base64Utils.encodeToString(sortedX5cCerts.get(0).getEncoded())); + + } catch (final CertificateEncodingException e) { + log.warn("Can not create DEBUG output", e); + + } + } + } + + } else if (StringUtils.isNotEmpty(x5t256)) { + log.debug("Found x5t256 fingerprint in JOSE header .... "); + final X509VerificationKeyResolver x509VerificationKeyResolver = new X509VerificationKeyResolver( + trustedCerts); + selectedKey = x509VerificationKeyResolver.resolveKey(jws, Collections.emptyList()); + + } else { + throw new JoseException("JWS contains NO signature certificate or NO certificate fingerprint"); + + } + + if (selectedKey == null) { + throw new JoseException("Can NOT select verification key for JWS. Signature verification FAILED"); + + } + + // set verification key + jws.setKey(selectedKey); + + // load payLoad + return new JwsResult( + jws.verifySignature(), + jws.getUnverifiedPayload(), + jws.getHeaders(), + x5cCerts); + + } + + /** + * Select signature algorithm for a given credential. + * + * @param key {@link X509Credential} that will be used for + * key operations + * @param rsaSigAlgorithm RSA based algorithm that should be used in case + * of RSA credential + * @param ecSigAlgorithm EC based algorithm that should be used in case + * of RSA credential + * @param friendlyNameForLogging KeyStore friendlyName for logging purposes + * @return either the RSA based algorithm or the EC based algorithm + * @throws EaafKeyUsageException In case of an unsupported private-key type + */ + private static String getKeyOperationAlgorithmFromCredential(Key key, + String rsaSigAlgorithm, String ecSigAlgorithm, String friendlyNameForLogging) + throws EaafKeyUsageException { + if (key instanceof RSAPrivateKey) { + return rsaSigAlgorithm; + + } else if (key instanceof ECPrivateKey) { + return ecSigAlgorithm; + + } else { + log.warn("Could NOT select the cryptographic algorithm from Private-Key type"); + throw new EaafKeyUsageException(EaafKeyUsageException.ERROR_CODE_01, + friendlyNameForLogging, + "Can not select cryptographic algorithm"); + + } + + } + + private JoseUtils() { + + } + + @Getter + @AllArgsConstructor + public static class JwsResult { + final boolean valid; + final String payLoad; + final Headers fullJoseHeader; + final List x5cCerts; + + } +} diff --git a/modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/utils/LoggingHandler.java b/modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/utils/LoggingHandler.java new file mode 100644 index 00000000..70290cd3 --- /dev/null +++ b/modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/utils/LoggingHandler.java @@ -0,0 +1,72 @@ +/* + * Copyright 2018 A-SIT Plus GmbH + * AT-specific eIDAS Connector has been developed in a cooperation between EGIZ, + * A-SIT Plus GmbH, A-SIT, and Graz University of Technology. + * + * Licensed under the EUPL, Version 1.2 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "License"); + * You may not use this work except in compliance with the License. + * You may obtain a copy of the License at: + * https://joinup.ec.europa.eu/news/understanding-eupl-v12 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. +*/ + +package at.asitplus.eidas.specific.modules.auth.eidas.v2.utils; + +import java.io.ByteArrayOutputStream; +import java.util.Set; + +import javax.xml.namespace.QName; +import javax.xml.soap.SOAPMessage; +import javax.xml.ws.handler.MessageContext; +import javax.xml.ws.handler.soap.SOAPHandler; +import javax.xml.ws.handler.soap.SOAPMessageContext; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class LoggingHandler implements SOAPHandler { + + Logger log = LoggerFactory.getLogger(LoggingHandler.class); + + @Override + public boolean handleMessage(SOAPMessageContext context) { + final SOAPMessage msg = context.getMessage(); + final ByteArrayOutputStream bos = new ByteArrayOutputStream(); + + try { + msg.writeTo(bos); + log.trace(bos.toString("UTF-8")); + log.trace(new String(bos.toByteArray(), "UTF-8")); + + } catch (final Exception e) { + log.trace(e.getMessage(), e); + } + return true; + } + + @Override + public boolean handleFault(SOAPMessageContext context) { + return handleMessage(context); + } + + @Override + public void close(MessageContext context) { + } + + @Override + public Set getHeaders() { + return null; + } + +} diff --git a/modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/validator/EidasResponseValidator.java b/modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/validator/EidasResponseValidator.java new file mode 100644 index 00000000..9d9a0647 --- /dev/null +++ b/modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/validator/EidasResponseValidator.java @@ -0,0 +1,175 @@ +/* + * Copyright 2018 A-SIT Plus GmbH + * AT-specific eIDAS Connector has been developed in a cooperation between EGIZ, + * A-SIT Plus GmbH, A-SIT, and Graz University of Technology. + * + * Licensed under the EUPL, Version 1.2 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "License"); + * You may not use this work except in compliance with the License. + * You may obtain a copy of the License at: + * https://joinup.ec.europa.eu/news/understanding-eupl-v12 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. +*/ + +package at.asitplus.eidas.specific.modules.auth.eidas.v2.validator; + +import java.util.List; + +import org.apache.commons.lang3.StringUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.google.common.collect.ImmutableSet; + +import at.asitplus.eidas.specific.modules.auth.eidas.v2.Constants; +import at.asitplus.eidas.specific.modules.auth.eidas.v2.exception.EidasValidationException; +import at.asitplus.eidas.specific.modules.auth.eidas.v2.service.EidasAttributeRegistry; +import at.asitplus.eidas.specific.modules.auth.eidas.v2.utils.EidasResponseUtils; +import at.gv.egiz.eaaf.core.api.IRequest; +import at.gv.egiz.eaaf.core.impl.data.Triple; +import eu.eidas.auth.commons.attribute.AttributeDefinition; +import eu.eidas.auth.commons.attribute.AttributeValue; +import eu.eidas.auth.commons.light.ILightResponse; +import eu.eidas.auth.commons.protocol.eidas.LevelOfAssurance; + +/** + * eIDAS Response validator implementation. + * + * @author tlenz + * + */ +public class EidasResponseValidator { + private static final Logger log = LoggerFactory.getLogger(EidasResponseValidator.class); + + /** + * Validate an eIDAS Response according to internal state. + * + * @param pendingReq Current pending request + * @param eidasResponse eIDAS response object + * @param spCountry Country-Code of the Service Provider + * @param citizenCountryCode Country-Code of the Citizen + * @param attrRegistry eIDAS Attribute registry implementation + * @throws EidasValidationException In case of an validation error + */ + public static void validateResponse(IRequest pendingReq, ILightResponse eidasResponse, String spCountry, + String citizenCountryCode, EidasAttributeRegistry attrRegistry) throws EidasValidationException { + + /*-----------------------------------------------------| + * validate received LoA against minimum required LoA | + *_____________________________________________________| + */ + final LevelOfAssurance respLoA = LevelOfAssurance.fromString(eidasResponse.getLevelOfAssurance()); + final List allowedLoAs = pendingReq.getServiceProviderConfiguration().getRequiredLoA(); + boolean loaValid = false; + for (final String allowedLoaString : allowedLoAs) { + final LevelOfAssurance allowedLoa = LevelOfAssurance.fromString(allowedLoaString); + if (respLoA.numericValue() >= allowedLoa.numericValue()) { + log.debug("Response contains valid LoA. Resume process ... "); + loaValid = true; + break; + + } else { + log.trace("Allowed LoA: " + allowedLoaString + " DOES NOT match response LoA: " + eidasResponse + .getLevelOfAssurance()); + } + + } + + if (!loaValid) { + log.error("eIDAS Response LevelOfAssurance is lower than the required! " + + "(Resp-LoA:{} Req-LoA:{} )", respLoA.getValue(), allowedLoAs.toArray()); + throw new EidasValidationException("eidas.06", new Object[] { respLoA.getValue() }); + + } + + /*-----------------------------------------------------| + * validate 'PersonalIdentifier' attribute | + *_____________________________________________________| + */ + final AttributeDefinition attrDefinition = attrRegistry.getCoreAttributeRegistry().getByFriendlyName( + Constants.eIDAS_ATTR_PERSONALIDENTIFIER).first(); + final ImmutableSet> attributeValues = eidasResponse.getAttributes() + .getAttributeMap().get(attrDefinition); + final List personalIdObj = EidasResponseUtils.translateStringListAttribute(attrDefinition, + attributeValues); + + // check if attribute exists + if (personalIdObj == null || personalIdObj.isEmpty()) { + log.warn("eIDAS Response include NO 'PersonalIdentifier' attriubte " + + ".... That can be a BIG problem in further processing steps"); + throw new EidasValidationException("eidas.05", new Object[] { "NO 'PersonalIdentifier' attriubte" }); + + } else if (personalIdObj.size() > 1) { + log.warn("eIDAS Response include MORE THAN ONE 'PersonalIdentifier' attriubtes " + + ".... That can be a BIG problem in further processing steps"); + throw new EidasValidationException("eidas.05", new Object[] { + "MORE THAN ONE 'PersonalIdentifier' attriubtes" }); + + } else { + final String natPersId = personalIdObj.get(0); + // validate attribute value format + final Triple split = + EidasResponseUtils.parseEidasPersonalIdentifier(natPersId); + if (split == null) { + throw new EidasValidationException("eidas.07", + new Object[] { + Constants.eIDAS_ATTR_PERSONALIDENTIFIER, + "Wrong identifier format" }); + + } else { + // validation according to eIDAS SAML Attribute Profile, Section 2.2.3 + if (StringUtils.isEmpty(split.getSecond())) { + log.warn("eIDAS attribute value for " + Constants.eIDAS_ATTR_PERSONALIDENTIFIER + + " includes NO destination country. Value:" + natPersId); + throw new EidasValidationException("eidas.07", + new Object[] { + Constants.eIDAS_ATTR_PERSONALIDENTIFIER, + "No or empty destination country" }); + + } + if (!split.getSecond().equalsIgnoreCase(spCountry)) { + log.warn("eIDAS attribute value for " + Constants.eIDAS_ATTR_PERSONALIDENTIFIER + + " includes wrong destination country. Value:" + natPersId + + " SP-Country:" + spCountry); + throw new EidasValidationException("eidas.07", + new Object[] { + Constants.eIDAS_ATTR_PERSONALIDENTIFIER, + "Destination country does not match to SP country" }); + + } + + if (StringUtils.isEmpty(split.getFirst())) { + log.warn("eIDAS attribute value for " + Constants.eIDAS_ATTR_PERSONALIDENTIFIER + + " includes NO citizen country. Value:" + natPersId); + throw new EidasValidationException("eidas.07", + new Object[] { + Constants.eIDAS_ATTR_PERSONALIDENTIFIER, + "No or empty citizen country" }); + + } + if (!split.getFirst().equalsIgnoreCase(citizenCountryCode)) { + log.warn("eIDAS attribute value for " + Constants.eIDAS_ATTR_PERSONALIDENTIFIER + + " includes a citizen country that does not match to service-provider country. " + + " Value:" + natPersId + + " citiczen Country:" + spCountry); + throw new EidasValidationException("eidas.07", + new Object[] { + Constants.eIDAS_ATTR_PERSONALIDENTIFIER, + "Citizen country does not match to eIDAS-node country that generates the response" }); + + } + } + } + + } +} diff --git a/modules/authmodule-eIDAS-v2/src/main/resources/META-INF/services/at.gv.egiz.components.spring.api.SpringResourceProvider b/modules/authmodule-eIDAS-v2/src/main/resources/META-INF/services/at.gv.egiz.components.spring.api.SpringResourceProvider new file mode 100644 index 00000000..a8d2991d --- /dev/null +++ b/modules/authmodule-eIDAS-v2/src/main/resources/META-INF/services/at.gv.egiz.components.spring.api.SpringResourceProvider @@ -0,0 +1 @@ +at.asitplus.eidas.specific.modules.auth.eidas.v2.EidasAuthenticationSpringResourceProvider \ No newline at end of file diff --git a/modules/authmodule-eIDAS-v2/src/main/resources/eIDAS.Authentication.process.xml b/modules/authmodule-eIDAS-v2/src/main/resources/eIDAS.Authentication.process.xml new file mode 100644 index 00000000..55bb1ace --- /dev/null +++ b/modules/authmodule-eIDAS-v2/src/main/resources/eIDAS.Authentication.process.xml @@ -0,0 +1,29 @@ + + + + + + + + + + + + + + + + + + + + diff --git a/modules/authmodule-eIDAS-v2/src/main/resources/eIDAS/additional-attributes.xml b/modules/authmodule-eIDAS-v2/src/main/resources/eIDAS/additional-attributes.xml new file mode 100644 index 00000000..a72ac1e8 --- /dev/null +++ b/modules/authmodule-eIDAS-v2/src/main/resources/eIDAS/additional-attributes.xml @@ -0,0 +1,42 @@ + + + + + + Dynamic attributes + + http://eidas.europa.eu/attributes/naturalperson/AdditionalAttribute + AdditionalAttribute + NaturalPerson + false + http://www.w3.org/2001/XMLSchema + string + xs + eu.eidas.auth.commons.attribute.impl.LiteralStringAttributeValueMarshaller + + http://eidas.europa.eu/attributes/legalperson/LegalAdditionalAttribute + LegalAdditionalAttribute + LegalPerson + false + http://www.w3.org/2001/XMLSchema + string + xs + eu.eidas.auth.commons.attribute.impl.LiteralStringAttributeValueMarshaller + + diff --git a/modules/authmodule-eIDAS-v2/src/main/resources/eIDAS/eidas-attributes.xml b/modules/authmodule-eIDAS-v2/src/main/resources/eIDAS/eidas-attributes.xml new file mode 100644 index 00000000..c9288d59 --- /dev/null +++ b/modules/authmodule-eIDAS-v2/src/main/resources/eIDAS/eidas-attributes.xml @@ -0,0 +1,379 @@ + + + + + + eIDAS attributes + + http://eidas.europa.eu/attributes/naturalperson/PersonIdentifier + PersonIdentifier + NaturalPerson + true + true + http://eidas.europa.eu/attributes/naturalperson + PersonIdentifierType + eidas-natural + eu.eidas.auth.commons.attribute.impl.LiteralStringAttributeValueMarshaller + + http://eidas.europa.eu/attributes/naturalperson/CurrentFamilyName + FamilyName + NaturalPerson + true + true + http://eidas.europa.eu/attributes/naturalperson + CurrentFamilyNameType + eidas-natural + eu.eidas.auth.commons.attribute.impl.LiteralStringAttributeValueMarshaller + + http://eidas.europa.eu/attributes/naturalperson/CurrentGivenName + FirstName + NaturalPerson + true + true + http://eidas.europa.eu/attributes/naturalperson + CurrentGivenNameType + eidas-natural + eu.eidas.auth.commons.attribute.impl.LiteralStringAttributeValueMarshaller + + http://eidas.europa.eu/attributes/naturalperson/DateOfBirth + DateOfBirth + NaturalPerson + true + http://eidas.europa.eu/attributes/naturalperson + DateOfBirthType + eidas-natural + eu.eidas.auth.commons.attribute.impl.DateTimeAttributeValueMarshaller + + http://eidas.europa.eu/attributes/naturalperson/BirthName + BirthName + NaturalPerson + false + true + http://eidas.europa.eu/attributes/naturalperson + BirthNameType + eidas-natural + eu.eidas.auth.commons.attribute.impl.LiteralStringAttributeValueMarshaller + + http://eidas.europa.eu/attributes/naturalperson/PlaceOfBirth + PlaceOfBirth + NaturalPerson + false + http://eidas.europa.eu/attributes/naturalperson + PlaceOfBirthType + eidas-natural + eu.eidas.auth.commons.attribute.impl.LiteralStringAttributeValueMarshaller + + http://eidas.europa.eu/attributes/naturalperson/CurrentAddress + CurrentAddress + NaturalPerson + false + http://eidas.europa.eu/attributes/naturalperson + CurrentAddressType + eidas-natural + eu.eidas.auth.commons.protocol.eidas.impl.CurrentAddressAttributeValueMarshaller + + http://eidas.europa.eu/attributes/naturalperson/Gender + Gender + NaturalPerson + false + http://eidas.europa.eu/attributes/naturalperson + GenderType + eidas-natural + eu.eidas.auth.commons.protocol.eidas.impl.GenderAttributeValueMarshaller + + http://eidas.europa.eu/attributes/legalperson/LegalPersonIdentifier + LegalPersonIdentifier + LegalPerson + true + true + http://eidas.europa.eu/attributes/legalperson + LegalPersonIdentifierType + eidas-legal + eu.eidas.auth.commons.attribute.impl.LiteralStringAttributeValueMarshaller + + http://eidas.europa.eu/attributes/legalperson/LegalName + LegalName + LegalPerson + true + true + http://eidas.europa.eu/attributes/legalperson + LegalNameType + eidas-legal + eu.eidas.auth.commons.attribute.impl.LiteralStringAttributeValueMarshaller + + http://eidas.europa.eu/attributes/legalperson/LegalPersonAddress + LegalAddress + LegalPerson + false + http://eidas.europa.eu/attributes/legalperson + LegalPersonAddressType + eidas-legal + eu.eidas.auth.commons.protocol.eidas.impl.LegalAddressAttributeValueMarshaller + + http://eidas.europa.eu/attributes/legalperson/VATRegistrationNumber + VATRegistration + LegalPerson + false + http://eidas.europa.eu/attributes/legalperson + VATRegistrationNumberType + eidas-legal + eu.eidas.auth.commons.attribute.impl.LiteralStringAttributeValueMarshaller + + http://eidas.europa.eu/attributes/legalperson/TaxReference + TaxReference + LegalPerson + false + http://eidas.europa.eu/attributes/legalperson + TaxReferenceType + eidas-legal + eu.eidas.auth.commons.attribute.impl.LiteralStringAttributeValueMarshaller + + http://eidas.europa.eu/attributes/legalperson/D-2012-17-EUIdentifier + D-2012-17-EUIdentifier + LegalPerson + false + http://eidas.europa.eu/attributes/legalperson + D-2012-17-EUIdentifierType + eidas-legal + eu.eidas.auth.commons.attribute.impl.LiteralStringAttributeValueMarshaller + + http://eidas.europa.eu/attributes/legalperson/LEI + LEI + LegalPerson + false + http://eidas.europa.eu/attributes/legalperson + LEIType + eidas-legal + eu.eidas.auth.commons.attribute.impl.LiteralStringAttributeValueMarshaller + + http://eidas.europa.eu/attributes/legalperson/EORI + EORI + LegalPerson + false + http://eidas.europa.eu/attributes/legalperson + EORIType + eidas-legal + eu.eidas.auth.commons.attribute.impl.LiteralStringAttributeValueMarshaller + + http://eidas.europa.eu/attributes/legalperson/SEED + SEED + LegalPerson + false + http://eidas.europa.eu/attributes/legalperson + SEEDType + eidas-legal + eu.eidas.auth.commons.attribute.impl.LiteralStringAttributeValueMarshaller + + http://eidas.europa.eu/attributes/legalperson/SIC + SIC + LegalPerson + false + http://eidas.europa.eu/attributes/legalperson + SICType + eidas-legal + eu.eidas.auth.commons.attribute.impl.LiteralStringAttributeValueMarshaller + + http://eidas.europa.eu/attributes/naturalperson/representative/PersonIdentifier + RepresentativePersonIdentifier + RepresentativeNaturalPerson + false + true + http://eidas.europa.eu/attributes/naturalperson/representative + PersonIdentifierType + eidas-natural + eu.eidas.auth.commons.attribute.impl.LiteralStringAttributeValueMarshaller + + http://eidas.europa.eu/attributes/naturalperson/representative/CurrentFamilyName + RepresentativeFamilyName + RepresentativeNaturalPerson + false + true + http://eidas.europa.eu/attributes/naturalperson/representative + CurrentFamilyNameType + eidas-reprentative-natural + eu.eidas.auth.commons.attribute.impl.LiteralStringAttributeValueMarshaller + + http://eidas.europa.eu/attributes/naturalperson/representative/CurrentGivenName + RepresentativeFirstName + RepresentativeNaturalPerson + false + true + http://eidas.europa.eu/attributes/naturalperson/representative + CurrentGivenNameType + eidas-reprentative-natural + eu.eidas.auth.commons.attribute.impl.LiteralStringAttributeValueMarshaller + + http://eidas.europa.eu/attributes/naturalperson/representative/DateOfBirth + RepresentativeDateOfBirth + RepresentativeNaturalPerson + false + http://eidas.europa.eu/attributes/naturalperson/representative + DateOfBirthType + eidas-reprentative-natural + eu.eidas.auth.commons.attribute.impl.DateTimeAttributeValueMarshaller + + http://eidas.europa.eu/attributes/naturalperson/representative/BirthName + RepresentativeBirthName + RepresentativeNaturalPerson + false + true + http://eidas.europa.eu/attributes/naturalperson/representative + BirthNameType + eidas-reprentative-natural + eu.eidas.auth.commons.attribute.impl.LiteralStringAttributeValueMarshaller + + http://eidas.europa.eu/attributes/naturalperson/representative/PlaceOfBirth + RepresentativePlaceOfBirth + RepresentativeNaturalPerson + false + http://eidas.europa.eu/attributes/naturalperson/representative + PlaceOfBirthType + eidas-reprentative-natural + eu.eidas.auth.commons.attribute.impl.LiteralStringAttributeValueMarshaller + + http://eidas.europa.eu/attributes/naturalperson/representative/CurrentAddress + RepresentativeCurrentAddress + RepresentativeNaturalPerson + false + http://eidas.europa.eu/attributes/naturalperson/representative + CurrentAddressType + eidas-reprentative-natural + eu.eidas.auth.commons.protocol.eidas.impl.RepvCurrentAddressAttributeValueMarshaller + + http://eidas.europa.eu/attributes/naturalperson/representative/Gender + RepresentativeGender + RepresentativeNaturalPerson + false + http://eidas.europa.eu/attributes/naturalperson/representative + GenderType + eidas-reprentative-natural + eu.eidas.auth.commons.protocol.eidas.impl.GenderAttributeValueMarshaller + + http://eidas.europa.eu/attributes/legalperson/representative/LegalPersonIdentifier + RepresentativeLegalPersonIdentifier + RepresentativeLegalPerson + false + true + http://eidas.europa.eu/attributes/legalperson/representative + LegalPersonIdentifierType + eidas-reprentative-legal + eu.eidas.auth.commons.attribute.impl.LiteralStringAttributeValueMarshaller + + http://eidas.europa.eu/attributes/legalperson/representative/LegalName + RepresentativeLegalName + RepresentativeLegalPerson + false + true + http://eidas.europa.eu/attributes/legalperson/representative + LegalNameType + eidas-reprentative-legal + eu.eidas.auth.commons.attribute.impl.LiteralStringAttributeValueMarshaller + + http://eidas.europa.eu/attributes/legalperson/representative/LegalPersonAddress + RepresentativeLegalAddress + RepresentativeLegalPerson + false + http://eidas.europa.eu/attributes/legalperson/representative + LegalPersonAddressType + eidas-reprentative-legal + eu.eidas.auth.commons.protocol.eidas.impl.RepvLegalAddressAttributeValueMarshaller + + http://eidas.europa.eu/attributes/legalperson/representative/VATRegistrationNumber + RepresentativeVATRegistration + RepresentativeLegalPerson + false + http://eidas.europa.eu/attributes/legalperson/representative + VATRegistrationNumberType + eidas-reprentative-legal + eu.eidas.auth.commons.attribute.impl.LiteralStringAttributeValueMarshaller + + http://eidas.europa.eu/attributes/legalperson/representative/TaxReference + RepresentativeTaxReference + RepresentativeLegalPerson + false + http://eidas.europa.eu/attributes/legalperson/representative + TaxReferenceType + eidas-reprentative-legal + eu.eidas.auth.commons.attribute.impl.LiteralStringAttributeValueMarshaller + + http://eidas.europa.eu/attributes/legalperson/representative/D-2012-17-EUIdentifier + RepresentativeD-2012-17-EUIdentifier + RepresentativeLegalPerson + false + http://eidas.europa.eu/attributes/legalperson/representative + D-2012-17-EUIdentifierType + eidas-reprentative-legal + eu.eidas.auth.commons.attribute.impl.LiteralStringAttributeValueMarshaller + + http://eidas.europa.eu/attributes/legalperson/representative/LEI + RepresentativeLEI + RepresentativeLegalPerson + false + http://eidas.europa.eu/attributes/legalperson/representative + LEIType + eidas-reprentative-legal + eu.eidas.auth.commons.attribute.impl.LiteralStringAttributeValueMarshaller + + http://eidas.europa.eu/attributes/legalperson/representative/EORI + RepresentativeEORI + RepresentativeLegalPerson + false + http://eidas.europa.eu/attributes/legalperson/representative + EORIType + eidas-reprentative-legal + eu.eidas.auth.commons.attribute.impl.LiteralStringAttributeValueMarshaller + + http://eidas.europa.eu/attributes/legalperson/representative/SEED + RepresentativeSEED + RepresentativeLegalPerson + false + http://eidas.europa.eu/attributes/legalperson/representative + SEEDType + eidas-reprentative-legal + eu.eidas.auth.commons.attribute.impl.LiteralStringAttributeValueMarshaller + + http://eidas.europa.eu/attributes/legalperson/representative/SIC + RepresentativeSIC + RepresentativeLegalPerson + false + http://eidas.europa.eu/attributes/legalperson/representative + SICType + eidas-reprentative-legal + eu.eidas.auth.commons.attribute.impl.LiteralStringAttributeValueMarshaller + + http://eidas.europa.eu/attributes/legalperson/representative/LegalPersonAddress + RepresentativeLegalAddress + RepresentativeLegalPerson + false + http://eidas.europa.eu/attributes/legalperson/representative + LegalPersonAddressType + eidas-reprentative-legal + eu.eidas.auth.commons.protocol.eidas.impl.RepvLegalAddressAttributeValueMarshaller + + http://eidas.europa.eu/attributes/legalperson/representative/VATRegistrationNumber + RepresentativeVATRegistration + RepresentativeLegalPerson + false + http://eidas.europa.eu/attributes/legalperson/representative + VATRegistrationNumberType + eidas-reprentative-legal + eu.eidas.auth.commons.attribute.impl.LiteralStringAttributeValueMarshaller + + + diff --git a/modules/authmodule-eIDAS-v2/src/main/resources/eidas_v2_auth.beans.xml b/modules/authmodule-eIDAS-v2/src/main/resources/eidas_v2_auth.beans.xml new file mode 100644 index 00000000..f37516f8 --- /dev/null +++ b/modules/authmodule-eIDAS-v2/src/main/resources/eidas_v2_auth.beans.xml @@ -0,0 +1,100 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/modules/authmodule-eIDAS-v2/src/main/resources/resources/xmldata/fakeIdL_IdL_template.xml b/modules/authmodule-eIDAS-v2/src/main/resources/resources/xmldata/fakeIdL_IdL_template.xml new file mode 100644 index 00000000..91b8e5e4 --- /dev/null +++ b/modules/authmodule-eIDAS-v2/src/main/resources/resources/xmldata/fakeIdL_IdL_template.xml @@ -0,0 +1,122 @@ + + + + + + urn:oasis:names:tc:SAML:1.0:cm:sender-vouches + + + + + wJO/bvDJjUysG0yARn7I6w== + urn:publicid:gv.at:baseid + + + XXXRúùd + XXXVàn Nisteĺrooy + + + 1969-02-13 + + + + + + + + + + + + + + + + + + + + + 4Y4FL09VhczsfYQgFPuycP8quJNZBAAu1R1rFXNodI2711B6BTMjAGQn6xuFWfd3/nyFav/MLTr/ + t2VazvANS4TRFxJAcWyIx7xbxCdzZr6gJ+FCmq4g5JPrQvt50v3JX+wKSYft1gHBOWlDn90Ia4Gm + P8MVuze21T+VVKM6ZklmS6d5PT1er/uYQFydGErmJ17xlSQG6Fi5xuftopBDyJxG1tL1KIebpLFg + gaM2EyuB1HxH8/+Mfqa4UgeqIH65 + + AQAB + + + + + + + + + + + + not(ancestor-or-self::pr:Identification) + + + + + + KEQEPY2O3Z3IRaISSSoRZVPzsHE= + + + + + gzGhjH1kdmPcPbgen0xojNIoJLk= + + + + + 06wqWHgplwpu3N5HMhzb6QC5NkXMO1z4N4oc1L6eDqwZlvFJ9X1XGW//QqviKO9oog3il7IzdfJwnjygR4trgGCIqx+JYCDHJCrG9l8zlxlSW0ZqfsygGXthutcQ1aeUpfO6jYuhnWOUywa8BgzukRtWT+AOJBQZPRYTb8IBmey+uAwlhFLni94eMOd81l+efCvkWi3jRajwsG8ZOaNxSZT3aEV5vj+32Aqtx2MPEVzQWtIA7GqZi+EzcdSdHQvHhg7UB+8kqbU70ENAJbEMTANFZYvLOJ0Om9KfDtPf/+R2TvTc360fNo9RnPl04pHPhCIjcGZhFZorBpUhXFwd2Q== + + + + MIIF3TCCBMWgAwIBAgIDByniMA0GCSqGSIb3DQEBBQUAMIGfMQswCQYDVQQGEwJBVDFIMEYGA1UECgw/QS1UcnVzdCBHZXMuIGYuIFNpY2hlcmhlaXRzc3lzdGVtZSBpbSBlbGVrdHIuIERhdGVudmVya2VociBHbWJIMSIwIAYDVQQLDBlhLXNpZ24tY29ycG9yYXRlLWxpZ2h0LTAyMSIwIAYDVQQDDBlhLXNpZ24tY29ycG9yYXRlLWxpZ2h0LTAyMB4XDTEwMDcyODExMzY0M1oXDTE1MDcyODExMzY0M1owgbYxCzAJBgNVBAYTAkFUMR4wHAYDVQQKDBVEYXRlbnNjaHV0emtvbW1pc3Npb24xIjAgBgNVBAsMGVN0YW1temFobHJlZ2lzdGVyYmVob2VyZGUxLjAsBgNVBAMMJVNpZ25hdHVyc2VydmljZSBEYXRlbnNjaHV0emtvbW1pc3Npb24xFTATBgNVBAUTDDMyNTkyODMyMzk5ODEcMBoGCSqGSIb3DQEJARYNZHNrQGRzay5ndi5hdDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAN+dBSEBGj2jUXIK1Mp3lVxc/Za+pJMiyKrX3G1ZxgX/ikx7D9scsPYMt473LlAWl9cmCbHbJK+PV2XNNdURLMUCIX+4vUNs2MHeDTQtX8BXjJFpwJYSoaRJQ39FVS/1r5sWcra9Hhdm7w5Gtx/2ukyDX0kdkxawkhP4EQEzi/SI+Fugn+WqgQ1nAdlbxb/dcBw5w1h9b3lmuwUf4z3ooQWUD2DgA/kKd1KejNR43mLUsmvSzevPxT9zs78pOR1OacB7IszTVJPXeOEaaNZHnnB/UeO3g8LEV/3OkXcUgcMkbIIiaBHlll71Pq0COj9kqjXoe7OrRjLY5i3KwOpa6TMCAwEAAaOCAgcwggIDMBMGA1UdIwQMMAqACEkcWDpP6A0DMH8GCCsGAQUFBwEBBHMwcTAnBggrBgEFBQcwAYYbaHR0cDovL29jc3AuYS10cnVzdC5hdC9vY3NwMEYGCCsGAQUFBzAChjpodHRwOi8vd3d3LmEtdHJ1c3QuYXQvY2VydHMvYS1zaWduLWNvcnBvcmF0ZS1saWdodC0wMmEuY3J0MFQGA1UdIARNMEswSQYGKigAEQESMD8wPQYIKwYBBQUHAgEWMWh0dHA6Ly93d3cuYS10cnVzdC5hdC9kb2NzL2NwL2Etc2lnbi1BbXRzc2lnbmF0dXIwgZ4GA1UdHwSBljCBkzCBkKCBjaCBioaBh2xkYXA6Ly9sZGFwLmEtdHJ1c3QuYXQvb3U9YS1zaWduLWNvcnBvcmF0ZS1saWdodC0wMixvPUEtVHJ1c3QsYz1BVD9jZXJ0aWZpY2F0ZXJldm9jYXRpb25saXN0P2Jhc2U/b2JqZWN0Y2xhc3M9ZWlkQ2VydGlmaWNhdGlvbkF1dGhvcml0eTARBgNVHQ4ECgQITAgOnhr0tbowDgYDVR0PAQH/BAQDAgSwMCAGA1UdEQQZMBeBFW1hcmN1cy5oaWxkQGRzay5ndi5hdDAJBgNVHRMEAjAAMA4GByooAAoBBwEEAwEB/zAUBgcqKAAKAQEBBAkMB0JTQi1EU0swDQYJKoZIhvcNAQEFBQADggEBAHTklnvPCH/bJSOlIPbLUEkSGuFHsektSZ8Vr22x/Yv7EzsxoQrJIiz2mQ2gQqFuExdWYxvsowjiSbiis9iUf1c0zscvDS3mIZxGs4M89XHsjHnIyb+Fuwnamw65QrFvM1tNB1ZMjxJ3x+YmHLHdtT3BEBcr3/NCRHd2S0HoBspNz9HVgJaZY1llR7poKBvnAc4g1i+QTvyVb00PtKxR9Lw/9ABInX/1pzpxqrPy7Ib2OP8z6dd3WHmIsCiSHUaj0Dxwwln6fYJjhxZ141SnbovlCLYtrsZLXoi9ljIqX4xO0PwMI2RfNc9cXxTRrRS6rEOvX7PpvgXiDXhp592Yyp4= + + + + + + + + + not(ancestor-or-self::dsig:Signature) + + + + + 8e7RjLnA4Mgltq5ruIJzheKGxu0= + + + + + + \ No newline at end of file diff --git a/modules/authmodule-eIDAS-v2/src/main/resources/szr_client/SZR-1.1.WSDL b/modules/authmodule-eIDAS-v2/src/main/resources/szr_client/SZR-1.1.WSDL new file mode 100644 index 00000000..3c34458d --- /dev/null +++ b/modules/authmodule-eIDAS-v2/src/main/resources/szr_client/SZR-1.1.WSDL @@ -0,0 +1,939 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + false + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/modules/authmodule-eIDAS-v2/src/main/resources/szr_client/SZR-1.WSDL b/modules/authmodule-eIDAS-v2/src/main/resources/szr_client/SZR-1.WSDL new file mode 100644 index 00000000..4ad2645a --- /dev/null +++ b/modules/authmodule-eIDAS-v2/src/main/resources/szr_client/SZR-1.WSDL @@ -0,0 +1,901 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + false + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/modules/authmodule-eIDAS-v2/src/main/resources/szr_client/SZR_v4.0.wsdl b/modules/authmodule-eIDAS-v2/src/main/resources/szr_client/SZR_v4.0.wsdl new file mode 100644 index 00000000..e7f296bd --- /dev/null +++ b/modules/authmodule-eIDAS-v2/src/main/resources/szr_client/SZR_v4.0.wsdl @@ -0,0 +1,441 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + false + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/modules/authmodule-eIDAS-v2/src/main/resources/szr_client/pvp1.xsd b/modules/authmodule-eIDAS-v2/src/main/resources/szr_client/pvp1.xsd new file mode 100644 index 00000000..09c0b1e3 --- /dev/null +++ b/modules/authmodule-eIDAS-v2/src/main/resources/szr_client/pvp1.xsd @@ -0,0 +1,133 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + additional authentication properties + + + + + + + + + + + + + + + + + + + + + + + additional authorization properties + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + additional principal attributes + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/modules/authmodule-eIDAS-v2/src/main/resources/szr_client/pvp19.xsd b/modules/authmodule-eIDAS-v2/src/main/resources/szr_client/pvp19.xsd new file mode 100644 index 00000000..596a2b99 --- /dev/null +++ b/modules/authmodule-eIDAS-v2/src/main/resources/szr_client/pvp19.xsd @@ -0,0 +1,133 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + additional authentication properties + + + + + + + + + + + + + + + + + + + + + + + additional authorization properties + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + additional principal attributes + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/modules/authmodule-eIDAS-v2/src/main/resources/szr_client/szr.xsd b/modules/authmodule-eIDAS-v2/src/main/resources/szr_client/szr.xsd new file mode 100644 index 00000000..85acfb65 --- /dev/null +++ b/modules/authmodule-eIDAS-v2/src/main/resources/szr_client/szr.xsd @@ -0,0 +1,388 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/modules/authmodule-eIDAS-v2/src/main/resources/szr_client/szr_ecdsa.xsd b/modules/authmodule-eIDAS-v2/src/main/resources/szr_client/szr_ecdsa.xsd new file mode 100644 index 00000000..87ee80be --- /dev/null +++ b/modules/authmodule-eIDAS-v2/src/main/resources/szr_client/szr_ecdsa.xsd @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/modules/authmodule-eIDAS-v2/src/main/resources/szr_client/szr_persondata.xsd b/modules/authmodule-eIDAS-v2/src/main/resources/szr_client/szr_persondata.xsd new file mode 100644 index 00000000..3c9ac932 --- /dev/null +++ b/modules/authmodule-eIDAS-v2/src/main/resources/szr_client/szr_persondata.xsd @@ -0,0 +1,54 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/modules/authmodule-eIDAS-v2/src/main/resources/szr_client/szr_pvp_sec.xsd b/modules/authmodule-eIDAS-v2/src/main/resources/szr_client/szr_pvp_sec.xsd new file mode 100644 index 00000000..5001c1b8 --- /dev/null +++ b/modules/authmodule-eIDAS-v2/src/main/resources/szr_client/szr_pvp_sec.xsd @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/modules/authmodule-eIDAS-v2/src/main/resources/szr_client/szr_v4.0-schemas.xml b/modules/authmodule-eIDAS-v2/src/main/resources/szr_client/szr_v4.0-schemas.xml new file mode 100644 index 00000000..d40efa45 --- /dev/null +++ b/modules/authmodule-eIDAS-v2/src/main/resources/szr_client/szr_v4.0-schemas.xml @@ -0,0 +1,54 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/modules/authmodule-eIDAS-v2/src/main/resources/szr_client/szr_v4.0-wsdl.xml b/modules/authmodule-eIDAS-v2/src/main/resources/szr_client/szr_v4.0-wsdl.xml new file mode 100644 index 00000000..f95c35f0 --- /dev/null +++ b/modules/authmodule-eIDAS-v2/src/main/resources/szr_client/szr_v4.0-wsdl.xml @@ -0,0 +1,10 @@ + + + + false + + + \ No newline at end of file diff --git a/modules/authmodule-eIDAS-v2/src/main/resources/szr_client/szr_v4.0.xsd b/modules/authmodule-eIDAS-v2/src/main/resources/szr_client/szr_v4.0.xsd new file mode 100644 index 00000000..2d25f2dc --- /dev/null +++ b/modules/authmodule-eIDAS-v2/src/main/resources/szr_client/szr_v4.0.xsd @@ -0,0 +1,443 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/modules/authmodule-eIDAS-v2/src/main/resources/szr_client/szr_xmldsig.xsd b/modules/authmodule-eIDAS-v2/src/main/resources/szr_client/szr_xmldsig.xsd new file mode 100644 index 00000000..96b50b40 --- /dev/null +++ b/modules/authmodule-eIDAS-v2/src/main/resources/szr_client/szr_xmldsig.xsd @@ -0,0 +1,31 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/modules/authmodule-eIDAS-v2/src/main/resources/templates/eidas_node_forward.html b/modules/authmodule-eIDAS-v2/src/main/resources/templates/eidas_node_forward.html new file mode 100644 index 00000000..186937d7 --- /dev/null +++ b/modules/authmodule-eIDAS-v2/src/main/resources/templates/eidas_node_forward.html @@ -0,0 +1,36 @@ + + + + + + + + +
Your login is being processed. Thank you for + waiting.
+ +
+
+ +
+ +
+ + + \ No newline at end of file diff --git a/modules/authmodule-eIDAS-v2/src/test/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/test/EidasAuthSpringResourceProviderTest.java b/modules/authmodule-eIDAS-v2/src/test/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/test/EidasAuthSpringResourceProviderTest.java new file mode 100644 index 00000000..aef290f5 --- /dev/null +++ b/modules/authmodule-eIDAS-v2/src/test/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/test/EidasAuthSpringResourceProviderTest.java @@ -0,0 +1,56 @@ +package at.asitplus.eidas.specific.modules.auth.eidas.v2.test; + +import java.io.IOException; +import java.io.InputStream; + +import org.apache.commons.io.IOUtils; +import org.junit.Assert; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.BlockJUnit4ClassRunner; +import org.springframework.core.io.Resource; + +import at.asitplus.eidas.specific.modules.auth.eidas.v2.EidasAuthenticationSpringResourceProvider; +import at.gv.egiz.eaaf.core.test.TestConstants; + + + +@RunWith(BlockJUnit4ClassRunner.class) +public class EidasAuthSpringResourceProviderTest { + + @Test + public void testSpringConfig() { + final EidasAuthenticationSpringResourceProvider test = + new EidasAuthenticationSpringResourceProvider(); + for (final Resource el : test.getResourcesToLoad()) { + try { + IOUtils.toByteArray(el.getInputStream()); + + } catch (final IOException e) { + Assert.fail("Ressouce: " + el.getFilename() + " not found"); + } + + } + + Assert.assertNotNull("no Name", test.getName()); + Assert.assertNull("Find package definitions", test.getPackagesToScan()); + + } + + @Test + public void testSpILoaderConfig() { + final InputStream el = this.getClass().getResourceAsStream(TestConstants.TEST_SPI_LOADER_PATH); + try { + final String spiFile = IOUtils.toString(el, "UTF-8"); + + Assert.assertEquals("Wrong classpath in SPI file", + EidasAuthenticationSpringResourceProvider.class.getName(), spiFile); + + + } catch (final IOException e) { + Assert.fail("Ressouce: " + TestConstants.TEST_SPI_LOADER_PATH + " not found"); + + } + } + +} diff --git a/modules/authmodule-eIDAS-v2/src/test/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/test/EidasAuthenticationModulImplTest.java b/modules/authmodule-eIDAS-v2/src/test/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/test/EidasAuthenticationModulImplTest.java new file mode 100644 index 00000000..86af87ad --- /dev/null +++ b/modules/authmodule-eIDAS-v2/src/test/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/test/EidasAuthenticationModulImplTest.java @@ -0,0 +1,121 @@ +package at.asitplus.eidas.specific.modules.auth.eidas.v2.test; + +import java.io.IOException; +import java.util.HashMap; +import java.util.Map; + +import org.apache.commons.lang3.RandomStringUtils; +import org.junit.Assert; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.core.io.Resource; +import org.springframework.core.io.ResourceLoader; +import org.springframework.test.annotation.DirtiesContext; +import org.springframework.test.annotation.DirtiesContext.ClassMode; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; + +import at.asitplus.eidas.specific.core.MsEidasNodeConstants; +import at.asitplus.eidas.specific.modules.auth.eidas.v2.EidasAuthenticationModulImpl; +import at.gv.egiz.eaaf.core.api.data.EaafConfigConstants; +import at.gv.egiz.eaaf.core.api.idp.IConfiguration; +import at.gv.egiz.eaaf.core.api.idp.process.ExecutionContext; +import at.gv.egiz.eaaf.core.impl.idp.auth.modules.ModuleRegistration; +import at.gv.egiz.eaaf.core.impl.idp.module.test.DummyConfiguration; +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; + +@RunWith(SpringJUnit4ClassRunner.class) +@ContextConfiguration(locations = { + "/SpringTest-context_tasks_test.xml", + "/SpringTest-context_basic_mapConfig.xml"}) +@DirtiesContext(classMode = ClassMode.BEFORE_CLASS) +public class EidasAuthenticationModulImplTest { + + @Autowired ModuleRegistration moduleReg; + @Autowired ResourceLoader loader; + + private final ExecutionContext executionContext = new ExecutionContextImpl(); + private DummySpConfiguration oaParam; + private TestRequestImpl pendingReq; + private EidasAuthenticationModulImpl authProcess = new EidasAuthenticationModulImpl(); + + /** + * jUnit class initializer. + * + */ + @BeforeClass + public static void classInitializer() throws IOException { + final String current = new java.io.File(".").toURI().toString(); + System.setProperty("eidas.ms.configuration", current + "../../basicConfig/default_config.properties"); + + } + + /** + * jUnit test set-up. + * + */ + @Before + public void initialize() { + Map configMap = new HashMap(); + configMap.put(EaafConfigConstants.SERVICE_UNIQUEIDENTIFIER, "http://test.com/test"); + IConfiguration basicConfig = new DummyConfiguration(); + oaParam = new DummySpConfiguration(configMap, basicConfig); + pendingReq = new TestRequestImpl(); + pendingReq.setSpConfig(oaParam); + } + + @Test + public void checkProcessDefinition() { + Assert.assertNotNull("AuthModule is null", authProcess); + Assert.assertNotNull("AuthModule process is null", authProcess.getProcessDefinitions()); + + for (String el : authProcess.getProcessDefinitions()) { + Resource res = loader.getResource(el); + Assert.assertTrue("AuthProcess description not extist", res.exists()); + + } + } + + @Test + public void countrySelected() throws Exception { + executionContext.put(MsEidasNodeConstants.REQ_PARAM_SELECTED_COUNTRY, RandomStringUtils.randomAlphanumeric(2)); + final String result = + moduleReg.selectProcess(executionContext, pendingReq); + Assert.assertNotNull("Process is null", result); + Assert.assertEquals("Process Id not match", "eIDASAuthentication_v2", result); + + } + + @Test + public void noCountryValid() throws Exception { + final String result = + moduleReg.selectProcess(executionContext, pendingReq); + + Assert.assertNull("Select wrong process", result); + + } + + @Test + public void selectCountryWrongType() throws Exception { + executionContext.put(MsEidasNodeConstants.REQ_PARAM_SELECTED_COUNTRY, 1); + final String result = + moduleReg.selectProcess(executionContext, pendingReq); + Assert.assertNull("Select wrong process", result); + + } + + @Test + public void selectCountryEmpty() throws Exception { + executionContext.put(MsEidasNodeConstants.REQ_PARAM_SELECTED_COUNTRY, ""); + final String result = + moduleReg.selectProcess(executionContext, pendingReq); + Assert.assertNull("Select wrong process", result); + + } + +} diff --git a/modules/authmodule-eIDAS-v2/src/test/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/test/EidasDataStoreTest.java b/modules/authmodule-eIDAS-v2/src/test/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/test/EidasDataStoreTest.java new file mode 100644 index 00000000..1051bd9f --- /dev/null +++ b/modules/authmodule-eIDAS-v2/src/test/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/test/EidasDataStoreTest.java @@ -0,0 +1,118 @@ +/* + * Copyright 2018 A-SIT Plus GmbH AT-specific eIDAS Connector has been developed + * in a cooperation between EGIZ, A-SIT Plus GmbH, A-SIT, and Graz University of + * Technology. + * + * Licensed under the EUPL, Version 1.2 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "License"); + * You may not use this work except in compliance with the License. You may + * obtain a copy of the License at: + * https://joinup.ec.europa.eu/news/understanding-eupl-v12 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" basis, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. The "NOTICE" text file + * is part of the distribution. Any derivative works that you distribute must + * include a readable copy of the "NOTICE" text file. +*/ + +package at.asitplus.eidas.specific.modules.auth.eidas.v2.test; + +//import java.security.MessageDigest; +// +//import org.apache.commons.lang3.StringUtils; +//import org.junit.Test; +//import org.junit.runner.RunWith; +//import org.springframework.beans.factory.annotation.Autowired; +//import org.springframework.test.context.ContextConfiguration; +//import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; +//import org.springframework.util.Base64Utils; +// +//import at.asitplus.eidas.specific.modules.auth.eidas.v2.exception.SQLiteServiceException; +//import at.asitplus.eidas.specific.modules.auth.eidas.v2.exception.eIDASAuthenticationException; +//import at.asitplus.eidas.specific.modules.auth.eidas.v2.utils.eIDASResponseUtils; +//import at.gv.egiz.eaaf.core.impl.data.Trible; +// +//@RunWith(SpringJUnit4ClassRunner.class) +//@ContextConfiguration("/SpringTest-context_basic_test.xml") +//public class EidasDataStoreTest { +// +// @Autowired +// private EidasDataStore dataStore; +// +// private static final String P1_TRANSID = "123456789"; +// private static final String P1_eIDASID = +// "DE/AT/121asdf1as5f1as6f1asd2f1asdf1asdf1asd23f1asdf1asdf4sd7fsdf1asdf1asd2f1asd56f7asdf4asdfasdf1"; +// +// private static final String P2_TRANSID = "987654321"; +// private static final String P2_eIDASID = +// "EE/AT/asfasfasdfasdfasdfasdfasdfasvafasdfasdfasdfasdfasdfasvascasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasd"; +// +// @Test +// public void dummyTest() { +// +// } +// +// @Test +// public void insertTestOne() throws SQLiteServiceException, eIDASAuthenticationException { +// Trible eidasId = eIDASResponseUtils.parseEidasPersonalIdentifier(P1_eIDASID); +// String ernbId = createHashFromUniqueId(eidasId.getThird()); +// dataStore.storeNationalId( +// P1_TRANSID, +// eidasId, +// ernbId); +// +// if (StringUtils.isEmpty(dataStore.getEidasRawNationalId(ernbId)) { +// && dataStore.getEidasRawNationalId(ernbId).equals(eidasId.getThird())) +// throw new SQLiteServiceException("No eIDAS RAW Id in SQLite DB", null); +// +// } +// +// if (StringUtils.isEmpty(dataStore.getErnbNationalId(eidasId)) { +// && dataStore.getErnbNationalId(eidasId).equals(ernbId)) +// throw new SQLiteServiceException("No ERnB Id in SQLite DB", null); +// } +// +// } +// +// @Test +// public void insertTestTwo() throws SQLiteServiceException, eIDASAuthenticationException { +// Trible eidasId = eIDASResponseUtils.parseEidasPersonalIdentifier(P2_eIDASID); +// String ernbId = createHashFromUniqueId(eidasId.getThird()); +// dataStore.storeNationalId( +// P2_TRANSID, +// eidasId, +// ernbId); +// +// if (StringUtils.isEmpty(dataStore.getEidasRawNationalId(ernbId)) { +// && dataStore.getEidasRawNationalId(ernbId).equals(eidasId.getThird())) +// throw new SQLiteServiceException("No eIDAS RAW Id in SQLite DB", null); +// +// } +// +// if (StringUtils.isEmpty(dataStore.getErnbNationalId(eidasId)) { +// && dataStore.getErnbNationalId(eidasId).equals(ernbId)) +// throw new SQLiteServiceException("No ERnB Id in SQLite DB", null); +// +// } +// +// } +// +// private String createHashFromUniqueId(String uniqueId) throws eIDASAuthenticationException { +// try { +// MessageDigest md = MessageDigest.getInstance("SHA-256"); +// byte[] hash = md.digest(uniqueId.getBytes("UTF-8")); +// String hashBase64 = new String(Base64Utils.encode(hash), "UTF-8").replaceAll("\r\n", ""); +// return hashBase64; +// +// } catch (Exception ex) { +// throw new eIDASAuthenticationException("internal.03", new Object[] {}, ex); +// +// } +// } +//} diff --git a/modules/authmodule-eIDAS-v2/src/test/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/test/EidasSignalServletTest.java b/modules/authmodule-eIDAS-v2/src/test/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/test/EidasSignalServletTest.java new file mode 100644 index 00000000..0d9d4fb8 --- /dev/null +++ b/modules/authmodule-eIDAS-v2/src/test/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/test/EidasSignalServletTest.java @@ -0,0 +1,244 @@ +package at.asitplus.eidas.specific.modules.auth.eidas.v2.test; + +import static at.asitplus.eidas.specific.core.MsEidasNodeConstants.PROP_CONFIG_SP_NEW_EID_MODE; + +import java.io.IOException; +import java.net.URISyntaxException; +import java.util.Arrays; +import java.util.Base64; +import java.util.HashMap; +import java.util.Map; + +import org.apache.commons.lang3.RandomStringUtils; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.powermock.core.classloader.annotations.PrepareForTest; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.mock.web.MockHttpServletRequest; +import org.springframework.mock.web.MockHttpServletResponse; +import org.springframework.test.annotation.DirtiesContext; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; +import org.springframework.web.context.request.RequestContextHolder; +import org.springframework.web.context.request.ServletRequestAttributes; +import org.springframework.web.servlet.config.annotation.EnableWebMvc; + +import at.asitplus.eidas.specific.core.test.config.dummy.MsConnectorDummyConfigMap; +import at.asitplus.eidas.specific.core.test.config.dummy.MsConnectorDummySpConfiguration; +import at.asitplus.eidas.specific.modules.auth.eidas.v2.Constants; +import at.asitplus.eidas.specific.modules.auth.eidas.v2.EidasSignalServlet; +import at.asitplus.eidas.specific.modules.auth.eidas.v2.tasks.CreateIdentityLinkTask; +import at.asitplus.eidas.specific.modules.auth.eidas.v2.test.dummy.DummySpecificCommunicationService; +import at.gv.egiz.eaaf.core.api.IRequestStorage; +import at.gv.egiz.eaaf.core.api.data.EaafConfigConstants; +import at.gv.egiz.eaaf.core.api.data.EaafConstants; +import at.gv.egiz.eaaf.core.api.storage.ITransactionStorage; +import at.gv.egiz.eaaf.core.exceptions.EaafException; +import at.gv.egiz.eaaf.core.exceptions.EaafStorageException; +import at.gv.egiz.eaaf.core.impl.idp.module.test.DummyProtocolAuthService; +import at.gv.egiz.eaaf.core.impl.idp.module.test.TestRequestImpl; +import at.gv.egiz.eaaf.core.impl.utils.Random; +import eu.eidas.auth.commons.EidasParameterKeys; +import eu.eidas.auth.commons.protocol.impl.AuthenticationResponse; +import eu.eidas.auth.commons.protocol.impl.AuthenticationResponse.Builder; +import eu.eidas.auth.commons.tx.BinaryLightToken; +import eu.eidas.specificcommunication.exception.SpecificCommunicationException; + +@RunWith(SpringJUnit4ClassRunner.class) +@PrepareForTest(CreateIdentityLinkTask.class) +@DirtiesContext(classMode = DirtiesContext.ClassMode.BEFORE_CLASS) +@ContextConfiguration(locations = { + "/SpringTest-context_tasks_test.xml", + "/SpringTest-context_basic_mapConfig.xml"}) +@EnableWebMvc +public class EidasSignalServletTest { + + @Autowired private MsConnectorDummyConfigMap basicConfig; + @Autowired private EidasSignalServlet controller; + @Autowired private IRequestStorage storage; + @Autowired private ITransactionStorage transStore; + @Autowired private DummyProtocolAuthService protAuthService; + @Autowired private DummySpecificCommunicationService connector; + + + private MockHttpServletRequest httpReq; + private MockHttpServletResponse httpResp; + private TestRequestImpl pendingReq; + private MsConnectorDummySpConfiguration oaParam; + + + /** + * jUnit test set-up. + */ + @Before + public void setUp() throws EaafStorageException, URISyntaxException { + httpReq = new MockHttpServletRequest("POST", "https://localhost/authhandler"); + httpResp = new MockHttpServletResponse(); + RequestContextHolder.resetRequestAttributes(); + RequestContextHolder.setRequestAttributes(new ServletRequestAttributes(httpReq, httpResp)); + + final Map spConfig = new HashMap<>(); + spConfig.put(EaafConfigConstants.SERVICE_UNIQUEIDENTIFIER, "testSp"); + spConfig.put("target", "urn:publicid:gv.at:cdid+XX"); + spConfig.put(PROP_CONFIG_SP_NEW_EID_MODE, "true"); + oaParam = new MsConnectorDummySpConfiguration(spConfig, basicConfig); + oaParam.setLoa(Arrays.asList(EaafConstants.EIDAS_LOA_HIGH)); + pendingReq = new TestRequestImpl(); + + pendingReq.setSpConfig(oaParam); + pendingReq.setPendingReqId(at.gv.egiz.eaaf.core.impl.utils.Random.nextProcessReferenceValue()); + pendingReq.setAuthUrl("http://test.com/"); + pendingReq.setTransactionId("avaasbav"); + pendingReq.setPiiTransactionId(RandomStringUtils.randomAlphanumeric(10)); + + connector.setiLightResponse(null); + + + } + + @Test + public void noResponsToken() throws IOException, EaafException { + //set-up + + //execute test + controller.restoreEidasAuthProcess(httpReq, httpResp); + + //validate state + Assert.assertNull("eIDAS response", httpReq.getAttribute(Constants.DATA_FULL_EIDAS_RESPONSE)); + Assert.assertNotNull("missing error", protAuthService.getException()); + Assert.assertEquals("Wrong errorId", "auth.26", + ((EaafException) protAuthService.getException()).getErrorId()); + + } + + @Test + public void unknownResponseToken() throws IOException, EaafException { + //set-up + httpReq.setParameter(EidasParameterKeys.TOKEN.toString(), + RandomStringUtils.randomAlphanumeric(10)); + + //execute test + controller.restoreEidasAuthProcess(httpReq, httpResp); + + //validate state + Assert.assertNull("eIDAS response", httpReq.getAttribute(Constants.DATA_FULL_EIDAS_RESPONSE)); + Assert.assertNotNull("missing error", protAuthService.getException()); + Assert.assertEquals("Wrong errorId", "auth.26", + ((EaafException) protAuthService.getException()).getErrorId()); + + } + + @Test + public void withRelayState() throws IOException, EaafException, SpecificCommunicationException { + //set-up + String relayState = RandomStringUtils.randomAlphanumeric(10); + pendingReq.setPendingReqId(relayState); + storage.storePendingRequest(pendingReq); + + Builder iLightResponse = new AuthenticationResponse.Builder(); + iLightResponse.id("_".concat(Random.nextHexRandom16())) + .issuer(RandomStringUtils.randomAlphabetic(10)) + .subject(RandomStringUtils.randomAlphabetic(10)) + .statusCode(Constants.SUCCESS_URI) + .inResponseTo("_".concat(Random.nextHexRandom16())) + .subjectNameIdFormat("afaf") + .relayState(relayState); + + AuthenticationResponse eidasResp = iLightResponse.build(); + BinaryLightToken token = connector.putResponse(eidasResp); + httpReq.setParameter(EidasParameterKeys.TOKEN.toString(), + Base64.getEncoder().encodeToString(token.getTokenBytes())); + + + //execute test + controller.restoreEidasAuthProcess(httpReq, httpResp); + + + //validate state + Assert.assertNotNull("eIDAS response", httpReq.getAttribute(Constants.DATA_FULL_EIDAS_RESPONSE)); + Assert.assertEquals("wrong eIDAS response", eidasResp, + httpReq.getAttribute(Constants.DATA_FULL_EIDAS_RESPONSE)); + + Assert.assertNotNull("missing error", protAuthService.getException()); + Assert.assertEquals("Wrong errorId", "PendingRequest object is not of type 'RequestImpl.class'", + ((EaafException) protAuthService.getException()).getErrorId()); + + } + + @Test + public void withOutRelayStateMissingPendingReq() throws IOException, EaafException, SpecificCommunicationException { + //set-up + String pendingReqId = RandomStringUtils.randomAlphanumeric(10); + pendingReq.setPendingReqId(pendingReqId); + storage.storePendingRequest(pendingReq); + + String inResponseTo = "_".concat(Random.nextHexRandom16()); + + Builder iLightResponse = new AuthenticationResponse.Builder(); + iLightResponse.id("_".concat(Random.nextHexRandom16())) + .issuer(RandomStringUtils.randomAlphabetic(10)) + .subject(RandomStringUtils.randomAlphabetic(10)) + .statusCode(Constants.SUCCESS_URI) + .inResponseTo(inResponseTo) + .subjectNameIdFormat("afaf"); + + AuthenticationResponse eidasResp = iLightResponse.build(); + BinaryLightToken token = connector.putResponse(eidasResp); + httpReq.setParameter(EidasParameterKeys.TOKEN.toString(), + Base64.getEncoder().encodeToString(token.getTokenBytes())); + + + //execute test + controller.restoreEidasAuthProcess(httpReq, httpResp); + + + //validate state + Assert.assertNull("eIDAS response", httpReq.getAttribute(Constants.DATA_FULL_EIDAS_RESPONSE)); + Assert.assertNotNull("missing error", protAuthService.getException()); + Assert.assertEquals("Wrong errorId", "auth.26", + ((EaafException) protAuthService.getException()).getErrorId()); + + } + + @Test + public void withInResponseToElement() throws IOException, EaafException, SpecificCommunicationException { + //set-up + String pendingReqId = RandomStringUtils.randomAlphanumeric(10); + pendingReq.setPendingReqId(pendingReqId); + storage.storePendingRequest(pendingReq); + + String inResponseTo = "_".concat(Random.nextHexRandom16()); + transStore.put(inResponseTo, pendingReqId, -1); + + Builder iLightResponse = new AuthenticationResponse.Builder(); + iLightResponse.id("_".concat(Random.nextHexRandom16())) + .issuer(RandomStringUtils.randomAlphabetic(10)) + .subject(RandomStringUtils.randomAlphabetic(10)) + .statusCode(Constants.SUCCESS_URI) + .inResponseTo(inResponseTo) + .subjectNameIdFormat("afaf"); + + AuthenticationResponse eidasResp = iLightResponse.build(); + BinaryLightToken token = connector.putResponse(eidasResp); + httpReq.setParameter(EidasParameterKeys.TOKEN.toString(), + Base64.getEncoder().encodeToString(token.getTokenBytes())); + + + //execute test + controller.restoreEidasAuthProcess(httpReq, httpResp); + + + //validate state + Assert.assertNotNull("eIDAS response", httpReq.getAttribute(Constants.DATA_FULL_EIDAS_RESPONSE)); + Assert.assertEquals("wrong eIDAS response", eidasResp, + httpReq.getAttribute(Constants.DATA_FULL_EIDAS_RESPONSE)); + + Assert.assertNotNull("missing error", protAuthService.getException()); + Assert.assertEquals("Wrong errorId", "PendingRequest object is not of type 'RequestImpl.class'", + ((EaafException) protAuthService.getException()).getErrorId()); + + } + +} diff --git a/modules/authmodule-eIDAS-v2/src/test/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/test/SzrClientTest.java b/modules/authmodule-eIDAS-v2/src/test/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/test/SzrClientTest.java new file mode 100644 index 00000000..4d9ae035 --- /dev/null +++ b/modules/authmodule-eIDAS-v2/src/test/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/test/SzrClientTest.java @@ -0,0 +1,439 @@ +/* + * Copyright 2018 A-SIT Plus GmbH + * AT-specific eIDAS Connector has been developed in a cooperation between EGIZ, + * A-SIT Plus GmbH, A-SIT, and Graz University of Technology. + * + * Licensed under the EUPL, Version 1.2 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "License"); + * You may not use this work except in compliance with the License. + * You may obtain a copy of the License at: + * https://joinup.ec.europa.eu/news/understanding-eupl-v12 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + */ + +package at.asitplus.eidas.specific.modules.auth.eidas.v2.test; + +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyList; +import static org.mockito.Mockito.when; + +import java.io.IOException; +import java.security.InvalidKeyException; +import java.security.MessageDigest; +import java.security.NoSuchProviderException; +import java.util.List; + +import javax.xml.bind.JAXBContext; +import javax.xml.bind.JAXBException; +import javax.xml.bind.Unmarshaller; +import javax.xml.parsers.ParserConfigurationException; +import javax.xml.ws.soap.SOAPFaultException; + +import org.apache.commons.io.IOUtils; +import org.apache.commons.lang3.RandomStringUtils; +import org.apache.commons.lang3.StringUtils; +import org.apache.cxf.binding.soap.SoapFault; +import org.joda.time.DateTime; +import org.jose4j.lang.JoseException; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Ignore; +import org.junit.Rule; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.test.annotation.DirtiesContext; +import org.springframework.test.annotation.DirtiesContext.ClassMode; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; +import org.springframework.util.Base64Utils; +import org.w3c.dom.Element; +import org.xml.sax.SAXException; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.JsonMappingException; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.github.skjolber.mockito.soap.SoapServiceRule; + +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.ErnbEidData; +import at.asitplus.eidas.specific.modules.auth.eidas.v2.exception.EidasSAuthenticationException; +import at.asitplus.eidas.specific.modules.auth.eidas.v2.exception.SzrCommunicationException; +import at.asitplus.eidas.specific.modules.auth.eidas.v2.szr.SzrClient; +import at.asitplus.eidas.specific.modules.auth.eidas.v2.utils.EidasResponseUtils; +import at.gv.e_government.reference.namespace.persondata._20020228.PersonNameType; +import at.gv.e_government.reference.namespace.persondata._20020228.PhysicalPersonType; +import at.gv.egiz.eaaf.core.api.data.EaafConstants; +import at.gv.egiz.eaaf.core.api.idp.auth.data.IIdentityLink; +import at.gv.egiz.eaaf.core.exceptions.EaafParserException; +import at.gv.egiz.eaaf.core.impl.data.Triple; +import at.gv.egiz.eaaf.core.impl.idp.auth.data.SimpleIdentityLinkAssertionParser; +import at.gv.egiz.eaaf.core.impl.utils.DomUtils; +import szrservices.GetBPKFromStammzahlEncryptedResponse; +import szrservices.GetBPKFromStammzahlEncryptedResponseType; +import szrservices.GetIdentityLinkEidasResponse; +import szrservices.IdentityLinkType; +import szrservices.PersonInfoType; +import szrservices.SZR; +import szrservices.SZRException_Exception; +import szrservices.SignContentEntry; +import szrservices.SignContentResponse; +import szrservices.SignContentResponseType; +import szrservices.TravelDocumentType; + +@RunWith(SpringJUnit4ClassRunner.class) +@ContextConfiguration(locations = { + "/SpringTest-context_tasks_test.xml", + "/SpringTest-context_basic_mapConfig.xml"}) +@DirtiesContext(classMode = ClassMode.AFTER_CLASS) +public class SzrClientTest { + private static final Logger log = LoggerFactory.getLogger(SzrClientTest.class); + + @Autowired SzrClient szrClient; + @Autowired MsConnectorDummyConfigMap basicConfig; + + private static ObjectMapper mapper = new ObjectMapper(); + + private static final String givenName = "Franz"; + private static final String familyName = "Mustermann"; + private static final String dateOfBirth = "1989-05-05"; + private static final String eIDASeID = "IS/AT/1234sdgsdfg56789ABCDEF"; + private static final String DUMMY_TARGET = EaafConstants.URN_PREFIX_CDID + "ZP"; + + private SZR szrMock = null; + ErnbEidData eidData = null; + + @Rule + public SoapServiceRule soap = SoapServiceRule.newInstance(); + + /** + * Initialize jUnit test. + */ + @Before + public void initializer() { + if (szrMock == null) { + szrMock = soap.mock(SZR.class, "http://localhost:1234/demoszr"); + + } + + eidData = new ErnbEidData(); + eidData.setFamilyName(familyName); + eidData.setGivenName(givenName); + eidData.setDateOfBirth(new DateTime()); + eidData.setCitizenCountryCode("IS"); + eidData.setPseudonym("1234sdgsdfg56789ABCDEF"); + + basicConfig.putConfigValue("eidas.ms.auth.eIDAS.szrclient.eidasbind.mds.inject", "false"); + + } + + + + + @Test + public void getStammzahlenEcryptedTest() throws JAXBException, SZRException_Exception, SzrCommunicationException { + final GetBPKFromStammzahlEncryptedResponse szrResponse = new GetBPKFromStammzahlEncryptedResponse(); + final GetBPKFromStammzahlEncryptedResponseType result1 = new GetBPKFromStammzahlEncryptedResponseType(); + szrResponse.getOut().add(result1); + + result1.setKey(RandomStringUtils.randomAlphanumeric(20)); + + // when(szrMock.getBPKFromStammzahlEncrypted(anyList())) + // .thenReturn(Arrays.asList(result1)); + when(szrMock.getStammzahlEncrypted(any(), any())).thenReturn(result1.getKey()); + + String stammzahlEncrypted = szrClient.getEncryptedStammzahl(new PersonInfoType()); + + Assert.assertEquals("bcBind not match", result1.getKey(), stammzahlEncrypted); + + when(szrMock.getStammzahlEncrypted(any(), any())).thenReturn(null); + try { + stammzahlEncrypted = szrClient.getEncryptedStammzahl(new PersonInfoType()); + } catch (SzrCommunicationException e) { + Assert.assertTrue("Not correct error", e.getMessage().contains("ernb.01")); + } + } + + @Test + public void getEidasBindRealSzrResponse() throws SZRException_Exception, SzrCommunicationException, IOException { + final SignContentResponse szrResponse = new SignContentResponse(); + final SignContentEntry result1 = new SignContentEntry(); + final SignContentResponseType content = new SignContentResponseType(); + content.getOut().add(result1); + szrResponse.setSignContentResponse(content); + + result1.setKey("bcBindReq"); + result1.setValue(IOUtils.toString(SzrClient.class.getResourceAsStream("/data/szr/signed_eidasBind.jws"))); + + when(szrMock.signContent(any(), anyList(), anyList())).thenReturn(content); + + final String bcBind = szrClient + .getEidsaBind(RandomStringUtils.randomAlphabetic(10), RandomStringUtils.randomAlphabetic(10), + RandomStringUtils.randomAlphabetic(10), eidData); + + Assert.assertNotNull("bcBind is null", bcBind); + Assert.assertEquals("bcBind not match", result1.getValue(), bcBind); + + } + + @Test + public void eidasBindNull() throws SZRException_Exception { + when(szrMock.signContent(any(), anyList(), anyList())).thenReturn(null); + + try { + szrClient + .getEidsaBind(RandomStringUtils.randomAlphabetic(10), RandomStringUtils.randomAlphabetic(10), + RandomStringUtils.randomAlphabetic(10), eidData); + } catch (SzrCommunicationException e) { + Assert.assertTrue("Not correct error", e.getMessage().contains("ernb.01")); + + } + } + + @Test + public void eidasBindInvalidResponse() throws SZRException_Exception { + final SignContentEntry result2 = new SignContentEntry(); + final SignContentResponseType content1 = new SignContentResponseType(); + content1.getOut().add(result2); + when(szrMock.signContent(any(), anyList(), anyList())).thenReturn(content1); + + try { + szrClient + .getEidsaBind(RandomStringUtils.randomAlphabetic(10), RandomStringUtils.randomAlphabetic(10), + RandomStringUtils.randomAlphabetic(10), eidData); + } catch (SzrCommunicationException e) { + Assert.assertTrue("Not correct error", e.getMessage().contains("ernb.01")); + + } + } + + public void eidasBindEmptyResponse() throws SZRException_Exception { + final SignContentEntry result2 = new SignContentEntry(); + final SignContentResponseType content1 = new SignContentResponseType(); + content1.getOut().add(result2); + result2.setKey("bcBindReq"); + result2.setValue(""); + when(szrMock.signContent(any(), anyList(), anyList())).thenReturn(content1); + + try { + szrClient + .getEidsaBind(RandomStringUtils.randomAlphabetic(10), RandomStringUtils.randomAlphabetic(10), + RandomStringUtils.randomAlphabetic(10), eidData); + } catch (SzrCommunicationException e) { + Assert.assertTrue("Not correct error", e.getMessage().contains("ernb.01")); + + } + } + + @Test + public void eidasBindValid() throws SZRException_Exception, SzrCommunicationException, JsonMappingException, + JsonProcessingException, JoseException { + final SignContentResponse szrResponse = new SignContentResponse(); + final SignContentEntry result1 = new SignContentEntry(); + final SignContentResponseType content = new SignContentResponseType(); + content.getOut().add(result1); + szrResponse.setSignContentResponse(content); + + result1.setKey("bcBindReq"); + result1.setValue(RandomStringUtils.randomAlphanumeric(100)); + + when(szrMock.signContent(any(), anyList(), anyList())).thenReturn(content); + + final String bcBind = szrClient + .getEidsaBind(RandomStringUtils.randomAlphabetic(10), RandomStringUtils.randomAlphabetic(10), + RandomStringUtils.randomAlphabetic(10), eidData); + + Assert.assertNotNull("bcBind is null", bcBind); + Assert.assertEquals("bcBind not match", result1.getValue(), bcBind); + + } + + @Test + public void eidasBindValidWithMds() throws SZRException_Exception, SzrCommunicationException, JoseException, + JsonMappingException, JsonProcessingException { + basicConfig.putConfigValue("eidas.ms.auth.eIDAS.szrclient.eidasbind.mds.inject", "true"); + + final SignContentResponse szrResponse = new SignContentResponse(); + final SignContentEntry result1 = new SignContentEntry(); + final SignContentResponseType content = new SignContentResponseType(); + content.getOut().add(result1); + szrResponse.setSignContentResponse(content); + + result1.setKey("bcBindReq"); + result1.setValue(RandomStringUtils.randomAlphanumeric(100)); + + when(szrMock.signContent(any(), anyList(), anyList())).thenReturn(content); + + final String bcBind = szrClient + .getEidsaBind(RandomStringUtils.randomAlphabetic(10), RandomStringUtils.randomAlphabetic(10), + RandomStringUtils.randomAlphabetic(10), eidData); + + Assert.assertNotNull("bcBind is null", bcBind); + Assert.assertEquals("bcBind not match", result1.getValue(), bcBind); + + } + + @Test + public void getIdentityLinkRawModeValidResponse() + throws SZRException_Exception, EaafParserException, NoSuchProviderException, IOException, InvalidKeyException, + EidasSAuthenticationException, JAXBException { + setSzrResponseIdentityLink("/data/szr/szr_resp_valid_1.xml"); + + try { + log.debug("Starting connecting SZR Gateway"); + final IdentityLinkType result = szrClient.getIdentityLinkInRawMode(getPersonInfo()); + + Assert.assertNotNull(result); + Assert.assertNotNull(result.getAssertion()); + + final IIdentityLink identityLink = new SimpleIdentityLinkAssertionParser((Element) result.getAssertion()) + .parseIdentityLink(); + Assert.assertNotNull(identityLink); + + System.out.println(identityLink.getSerializedSamlAssertion()); + + checkElement("Mustermann", identityLink.getFamilyName()); + checkElement("Hans", identityLink.getGivenName()); + checkElement("1989-05-05", identityLink.getDateOfBirth()); + checkElement("urn:publicid:gv.at:baseid", identityLink.getIdentificationType()); + checkElement("k+zDM1BVpN1WJO4x7ZQ3ng==", identityLink.getIdentificationValue()); + Assert.assertNotNull(identityLink.getSerializedSamlAssertion()); + Assert.assertNotNull(identityLink.getSamlAssertion()); + + } catch (final SzrCommunicationException e) { + Assert.fail(); + + } + + } + + @Test + public void getIdentityLinkRawModeErrorTravelerDocExists() + throws SZRException_Exception, EaafParserException, NoSuchProviderException, IOException, InvalidKeyException, + EidasSAuthenticationException, JAXBException, ParserConfigurationException, SAXException { + setSzrExceptionIdentityLink("/data/szr/szr_resp_error_travelerdocexists.xml"); + + try { + log.debug("Starting connecting SZR Gateway"); + szrClient.getIdentityLinkInRawMode(getPersonInfo()); + Assert.fail(); + + } catch (final SzrCommunicationException e) { + checkElement("ernb.02", e.getErrorId()); + Assert.assertNotNull(e.getCause()); + org.springframework.util.Assert.isInstanceOf(SOAPFaultException.class, e.getCause()); + Assert.assertNotNull(((SOAPFaultException) e.getCause()).getFault()); + checkElement("p344:F455", ((SOAPFaultException) e.getCause()).getFault().getFaultCode()); + checkElement( + "The travel document you sent to insert a person already exists for another person. " + "Either check the document or have the person altered accordingly", + ((SOAPFaultException) e.getCause()).getFault().getFaultString()); + + } + + } + + @Ignore + @Test + public void getBpkTest() throws SZRException_Exception, EidasSAuthenticationException { + final List bPK = szrClient.getBpk(getPersonInfo(), DUMMY_TARGET, basicConfig + .getBasicConfiguration(Constants.CONIG_PROPS_EIDAS_SZRCLIENT_PARAMS_VKZ, "no VKZ defined")); + + if (bPK.isEmpty()) { + throw new SzrCommunicationException("ernb.01", new Object[]{"bPK list is empty"}); + } + for (final String b : bPK) { + if (StringUtils.isEmpty(b)) { + throw new SzrCommunicationException("ernb.01", new Object[]{"bPK is null or empty"}); + } + } + + } + + private void checkElement(String expected, String value) { + Assert.assertNotNull(value); + Assert.assertEquals(expected, value); + + } + + private void setSzrResponseIdentityLink(String responseXmlPath) throws JAXBException, SZRException_Exception { + final JAXBContext jaxbContext = JAXBContext + .newInstance(szrservices.ObjectFactory.class, org.w3._2001._04.xmldsig_more.ObjectFactory.class, + org.w3._2000._09.xmldsig.ObjectFactory.class, + at.gv.e_government.reference.namespace.persondata._20020228.ObjectFactory.class); + final Unmarshaller jaxbUnmarshaller = jaxbContext.createUnmarshaller(); + final GetIdentityLinkEidasResponse szrResponse = (GetIdentityLinkEidasResponse) jaxbUnmarshaller + .unmarshal(this.getClass().getResourceAsStream(responseXmlPath)); + when(szrMock.getIdentityLinkEidas(any(PersonInfoType.class))).thenReturn(szrResponse.getGetIdentityLinkReturn()); + + } + + private void setSzrExceptionIdentityLink(String responseXmlPath) + throws JAXBException, ParserConfigurationException, SAXException, IOException, SZRException_Exception { + final Element detailerror = DomUtils.parseXmlNonValidating(this.getClass().getResourceAsStream(responseXmlPath)); + final javax.xml.namespace.QName qName = new javax.xml.namespace.QName("urn:SZRServices", "F455", "p344"); + final SoapFault fault = new SoapFault( + "The travel document you sent to insert a person already exists for another person. " + "Either check the document or have the person altered accordingly", + qName); + fault.setRole("urn:SZRServices"); + fault.setDetail(detailerror); + when(szrMock.getIdentityLinkEidas(any(PersonInfoType.class))).thenThrow(fault); + + } + + private String createHashFromUniqueId(String uniqueId) throws EidasSAuthenticationException { + try { + final MessageDigest md = MessageDigest.getInstance("SHA-256"); + final byte[] hash = md.digest(uniqueId.getBytes("UTF-8")); + final String hashBase64 = new String(Base64Utils.encode(hash), "UTF-8").replaceAll("\r\n", ""); + return hashBase64; + + } catch (final Exception ex) { + throw new EidasSAuthenticationException("internal.03", new Object[]{}, ex); + + } + } + + private PersonInfoType getPersonInfo() throws EidasSAuthenticationException { + final PersonInfoType personInfo = new PersonInfoType(); + final PersonNameType personName = new PersonNameType(); + final PhysicalPersonType naturalPerson = new PhysicalPersonType(); + final TravelDocumentType eDocument = new TravelDocumentType(); + + naturalPerson.setName(personName); + personInfo.setPerson(naturalPerson); + personInfo.setTravelDocument(eDocument); + + // parse some eID attributes + final Triple eIdentifier = EidasResponseUtils.parseEidasPersonalIdentifier(eIDASeID); + final String uniqueId = createHashFromUniqueId(eIdentifier.getThird()); + final String citizenCountry = eIdentifier.getFirst(); + + // person information + personName.setFamilyName(familyName); + personName.setGivenName(givenName); + naturalPerson.setDateOfBirth(dateOfBirth); + eDocument.setIssuingCountry(citizenCountry); + eDocument.setDocumentNumber(uniqueId); + + // eID document information + eDocument.setDocumentType(basicConfig + .getBasicConfiguration(Constants.CONIG_PROPS_EIDAS_SZRCLIENT_PARAMS_EDOCUMENTTYPE, + Constants.SZR_CONSTANTS_DEFAULT_DOCUMENT_TYPE)); + + return personInfo; + } + +} diff --git a/modules/authmodule-eIDAS-v2/src/test/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/test/SzrClientTestProduction.java b/modules/authmodule-eIDAS-v2/src/test/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/test/SzrClientTestProduction.java new file mode 100644 index 00000000..1e7ff369 --- /dev/null +++ b/modules/authmodule-eIDAS-v2/src/test/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/test/SzrClientTestProduction.java @@ -0,0 +1,236 @@ +/* + * Copyright 2018 A-SIT Plus GmbH + * AT-specific eIDAS Connector has been developed in a cooperation between EGIZ, + * A-SIT Plus GmbH, A-SIT, and Graz University of Technology. + * + * Licensed under the EUPL, Version 1.2 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "License"); + * You may not use this work except in compliance with the License. + * You may obtain a copy of the License at: + * https://joinup.ec.europa.eu/news/understanding-eupl-v12 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. +*/ + +package at.asitplus.eidas.specific.modules.auth.eidas.v2.test; + +import java.io.IOException; +import java.security.InvalidKeyException; +import java.security.MessageDigest; +import java.security.NoSuchProviderException; +import java.util.List; + +import org.apache.commons.lang3.RandomStringUtils; +import org.apache.commons.lang3.StringUtils; +import org.bouncycastle.util.encoders.Base64; +import org.joda.time.DateTime; +import org.junit.Assert; +import org.junit.Ignore; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.test.annotation.IfProfileValue; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.TestPropertySource; +import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; +import org.springframework.util.Base64Utils; +import org.w3c.dom.Element; + +import at.asitplus.eidas.specific.modules.auth.eidas.v2.Constants; +import at.asitplus.eidas.specific.modules.auth.eidas.v2.dao.ErnbEidData; +import at.asitplus.eidas.specific.modules.auth.eidas.v2.exception.EidasSAuthenticationException; +import at.asitplus.eidas.specific.modules.auth.eidas.v2.exception.SzrCommunicationException; +import at.asitplus.eidas.specific.modules.auth.eidas.v2.szr.SzrClient; +import at.asitplus.eidas.specific.modules.auth.eidas.v2.utils.EidasResponseUtils; +import at.gv.e_government.reference.namespace.persondata._20020228.PersonNameType; +import at.gv.e_government.reference.namespace.persondata._20020228.PhysicalPersonType; +import at.gv.egiz.eaaf.core.api.data.EaafConstants; +import at.gv.egiz.eaaf.core.api.idp.IConfiguration; +import at.gv.egiz.eaaf.core.api.idp.auth.data.IIdentityLink; +import at.gv.egiz.eaaf.core.exceptions.EaafParserException; +import at.gv.egiz.eaaf.core.impl.data.Triple; +import at.gv.egiz.eaaf.core.impl.idp.auth.data.SimpleIdentityLinkAssertionParser; +import szrservices.IdentityLinkType; +import szrservices.PersonInfoType; +import szrservices.SZRException_Exception; +import szrservices.TravelDocumentType; + + +@IfProfileValue(name = "spring.profiles.active", value = "devEnvironment") +@RunWith(SpringJUnit4ClassRunner.class) +@ContextConfiguration(locations = { + "/SpringTest-context_tasks_test.xml", + "/SpringTest-context_basic_realConfig.xml"}) +@TestPropertySource(locations = { + //"classpath:/application.properties", + "file:/home/tlenz/Projekte/config/ms_connector/default_config.properties", + }) +public class SzrClientTestProduction { + private static final Logger log = LoggerFactory.getLogger(SzrClientTestProduction.class); + + @Autowired + SzrClient szrClient; + @Autowired + IConfiguration basicConfig; + + private static final String givenName = "Franz"; + private static final String familyName = "Mustermann"; + // private static final String dateOfBirth = "1989-05-05"; + private static final String dateOfBirth = "1989-05-04"; + private static final String eIDASeID = "IS/AT/1234ffgsdfg56789ABCDEF"; + + private static final String DUMMY_TARGET = EaafConstants.URN_PREFIX_CDID + "ZP"; + + @Test + public void dummyTest() { + + } + + @Test + public void getVsz() throws SzrCommunicationException, EidasSAuthenticationException { + String vsz = szrClient.getEncryptedStammzahl(getPersonInfo()); + Assert.assertNotNull("vsz", vsz); + + } + + @Test + public void getEidasBind() throws SzrCommunicationException, EidasSAuthenticationException { + String vsz = RandomStringUtils.randomAlphanumeric(10); + String bindingPubKey = Base64.toBase64String(RandomStringUtils.random(20).getBytes()); + String eidStatus = "urn:eidgvat:eid.status.eidas"; + ErnbEidData eidData = new ErnbEidData(); + eidData.setFamilyName(familyName); + eidData.setGivenName(givenName); + eidData.setDateOfBirth(new DateTime()); + eidData.setCitizenCountryCode("IS"); + eidData.setPseudonym("1234sdgsdfg56789ABCDEF"); + + + String eidasBind = szrClient.getEidsaBind(vsz, bindingPubKey, eidStatus, eidData); + + Assert.assertNotNull("eidasBind", eidasBind); + + } + + + @Test + public void getIdentityLinkRawMode() throws SZRException_Exception, EaafParserException, + NoSuchProviderException, IOException, InvalidKeyException, EidasSAuthenticationException { + log.debug("Starting connecting SZR Gateway"); + final IdentityLinkType result = szrClient.getIdentityLinkInRawMode( + getPersonInfo()); + + final Element idlFromSzr = (Element) result.getAssertion(); + final IIdentityLink identityLink = new SimpleIdentityLinkAssertionParser(idlFromSzr).parseIdentityLink(); + + if (identityLink == null) { + throw new SzrCommunicationException("ernb.00", new Object[] { "NO IDL object" }); + } + + System.out.println(identityLink.getSerializedSamlAssertion()); + + if (StringUtils.isEmpty(identityLink.getFamilyName())) { + throw new SzrCommunicationException("ernb.00", new Object[] { "NO FamilyName from IDL" }); + } + + if (StringUtils.isEmpty(identityLink.getGivenName())) { + throw new SzrCommunicationException("ernb.00", new Object[] { "NO GivenName from IDL" }); + } + + if (StringUtils.isEmpty(identityLink.getDateOfBirth())) { + throw new SzrCommunicationException("ernb.00", new Object[] { "NO DateOfBirthName from IDL" }); + } + + if (StringUtils.isEmpty(identityLink.getIdentificationType())) { + throw new SzrCommunicationException("ernb.00", new Object[] { "NO baseIdType from IDL" }); + } + + if (StringUtils.isEmpty(identityLink.getIdentificationValue())) { + throw new SzrCommunicationException("ernb.00", new Object[] { "NO baseId from IDL" }); + } + + if (StringUtils.isEmpty(identityLink.getSerializedSamlAssertion())) { + throw new SzrCommunicationException("ernb.00", new Object[] { "NO serialized IDL" }); + } + + if (identityLink.getSamlAssertion() == null) { + throw new SzrCommunicationException("ernb.00", new Object[] { "NO raw IDL" }); + } + + } + + + @Ignore + @Test + public void getBpkTest() throws SZRException_Exception, EidasSAuthenticationException { + final List bPK = szrClient.getBpk(getPersonInfo(), DUMMY_TARGET, + basicConfig.getBasicConfiguration( + Constants.CONIG_PROPS_EIDAS_SZRCLIENT_PARAMS_VKZ, + "no VKZ defined")); + + if (bPK.isEmpty()) { + throw new SzrCommunicationException("ernb.01", new Object[]{"bPK list is empty"}); + } + for (String b : bPK) { + if (StringUtils.isEmpty(b)) { + throw new SzrCommunicationException("ernb.01", new Object[]{"bPK is null or empty"}); + } + } + + } + + private String createHashFromUniqueId(String uniqueId) throws EidasSAuthenticationException { + try { + final MessageDigest md = MessageDigest.getInstance("SHA-256"); + final byte[] hash = md.digest(uniqueId.getBytes("UTF-8")); + final String hashBase64 = new String(Base64Utils.encode(hash), "UTF-8").replaceAll("\r\n", ""); + return hashBase64; + + } catch (final Exception ex) { + throw new EidasSAuthenticationException("internal.03", new Object[] {}, ex); + + } + } + + private PersonInfoType getPersonInfo() throws EidasSAuthenticationException { + final PersonInfoType personInfo = new PersonInfoType(); + final PersonNameType personName = new PersonNameType(); + final PhysicalPersonType naturalPerson = new PhysicalPersonType(); + final TravelDocumentType eDocument = new TravelDocumentType(); + + naturalPerson.setName(personName); + personInfo.setPerson(naturalPerson); + personInfo.setTravelDocument(eDocument); + + // parse some eID attributes + final Triple eIdentifier = + EidasResponseUtils.parseEidasPersonalIdentifier(eIDASeID); + final String uniqueId = createHashFromUniqueId(eIdentifier.getThird()); + final String citizenCountry = eIdentifier.getFirst(); + + // person information + personName.setFamilyName(familyName); + personName.setGivenName(givenName); + naturalPerson.setDateOfBirth(dateOfBirth); + eDocument.setIssuingCountry(citizenCountry); + eDocument.setDocumentNumber(uniqueId); + + // eID document information + eDocument.setDocumentType(basicConfig.getBasicConfiguration( + Constants.CONIG_PROPS_EIDAS_SZRCLIENT_PARAMS_EDOCUMENTTYPE, + Constants.SZR_CONSTANTS_DEFAULT_DOCUMENT_TYPE)); + + return personInfo; + } +} diff --git a/modules/authmodule-eIDAS-v2/src/test/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/test/dummy/DummySpecificCommunicationService.java b/modules/authmodule-eIDAS-v2/src/test/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/test/dummy/DummySpecificCommunicationService.java new file mode 100644 index 00000000..78294047 --- /dev/null +++ b/modules/authmodule-eIDAS-v2/src/test/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/test/dummy/DummySpecificCommunicationService.java @@ -0,0 +1,66 @@ +package at.asitplus.eidas.specific.modules.auth.eidas.v2.test.dummy; + +import java.util.Collection; + +import eu.eidas.auth.commons.attribute.AttributeDefinition; +import eu.eidas.auth.commons.light.ILightRequest; +import eu.eidas.auth.commons.light.ILightResponse; +import eu.eidas.auth.commons.tx.BinaryLightToken; +import eu.eidas.specificcommunication.BinaryLightTokenHelper; +import eu.eidas.specificcommunication.exception.SpecificCommunicationException; +import eu.eidas.specificcommunication.protocol.SpecificCommunicationService; +import lombok.Setter; + +public class DummySpecificCommunicationService implements SpecificCommunicationService { + + private ILightRequest lightRequest; + private ILightResponse lightResponse; + + @Setter + private SpecificCommunicationException error; + + @Override + public BinaryLightToken putRequest(ILightRequest lightRequest) throws SpecificCommunicationException { + this.lightRequest = lightRequest; + return BinaryLightTokenHelper.createBinaryLightToken("Test", "TestSecret", "SHA-256"); + } + + @Override + public ILightRequest getAndRemoveRequest(String tokenBase64, Collection> registry) + throws SpecificCommunicationException { + if (error != null) { + throw error; + + } + return lightRequest; + } + + @Override + public BinaryLightToken putResponse(ILightResponse lightResponse) throws SpecificCommunicationException { + this.lightResponse = lightResponse; + return BinaryLightTokenHelper.createBinaryLightToken("Test", "TestSecret", "SHA-256"); + } + + @Override + public ILightResponse getAndRemoveResponse(String tokenBase64, Collection> registry) + throws SpecificCommunicationException { + return lightResponse; + } + + public ILightRequest getiLightRequest() { + return lightRequest; + } + + public void setiLightRequest(ILightRequest lightReques) { + this.lightRequest = lightReques; + } + + public ILightResponse getiLightResponse() { + return lightResponse; + } + + public void setiLightResponse(ILightResponse lightResponse) { + this.lightResponse = lightResponse; + } + +} diff --git a/modules/authmodule-eIDAS-v2/src/test/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/test/tasks/CreateIdentityLinkTaskEidNewTest.java b/modules/authmodule-eIDAS-v2/src/test/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/test/tasks/CreateIdentityLinkTaskEidNewTest.java new file mode 100644 index 00000000..e1a29137 --- /dev/null +++ b/modules/authmodule-eIDAS-v2/src/test/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/test/tasks/CreateIdentityLinkTaskEidNewTest.java @@ -0,0 +1,491 @@ +package at.asitplus.eidas.specific.modules.auth.eidas.v2.test.tasks; + +import static at.asitplus.eidas.specific.core.MsEidasNodeConstants.PROP_CONFIG_SP_NEW_EID_MODE; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.powermock.api.mockito.PowerMockito.when; + +import java.net.URISyntaxException; +import java.security.KeyStore; +import java.security.Provider; +import java.security.cert.X509Certificate; +import java.util.Arrays; +import java.util.Collections; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; + +import org.apache.commons.lang3.RandomStringUtils; +import org.jetbrains.annotations.NotNull; +import org.jose4j.jwa.AlgorithmConstraints; +import org.jose4j.jwa.AlgorithmConstraints.ConstraintType; +import org.jose4j.jws.AlgorithmIdentifiers; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.ArgumentCaptor; +import org.powermock.core.classloader.annotations.PrepareForTest; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.mock.web.MockHttpServletRequest; +import org.springframework.mock.web.MockHttpServletResponse; +import org.springframework.test.annotation.DirtiesContext; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; +import org.springframework.web.context.request.RequestContextHolder; +import org.springframework.web.context.request.ServletRequestAttributes; + +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.github.skjolber.mockito.soap.SoapServiceRule; + +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.exception.SzrCommunicationException; +import at.asitplus.eidas.specific.modules.auth.eidas.v2.service.EidasAttributeRegistry; +import at.asitplus.eidas.specific.modules.auth.eidas.v2.tasks.CreateIdentityLinkTask; +import at.asitplus.eidas.specific.modules.auth.eidas.v2.utils.JoseUtils; +import at.asitplus.eidas.specific.modules.auth.eidas.v2.utils.JoseUtils.JwsResult; +import at.gv.egiz.eaaf.core.api.IRequest; +import at.gv.egiz.eaaf.core.api.IRequestStorage; +import at.gv.egiz.eaaf.core.api.data.EaafConfigConstants; +import at.gv.egiz.eaaf.core.api.data.EaafConstants; +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.EaafException; +import at.gv.egiz.eaaf.core.exceptions.EaafStorageException; +import at.gv.egiz.eaaf.core.exceptions.TaskExecutionException; +import at.gv.egiz.eaaf.core.impl.credential.EaafKeyStoreFactory; +import at.gv.egiz.eaaf.core.impl.credential.EaafKeyStoreUtils; +import at.gv.egiz.eaaf.core.impl.credential.KeyStoreConfiguration; +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.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 at.gv.egiz.eaaf.core.impl.utils.Random; +import eu.eidas.auth.commons.attribute.AttributeDefinition; +import eu.eidas.auth.commons.attribute.ImmutableAttributeMap; +import eu.eidas.auth.commons.attribute.ImmutableAttributeMap.Builder; +import eu.eidas.auth.commons.protocol.impl.AuthenticationResponse; +import lombok.val; +import szrservices.JwsHeaderParam; +import szrservices.PersonInfoType; +import szrservices.SZR; +import szrservices.SignContentEntry; +import szrservices.SignContentResponseType; + +@RunWith(SpringJUnit4ClassRunner.class) +@PrepareForTest(CreateIdentityLinkTask.class) +@DirtiesContext(classMode = DirtiesContext.ClassMode.BEFORE_CLASS) +@ContextConfiguration(locations = { + "/SpringTest-context_tasks_test.xml", + "/SpringTest-context_basic_mapConfig.xml"}) +public class CreateIdentityLinkTaskEidNewTest { + + @Autowired(required = true) + private CreateIdentityLinkTask task; + + @Autowired(required = true) + private MsConnectorDummyConfigMap basicConfig; + @Autowired + protected EidasAttributeRegistry attrRegistry; + + @Autowired + EaafKeyStoreFactory keyStoreFactory; + + @Autowired + private IRequestStorage requestStorage; + + final ExecutionContext executionContext = new ExecutionContextImpl(); + private MockHttpServletRequest httpReq; + private MockHttpServletResponse httpResp; + private TestRequestImpl pendingReq; + private DummySpConfiguration oaParam; + private SZR szrMock; + + private static final String PW = "f/+saJBc3a}*/T^s"; + private static final String ALIAS = "connectorkeypair"; + + private static final List BINDING_AUTH_ALGORITHM_WHITELIST_SIGNING = Collections.unmodifiableList(Arrays + .asList(AlgorithmIdentifiers.ECDSA_USING_P256_CURVE_AND_SHA256, + AlgorithmIdentifiers.ECDSA_USING_P521_CURVE_AND_SHA512, AlgorithmIdentifiers.RSA_PSS_USING_SHA256, + AlgorithmIdentifiers.RSA_PSS_USING_SHA512)); + + private static ObjectMapper mapper = new ObjectMapper(); + + private AuthenticationResponse response; + + @Rule + public final SoapServiceRule soap = SoapServiceRule.newInstance(); + + /** + * jUnit test set-up. + */ + @Before + public void setUp() throws EaafStorageException, URISyntaxException { + + httpReq = new MockHttpServletRequest("POST", "https://localhost/authhandler"); + httpResp = new MockHttpServletResponse(); + RequestContextHolder.resetRequestAttributes(); + RequestContextHolder.setRequestAttributes(new ServletRequestAttributes(httpReq, httpResp)); + + basicConfig.putConfigValue("eidas.ms.auth.eIDAS.szrclient.debug.useDummySolution", "false"); + + final Map spConfig = new HashMap<>(); + spConfig.put(EaafConfigConstants.SERVICE_UNIQUEIDENTIFIER, "testSp"); + spConfig.put("target", "urn:publicid:gv.at:cdid+XX"); + spConfig.put(PROP_CONFIG_SP_NEW_EID_MODE, "true"); + oaParam = new DummySpConfiguration(spConfig, basicConfig); + pendingReq = new TestRequestImpl(); + + response = buildDummyAuthResponse(false); + pendingReq.getSessionData(AuthProcessDataWrapper.class) + .setGenericDataToSession(Constants.DATA_FULL_EIDAS_RESPONSE, response); + + + pendingReq.setSpConfig(oaParam); + pendingReq.setPendingReqId(at.gv.egiz.eaaf.core.impl.utils.Random.nextProcessReferenceValue()); + pendingReq.setAuthUrl("http://test.com/"); + pendingReq.setTransactionId("avaasbav"); + pendingReq.setPiiTransactionId(RandomStringUtils.randomAlphanumeric(10)); + + executionContext.put(MsEidasNodeConstants.REQ_PARAM_SELECTED_COUNTRY, "XX"); + executionContext.put(EaafConstants.PROCESS_ENGINE_REQUIRES_NO_POSTAUTH_REDIRECT, true); + + szrMock = soap.mock(SZR.class, "http://localhost:1234/demoszr"); + } + + @Test + public void successfulProcessWithDeInfos() throws Exception { + //initialize test + response = buildDummyAuthResponse(true); + pendingReq.getSessionData(AuthProcessDataWrapper.class) + .setGenericDataToSession(Constants.DATA_FULL_EIDAS_RESPONSE, response); + + String vsz = RandomStringUtils.randomNumeric(10); + when(szrMock, "getStammzahlEncrypted", any(), any()).thenReturn(vsz); + val signContentResp = new SignContentResponseType(); + final SignContentEntry signContentEntry = new SignContentEntry(); + signContentEntry.setValue(RandomStringUtils.randomAlphanumeric(10)); + signContentResp.getOut().add(signContentEntry); + when(szrMock, "signContent", any(), any(), any()).thenReturn(signContentResp); + + String randomTestSp = RandomStringUtils.randomAlphabetic(10); + pendingReq.setRawDataToTransaction(MsEidasNodeConstants.DATA_REQUESTERID, randomTestSp); + + //perform test + task.execute(pendingReq, executionContext); + + //validate state + // check if pendingRequest was stored + IRequest storedPendingReq = requestStorage.getPendingRequest(pendingReq.getPendingRequestId()); + Assert.assertNotNull("pendingReq not stored", storedPendingReq); + + //check data in session + final AuthProcessDataWrapper authProcessData = storedPendingReq.getSessionData(AuthProcessDataWrapper.class); + Assert.assertNotNull("AuthProcessData", authProcessData); + Assert.assertNotNull("eidasBind", authProcessData.getGenericDataFromSession(MsEidasNodeConstants.AUTH_DATA_EIDAS_BIND, String.class)); + + String authBlock = authProcessData.getGenericDataFromSession(MsEidasNodeConstants.AUTH_DATA_SZR_AUTHBLOCK, String.class); + Assert.assertNotNull("AuthBlock", authBlock); + + Assert.assertTrue("EID process", authProcessData.isEidProcess()); + Assert.assertTrue("foreigner process", authProcessData.isForeigner()); + Assert.assertEquals("EID-ISSUING_NATION", "LU", + authProcessData.getGenericDataFromSession(PvpAttributeDefinitions.EID_ISSUING_NATION_NAME, String.class)); + Assert.assertNotNull("LoA is null", authProcessData.getQaaLevel()); + Assert.assertEquals("LoA", response.getLevelOfAssurance(), + authProcessData.getQaaLevel()); + + + // check authblock signature + final AlgorithmConstraints constraints = new AlgorithmConstraints(ConstraintType.PERMIT, + BINDING_AUTH_ALGORITHM_WHITELIST_SIGNING.toArray(new String[BINDING_AUTH_ALGORITHM_WHITELIST_SIGNING.size()])); + Pair keyStore = getKeyStore(); + X509Certificate[] trustedCerts = EaafKeyStoreUtils + .getPrivateKeyAndCertificates(keyStore.getFirst(), ALIAS, PW.toCharArray(), true, "junit").getSecond(); + JwsResult result = JoseUtils.validateSignature(authBlock, Arrays.asList(trustedCerts), constraints); + Assert.assertTrue("AuthBlock not valid", result.isValid()); + JsonNode authBlockJson = mapper.readTree(result.getPayLoad()); + Assert.assertNotNull("deserialized AuthBlock", authBlockJson); + + Assert.assertNotNull("no piiTransactionId in pendingRequesdt", + storedPendingReq.getUniquePiiTransactionIdentifier()); + Assert.assertEquals("piiTransactionId", storedPendingReq.getUniquePiiTransactionIdentifier(), + authBlockJson.get("piiTransactionId").asText()); + Assert.assertEquals("appId", randomTestSp, authBlockJson.get("appId").asText()); + Assert.assertFalse("'challenge' is null", authBlockJson.get("challenge").asText().isEmpty()); + Assert.assertFalse("'timestamp' is null", authBlockJson.get("timestamp").asText().isEmpty()); + Assert.assertFalse("binding pubKey", authBlockJson.has("bindingPublicKey")); + + + // check vsz request + ArgumentCaptor argument4 = ArgumentCaptor.forClass(PersonInfoType.class); + ArgumentCaptor argument5 = ArgumentCaptor.forClass(Boolean.class); + verify(szrMock, times(1)).getStammzahlEncrypted(argument4.capture(), argument5.capture()); + + Boolean param5 = argument5.getValue(); + Assert.assertTrue("insertERnP flag", param5); + PersonInfoType person = argument4.getValue(); + Assert.assertEquals("FamilyName", + response.getAttributes().getAttributeValuesByFriendlyName("FamilyName").getFirstValue( + response.getAttributes().getDefinitionsByFriendlyName("FamilyName").iterator().next()), + person.getPerson().getName().getFamilyName()); + Assert.assertEquals("GivenName", + response.getAttributes().getAttributeValuesByFriendlyName("FirstName").getFirstValue( + response.getAttributes().getDefinitionsByFriendlyName("FirstName").iterator().next()), + person.getPerson().getName().getGivenName()); + Assert.assertEquals("DateOfBirth", + response.getAttributes().getAttributeValuesByFriendlyName("DateOfBirth").getFirstValue( + response.getAttributes().getDefinitionsByFriendlyName("DateOfBirth").iterator().next()) + .toString().split("T")[0], + person.getPerson().getDateOfBirth()); + + Assert.assertEquals("PlaceOfBirth", + response.getAttributes().getAttributeValuesByFriendlyName("PlaceOfBirth").getFirstValue( + response.getAttributes().getDefinitionsByFriendlyName("PlaceOfBirth").iterator().next()), + person.getPerson().getPlaceOfBirth()); + Assert.assertEquals("BirthName", + response.getAttributes().getAttributeValuesByFriendlyName("BirthName").getFirstValue( + response.getAttributes().getDefinitionsByFriendlyName("BirthName").iterator().next()), + person.getPerson().getAlternativeName().getFamilyName()); + + Assert.assertEquals("CitizenCountry", "LU", person.getTravelDocument().getIssuingCountry()); + Assert.assertEquals("DocumentType", "ELEKTR_DOKUMENT", person.getTravelDocument().getDocumentType()); + + Assert.assertEquals("Identifier", + response.getAttributes().getAttributeValuesByFriendlyName("PersonIdentifier").getFirstValue( + response.getAttributes().getDefinitionsByFriendlyName("PersonIdentifier").iterator().next()) + .toString().split("/")[2], + person.getTravelDocument().getDocumentNumber()); + + // check bcBind singing request + ArgumentCaptor argument1 = ArgumentCaptor.forClass(Boolean.class); + ArgumentCaptor> argument2 = ArgumentCaptor.forClass(List.class); + ArgumentCaptor> argument3 = ArgumentCaptor.forClass(List.class); + verify(szrMock, times(1)).signContent(argument1.capture(), argument2.capture(), argument3.capture()); + Boolean param1 = argument1.getValue(); + Assert.assertFalse("addCert flag", param1); + + List param2 = argument2.getValue(); + Assert.assertNotNull("JWS Headers", param2); + Assert.assertFalse("JWS Headers empty", param2.isEmpty()); + Assert.assertEquals("Wrong JWS header size", 1, param2.size()); + Assert.assertEquals("Missing JWS header key", "urn:at.gv.eid:bindtype", param2.get(0).getKey()); + Assert.assertEquals("Missing JWS header value", "urn:at.gv.eid:eidasBind", param2.get(0).getValue()); + + List param3 = argument3.getValue(); + Assert.assertNotNull("sign Payload", param3); + Assert.assertEquals("wrong sign-payload size", 1, param3.size()); + Assert.assertNotNull("payload", param3.get(0).getValue().getBytes()); + JsonNode bcBind = mapper.readTree(param3.get(0).getValue().getBytes()); + Assert.assertNotNull("bcbind req", bcBind); + + Assert.assertEquals("vsz", vsz, bcBind.get("urn:eidgvat:attributes.vsz.value").asText()); + Assert.assertEquals("eid status", "urn:eidgvat:eid.status.eidas", + bcBind.get("urn:eidgvat:attributes.eid.status").asText()); + Assert.assertTrue("pubKeys", bcBind.has("urn:eidgvat:attributes.user.pubkeys")); + Assert.assertTrue("pubKeys", bcBind.get("urn:eidgvat:attributes.user.pubkeys").isArray()); + Iterator pubKeys = bcBind.get("urn:eidgvat:attributes.user.pubkeys").elements(); + Assert.assertTrue("No PubKey", pubKeys.hasNext()); + Assert.assertEquals("Wrong pubKey", + "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAmxcB5jnrAwGn7xjgVFv1UBUv1pluwDRFQx7x5O6rSn7pblYfwaWeKa8y" + + "jS5BDDaZ00mhhnSlm2XByNrkg5yBGetTgBGtQVAxV5apfuAWN8TS3uSXgdZol7Khd6kraUITtnulvLe8tNaboom5P0zN6UxbJN" + + "NVLishVp80HiRXiDbplCTUk8b5cYtmivdb0+5JBTa7L5N/anRVnHHoJCXgNPTouO8daUHZbG1mPk0HgqD8rhZ+OBzE+APKH9No" + + "agedSrGRDLdIgZxkrg0mxmfsZQIi2wdJSi3y0PAjEps/s4j0nmw9bPRgCMNLBqqjxtN5JKC8E1yyLm7YefXv/nPaMwIDAQAB", + pubKeys.next().asText()); + Assert.assertFalse("More than one PubKey", pubKeys.hasNext()); + + } + + @Test + public void successfulProcessWithStandardInfos() throws Exception { + //initialize test + String vsz = RandomStringUtils.randomNumeric(10); + when(szrMock, "getStammzahlEncrypted", any(), any()).thenReturn(vsz); + val signContentResp = new SignContentResponseType(); + final SignContentEntry signContentEntry = new SignContentEntry(); + signContentEntry.setValue(RandomStringUtils.randomAlphanumeric(10)); + signContentResp.getOut().add(signContentEntry); + when(szrMock, "signContent", any(), any(), any()).thenReturn(signContentResp); + + String randomTestSp = RandomStringUtils.randomAlphabetic(10); + String bindingPubKey = RandomStringUtils.randomAlphabetic(10); + pendingReq.setRawDataToTransaction(MsEidasNodeConstants.DATA_REQUESTERID, randomTestSp); + pendingReq.setRawDataToTransaction(MsEidasNodeConstants.EID_BINDING_PUBLIC_KEY_NAME, bindingPubKey); + + //perform test + task.execute(pendingReq, executionContext); + + //validate state + // check if pendingRequest was stored + IRequest storedPendingReq = requestStorage.getPendingRequest(pendingReq.getPendingRequestId()); + Assert.assertNotNull("pendingReq not stored", storedPendingReq); + + //check data in session + final AuthProcessDataWrapper authProcessData = storedPendingReq.getSessionData(AuthProcessDataWrapper.class); + Assert.assertNotNull("AuthProcessData", authProcessData); + Assert.assertNotNull("eidasBind", authProcessData.getGenericDataFromSession(MsEidasNodeConstants.AUTH_DATA_EIDAS_BIND, String.class)); + + // check authblock signature + String authBlock = authProcessData.getGenericDataFromSession(MsEidasNodeConstants.AUTH_DATA_SZR_AUTHBLOCK, String.class); + Assert.assertNotNull("AuthBlock", authBlock); + final AlgorithmConstraints constraints = new AlgorithmConstraints(ConstraintType.PERMIT, + BINDING_AUTH_ALGORITHM_WHITELIST_SIGNING.toArray(new String[BINDING_AUTH_ALGORITHM_WHITELIST_SIGNING.size()])); + Pair keyStore = getKeyStore(); + X509Certificate[] trustedCerts = EaafKeyStoreUtils + .getPrivateKeyAndCertificates(keyStore.getFirst(), ALIAS, PW.toCharArray(), true, "junit").getSecond(); + JwsResult result = JoseUtils.validateSignature(authBlock, Arrays.asList(trustedCerts), constraints); + Assert.assertTrue("AuthBlock not valid", result.isValid()); + JsonNode authBlockJson = mapper.readTree(result.getPayLoad()); + Assert.assertNotNull("deserialized AuthBlock", authBlockJson); + + Assert.assertNotNull("no piiTransactionId in pendingRequesdt", + storedPendingReq.getUniquePiiTransactionIdentifier()); + Assert.assertEquals("piiTransactionId", storedPendingReq.getUniquePiiTransactionIdentifier(), + authBlockJson.get("piiTransactionId").asText()); + Assert.assertEquals("appId", randomTestSp, authBlockJson.get("appId").asText()); + Assert.assertFalse("'challenge' is null", authBlockJson.get("challenge").asText().isEmpty()); + Assert.assertFalse("'timestamp' is null", authBlockJson.get("timestamp").asText().isEmpty()); + Assert.assertTrue("binding pubKey", authBlockJson.has("bindingPublicKey")); + Assert.assertEquals("binding PubKey", bindingPubKey, authBlockJson.get("bindingPublicKey").asText()); + + Assert.assertTrue("EID process", authProcessData.isEidProcess()); + Assert.assertTrue("foreigner process", authProcessData.isForeigner()); + Assert.assertEquals("EID-ISSUING_NATION", "LU", + authProcessData.getGenericDataFromSession(PvpAttributeDefinitions.EID_ISSUING_NATION_NAME, String.class)); + Assert.assertNotNull("LoA is null", authProcessData.getQaaLevel()); + Assert.assertEquals("LoA", response.getLevelOfAssurance(), + authProcessData.getQaaLevel()); + + // check vsz request + ArgumentCaptor argument4 = ArgumentCaptor.forClass(PersonInfoType.class); + ArgumentCaptor argument5 = ArgumentCaptor.forClass(Boolean.class); + verify(szrMock, times(1)).getStammzahlEncrypted(argument4.capture(), argument5.capture()); + + Boolean param5 = argument5.getValue(); + Assert.assertTrue("insertERnP flag", param5); + PersonInfoType person = argument4.getValue(); + Assert.assertEquals("FamilyName", + response.getAttributes().getAttributeValuesByFriendlyName("FamilyName").getFirstValue( + response.getAttributes().getDefinitionsByFriendlyName("FamilyName").iterator().next()), + person.getPerson().getName().getFamilyName()); + Assert.assertEquals("GivenName", + response.getAttributes().getAttributeValuesByFriendlyName("FirstName").getFirstValue( + response.getAttributes().getDefinitionsByFriendlyName("FirstName").iterator().next()), + person.getPerson().getName().getGivenName()); + Assert.assertEquals("DateOfBirth", + response.getAttributes().getAttributeValuesByFriendlyName("DateOfBirth").getFirstValue( + response.getAttributes().getDefinitionsByFriendlyName("DateOfBirth").iterator().next()) + .toString().split("T")[0], + person.getPerson().getDateOfBirth()); + + Assert.assertNull("PlaceOfBirth", person.getPerson().getPlaceOfBirth()); + Assert.assertNull("BirthName", person.getPerson().getAlternativeName()); + + Assert.assertEquals("CitizenCountry", "LU", person.getTravelDocument().getIssuingCountry()); + Assert.assertEquals("DocumentType", "ELEKTR_DOKUMENT", person.getTravelDocument().getDocumentType()); + + Assert.assertEquals("Identifier", + response.getAttributes().getAttributeValuesByFriendlyName("PersonIdentifier").getFirstValue( + response.getAttributes().getDefinitionsByFriendlyName("PersonIdentifier").iterator().next()) + .toString().split("/")[2], + person.getTravelDocument().getDocumentNumber()); + + + } + + @Test + public void getStammzahlEncryptedExceptionTest() throws Exception { + try { + when(szrMock, "getStammzahlEncrypted", any(), any()).thenReturn(null); + task.execute(pendingReq, executionContext); + } catch (TaskExecutionException e) { + Assert.assertEquals("Incorrect exception thrown", e.getMessage(), + "IdentityLink generation for foreign person " + "FAILED."); + Assert.assertEquals("Incorrect exception thrown", ((SzrCommunicationException) e.getCause()).getErrorId(), + "ernb.01"); + Assert.assertTrue("Incorrect exception thrown", e.getCause().getMessage().contains("Stammzahl response empty")); + } + } + + @Test + public void signContentExceptionTest() throws Exception { + try { + when(szrMock, "getStammzahlEncrypted", any(), any()).thenReturn(RandomStringUtils.randomNumeric(10)); + when(szrMock, "signContent", any(), any(), any()).thenReturn(null); + task.execute(pendingReq, executionContext); + } catch (TaskExecutionException e) { + Assert.assertEquals("Incorrect exception thrown", e.getMessage(), + "IdentityLink generation for foreign person " + "FAILED."); + Assert.assertEquals("Incorrect exception thrown", ((SzrCommunicationException) e.getCause()).getErrorId(), + "ernb.01"); + Assert.assertTrue("Incorrect exception thrown", e.getCause().getMessage().contains("BcBind response empty")); + } + } + + private Pair getKeyStore() throws EaafException { + // read Connector wide config data TODO connector wide! + String keyStoreName = basicConfig.getBasicConfiguration(MsEidasNodeConstants.PROP_CONFIG_AUTHBLOCK_KEYSTORE_NAME); + String keyStorePw = basicConfig.getBasicConfiguration(MsEidasNodeConstants.PROP_CONFIG_AUTHBLOCK_KEYSTORE_PASSWORD); + String keyStorePath = basicConfig.getBasicConfiguration(MsEidasNodeConstants.PROP_CONFIG_AUTHBLOCK_KEYSTORE_PATH); + String keyStoreType = basicConfig.getBasicConfiguration(MsEidasNodeConstants.PROP_CONFIG_AUTHBLOCK_KEYSTORE_TYPE); + + + //build new KeyStore configuration + KeyStoreConfiguration keyStoreConfiguration = new KeyStoreConfiguration(); + keyStoreConfiguration.setFriendlyName("jUnit test"); + + keyStoreConfiguration.setSoftKeyStoreFilePath(keyStorePath); + keyStoreConfiguration.setSoftKeyStorePassword(keyStorePw); + keyStoreConfiguration.setKeyStoreType(KeyStoreConfiguration.KeyStoreType.fromString(keyStoreType)); + keyStoreConfiguration.setKeyStoreName(keyStoreName); + + //build new KeyStore based on configuration + return keyStoreFactory.buildNewKeyStore(keyStoreConfiguration); + + } + + @NotNull + private AuthenticationResponse buildDummyAuthResponse(boolean withAll) throws URISyntaxException { + final AttributeDefinition attributeDef = attrRegistry.getCoreAttributeRegistry().getByFriendlyName( + Constants.eIDAS_ATTR_PERSONALIDENTIFIER).first(); + final AttributeDefinition attributeDef2 = attrRegistry.getCoreAttributeRegistry().getByFriendlyName( + Constants.eIDAS_ATTR_CURRENTFAMILYNAME).first(); + final AttributeDefinition attributeDef3 = attrRegistry.getCoreAttributeRegistry().getByFriendlyName( + Constants.eIDAS_ATTR_CURRENTGIVENNAME).first(); + final AttributeDefinition attributeDef4 = attrRegistry.getCoreAttributeRegistry().getByFriendlyName( + Constants.eIDAS_ATTR_DATEOFBIRTH).first(); + final AttributeDefinition attributeDef5 = attrRegistry.getCoreAttributeRegistry().getByFriendlyName( + Constants.eIDAS_ATTR_PLACEOFBIRTH).first(); + final AttributeDefinition attributeDef6 = attrRegistry.getCoreAttributeRegistry().getByFriendlyName( + Constants.eIDAS_ATTR_BIRTHNAME).first(); + + final Builder attributeMap = ImmutableAttributeMap.builder(); + attributeMap.put(attributeDef, "LU/AT/" + RandomStringUtils.randomNumeric(64)); + attributeMap.put(attributeDef2, RandomStringUtils.randomAlphabetic(10)); + attributeMap.put(attributeDef3, RandomStringUtils.randomAlphabetic(10)); + attributeMap.put(attributeDef4, "2001-01-01"); + if (withAll) { + attributeMap.put(attributeDef5, RandomStringUtils.randomAlphabetic(10)); + attributeMap.put(attributeDef6, RandomStringUtils.randomAlphabetic(10)); + + } + + val b = new AuthenticationResponse.Builder(); + return b.id("_".concat(Random.nextHexRandom16())) + .issuer(RandomStringUtils.randomAlphabetic(10)) + .subject(RandomStringUtils.randomAlphabetic(10)) + .statusCode(Constants.SUCCESS_URI) + .inResponseTo("_".concat(Random.nextHexRandom16())) + .subjectNameIdFormat("afaf") + .levelOfAssurance(EaafConstants.EIDAS_LOA_PREFIX + RandomStringUtils.randomAlphabetic(5)) + .attributes(attributeMap.build()) + .build(); + } +} diff --git a/modules/authmodule-eIDAS-v2/src/test/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/test/tasks/CreateIdentityLinkTaskTest.java b/modules/authmodule-eIDAS-v2/src/test/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/test/tasks/CreateIdentityLinkTaskTest.java new file mode 100644 index 00000000..d6485158 --- /dev/null +++ b/modules/authmodule-eIDAS-v2/src/test/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/test/tasks/CreateIdentityLinkTaskTest.java @@ -0,0 +1,464 @@ +package at.asitplus.eidas.specific.modules.auth.eidas.v2.test.tasks; + +import static at.asitplus.eidas.specific.core.MsEidasNodeConstants.PROP_CONFIG_SP_NEW_EID_MODE; +import static org.mockito.ArgumentMatchers.any; + +import java.net.URISyntaxException; +import java.util.HashMap; +import java.util.Map; + +import javax.xml.bind.JAXBContext; +import javax.xml.bind.JAXBException; +import javax.xml.bind.Unmarshaller; + +import org.apache.commons.lang3.RandomStringUtils; +import org.jetbrains.annotations.NotNull; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.powermock.core.classloader.annotations.PrepareForTest; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.mock.web.MockHttpServletRequest; +import org.springframework.mock.web.MockHttpServletResponse; +import org.springframework.test.annotation.DirtiesContext; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; +import org.springframework.web.context.request.RequestContextHolder; +import org.springframework.web.context.request.ServletRequestAttributes; + +import com.github.skjolber.mockito.soap.SoapServiceRule; + +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.service.EidasAttributeRegistry; +import at.asitplus.eidas.specific.modules.auth.eidas.v2.tasks.CreateIdentityLinkTask; +import at.gv.egiz.eaaf.core.api.IRequest; +import at.gv.egiz.eaaf.core.api.IRequestStorage; +import at.gv.egiz.eaaf.core.api.data.EaafConfigConstants; +import at.gv.egiz.eaaf.core.api.data.EaafConstants; +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.EaafException; +import at.gv.egiz.eaaf.core.exceptions.EaafStorageException; +import at.gv.egiz.eaaf.core.exceptions.TaskExecutionException; +import at.gv.egiz.eaaf.core.impl.credential.EaafKeyStoreFactory; +import at.gv.egiz.eaaf.core.impl.idp.auth.data.AuthProcessDataWrapper; +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 at.gv.egiz.eaaf.core.impl.utils.Random; +import eu.eidas.auth.commons.attribute.AttributeDefinition; +import eu.eidas.auth.commons.attribute.ImmutableAttributeMap; +import eu.eidas.auth.commons.protocol.impl.AuthenticationResponse; +import lombok.val; +import szrservices.GetBPK; +import szrservices.GetBPKResponse; +import szrservices.GetIdentityLinkEidasResponse; +import szrservices.PersonInfoType; +import szrservices.SZR; +import szrservices.SZRException_Exception; + +@RunWith(SpringJUnit4ClassRunner.class) +@PrepareForTest(CreateIdentityLinkTask.class) +@DirtiesContext(classMode = DirtiesContext.ClassMode.BEFORE_CLASS) +@ContextConfiguration(locations = { + "/SpringTest-context_tasks_test.xml", + "/SpringTest-context_basic_mapConfig.xml"}) +public class CreateIdentityLinkTaskTest { + + @Autowired(required = true) + private CreateIdentityLinkTask task; + + @Autowired(required = true) + private MsConnectorDummyConfigMap basicConfig; + @Autowired + protected EidasAttributeRegistry attrRegistry; + + @Autowired + EaafKeyStoreFactory keyStoreFactory; + + @Autowired + private IRequestStorage requestStorage; + + final ExecutionContext executionContext = new ExecutionContextImpl(); + private MockHttpServletRequest httpReq; + private MockHttpServletResponse httpResp; + private TestRequestImpl pendingReq; + private DummySpConfiguration oaParam; + private SZR szrMock; + + private AuthenticationResponse response; + private Map spConfig; + + @Rule + public final SoapServiceRule soap = SoapServiceRule.newInstance(); + + /** + * jUnit test set-up. + */ + @Before + public void setUp() throws EaafStorageException, URISyntaxException { + + httpReq = new MockHttpServletRequest("POST", "https://localhost/authhandler"); + httpResp = new MockHttpServletResponse(); + RequestContextHolder.resetRequestAttributes(); + RequestContextHolder.setRequestAttributes(new ServletRequestAttributes(httpReq, httpResp)); + + basicConfig.putConfigValue("eidas.ms.auth.eIDAS.szrclient.debug.useDummySolution", "false"); + basicConfig.putConfigValue("eidas.ms.auth.eIDAS.szrclient.revisionlog.eidmapping.active", "false"); + basicConfig.putConfigValue("eidas.ms.auth.eIDAS.szrclient.params.useSZRForbPKCalculation", "false"); + + spConfig = new HashMap<>(); + spConfig.put(EaafConfigConstants.SERVICE_UNIQUEIDENTIFIER, "testSp"); + spConfig.put("target", "urn:publicid:gv.at:cdid+XX"); + spConfig.put(PROP_CONFIG_SP_NEW_EID_MODE, "false"); + oaParam = new DummySpConfiguration(spConfig, basicConfig); + pendingReq = new TestRequestImpl(); + + response = buildDummyAuthResponse(); + + pendingReq.getSessionData(AuthProcessDataWrapper.class) + .setGenericDataToSession(Constants.DATA_FULL_EIDAS_RESPONSE, response); + pendingReq.setSpConfig(oaParam); + pendingReq.setPendingReqId(at.gv.egiz.eaaf.core.impl.utils.Random.nextProcessReferenceValue()); + pendingReq.setAuthUrl("http://test.com/"); + pendingReq.setTransactionId("avaasbav"); + pendingReq.setPiiTransactionId(RandomStringUtils.randomAlphanumeric(10)); + + executionContext.put(MsEidasNodeConstants.REQ_PARAM_SELECTED_COUNTRY, "XX"); + executionContext.put(EaafConstants.PROCESS_ENGINE_REQUIRES_NO_POSTAUTH_REDIRECT, true); + + szrMock = soap.mock(SZR.class, "http://localhost:1234/demoszr"); + } + + + @Test + public void buildIdentityLink() throws Exception { + //initialize test + setSzrResponseIdentityLink("/data/szr/szr_resp_valid_1.xml"); + + String randomTestSp = RandomStringUtils.randomAlphabetic(10); + pendingReq.setRawDataToTransaction(MsEidasNodeConstants.DATA_REQUESTERID, randomTestSp); + + basicConfig.putConfigValue("eidas.ms.auth.eIDAS.szrclient.debug.useDummySolution", "false"); + + + //perform test + task.execute(pendingReq, executionContext); + + + //validate state + // check if pendingRequest was stored + IRequest storedPendingReq = requestStorage.getPendingRequest(pendingReq.getPendingRequestId()); + Assert.assertNotNull("pendingReq not stored", storedPendingReq); + + //check data in session + final AuthProcessDataWrapper authProcessData = storedPendingReq.getSessionData(AuthProcessDataWrapper.class); + Assert.assertNotNull("AuthProcessData", authProcessData); + Assert.assertNull("eidasBind", authProcessData.getGenericDataFromSession(MsEidasNodeConstants.AUTH_DATA_EIDAS_BIND, String.class)); + + String authBlock = authProcessData.getGenericDataFromSession(MsEidasNodeConstants.AUTH_DATA_SZR_AUTHBLOCK, String.class); + Assert.assertNull("AuthBlock", authBlock); + + Assert.assertFalse("EID process", authProcessData.isEidProcess()); + Assert.assertTrue("foreigner process", authProcessData.isForeigner()); + Assert.assertEquals("EID-ISSUING_NATION", "LU", + authProcessData.getGenericDataFromSession(PvpAttributeDefinitions.EID_ISSUING_NATION_NAME, String.class)); + Assert.assertNotNull("LoA is null", authProcessData.getQaaLevel()); + Assert.assertEquals("LoA", response.getLevelOfAssurance(), + authProcessData.getQaaLevel()); + + Assert.assertNotNull("IDL", authProcessData.getIdentityLink()); + checkElement("Mustermann", authProcessData.getIdentityLink().getFamilyName()); + checkElement("Hans", authProcessData.getIdentityLink().getGivenName()); + checkElement("1989-05-05", authProcessData.getIdentityLink().getDateOfBirth()); + checkElement("urn:publicid:gv.at:baseid", authProcessData.getIdentityLink().getIdentificationType()); + checkElement("k+zDM1BVpN1WJO4x7ZQ3ng==", authProcessData.getIdentityLink().getIdentificationValue()); + Assert.assertNotNull(authProcessData.getIdentityLink().getSerializedSamlAssertion()); + Assert.assertNotNull(authProcessData.getIdentityLink().getSamlAssertion()); + + Assert.assertNotNull("no bPK", authProcessData.getGenericDataFromSession(PvpAttributeDefinitions.BPK_NAME)); + Assert.assertEquals("wrong bPK", "XX:FkXtOaSSeR3elyL9KLLvijIYDMU=", + authProcessData.getGenericDataFromSession(PvpAttributeDefinitions.BPK_NAME)); + + } + + @Test + public void buildIdentityLinkWithWbpk() throws Exception { + //initialize test + setSzrResponseIdentityLink("/data/szr/szr_resp_valid_1.xml"); + spConfig.put("target", EaafConstants.URN_PREFIX_WBPK + "FN+123456i"); + + String randomTestSp = RandomStringUtils.randomAlphabetic(10); + pendingReq.setRawDataToTransaction(MsEidasNodeConstants.DATA_REQUESTERID, randomTestSp); + + basicConfig.putConfigValue("eidas.ms.auth.eIDAS.szrclient.debug.useDummySolution", "false"); + basicConfig.putConfigValue("eidas.ms.auth.eIDAS.szrclient.revisionlog.eidmapping.active", "true"); + + //perform test + task.execute(pendingReq, executionContext); + + + //validate state + // check if pendingRequest was stored + IRequest storedPendingReq = requestStorage.getPendingRequest(pendingReq.getPendingRequestId()); + Assert.assertNotNull("pendingReq not stored", storedPendingReq); + + //check data in session + final AuthProcessDataWrapper authProcessData = storedPendingReq.getSessionData(AuthProcessDataWrapper.class); + Assert.assertNotNull("AuthProcessData", authProcessData); + Assert.assertNull("eidasBind", authProcessData.getGenericDataFromSession(MsEidasNodeConstants.AUTH_DATA_EIDAS_BIND, String.class)); + + String authBlock = authProcessData.getGenericDataFromSession(MsEidasNodeConstants.AUTH_DATA_SZR_AUTHBLOCK, String.class); + Assert.assertNull("AuthBlock", authBlock); + + Assert.assertFalse("EID process", authProcessData.isEidProcess()); + Assert.assertTrue("foreigner process", authProcessData.isForeigner()); + Assert.assertEquals("EID-ISSUING_NATION", "LU", + authProcessData.getGenericDataFromSession(PvpAttributeDefinitions.EID_ISSUING_NATION_NAME, String.class)); + Assert.assertNotNull("LoA is null", authProcessData.getQaaLevel()); + Assert.assertEquals("LoA", response.getLevelOfAssurance(), + authProcessData.getQaaLevel()); + + Assert.assertNotNull("no bPK", authProcessData.getGenericDataFromSession(PvpAttributeDefinitions.BPK_NAME)); + Assert.assertEquals("wrong bPK", "FN+123456i:D26vJncPS2W790RH/LP04V+vNOQ=", + authProcessData.getGenericDataFromSession(PvpAttributeDefinitions.BPK_NAME)); + + } + + @Test + public void buildIdentityLinkWithEidasBpk() throws Exception { + //initialize test + setSzrResponseIdentityLink("/data/szr/szr_resp_valid_2.xml"); + spConfig.put("target", EaafConstants.URN_PREFIX_EIDAS + "AT+EU"); + + String randomTestSp = RandomStringUtils.randomAlphabetic(10); + pendingReq.setRawDataToTransaction(MsEidasNodeConstants.DATA_REQUESTERID, randomTestSp); + + basicConfig.putConfigValue("eidas.ms.auth.eIDAS.szrclient.debug.useDummySolution", "false"); + basicConfig.putConfigValue("eidas.ms.auth.eIDAS.szrclient.revisionlog.eidmapping.active", "true"); + + //perform test + task.execute(pendingReq, executionContext); + + + //validate state + // check if pendingRequest was stored + IRequest storedPendingReq = requestStorage.getPendingRequest(pendingReq.getPendingRequestId()); + Assert.assertNotNull("pendingReq not stored", storedPendingReq); + + //check data in session + final AuthProcessDataWrapper authProcessData = storedPendingReq.getSessionData(AuthProcessDataWrapper.class); + Assert.assertNotNull("AuthProcessData", authProcessData); + Assert.assertNull("eidasBind", authProcessData.getGenericDataFromSession(MsEidasNodeConstants.AUTH_DATA_EIDAS_BIND, String.class)); + + String authBlock = authProcessData.getGenericDataFromSession(MsEidasNodeConstants.AUTH_DATA_SZR_AUTHBLOCK, String.class); + Assert.assertNull("AuthBlock", authBlock); + + Assert.assertFalse("EID process", authProcessData.isEidProcess()); + Assert.assertTrue("foreigner process", authProcessData.isForeigner()); + Assert.assertEquals("EID-ISSUING_NATION", "LU", + authProcessData.getGenericDataFromSession(PvpAttributeDefinitions.EID_ISSUING_NATION_NAME, String.class)); + Assert.assertNotNull("LoA is null", authProcessData.getQaaLevel()); + Assert.assertEquals("LoA", response.getLevelOfAssurance(), + authProcessData.getQaaLevel()); + + Assert.assertNotNull("IDL", authProcessData.getIdentityLink()); + checkElement("Musterfrau", authProcessData.getIdentityLink().getFamilyName()); + checkElement("Martina", authProcessData.getIdentityLink().getGivenName()); + checkElement("1991-04-15", authProcessData.getIdentityLink().getDateOfBirth()); + checkElement("urn:publicid:gv.at:baseid", authProcessData.getIdentityLink().getIdentificationType()); + checkElement("k+zDM1BV1312312332x7ZQ3ng==", authProcessData.getIdentityLink().getIdentificationValue()); + + Assert.assertNotNull("no bPK", authProcessData.getGenericDataFromSession(PvpAttributeDefinitions.BPK_NAME)); + Assert.assertEquals("wrong bPK", "AT+EU:AT/EU/1+wqDl059/02Ptny0g+LyuLDJV0=", + authProcessData.getGenericDataFromSession(PvpAttributeDefinitions.BPK_NAME)); + + } + + @Test + public void buildIdentityLinkWithUnknownBpk() throws Exception { + //initialize test + setSzrResponseIdentityLink("/data/szr/szr_resp_valid_1.xml"); + spConfig.put("target", "urn:notextis:1234"); + + String randomTestSp = RandomStringUtils.randomAlphabetic(10); + pendingReq.setRawDataToTransaction(MsEidasNodeConstants.DATA_REQUESTERID, randomTestSp); + + basicConfig.putConfigValue("eidas.ms.auth.eIDAS.szrclient.debug.useDummySolution", "false"); + basicConfig.putConfigValue("eidas.ms.auth.eIDAS.szrclient.revisionlog.eidmapping.active", "true"); + + try { + task.execute(pendingReq, executionContext); + Assert.fail("unknown bPKType not detected"); + + } catch (TaskExecutionException e) { + Assert.assertEquals("ErrorId", "builder.33", + ((EaafException) e.getOriginalException()).getErrorId()); + Assert.assertEquals("wrong parameter size", 1, ((EaafException) e.getOriginalException()) + .getParams().length); + + } + } + + @Test + public void noBpkResult() throws Exception { + //initialize test + setSzrResponseIdentityLink("/data/szr/szr_resp_valid_1.xml"); + GetBPKResponse getBpkResp = new GetBPKResponse(); + org.mockito.Mockito.when(szrMock.getBPK(any(GetBPK.class))).thenReturn(getBpkResp ); + + spConfig.put("target", "urn:notextis:1234"); + + String randomTestSp = RandomStringUtils.randomAlphabetic(10); + pendingReq.setRawDataToTransaction(MsEidasNodeConstants.DATA_REQUESTERID, randomTestSp); + + basicConfig.putConfigValue("eidas.ms.auth.eIDAS.szrclient.debug.useDummySolution", "false"); + basicConfig.putConfigValue("eidas.ms.auth.eIDAS.szrclient.revisionlog.eidmapping.active", "true"); + basicConfig.putConfigValue("eidas.ms.auth.eIDAS.szrclient.params.useSZRForbPKCalculation", "true"); + + try { + task.execute(pendingReq, executionContext); + Assert.fail("unknown bPKType not detected"); + + } catch (TaskExecutionException e) { + Assert.assertEquals("ErrorId", "ernb.01", + ((EaafException) e.getOriginalException()).getErrorId()); + + } + } + + @Test + public void bPKFromSzr() throws Exception { + //initialize test + setSzrResponseIdentityLink("/data/szr/szr_resp_valid_1.xml"); + String bpk = RandomStringUtils.randomAlphanumeric(10); + GetBPKResponse getBpkResp = new GetBPKResponse(); + getBpkResp.getGetBPKReturn().add(bpk); + org.mockito.Mockito.when(szrMock.getBPK(any(GetBPK.class))).thenReturn(getBpkResp ); + + spConfig.put("target", "urn:notextis:1234"); + + String randomTestSp = RandomStringUtils.randomAlphabetic(10); + pendingReq.setRawDataToTransaction(MsEidasNodeConstants.DATA_REQUESTERID, randomTestSp); + + basicConfig.putConfigValue("eidas.ms.auth.eIDAS.szrclient.debug.useDummySolution", "false"); + basicConfig.putConfigValue("eidas.ms.auth.eIDAS.szrclient.revisionlog.eidmapping.active", "true"); + basicConfig.putConfigValue("eidas.ms.auth.eIDAS.szrclient.params.useSZRForbPKCalculation", "true"); + + //execute test + task.execute(pendingReq, executionContext); + + + //validate state + // check if pendingRequest was stored + IRequest storedPendingReq = requestStorage.getPendingRequest(pendingReq.getPendingRequestId()); + Assert.assertNotNull("pendingReq not stored", storedPendingReq); + + //check data in session + final AuthProcessDataWrapper authProcessData = storedPendingReq.getSessionData(AuthProcessDataWrapper.class); + Assert.assertNotNull("AuthProcessData", authProcessData); + Assert.assertNull("eidasBind", authProcessData.getGenericDataFromSession(MsEidasNodeConstants.AUTH_DATA_EIDAS_BIND, String.class)); + + String authBlock = authProcessData.getGenericDataFromSession(MsEidasNodeConstants.AUTH_DATA_SZR_AUTHBLOCK, String.class); + Assert.assertNull("AuthBlock", authBlock); + + Assert.assertFalse("EID process", authProcessData.isEidProcess()); + Assert.assertTrue("foreigner process", authProcessData.isForeigner()); + Assert.assertEquals("EID-ISSUING_NATION", "LU", + authProcessData.getGenericDataFromSession(PvpAttributeDefinitions.EID_ISSUING_NATION_NAME, String.class)); + Assert.assertNotNull("LoA is null", authProcessData.getQaaLevel()); + Assert.assertEquals("LoA", response.getLevelOfAssurance(), + authProcessData.getQaaLevel()); + + Assert.assertNotNull("no bPK", authProcessData.getGenericDataFromSession(PvpAttributeDefinitions.BPK_NAME)); + Assert.assertEquals("wrong bPK", bpk, + authProcessData.getGenericDataFromSession(PvpAttributeDefinitions.BPK_NAME)); + } + + @Test + public void buildDummyIdl() throws Exception { + //initialize test + String randomTestSp = RandomStringUtils.randomAlphabetic(10); + pendingReq.setRawDataToTransaction(MsEidasNodeConstants.DATA_REQUESTERID, randomTestSp); + + basicConfig.putConfigValue("eidas.ms.auth.eIDAS.szrclient.debug.useDummySolution", "true"); + + + //perform test + task.execute(pendingReq, executionContext); + + + //validate state + // check if pendingRequest was stored + IRequest storedPendingReq = requestStorage.getPendingRequest(pendingReq.getPendingRequestId()); + Assert.assertNotNull("pendingReq not stored", storedPendingReq); + + //check data in session + final AuthProcessDataWrapper authProcessData = storedPendingReq.getSessionData(AuthProcessDataWrapper.class); + Assert.assertNotNull("AuthProcessData", authProcessData); + Assert.assertNull("eidasBind", authProcessData.getGenericDataFromSession(MsEidasNodeConstants.AUTH_DATA_EIDAS_BIND, String.class)); + + String authBlock = authProcessData.getGenericDataFromSession(MsEidasNodeConstants.AUTH_DATA_SZR_AUTHBLOCK, String.class); + Assert.assertNull("AuthBlock", authBlock); + + Assert.assertFalse("EID process", authProcessData.isEidProcess()); + Assert.assertTrue("foreigner process", authProcessData.isForeigner()); + Assert.assertEquals("EID-ISSUING_NATION", "LU", + authProcessData.getGenericDataFromSession(PvpAttributeDefinitions.EID_ISSUING_NATION_NAME, String.class)); + Assert.assertNotNull("LoA is null", authProcessData.getQaaLevel()); + Assert.assertEquals("LoA", response.getLevelOfAssurance(), + authProcessData.getQaaLevel()); + + Assert.assertNotNull("IDL", authProcessData.getIdentityLink()); + + } + + private void setSzrResponseIdentityLink(String responseXmlPath) throws JAXBException, SZRException_Exception { + final JAXBContext jaxbContext = JAXBContext + .newInstance(szrservices.ObjectFactory.class, org.w3._2001._04.xmldsig_more.ObjectFactory.class, + org.w3._2000._09.xmldsig.ObjectFactory.class, + at.gv.e_government.reference.namespace.persondata._20020228.ObjectFactory.class); + final Unmarshaller jaxbUnmarshaller = jaxbContext.createUnmarshaller(); + final GetIdentityLinkEidasResponse szrResponse = (GetIdentityLinkEidasResponse) jaxbUnmarshaller + .unmarshal(this.getClass().getResourceAsStream(responseXmlPath)); + org.mockito.Mockito.when(szrMock.getIdentityLinkEidas(any(PersonInfoType.class))).thenReturn(szrResponse.getGetIdentityLinkReturn()); + + } + private void checkElement(String expected, String value) { + Assert.assertNotNull(value); + Assert.assertEquals(expected, value); + + } + + @NotNull + private AuthenticationResponse buildDummyAuthResponse() throws URISyntaxException { + final AttributeDefinition attributeDef = attrRegistry.getCoreAttributeRegistry().getByFriendlyName( + Constants.eIDAS_ATTR_PERSONALIDENTIFIER).first(); + final AttributeDefinition attributeDef2 = attrRegistry.getCoreAttributeRegistry().getByFriendlyName( + Constants.eIDAS_ATTR_CURRENTFAMILYNAME).first(); + final AttributeDefinition attributeDef3 = attrRegistry.getCoreAttributeRegistry().getByFriendlyName( + Constants.eIDAS_ATTR_CURRENTGIVENNAME).first(); + final AttributeDefinition attributeDef4 = attrRegistry.getCoreAttributeRegistry().getByFriendlyName( + Constants.eIDAS_ATTR_DATEOFBIRTH).first(); + + final ImmutableAttributeMap attributeMap = ImmutableAttributeMap.builder() + .put(attributeDef, "LU/AT/" + RandomStringUtils.randomNumeric(64)) + .put(attributeDef2, RandomStringUtils.randomAlphabetic(10)) + .put(attributeDef3, RandomStringUtils.randomAlphabetic(10)).put(attributeDef4, "2001-01-01").build(); + + val b = new AuthenticationResponse.Builder(); + return b.id("_".concat(Random.nextHexRandom16())) + .issuer(RandomStringUtils.randomAlphabetic(10)) + .subject(RandomStringUtils.randomAlphabetic(10)) + .statusCode("200") + .inResponseTo("_".concat(Random.nextHexRandom16())) + .subjectNameIdFormat("afaf") + .levelOfAssurance(EaafConstants.EIDAS_LOA_PREFIX + RandomStringUtils.randomAlphabetic(5)) + .attributes(attributeMap) + .build(); + } +} diff --git a/modules/authmodule-eIDAS-v2/src/test/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/test/tasks/GenerateAuthnRequestTaskTest.java b/modules/authmodule-eIDAS-v2/src/test/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/test/tasks/GenerateAuthnRequestTaskTest.java new file mode 100644 index 00000000..5ebe8225 --- /dev/null +++ b/modules/authmodule-eIDAS-v2/src/test/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/test/tasks/GenerateAuthnRequestTaskTest.java @@ -0,0 +1,637 @@ +package at.asitplus.eidas.specific.modules.auth.eidas.v2.test.tasks; + +import static org.junit.Assert.assertNull; + +import java.io.UnsupportedEncodingException; +import java.util.HashMap; +import java.util.Map; + +import org.apache.commons.lang3.RandomStringUtils; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.mock.web.MockHttpServletRequest; +import org.springframework.mock.web.MockHttpServletResponse; +import org.springframework.test.annotation.DirtiesContext; +import org.springframework.test.annotation.DirtiesContext.ClassMode; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; +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.exception.EidasSAuthenticationException; +import at.asitplus.eidas.specific.modules.auth.eidas.v2.tasks.GenerateAuthnRequestTask; +import at.asitplus.eidas.specific.modules.auth.eidas.v2.test.dummy.DummySpecificCommunicationService; +import at.gv.egiz.eaaf.core.api.data.EaafConfigConstants; +import at.gv.egiz.eaaf.core.api.data.EaafConstants; +import at.gv.egiz.eaaf.core.api.idp.process.ExecutionContext; +import at.gv.egiz.eaaf.core.exceptions.EaafConfigurationException; +import at.gv.egiz.eaaf.core.exceptions.EaafException; +import at.gv.egiz.eaaf.core.exceptions.EaafStorageException; +import at.gv.egiz.eaaf.core.exceptions.GuiBuildException; +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 eu.eidas.auth.commons.light.ILightRequest; +import eu.eidas.specificcommunication.exception.SpecificCommunicationException; + +@RunWith(SpringJUnit4ClassRunner.class) +@ContextConfiguration(locations = { + "/SpringTest-context_tasks_test.xml", + "/SpringTest-context_basic_mapConfig.xml"}) +@DirtiesContext(classMode = ClassMode.BEFORE_CLASS) +public class GenerateAuthnRequestTaskTest { + + @Autowired(required = true) + private GenerateAuthnRequestTask task; + @Autowired(required = true) + private DummySpecificCommunicationService commService; + @Autowired(required = true) + private MsConnectorDummyConfigMap basicConfig; + + final ExecutionContext executionContext = new ExecutionContextImpl(); + private MockHttpServletRequest httpReq; + private MockHttpServletResponse httpResp; + private TestRequestImpl pendingReq; + private DummySpConfiguration oaParam; + private Map spConfig; + + + /** + * jUnit test set-up. + * + */ + @Before + public void setUp() { + + httpReq = new MockHttpServletRequest("POST", "https://localhost/authhandler"); + httpResp = new MockHttpServletResponse(); + RequestContextHolder.resetRequestAttributes(); + RequestContextHolder.setRequestAttributes(new ServletRequestAttributes(httpReq, httpResp)); + + spConfig = new HashMap<>(); + spConfig.put(EaafConfigConstants.SERVICE_UNIQUEIDENTIFIER, "testSp"); + spConfig.put("target", "urn:publicid:gv.at:cdid+XX"); + oaParam = new DummySpConfiguration(spConfig, basicConfig); + + pendingReq = new TestRequestImpl(); + pendingReq.setSpConfig(oaParam); + pendingReq.setPendingReqId(at.gv.egiz.eaaf.core.impl.utils.Random.nextProcessReferenceValue()); + pendingReq.setAuthUrl("http://test.com/"); + + basicConfig.putConfigValue("eidas.ms.auth.eIDAS.node_v2.requesterId.useHashedForm", "true"); + basicConfig.putConfigValue("eidas.ms.auth.eIDAS.node_v2.entityId", + RandomStringUtils.randomAlphabetic(10)); + basicConfig.putConfigValue( + "eidas.ms.auth.eIDAS.node_v2.forward.endpoint", + "http://test/" + RandomStringUtils.randomAlphabetic(5)); + basicConfig.putConfigValue( + "eidas.ms.auth.eIDAS.node_v2.forward.method", "GET"); + basicConfig.removeConfigValue("eidas.ms.auth.eIDAS.node_v2.requested.nameIdFormat"); + + } + + @Test + public void missingIssuer() { + executionContext.put(MsEidasNodeConstants.REQ_PARAM_SELECTED_COUNTRY, "CC"); + basicConfig.removeConfigValue("eidas.ms.auth.eIDAS.node_v2.entityId"); + + //execute test + try { + task.execute(pendingReq, executionContext); + Assert.fail("Missing Issuer not detected"); + + } catch (final TaskExecutionException e) { + // forward URL is not set in example config + org.springframework.util.Assert.isInstanceOf(EaafConfigurationException.class, e.getOriginalException(), + "Wrong exception"); + Assert.assertEquals("wrong errorCode", "config.27", ((EaafException) e.getOriginalException()) + .getErrorId()); + Assert.assertEquals("wrong parameter size", 1, ((EaafException) e.getOriginalException()) + .getParams().length); + + } + } + + @Test + public void missingForwardUrl() { + executionContext.put(MsEidasNodeConstants.REQ_PARAM_SELECTED_COUNTRY, "CC"); + basicConfig.removeConfigValue("eidas.ms.auth.eIDAS.node_v2.forward.endpoint"); + + //execute test + try { + task.execute(pendingReq, executionContext); + Assert.fail("Missing Forward-URL not detected"); + + } catch (final TaskExecutionException e) { + // forward URL is not set in example config + org.springframework.util.Assert.isInstanceOf(EaafConfigurationException.class, e.getOriginalException(), + "Wrong exception"); + Assert.assertEquals("wrong errorCode", "config.08", ((EaafException) e.getOriginalException()) + .getErrorId()); + Assert.assertEquals("wrong parameter size", 1, ((EaafException) e.getOriginalException()) + .getParams().length); + Assert.assertEquals("wrong errorMsg", Constants.CONIG_PROPS_EIDAS_CONNECTOR_NODE_FORWARD_URL, ((EaafException) e + .getOriginalException()).getParams()[0]); + + } + } + + @Test + public void selectUnknownStage() { + executionContext.put(MsEidasNodeConstants.REQ_PARAM_SELECTED_COUNTRY, "CC"); + String stage = RandomStringUtils.randomAlphabetic(5); + executionContext.put("selectedEnvironment", stage); + + //execute test + try { + task.execute(pendingReq, executionContext); + Assert.fail("Missing Forward-URL not detected"); + + } catch (final TaskExecutionException e) { + // forward URL is not set in example config + org.springframework.util.Assert.isInstanceOf(EaafConfigurationException.class, e.getOriginalException(), + "Wrong exception"); + Assert.assertEquals("wrong errorCode", "config.08", ((EaafException) e.getOriginalException()) + .getErrorId()); + Assert.assertEquals("wrong parameter size", 1, ((EaafException) e.getOriginalException()) + .getParams().length); + Assert.assertEquals("wrong errorMsg", Constants.CONIG_PROPS_EIDAS_CONNECTOR_NODE_FORWARD_URL + "." + stage, ((EaafException) e + .getOriginalException()).getParams()[0]); + + } + } + + @Test + public void selectQsEndpoint() throws TaskExecutionException, + SpecificCommunicationException, EaafStorageException { + //set-up test + executionContext.put(MsEidasNodeConstants.REQ_PARAM_SELECTED_COUNTRY, "CC"); + executionContext.put("selectedEnvironment", "qs"); + + String dynEndPoint = "http://test/" + RandomStringUtils.randomAlphabetic(5); + basicConfig.putConfigValue( + "eidas.ms.auth.eIDAS.node_v2.forward.endpoint.qs", dynEndPoint); + basicConfig.putConfigValue( + "eidas.ms.auth.eIDAS.node_v2.forward.method", "GET"); + + + //perform test + task.execute(pendingReq, executionContext); + + //validate state + Assert.assertEquals("Wrong http statusCode", 302, httpResp.getStatus()); + Assert.assertNotNull("No redirect header", httpResp.getHeaderValue("Location")); + Assert.assertTrue("Wrong redirect endpoint", + ((String) httpResp.getHeaderValue("Location")).startsWith(dynEndPoint)); + + } + + @Test + public void selectTestEndpoint() throws TaskExecutionException, + SpecificCommunicationException, EaafStorageException { + //set-up test + executionContext.put(MsEidasNodeConstants.REQ_PARAM_SELECTED_COUNTRY, "CC"); + executionContext.put("selectedEnvironment", "test"); + + String dynEndPoint = "http://test/" + RandomStringUtils.randomAlphabetic(5); + basicConfig.putConfigValue( + "eidas.ms.auth.eIDAS.node_v2.forward.endpoint.test", dynEndPoint); + basicConfig.putConfigValue( + "eidas.ms.auth.eIDAS.node_v2.forward.method", "GET"); + + + //perform test + task.execute(pendingReq, executionContext); + + //validate state + Assert.assertEquals("Wrong http statusCode", 302, httpResp.getStatus()); + Assert.assertNotNull("No redirect header", httpResp.getHeaderValue("Location")); + Assert.assertTrue("Wrong redirect endpoint", + ((String) httpResp.getHeaderValue("Location")).startsWith(dynEndPoint)); + + } + + @Test + public void selectDevEndpoint() throws TaskExecutionException, + SpecificCommunicationException, EaafStorageException { + //set-up test + executionContext.put(MsEidasNodeConstants.REQ_PARAM_SELECTED_COUNTRY, "CC"); + executionContext.put("selectedEnvironment", "dev"); + + String dynEndPoint = "http://test/" + RandomStringUtils.randomAlphabetic(5); + basicConfig.putConfigValue( + "eidas.ms.auth.eIDAS.node_v2.forward.endpoint.dev", dynEndPoint); + basicConfig.putConfigValue( + "eidas.ms.auth.eIDAS.node_v2.forward.method", "GET"); + + + //perform test + task.execute(pendingReq, executionContext); + + //validate state + Assert.assertEquals("Wrong http statusCode", 302, httpResp.getStatus()); + Assert.assertNotNull("No redirect header", httpResp.getHeaderValue("Location")); + Assert.assertTrue("Wrong redirect endpoint", + ((String) httpResp.getHeaderValue("Location")).startsWith(dynEndPoint)); + + } + + @Test + public void noCountryCode() { + try { + task.execute(pendingReq, executionContext); + Assert.fail("No countryCode not detected"); + + } catch (final TaskExecutionException e) { + Assert.assertEquals("wrong pendingReqId", pendingReq.getPendingRequestId(), e.getPendingRequestID()); + org.springframework.util.Assert.isInstanceOf(EidasSAuthenticationException.class, e + .getOriginalException(), "Wrong exception"); + Assert.assertEquals("wrong errorCode", "eidas.03", ((EaafException) e.getOriginalException()) + .getErrorId()); + + } + } + + @Test + public void withStaticProviderNameForPublicSPs() throws TaskExecutionException, + SpecificCommunicationException { + executionContext.put(MsEidasNodeConstants.REQ_PARAM_SELECTED_COUNTRY, "CC"); + + basicConfig.putConfigValue( + "eidas.ms.auth.eIDAS.node_v2.publicSectorTargets", ".*"); + basicConfig.putConfigValue( + "eidas.ms.auth.eIDAS.node_v2.workarounds.addAlwaysProviderName", "true"); + basicConfig.putConfigValue( + "eidas.ms.auth.eIDAS.node_v2.workarounds.useRequestIdAsTransactionIdentifier", "true"); + basicConfig.putConfigValue( + "eidas.ms.auth.eIDAS.node_v2.workarounds.useStaticProviderNameForPublicSPs", "true"); + basicConfig.removeConfigValue("eidas.ms.auth.eIDAS.node_v2.staticProviderNameForPublicSPs"); + + + //execute test + task.execute(pendingReq, executionContext); + + //validate state + final ILightRequest eidasReq = commService.getAndRemoveRequest(null, null); + + Assert.assertEquals("ProviderName is not Static", + Constants.DEFAULT_PROPS_EIDAS_NODE_STATIC_PROVIDERNAME_FOR_PUBLIC_SP, eidasReq.getProviderName()); + Assert.assertEquals("no PublicSP", "public", eidasReq.getSpType()); + Assert.assertEquals("wrong LoA", "http://eidas.europa.eu/LoA/high", eidasReq.getLevelOfAssurance()); + + } + + @Test + public void withCustomStaticProviderNameForPublicSPs() throws TaskExecutionException, + SpecificCommunicationException { + String cc = RandomStringUtils.randomAlphabetic(2); + executionContext.put(MsEidasNodeConstants.REQ_PARAM_SELECTED_COUNTRY, cc); + + basicConfig.putConfigValue( + "eidas.ms.auth.eIDAS.node_v2.publicSectorTargets", ".*"); + basicConfig.putConfigValue( + "eidas.ms.auth.eIDAS.node_v2.workarounds.addAlwaysProviderName", "true"); + basicConfig.putConfigValue( + "eidas.ms.auth.eIDAS.node_v2.workarounds.useRequestIdAsTransactionIdentifier", "true"); + basicConfig.putConfigValue( + "eidas.ms.auth.eIDAS.node_v2.workarounds.addAlwaysProviderNames", "true"); + basicConfig.putConfigValue( + "eidas.ms.auth.eIDAS.node_v2.staticProviderNameForPublicSPs", "myNode"); + + //execute test + task.execute(pendingReq, executionContext); + + //validate state + final ILightRequest eidasReq = commService.getAndRemoveRequest(null, null); + + Assert.assertEquals("wrong issuer", + basicConfig.getBasicConfiguration("eidas.ms.auth.eIDAS.node_v2.entityId"), eidasReq.getIssuer()); + Assert.assertEquals("ProviderName is not Static", "myNode", eidasReq.getProviderName()); + Assert.assertEquals("no PublicSP", "public", eidasReq.getSpType()); + Assert.assertEquals("wrong LoA", "http://eidas.europa.eu/LoA/high", eidasReq.getLevelOfAssurance()); + Assert.assertEquals("wrong CC", cc, eidasReq.getCitizenCountryCode()); + assertNull("NameIdPolicy not null", eidasReq.getNameIdFormat()); + + } + + @Test + public void withDynamicProviderNameForPublicSPs() throws TaskExecutionException, + SpecificCommunicationException, EaafStorageException, UnsupportedEncodingException { + //set-up test + executionContext.put(MsEidasNodeConstants.REQ_PARAM_SELECTED_COUNTRY, "CC"); + executionContext.put("selectedEnvironment", "prod"); + + String providerName = RandomStringUtils.randomAlphanumeric(10); + pendingReq.setRawDataToTransaction(Constants.DATA_PROVIDERNAME, providerName); + + basicConfig.removeConfigValue("eidas.ms.auth.eIDAS.node_v2.publicSectorTargets"); + basicConfig.putConfigValue( + "eidas.ms.auth.eIDAS.node_v2.workarounds.addAlwaysProviderName", "true"); + basicConfig.putConfigValue( + "eidas.ms.auth.eIDAS.node_v2.workarounds.useRequestIdAsTransactionIdentifier", "true"); + basicConfig.putConfigValue( + "eidas.ms.auth.eIDAS.node_v2.workarounds.useStaticProviderNameForPublicSPs", "false"); + + String nameIdFormat = RandomStringUtils.randomAlphabetic(10); + basicConfig.putConfigValue( + "eidas.ms.auth.eIDAS.node_v2.requested.nameIdFormat", nameIdFormat); + + String dynEndPoint = "http://test/" + RandomStringUtils.randomAlphabetic(5); + basicConfig.putConfigValue( + "eidas.ms.auth.eIDAS.node_v2.forward.endpoint", dynEndPoint); + basicConfig.putConfigValue( + "eidas.ms.auth.eIDAS.node_v2.forward.method", "GET"); + + //execute test + task.execute(pendingReq, executionContext); + + //validate state + Assert.assertEquals("Wrong http statusCode", 302, httpResp.getStatus()); + Assert.assertNotNull("No redirect header", httpResp.getHeaderValue("Location")); + Assert.assertTrue("Wrong redirect endpoint", + ((String) httpResp.getHeaderValue("Location")).startsWith(dynEndPoint)); + + + final ILightRequest eidasReq = commService.getAndRemoveRequest(null, null); + + Assert.assertNotNull("ProviderName found", eidasReq.getProviderName()); + Assert.assertEquals("PrividerName", providerName, eidasReq.getProviderName()); + Assert.assertNull("RequesterId found", eidasReq.getRequesterId()); + Assert.assertEquals("no PublicSP", "public", eidasReq.getSpType()); + Assert.assertEquals("wrong LoA", EaafConstants.EIDAS_LOA_HIGH, + eidasReq.getLevelOfAssurance()); + + Assert.assertEquals("Wrong req. attr. size", 4, eidasReq.getRequestedAttributes().size()); + Assert.assertEquals("NameIdFormat", nameIdFormat, eidasReq.getNameIdFormat()); + + } + + @Test + public void publicSpWithCountryLu() throws TaskExecutionException, + SpecificCommunicationException, EaafStorageException, UnsupportedEncodingException { + //set-up test + executionContext.put(MsEidasNodeConstants.REQ_PARAM_SELECTED_COUNTRY, "LU"); + executionContext.put("selectedEnvironment", "prod"); + + String providerName = RandomStringUtils.randomAlphanumeric(10); + pendingReq.setRawDataToTransaction(Constants.DATA_PROVIDERNAME, providerName); + + basicConfig.removeConfigValue("eidas.ms.auth.eIDAS.node_v2.publicSectorTargets"); + basicConfig.putConfigValue( + "eidas.ms.auth.eIDAS.node_v2.workarounds.addAlwaysProviderName", "true"); + basicConfig.putConfigValue( + "eidas.ms.auth.eIDAS.node_v2.workarounds.useRequestIdAsTransactionIdentifier", "true"); + + String dynEndPoint = "http://test/" + RandomStringUtils.randomAlphabetic(5); + basicConfig.putConfigValue( + "eidas.ms.auth.eIDAS.node_v2.forward.endpoint", dynEndPoint); + basicConfig.putConfigValue( + "eidas.ms.auth.eIDAS.node_v2.forward.method", "GET"); + + //execute test + task.execute(pendingReq, executionContext); + + //validate state + Assert.assertEquals("Wrong http statusCode", 302, httpResp.getStatus()); + Assert.assertNotNull("No redirect header", httpResp.getHeaderValue("Location")); + Assert.assertTrue("Wrong redirect endpoint", + ((String) httpResp.getHeaderValue("Location")).startsWith(dynEndPoint)); + + + final ILightRequest eidasReq = commService.getAndRemoveRequest(null, null); + + Assert.assertEquals("PrividerName", "myNode", eidasReq.getProviderName()); + Assert.assertEquals("RequesterId found", "myNode", eidasReq.getRequesterId()); + Assert.assertEquals("no PublicSP", "public", eidasReq.getSpType()); + Assert.assertEquals("wrong LoA", EaafConstants.EIDAS_LOA_HIGH, + eidasReq.getLevelOfAssurance()); + + Assert.assertEquals("Wrong req. attr. size", 4, eidasReq.getRequestedAttributes().size()); + + } + + @Test + public void privateSpWithCountryLu() throws TaskExecutionException, + SpecificCommunicationException, EaafStorageException, UnsupportedEncodingException { + //set-up test + executionContext.put(MsEidasNodeConstants.REQ_PARAM_SELECTED_COUNTRY, "LU"); + executionContext.put("selectedEnvironment", "prod"); + + String providerName = RandomStringUtils.randomAlphanumeric(10); + String requesterId = RandomStringUtils.randomAlphanumeric(10); + pendingReq.setRawDataToTransaction(Constants.DATA_PROVIDERNAME, providerName); + pendingReq.setRawDataToTransaction(Constants.DATA_REQUESTERID, requesterId); + + spConfig.put("target", + EaafConstants.URN_PREFIX_WBPK_TARGET_WITH_X + "FN+" + RandomStringUtils.randomNumeric(6)); + + basicConfig.removeConfigValue("eidas.ms.auth.eIDAS.node_v2.publicSectorTargets"); + basicConfig.putConfigValue( + "eidas.ms.auth.eIDAS.node_v2.workarounds.addAlwaysProviderName", "true"); + basicConfig.putConfigValue( + "eidas.ms.auth.eIDAS.node_v2.workarounds.useRequestIdAsTransactionIdentifier", "true"); + basicConfig.putConfigValue( + "eidas.ms.auth.eIDAS.node_v2.workarounds.useStaticProviderNameForPublicSPs", "true"); + + String dynEndPoint = "http://test/" + RandomStringUtils.randomAlphabetic(5); + basicConfig.putConfigValue( + "eidas.ms.auth.eIDAS.node_v2.forward.endpoint", dynEndPoint); + basicConfig.putConfigValue( + "eidas.ms.auth.eIDAS.node_v2.forward.method", "GET"); + + //execute test + task.execute(pendingReq, executionContext); + + //validate state + Assert.assertEquals("Wrong http statusCode", 302, httpResp.getStatus()); + Assert.assertNotNull("No redirect header", httpResp.getHeaderValue("Location")); + Assert.assertTrue("Wrong redirect endpoint", + ((String) httpResp.getHeaderValue("Location")).startsWith(dynEndPoint)); + + + final ILightRequest eidasReq = commService.getAndRemoveRequest(null, null); + + Assert.assertEquals("PrividerName", "myNode", eidasReq.getProviderName()); + Assert.assertEquals("RequesterId", "myNode", eidasReq.getRequesterId()); + Assert.assertEquals("no PublicSP", "private", eidasReq.getSpType()); + Assert.assertEquals("wrong LoA", EaafConstants.EIDAS_LOA_HIGH, + eidasReq.getLevelOfAssurance()); + + Assert.assertEquals("Wrong req. attr. size", 4, eidasReq.getRequestedAttributes().size()); + + } + + @Test + public void withEidasNodePostReqNotValidTemplate() throws TaskExecutionException, + SpecificCommunicationException, EaafStorageException, UnsupportedEncodingException { + //set-up test + executionContext.put(MsEidasNodeConstants.REQ_PARAM_SELECTED_COUNTRY, "CC"); + String providerName = RandomStringUtils.randomAlphanumeric(10); + pendingReq.setRawDataToTransaction(Constants.DATA_PROVIDERNAME, providerName); + + basicConfig.removeConfigValue("eidas.ms.auth.eIDAS.node_v2.publicSectorTargets"); + basicConfig.putConfigValue( + "eidas.ms.auth.eIDAS.node_v2.workarounds.addAlwaysProviderName", "true"); + basicConfig.putConfigValue( + "eidas.ms.auth.eIDAS.node_v2.workarounds.useRequestIdAsTransactionIdentifier", "true"); + basicConfig.putConfigValue( + "eidas.ms.auth.eIDAS.node_v2.workarounds.useStaticProviderNameForPublicSPs", "false"); + + + String dynEndPoint = "http://test/" + RandomStringUtils.randomAlphabetic(5); + basicConfig.putConfigValue( + "eidas.ms.auth.eIDAS.node_v2.forward.endpoint", dynEndPoint); + basicConfig.putConfigValue( + "eidas.ms.auth.eIDAS.node_v2.forward.method", "POST"); + + //execute test + try { + task.execute(pendingReq, executionContext); + Assert.fail("Missing template not detected"); + + } catch (TaskExecutionException e) { + Assert.assertEquals("ErrorCode", "Could not resolve view with name 'eidas_node_forward.html' ", + ((GuiBuildException) e.getOriginalException()).getMessage()); + + } + } + + @Test + public void withDynamicProviderNameForPrivateSPs() throws TaskExecutionException, + SpecificCommunicationException, EaafStorageException { + //set-up test + executionContext.put(MsEidasNodeConstants.REQ_PARAM_SELECTED_COUNTRY, "CC"); + spConfig.put("target", + EaafConstants.URN_PREFIX_WBPK_TARGET_WITH_X + "FN+" + RandomStringUtils.randomNumeric(6)); + String providerName = RandomStringUtils.randomAlphanumeric(10); + pendingReq.setRawDataToTransaction(Constants.DATA_PROVIDERNAME, providerName); + pendingReq.setRawDataToTransaction(Constants.DATA_REQUESTERID, "http://junit.sp"); + + basicConfig.removeConfigValue("eidas.ms.auth.eIDAS.node_v2.publicSectorTargets"); + basicConfig.putConfigValue( + "eidas.ms.auth.eIDAS.node_v2.workarounds.addAlwaysProviderName", "true"); + basicConfig.putConfigValue( + "eidas.ms.auth.eIDAS.node_v2.workarounds.useRequestIdAsTransactionIdentifier", "true"); + basicConfig.putConfigValue( + "eidas.ms.auth.eIDAS.node_v2.workarounds.useStaticProviderNameForPublicSPs", "false"); + + String dynEndPoint = "http://test/" + RandomStringUtils.randomAlphabetic(5); + basicConfig.putConfigValue( + "eidas.ms.auth.eIDAS.node_v2.forward.endpoint", dynEndPoint); + basicConfig.putConfigValue( + "eidas.ms.auth.eIDAS.node_v2.forward.method", "GET"); + + + //perform test + task.execute(pendingReq, executionContext); + + //validate state + Assert.assertEquals("Wrong http statusCode", 302, httpResp.getStatus()); + Assert.assertNotNull("No redirect header", httpResp.getHeaderValue("Location")); + Assert.assertTrue("Wrong redirect endpoint", + ((String) httpResp.getHeaderValue("Location")).startsWith(dynEndPoint)); + + + final ILightRequest eidasReq = commService.getAndRemoveRequest(null, null); + + Assert.assertEquals("PrividerName", providerName, eidasReq.getProviderName()); + Assert.assertEquals("RequesterId", "Wr8LrrVf5SYneblOlZdZNaLQQCCgzklfKQvyeZjBx10=", eidasReq.getRequesterId()); + Assert.assertEquals("no PublicSP", "private", eidasReq.getSpType()); + Assert.assertEquals("wrong LoA", "http://eidas.europa.eu/LoA/high", eidasReq.getLevelOfAssurance()); + + } + + @Test + public void privateSPWithoutRequestIdHashing() throws TaskExecutionException, + SpecificCommunicationException, EaafStorageException { + //set-up test + executionContext.put(MsEidasNodeConstants.REQ_PARAM_SELECTED_COUNTRY, "CC"); + spConfig.put("target", + EaafConstants.URN_PREFIX_WBPK_TARGET_WITH_X + "FN+" + RandomStringUtils.randomNumeric(6)); + String providerName = RandomStringUtils.randomAlphanumeric(10); + String requesterId = RandomStringUtils.randomAlphanumeric(10); + pendingReq.setRawDataToTransaction(Constants.DATA_PROVIDERNAME, providerName); + pendingReq.setRawDataToTransaction(Constants.DATA_REQUESTERID, requesterId); + + basicConfig.removeConfigValue("eidas.ms.auth.eIDAS.node_v2.publicSectorTargets"); + basicConfig.putConfigValue( + "eidas.ms.auth.eIDAS.node_v2.workarounds.addAlwaysProviderName", "true"); + basicConfig.putConfigValue( + "eidas.ms.auth.eIDAS.node_v2.workarounds.useRequestIdAsTransactionIdentifier", "true"); + basicConfig.putConfigValue( + "eidas.ms.auth.eIDAS.node_v2.workarounds.useStaticProviderNameForPublicSPs", "false"); + basicConfig.putConfigValue("eidas.ms.auth.eIDAS.node_v2.requesterId.useHashedForm", "false"); + + String dynEndPoint = "http://test/" + RandomStringUtils.randomAlphabetic(5); + basicConfig.putConfigValue( + "eidas.ms.auth.eIDAS.node_v2.forward.endpoint", dynEndPoint); + basicConfig.putConfigValue( + "eidas.ms.auth.eIDAS.node_v2.forward.method", "GET"); + + + //perform test + task.execute(pendingReq, executionContext); + + //validate state + Assert.assertEquals("Wrong http statusCode", 302, httpResp.getStatus()); + Assert.assertNotNull("No redirect header", httpResp.getHeaderValue("Location")); + Assert.assertTrue("Wrong redirect endpoint", + ((String) httpResp.getHeaderValue("Location")).startsWith(dynEndPoint)); + + + final ILightRequest eidasReq = commService.getAndRemoveRequest(null, null); + + Assert.assertEquals("PrividerName", providerName, eidasReq.getProviderName()); + Assert.assertEquals("RequesterId", requesterId, eidasReq.getRequesterId()); + Assert.assertEquals("no PublicSP", "private", eidasReq.getSpType()); + Assert.assertEquals("wrong LoA", "http://eidas.europa.eu/LoA/high", eidasReq.getLevelOfAssurance()); + + } + + @Test + public void withoutProviderNameForPublicSPs() throws TaskExecutionException, + SpecificCommunicationException, EaafStorageException { + //set-up test + executionContext.put(MsEidasNodeConstants.REQ_PARAM_SELECTED_COUNTRY, "CC"); + String providerName = RandomStringUtils.randomAlphanumeric(10); + pendingReq.setRawDataToTransaction(Constants.DATA_PROVIDERNAME, providerName); + + basicConfig.removeConfigValue("eidas.ms.auth.eIDAS.node_v2.publicSectorTargets"); + basicConfig.putConfigValue( + "eidas.ms.auth.eIDAS.node_v2.workarounds.addAlwaysProviderName", "false"); + basicConfig.putConfigValue( + "eidas.ms.auth.eIDAS.node_v2.workarounds.useRequestIdAsTransactionIdentifier", "false"); + basicConfig.putConfigValue( + "eidas.ms.auth.eIDAS.node_v2.workarounds.useStaticProviderNameForPublicSPs", "false"); + + + String dynEndPoint = "http://test/" + RandomStringUtils.randomAlphabetic(5); + basicConfig.putConfigValue( + "eidas.ms.auth.eIDAS.node_v2.forward.endpoint", dynEndPoint); + basicConfig.putConfigValue( + "eidas.ms.auth.eIDAS.node_v2.forward.method", "GET"); + + + //execute test + task.execute(pendingReq, executionContext); + + //validate state + Assert.assertEquals("Wrong http statusCode", 302, httpResp.getStatus()); + + final ILightRequest eidasReq = commService.getAndRemoveRequest(null, null); + + Assert.assertNull("ProviderName found", eidasReq.getProviderName()); + Assert.assertNull("RequesterId found", eidasReq.getRequesterId()); + Assert.assertEquals("no PublicSP", "public", eidasReq.getSpType()); + Assert.assertEquals("wrong LoA", "http://eidas.europa.eu/LoA/high", eidasReq.getLevelOfAssurance()); + + } + +} diff --git a/modules/authmodule-eIDAS-v2/src/test/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/test/tasks/ReceiveEidasResponseTaskTest.java b/modules/authmodule-eIDAS-v2/src/test/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/test/tasks/ReceiveEidasResponseTaskTest.java new file mode 100644 index 00000000..53a49bac --- /dev/null +++ b/modules/authmodule-eIDAS-v2/src/test/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/test/tasks/ReceiveEidasResponseTaskTest.java @@ -0,0 +1,223 @@ +package at.asitplus.eidas.specific.modules.auth.eidas.v2.test.tasks; + +import static at.asitplus.eidas.specific.core.MsEidasNodeConstants.PROP_CONFIG_SP_NEW_EID_MODE; + +import java.net.URISyntaxException; +import java.util.Arrays; +import java.util.HashMap; +import java.util.Map; + +import org.apache.commons.lang3.RandomStringUtils; +import org.jetbrains.annotations.NotNull; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.powermock.core.classloader.annotations.PrepareForTest; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.mock.web.MockHttpServletRequest; +import org.springframework.mock.web.MockHttpServletResponse; +import org.springframework.test.annotation.DirtiesContext; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; +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.core.test.config.dummy.MsConnectorDummySpConfiguration; +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.auth.eidas.v2.tasks.CreateIdentityLinkTask; +import at.asitplus.eidas.specific.modules.auth.eidas.v2.tasks.ReceiveAuthnResponseTask; +import at.gv.egiz.eaaf.core.api.IRequest; +import at.gv.egiz.eaaf.core.api.IRequestStorage; +import at.gv.egiz.eaaf.core.api.data.EaafConfigConstants; +import at.gv.egiz.eaaf.core.api.data.EaafConstants; +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.PendingReqIdValidationException; +import at.gv.egiz.eaaf.core.exceptions.TaskExecutionException; +import at.gv.egiz.eaaf.core.impl.idp.auth.data.EidAuthProcessDataWrapper; +import at.gv.egiz.eaaf.core.impl.idp.module.test.TestRequestImpl; +import at.gv.egiz.eaaf.core.impl.idp.process.ExecutionContextImpl; +import at.gv.egiz.eaaf.core.impl.utils.Random; +import eu.eidas.auth.commons.attribute.AttributeDefinition; +import eu.eidas.auth.commons.attribute.ImmutableAttributeMap; +import eu.eidas.auth.commons.protocol.impl.AuthenticationResponse; +import lombok.val; + +@RunWith(SpringJUnit4ClassRunner.class) +@PrepareForTest(CreateIdentityLinkTask.class) +@DirtiesContext(classMode = DirtiesContext.ClassMode.BEFORE_CLASS) +@ContextConfiguration(locations = { + "/SpringTest-context_tasks_test.xml", + "/SpringTest-context_basic_mapConfig.xml"}) +public class ReceiveEidasResponseTaskTest { + + @Autowired(required = true) + private ReceiveAuthnResponseTask task; + + @Autowired(required = true) + private MsConnectorDummyConfigMap basicConfig; + @Autowired + protected EidasAttributeRegistry attrRegistry; + + @Autowired private IRequestStorage storage; + + final ExecutionContext executionContext = new ExecutionContextImpl(); + private MockHttpServletRequest httpReq; + private MockHttpServletResponse httpResp; + private TestRequestImpl pendingReq; + private MsConnectorDummySpConfiguration oaParam; + + /** + * jUnit test set-up. + */ + @Before + public void setUp() throws EaafStorageException, URISyntaxException { + + httpReq = new MockHttpServletRequest("POST", "https://localhost/authhandler"); + httpResp = new MockHttpServletResponse(); + RequestContextHolder.resetRequestAttributes(); + RequestContextHolder.setRequestAttributes(new ServletRequestAttributes(httpReq, httpResp)); + + basicConfig.putConfigValue("eidas.ms.auth.eIDAS.szrclient.debug.useDummySolution", "false"); + basicConfig.putConfigValue("eidas.ms.auth.eIDAS.eid.testidentity.default", "false"); + + final Map spConfig = new HashMap<>(); + spConfig.put(EaafConfigConstants.SERVICE_UNIQUEIDENTIFIER, "testSp"); + spConfig.put("target", "urn:publicid:gv.at:cdid+XX"); + spConfig.put(PROP_CONFIG_SP_NEW_EID_MODE, "true"); + oaParam = new MsConnectorDummySpConfiguration(spConfig, basicConfig); + oaParam.setLoa(Arrays.asList(EaafConstants.EIDAS_LOA_HIGH)); + pendingReq = new TestRequestImpl(); + + pendingReq.setSpConfig(oaParam); + pendingReq.setPendingReqId(at.gv.egiz.eaaf.core.impl.utils.Random.nextProcessReferenceValue()); + pendingReq.setAuthUrl("http://test.com/"); + pendingReq.setTransactionId("avaasbav"); + pendingReq.setPiiTransactionId(RandomStringUtils.randomAlphanumeric(10)); + + executionContext.put(MsEidasNodeConstants.REQ_PARAM_SELECTED_COUNTRY, "LU"); + executionContext.put(EaafConstants.PROCESS_ENGINE_REQUIRES_NO_POSTAUTH_REDIRECT, true); + + } + + @Test + public void missingEidasResponse() { + try { + task.execute(pendingReq, executionContext); + Assert.fail("No eIDAS response not detected"); + + } catch (TaskExecutionException e) { + Assert.assertEquals("ErrorId", "eidas.01", + ((EaafException) e.getOriginalException()).getErrorId()); + + } + } + + @Test + public void notSuccessEidasResponse() throws URISyntaxException { + String statusCode = RandomStringUtils.randomAlphabetic(10); + httpReq.setAttribute(Constants.DATA_FULL_EIDAS_RESPONSE, + buildDummyAuthResponse(statusCode)); + + + try { + task.execute(pendingReq, executionContext); + Assert.fail("No eIDAS response not detected"); + + } catch (TaskExecutionException e) { + Assert.assertEquals("ErrorId", "eidas.02", + ((EaafException) e.getOriginalException()).getErrorId()); + Assert.assertEquals("wrong parameter size", 2, ((EaafException) e.getOriginalException()) + .getParams().length); + Assert.assertEquals("wrong errorMsg", statusCode, ((EaafException) e + .getOriginalException()).getParams()[0]); + + } + } + + @Test + public void success() throws URISyntaxException, TaskExecutionException, PendingReqIdValidationException { + @NotNull + AuthenticationResponse eidasResponse = buildDummyAuthResponse(Constants.SUCCESS_URI); + httpReq.setAttribute(Constants.DATA_FULL_EIDAS_RESPONSE, eidasResponse); + executionContext.put(MsEidasNodeConstants.REQ_PARAM_SELECTED_COUNTRY, "LU"); + + //execute test + task.execute(pendingReq, executionContext); + + //validate state + IRequest storedReq = storage.getPendingRequest(pendingReq.getPendingRequestId()); + Assert.assertNotNull("pendingReq not stored", storedReq); + + final EidAuthProcessDataWrapper authProcessData = storedReq.getSessionData(EidAuthProcessDataWrapper.class); + Assert.assertEquals("LoA", eidasResponse.getLevelOfAssurance(), authProcessData.getQaaLevel()); + Assert.assertNotNull("eIDAS response", + authProcessData.getGenericDataFromSession(Constants.DATA_FULL_EIDAS_RESPONSE)); + Assert.assertEquals("eIDAS response", eidasResponse, + authProcessData.getGenericDataFromSession(Constants.DATA_FULL_EIDAS_RESPONSE)); + Assert.assertFalse("testIdentity flag", authProcessData.isTestIdentity()); + + } + + @Test + public void successWithTestIdentity() throws URISyntaxException, TaskExecutionException, PendingReqIdValidationException { + basicConfig.putConfigValue("eidas.ms.auth.eIDAS.eid.testidentity.default", "true"); + + @NotNull + AuthenticationResponse eidasResponse = buildDummyAuthResponse(Constants.SUCCESS_URI); + httpReq.setAttribute(Constants.DATA_FULL_EIDAS_RESPONSE, eidasResponse); + executionContext.put(MsEidasNodeConstants.REQ_PARAM_SELECTED_COUNTRY, "LU"); + + //execute test + task.execute(pendingReq, executionContext); + + //validate state + IRequest storedReq = storage.getPendingRequest(pendingReq.getPendingRequestId()); + Assert.assertNotNull("pendingReq not stored", storedReq); + + final EidAuthProcessDataWrapper authProcessData = storedReq.getSessionData(EidAuthProcessDataWrapper.class); + Assert.assertEquals("LoA", eidasResponse.getLevelOfAssurance(), authProcessData.getQaaLevel()); + Assert.assertNotNull("eIDAS response", + authProcessData.getGenericDataFromSession(Constants.DATA_FULL_EIDAS_RESPONSE)); + Assert.assertEquals("eIDAS response", eidasResponse, + authProcessData.getGenericDataFromSession(Constants.DATA_FULL_EIDAS_RESPONSE)); + Assert.assertTrue("testIdentity flag", authProcessData.isTestIdentity()); + + } + + + + @NotNull + private AuthenticationResponse buildDummyAuthResponse(String statusCode) throws URISyntaxException { + final AttributeDefinition attributeDef = attrRegistry.getCoreAttributeRegistry().getByFriendlyName( + Constants.eIDAS_ATTR_PERSONALIDENTIFIER).first(); + final AttributeDefinition attributeDef2 = attrRegistry.getCoreAttributeRegistry().getByFriendlyName( + Constants.eIDAS_ATTR_CURRENTFAMILYNAME).first(); + final AttributeDefinition attributeDef3 = attrRegistry.getCoreAttributeRegistry().getByFriendlyName( + Constants.eIDAS_ATTR_CURRENTGIVENNAME).first(); + final AttributeDefinition attributeDef4 = attrRegistry.getCoreAttributeRegistry().getByFriendlyName( + Constants.eIDAS_ATTR_DATEOFBIRTH).first(); + + final ImmutableAttributeMap attributeMap = ImmutableAttributeMap.builder() + .put(attributeDef, "LU/AT/" + RandomStringUtils.randomNumeric(64)) + .put(attributeDef2, RandomStringUtils.randomAlphabetic(10)) + .put(attributeDef3, RandomStringUtils.randomAlphabetic(10)).put(attributeDef4, "2001-01-01").build(); + + val b = new AuthenticationResponse.Builder(); + return b.id("_".concat(Random.nextHexRandom16())) + .issuer(RandomStringUtils.randomAlphabetic(10)) + .subject(RandomStringUtils.randomAlphabetic(10)) + .statusCode(statusCode) + .inResponseTo("_".concat(Random.nextHexRandom16())) + .subjectNameIdFormat("afaf") + .levelOfAssurance(EaafConstants.EIDAS_LOA_HIGH) + .attributes(attributeMap) + .build(); + } + +} diff --git a/modules/authmodule-eIDAS-v2/src/test/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/test/utils/JoseUtilsTest.java b/modules/authmodule-eIDAS-v2/src/test/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/test/utils/JoseUtilsTest.java new file mode 100644 index 00000000..ad38e371 --- /dev/null +++ b/modules/authmodule-eIDAS-v2/src/test/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/test/utils/JoseUtilsTest.java @@ -0,0 +1,139 @@ +package at.asitplus.eidas.specific.modules.auth.eidas.v2.test.utils; + +import java.io.IOException; +import java.security.KeyStore; +import java.security.KeyStoreException; +import java.security.Provider; +import java.security.cert.X509Certificate; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; + +import org.apache.commons.lang3.RandomStringUtils; +import org.jose4j.jwa.AlgorithmConstraints; +import org.jose4j.jwa.AlgorithmConstraints.ConstraintType; +import org.jose4j.jws.AlgorithmIdentifiers; +import org.jose4j.lang.JoseException; +import org.junit.Assert; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.powermock.core.classloader.annotations.PrepareForTest; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.test.annotation.DirtiesContext; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; + +import at.asitplus.eidas.specific.modules.auth.eidas.v2.tasks.CreateIdentityLinkTask; +import at.asitplus.eidas.specific.modules.auth.eidas.v2.utils.JoseUtils; +import at.asitplus.eidas.specific.modules.auth.eidas.v2.utils.JoseUtils.JwsResult; +import at.gv.egiz.eaaf.core.exceptions.EaafException; +import at.gv.egiz.eaaf.core.impl.credential.EaafKeyStoreFactory; +import at.gv.egiz.eaaf.core.impl.credential.EaafKeyStoreUtils; +import at.gv.egiz.eaaf.core.impl.credential.KeyStoreConfiguration; +import at.gv.egiz.eaaf.core.impl.credential.KeyStoreConfiguration.KeyStoreType; +import at.gv.egiz.eaaf.core.impl.data.Pair; + +@RunWith(SpringJUnit4ClassRunner.class) +@PrepareForTest(CreateIdentityLinkTask.class) +@DirtiesContext(classMode = DirtiesContext.ClassMode.BEFORE_CLASS) +@ContextConfiguration(locations = { + "/SpringTest-context_tasks_test.xml", + "/SpringTest-context_basic_mapConfig.xml"}) +public class JoseUtilsTest { + + @Autowired private EaafKeyStoreFactory keyStoreFactory; + + private static final List AUTH_ALGORITHM_WHITELIST_SIGNING = Collections.unmodifiableList( + Arrays.asList( + AlgorithmIdentifiers.ECDSA_USING_P256_CURVE_AND_SHA256, + AlgorithmIdentifiers.ECDSA_USING_P521_CURVE_AND_SHA512, + AlgorithmIdentifiers.RSA_PSS_USING_SHA256, + AlgorithmIdentifiers.RSA_PSS_USING_SHA512)); + + + @Test + public void missingKey() throws EaafException, JoseException, KeyStoreException, IOException { + + KeyStoreConfiguration config = new KeyStoreConfiguration(); + config.setFriendlyName("jUnittest"); + config.setKeyStoreType(KeyStoreType.JKS); + config.setSoftKeyStoreFilePath("../data/junit.jks"); + config.setSoftKeyStorePassword("password"); + + Pair keyStore = keyStoreFactory.buildNewKeyStore(config); + String payLoad = RandomStringUtils.randomAlphanumeric(100); + + //check signing + try { + JoseUtils.createSignature(keyStore, "notExist", "password".toCharArray(), payLoad , true, "jUnitTest"); + Assert.fail("missing Key not detected"); + + } catch (EaafException e) { + Assert.assertEquals("ErrorId", "internal.keystore.09", e.getErrorId()); + + } + } + + @Test + public void createRsaSignature() throws EaafException, JoseException, KeyStoreException, IOException { + + KeyStoreConfiguration config = new KeyStoreConfiguration(); + config.setFriendlyName("jUnittest"); + config.setKeyStoreType(KeyStoreType.JKS); + config.setSoftKeyStoreFilePath("../data/junit.jks"); + config.setSoftKeyStorePassword("password"); + + Pair keyStore = keyStoreFactory.buildNewKeyStore(config); + String payLoad = RandomStringUtils.randomAlphanumeric(100); + + //check signing + String result = JoseUtils.createSignature(keyStore, "meta", "password".toCharArray(), payLoad , true, "jUnitTest"); + + Assert.assertNotNull("signed message", result); + Assert.assertFalse("signed msg empty", result.isEmpty()); + + + //validate + List trustedCerts = EaafKeyStoreUtils.readCertsFromKeyStore(keyStore.getFirst()); + final AlgorithmConstraints constraints = new AlgorithmConstraints(ConstraintType.PERMIT, + AUTH_ALGORITHM_WHITELIST_SIGNING + .toArray(new String[AUTH_ALGORITHM_WHITELIST_SIGNING.size()])); + JwsResult verify = JoseUtils.validateSignature(result, trustedCerts, constraints); + + Assert.assertTrue("sig. verify", verify.isValid()); + Assert.assertEquals("payload", payLoad, verify.getPayLoad()); + + } + + @Test + public void createEccSignature() throws EaafException, JoseException, KeyStoreException, IOException { + + KeyStoreConfiguration config = new KeyStoreConfiguration(); + config.setFriendlyName("jUnittest"); + config.setKeyStoreType(KeyStoreType.JKS); + config.setSoftKeyStoreFilePath("../data/junit.jks"); + config.setSoftKeyStorePassword("password"); + + Pair keyStore = keyStoreFactory.buildNewKeyStore(config); + String payLoad = RandomStringUtils.randomAlphanumeric(100); + + //check signing + String result = JoseUtils.createSignature(keyStore, "sig", "password".toCharArray(), payLoad , true, "jUnitTest"); + + Assert.assertNotNull("signed message", result); + Assert.assertFalse("signed msg empty", result.isEmpty()); + + + //validate + List trustedCerts = EaafKeyStoreUtils.readCertsFromKeyStore(keyStore.getFirst()); + final AlgorithmConstraints constraints = new AlgorithmConstraints(ConstraintType.PERMIT, + AUTH_ALGORITHM_WHITELIST_SIGNING + .toArray(new String[AUTH_ALGORITHM_WHITELIST_SIGNING.size()])); + JwsResult verify = JoseUtils.validateSignature(result, trustedCerts, constraints); + + Assert.assertTrue("sig. verify", verify.isValid()); + Assert.assertEquals("payload", payLoad, verify.getPayLoad()); + + } + +} diff --git a/modules/authmodule-eIDAS-v2/src/test/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/test/validation/EidasAttributePostProcessingTest.java b/modules/authmodule-eIDAS-v2/src/test/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/test/validation/EidasAttributePostProcessingTest.java new file mode 100644 index 00000000..9bb51cd9 --- /dev/null +++ b/modules/authmodule-eIDAS-v2/src/test/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/test/validation/EidasAttributePostProcessingTest.java @@ -0,0 +1,460 @@ +/* + * Copyright 2018 A-SIT Plus GmbH + * AT-specific eIDAS Connector has been developed in a cooperation between EGIZ, + * A-SIT Plus GmbH, A-SIT, and Graz University of Technology. + * + * Licensed under the EUPL, Version 1.2 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "License"); + * You may not use this work except in compliance with the License. + * You may obtain a copy of the License at: + * https://joinup.ec.europa.eu/news/understanding-eupl-v12 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. +*/ + +package at.asitplus.eidas.specific.modules.auth.eidas.v2.test.validation; + +import static org.junit.Assert.fail; + +import java.io.IOException; +import java.text.SimpleDateFormat; +import java.util.HashMap; +import java.util.Map; + +import org.joda.time.DateTime; +import org.junit.BeforeClass; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.test.annotation.DirtiesContext; +import org.springframework.test.annotation.DirtiesContext.ClassMode; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; + +import at.asitplus.eidas.specific.modules.auth.eidas.v2.Constants; +import at.asitplus.eidas.specific.modules.auth.eidas.v2.dao.ErnbEidData; +import at.asitplus.eidas.specific.modules.auth.eidas.v2.service.CcSpecificEidProcessingService; + +@RunWith(SpringJUnit4ClassRunner.class) +@ContextConfiguration(locations = { + "/SpringTest-context_tasks_test.xml", + "/SpringTest-context_basic_mapConfig.xml"}) +@DirtiesContext(classMode = ClassMode.AFTER_CLASS) +public class EidasAttributePostProcessingTest { + + @Autowired + private CcSpecificEidProcessingService postProcessor; + + // lower case + private static final String P1_eIDASID = + "DE/AT/532eaabd9574880dbf76b9b8cc00832c20a6ec113d682299550d7a6e0f345e25"; + private static final String P1_GIVENNAME = "Max"; + private static final String P1_FAMILYNAME = "Mustermann"; + private static final DateTime P1_DATEOFBIRTH = DateTime.now(); + private static final String P1_PLACEOFBIRTH = "Nirgendwo"; + private static final String P1_BIRTHNAME = "Musterkind"; + + // mixed + private static final String P3_eIDASID = + "DE/AT/532eaabd9574880dbf76b9b8cc00832c20A6ec113d682299550d7a6e0f345e25"; + private static final String P3_GIVENNAME = "Max"; + private static final String P3_FAMILYNAME = "Mustermann"; + private static final DateTime P3_DATEOFBIRTH = DateTime.now(); + private static final String P3_PLACEOFBIRTH = "Nirgendwo"; + private static final String P3_BIRTHNAME = "Musterkind"; + + // upper case + private static final String P4_eIDASID = + "DE/AT/532EAABD9574880DBF76B9B8CC00832C20A6EC113D682299550D7A6E0F345E25"; + private static final String P4_GIVENNAME = "Max"; + private static final String P4_FAMILYNAME = "Mustermann"; + private static final DateTime P4_DATEOFBIRTH = DateTime.now(); + private static final String P4_PLACEOFBIRTH = "Nirgendwo"; + private static final String P4_BIRTHNAME = "Musterkind"; + + // To long identifier + private static final String P5_eIDASID = + "DE/AT/532EAABD9574880DBF76B9B8CC00832C20A6EC113D682299550D7A6E0F345E251"; + private static final String P5_GIVENNAME = "Max"; + private static final String P5_FAMILYNAME = "Mustermann"; + private static final DateTime P5_DATEOFBIRTH = DateTime.now(); + private static final String P5_PLACEOFBIRTH = "Nirgendwo"; + private static final String P5_BIRTHNAME = "Musterkind"; + + // to short identifier + private static final String P6_eIDASID = "DE/AT/532EAABD9574880DBF76B9B8CC00832C20A6EC113D682299550D7A6E0F"; + private static final String P6_GIVENNAME = "Max"; + private static final String P6_FAMILYNAME = "Mustermann"; + private static final DateTime P6_DATEOFBIRTH = DateTime.now(); + private static final String P6_PLACEOFBIRTH = "Nirgendwo"; + private static final String P6_BIRTHNAME = "Musterkind"; + + // no hex encoded identifier + private static final String P7_eIDASID = "DE/AT/532EAABD9574880DBF76B9B8CC00832C20A6EC113D682299550D7A6E0F"; + private static final String P7_GIVENNAME = "Max"; + private static final String P7_FAMILYNAME = "Mustermann"; + private static final DateTime P7_DATEOFBIRTH = DateTime.now(); + private static final String P7_PLACEOFBIRTH = "Nirgendwo"; + private static final String P7_BIRTHNAME = "Musterkind"; + + private static final String P2_eIDASID = + "EE/AT/asfasfasdfasdfasdfasdfasdfasvafasdfasdfasdfasdfasdfasvascasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasd"; + private static final String P2_GIVENNAME = "Max"; + private static final String P2_FAMILYNAME = "Mustermann"; + private static final DateTime P2_DATEOFBIRTH = DateTime.now(); + private static final String P2_PLACEOFBIRTH = "Nirgendwo"; + private static final String P2_BIRTHNAME = "Musterkind"; + + /** + * jUnit class initializer. + * + * @throws IOException In case of an error + */ + @BeforeClass + public static void classInitializer() throws IOException { + final String current = new java.io.File(".").toURI().toString(); + System.setProperty("eidas.ms.configuration", current + "../../basicConfig/default_config.properties"); + + } + + @Test + public void deWithHexLowerCase() throws Exception { + try { + final ErnbEidData result = postProcessor.postProcess( + generateInputData( + P1_eIDASID, + P1_FAMILYNAME, + P1_GIVENNAME, + P1_DATEOFBIRTH, + P1_PLACEOFBIRTH, + P1_BIRTHNAME)); + + validate(result, + "Uy6qvZV0iA2/drm4zACDLCCm7BE9aCKZVQ16bg80XiU=", + P1_FAMILYNAME, + P1_GIVENNAME, + P1_DATEOFBIRTH, + P1_PLACEOFBIRTH, + P1_BIRTHNAME); + + } catch (final Exception e) { + e.printStackTrace(); + fail(e.getMessage()); + + } + } + + @Test + public void deWithHexMixedCase() throws Exception { + try { + final ErnbEidData result = postProcessor.postProcess( + generateInputData( + P3_eIDASID, + P3_FAMILYNAME, + P3_GIVENNAME, + P3_DATEOFBIRTH, + P3_PLACEOFBIRTH, + P3_BIRTHNAME)); + + validate(result, + "Uy6qvZV0iA2/drm4zACDLCCm7BE9aCKZVQ16bg80XiU=", + P3_FAMILYNAME, + P3_GIVENNAME, + P3_DATEOFBIRTH, + P3_PLACEOFBIRTH, + P3_BIRTHNAME); + + } catch (final Exception e) { + e.printStackTrace(); + fail(e.getMessage()); + + } + } + + @Test + public void deWithHexUpperCase() throws Exception { + try { + final ErnbEidData result = postProcessor.postProcess( + generateInputData( + P4_eIDASID, + P4_FAMILYNAME, + P4_GIVENNAME, + P4_DATEOFBIRTH, + P4_PLACEOFBIRTH, + P4_BIRTHNAME)); + + validate(result, + "Uy6qvZV0iA2/drm4zACDLCCm7BE9aCKZVQ16bg80XiU=", + P4_FAMILYNAME, + P4_GIVENNAME, + P4_DATEOFBIRTH, + P4_PLACEOFBIRTH, + P4_BIRTHNAME); + + } catch (final Exception e) { + e.printStackTrace(); + fail(e.getMessage()); + + } + } + + @Test + public void deWithHexTooLongCase() throws Exception { + try { + postProcessor.postProcess( + generateInputData( + P5_eIDASID, + P5_FAMILYNAME, + P5_GIVENNAME, + P5_DATEOFBIRTH, + P5_PLACEOFBIRTH, + P5_BIRTHNAME)); + + } catch (final Exception e) { + return; + + } + + fail("Too long input accepted"); + } + + @Test + public void deWithHexTooShortCase() throws Exception { + try { + postProcessor.postProcess( + generateInputData( + P6_eIDASID, + P6_FAMILYNAME, + P6_GIVENNAME, + P6_DATEOFBIRTH, + P6_PLACEOFBIRTH, + P6_BIRTHNAME)); + + } catch (final Exception e) { + return; + + } + + fail("Too short input accepted"); + } + + @Test + public void deWithNoHexCase() throws Exception { + try { + postProcessor.postProcess( + generateInputData( + P7_eIDASID, + P7_FAMILYNAME, + P7_GIVENNAME, + P7_DATEOFBIRTH, + P7_PLACEOFBIRTH, + P7_BIRTHNAME)); + + } catch (final Exception e) { + return; + + } + + fail("Not hex encoded input accepted"); + } + + @Test + public void eeTestCase() throws Exception { + try { + final ErnbEidData result = postProcessor.postProcess( + generateInputData( + P2_eIDASID, + P2_FAMILYNAME, + P2_GIVENNAME, + P2_DATEOFBIRTH, + P2_PLACEOFBIRTH, + P2_BIRTHNAME)); + + validate(result, + "asfasfasdfasdfasdfasdfasdfasvafasdfasdfasdfasdfasdfasvascasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasd", + P2_FAMILYNAME, + P2_GIVENNAME, + P2_DATEOFBIRTH, + P2_PLACEOFBIRTH, + P2_BIRTHNAME); + + } catch (final Exception e) { + e.printStackTrace(); + fail(e.getMessage()); + + } + } + + @Test + public void eeTestFamilyNameMissingCase() throws Exception { + try { + final ErnbEidData result = postProcessor.postProcess( + generateInputData( + P2_eIDASID, + null, + P2_GIVENNAME, + P2_DATEOFBIRTH, + P2_PLACEOFBIRTH, + P2_BIRTHNAME)); + + validate(result, + "asfasfasdfasdfasdfasdfasdfasvafasdfasdfasdfasdfasdfasvascasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasd", + P2_FAMILYNAME, + P2_GIVENNAME, + P2_DATEOFBIRTH, + P2_PLACEOFBIRTH, + P2_BIRTHNAME); + + } catch (final Exception e) { + return; + + } + + fail("FamilyName missing input accepted"); + + } + + @Test + public void eeTestGivenNameMissingCase() throws Exception { + try { + final ErnbEidData result = postProcessor.postProcess( + generateInputData( + P2_eIDASID, + P2_FAMILYNAME, + null, + P2_DATEOFBIRTH, + P2_PLACEOFBIRTH, + P2_BIRTHNAME)); + + validate(result, + "asfasfasdfasdfasdfasdfasdfasvafasdfasdfasdfasdfasdfasvascasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasd", + P2_FAMILYNAME, + P2_GIVENNAME, + P2_DATEOFBIRTH, + P2_PLACEOFBIRTH, + P2_BIRTHNAME); + + } catch (final Exception e) { + return; + + } + + fail("GivenName missing input accepted"); + + } + + @Test + public void eeTestDateOfBirthMissingCase() throws Exception { + try { + final ErnbEidData result = postProcessor.postProcess( + generateInputData( + P2_eIDASID, + P2_FAMILYNAME, + P2_GIVENNAME, + null, + P2_PLACEOFBIRTH, + P2_BIRTHNAME)); + + validate(result, + "asfasfasdfasdfasdfasdfasdfasvafasdfasdfasdfasdfasdfasvascasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasd", + P2_FAMILYNAME, + P2_GIVENNAME, + P2_DATEOFBIRTH, + P2_PLACEOFBIRTH, + P2_BIRTHNAME); + + } catch (final Exception e) { + return; + + } + + fail("DateOfBirth missing input accepted"); + + } + + @Test + public void eeTestIdMissingCase() throws Exception { + try { + final ErnbEidData result = postProcessor.postProcess( + generateInputData( + null, + P2_FAMILYNAME, + P2_GIVENNAME, + P2_DATEOFBIRTH, + P2_PLACEOFBIRTH, + P2_BIRTHNAME)); + + validate(result, + "asfasfasdfasdfasdfasdfasdfasvafasdfasdfasdfasdfasdfasvascasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasd", + P2_FAMILYNAME, + P2_GIVENNAME, + P2_DATEOFBIRTH, + P2_PLACEOFBIRTH, + P2_BIRTHNAME); + + } catch (final Exception e) { + return; + + } + + fail("eIDAS-Id missing input accepted"); + + } + + private Map generateInputData(String id, String familyName, String givenName, + DateTime dateOfBirth, String placeOfBirth, String birthName) { + final Map result = new HashMap<>(); + result.put(Constants.eIDAS_ATTR_PERSONALIDENTIFIER, id); + result.put(Constants.eIDAS_ATTR_CURRENTGIVENNAME, givenName); + result.put(Constants.eIDAS_ATTR_CURRENTFAMILYNAME, familyName); + result.put(Constants.eIDAS_ATTR_DATEOFBIRTH, dateOfBirth); + result.put(Constants.eIDAS_ATTR_PLACEOFBIRTH, placeOfBirth); + result.put(Constants.eIDAS_ATTR_BIRTHNAME, birthName); + return result; + + } + + private void validate(ErnbEidData result, String id, String familyName, String givenName, + DateTime dateOfBirth, String placeOfBirth, String birthName) { + if (!result.getPseudonym().equals(id)) { + fail(result.getPseudonym() + "is not equal to " + id); + } + + if (!result.getFamilyName().equals(familyName)) { + fail(result.getFamilyName() + "is not equal to " + familyName); + } + + if (!result.getGivenName().equals(givenName)) { + fail(result.getGivenName() + "is not equal to " + givenName); + } + + if (!result.getDateOfBirth().equals(dateOfBirth)) { + fail(result.getDateOfBirth() + "is not equal to " + dateOfBirth); + } + + if (!result.getFormatedDateOfBirth().equals(new SimpleDateFormat("yyyy-MM-dd").format(dateOfBirth + .toDate()))) { + fail(result.getDateOfBirth() + "is not equal to " + new SimpleDateFormat("yyyy-MM-dd").format( + dateOfBirth.toDate())); + } + + if (!result.getPlaceOfBirth().equals(placeOfBirth)) { + fail(result.getPlaceOfBirth() + "is not equal to " + placeOfBirth); + } + + if (!result.getBirthName().equals(birthName)) { + fail(result.getBirthName() + "is not equal to " + birthName); + } + + } + +} diff --git a/modules/authmodule-eIDAS-v2/src/test/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/test/validation/EidasRequestPreProcessingFirstTest.java b/modules/authmodule-eIDAS-v2/src/test/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/test/validation/EidasRequestPreProcessingFirstTest.java new file mode 100644 index 00000000..610801a6 --- /dev/null +++ b/modules/authmodule-eIDAS-v2/src/test/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/test/validation/EidasRequestPreProcessingFirstTest.java @@ -0,0 +1,193 @@ +/* + * Copyright 2018 A-SIT Plus GmbH + * AT-specific eIDAS Connector has been developed in a cooperation between EGIZ, + * A-SIT Plus GmbH, A-SIT, and Graz University of Technology. + * + * Licensed under the EUPL, Version 1.2 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "License"); + * You may not use this work except in compliance with the License. + * You may obtain a copy of the License at: + * https://joinup.ec.europa.eu/news/understanding-eupl-v12 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. +*/ + +package at.asitplus.eidas.specific.modules.auth.eidas.v2.test.validation; + +import java.io.IOException; +import java.util.HashMap; +import java.util.Map; +import java.util.UUID; + +import org.junit.Assert; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.test.annotation.DirtiesContext; +import org.springframework.test.annotation.DirtiesContext.ClassMode; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.TestPropertySource; +import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; + +import at.asitplus.eidas.specific.modules.auth.eidas.v2.Constants; +import at.asitplus.eidas.specific.modules.auth.eidas.v2.exception.EidPostProcessingException; +import at.asitplus.eidas.specific.modules.auth.eidas.v2.service.CcSpecificEidProcessingService; +import at.gv.egiz.eaaf.core.api.data.EaafConfigConstants; +import at.gv.egiz.eaaf.core.api.data.EaafConstants; +import at.gv.egiz.eaaf.core.api.idp.IConfigurationWithSP; +import at.gv.egiz.eaaf.core.impl.idp.module.test.DummySpConfiguration; +import at.gv.egiz.eaaf.core.impl.idp.module.test.TestRequestImpl; +import eu.eidas.auth.commons.light.impl.LightRequest; +import eu.eidas.auth.commons.light.impl.LightRequest.Builder; + +@RunWith(SpringJUnit4ClassRunner.class) +@ContextConfiguration(locations = { + "/SpringTest-context_tasks_test.xml", + "/SpringTest-context_basic_realConfig.xml"}) +@TestPropertySource(locations = {"classpath:/config/junit_config_de_attributes.properties"}) +@DirtiesContext(classMode = ClassMode.AFTER_CLASS) +public class EidasRequestPreProcessingFirstTest { + + @Autowired + private IConfigurationWithSP basicConfig; + @Autowired + private CcSpecificEidProcessingService preProcessor; + + private TestRequestImpl pendingReq; + private DummySpConfiguration oaParam; + private Builder authnRequestBuilder; + private Map spConfig; + + /** + * jUnit class initializer. + * + * @throws IOException In case of an error + */ + @BeforeClass + public static void classInitializer() throws IOException { +// final String current = new java.io.File(".").toURI().toString(); +// System.setProperty("eidas.ms.configuration", +// current + "src/test/resources/config/junit_config_de_attributes.properties"); + + } + + /** + * jUnit test set-up. + * + */ + @Before + public void setUp() { + + spConfig = new HashMap<>(); + spConfig.put(EaafConfigConstants.SERVICE_UNIQUEIDENTIFIER, "testSp"); + spConfig.put("target", "urn:publicid:gv.at:cdid+XX"); + oaParam = new DummySpConfiguration(spConfig, basicConfig); + + pendingReq = new TestRequestImpl(); + pendingReq.setSpConfig(oaParam); + pendingReq.setPendingReqId(at.gv.egiz.eaaf.core.impl.utils.Random.nextProcessReferenceValue()); + pendingReq.setAuthUrl("http://test.com/"); + + authnRequestBuilder = LightRequest.builder(); + authnRequestBuilder.id(UUID.randomUUID().toString()); + authnRequestBuilder.issuer("Test"); + authnRequestBuilder.levelOfAssurance(EaafConstants.EIDAS_LOA_HIGH); + + } + + @Test + public void prePreProcessGeneric() throws EidPostProcessingException { + final String testCountry = "XX"; + authnRequestBuilder.citizenCountryCode(testCountry); + preProcessor.preProcess(testCountry, pendingReq, authnRequestBuilder); + + final LightRequest lightReq = authnRequestBuilder.build(); + + Assert.assertEquals("ProviderName is not Static", + Constants.DEFAULT_PROPS_EIDAS_NODE_STATIC_PROVIDERNAME_FOR_PUBLIC_SP, lightReq.getProviderName()); + Assert.assertEquals("no PublicSP", "public", lightReq.getSpType()); + Assert.assertEquals("Requested attribute size not match", 4, lightReq.getRequestedAttributes().size()); + + } + + @Test + public void prePreProcessGenericNoCountryCode() throws EidPostProcessingException { + final String testCountry = "XX"; + authnRequestBuilder.citizenCountryCode(testCountry); + preProcessor.preProcess(null, pendingReq, authnRequestBuilder); + + final LightRequest lightReq = authnRequestBuilder.build(); + + Assert.assertEquals("ProviderName is not Static", + Constants.DEFAULT_PROPS_EIDAS_NODE_STATIC_PROVIDERNAME_FOR_PUBLIC_SP, lightReq.getProviderName()); + Assert.assertEquals("no PublicSP", "public", lightReq.getSpType()); + Assert.assertEquals("Requested attribute size not match", 4, lightReq.getRequestedAttributes().size()); + + } + + @Test + public void prePreProcessDE() throws EidPostProcessingException { + + final String testCountry = "DE"; + authnRequestBuilder.citizenCountryCode(testCountry); + preProcessor.preProcess(testCountry, pendingReq, authnRequestBuilder); + + final LightRequest lightReq = authnRequestBuilder.build(); + + Assert.assertEquals("ProviderName is not Static", + Constants.DEFAULT_PROPS_EIDAS_NODE_STATIC_PROVIDERNAME_FOR_PUBLIC_SP, lightReq.getProviderName()); + Assert.assertNotSame("RequesterId was set", lightReq.getRequesterId()); + Assert.assertEquals("no PublicSP", "public", lightReq.getSpType()); + Assert.assertEquals("Requested attribute size not match", 8, lightReq.getRequestedAttributes().size()); + + } + + @Test + public void prePreProcessNlWithUpgrade() throws EidPostProcessingException { + + final String testCountry = "NL"; + spConfig.put("loa", EaafConstants.EIDAS_LOA_LOW); + authnRequestBuilder.citizenCountryCode(testCountry); + authnRequestBuilder.levelOfAssurance(EaafConstants.EIDAS_LOA_LOW); + + preProcessor.preProcess(testCountry, pendingReq, authnRequestBuilder); + + final LightRequest lightReq = authnRequestBuilder.build(); + + Assert.assertNotSame("RequesterId was set", lightReq.getRequesterId()); + Assert.assertEquals("no PublicSP", "public", lightReq.getSpType()); + Assert.assertEquals("Requested attribute size not match", 4, lightReq.getRequestedAttributes().size()); + + Assert.assertEquals("wrong LoA", EaafConstants.EIDAS_LOA_SUBSTANTIAL, lightReq.getLevelOfAssurance()); + + } + + @Test + public void prePreProcessNlWithOutUpgrade() throws EidPostProcessingException { + + final String testCountry = "NL"; + authnRequestBuilder.citizenCountryCode(testCountry); + preProcessor.preProcess(testCountry, pendingReq, authnRequestBuilder); + + final LightRequest lightReq = authnRequestBuilder.build(); + + Assert.assertNotSame("RequesterId was set", lightReq.getRequesterId()); + Assert.assertEquals("no PublicSP", "public", lightReq.getSpType()); + Assert.assertEquals("Requested attribute size not match", 4, lightReq.getRequestedAttributes().size()); + + Assert.assertEquals("wrong LoA", EaafConstants.EIDAS_LOA_HIGH, lightReq.getLevelOfAssurance()); + + } + +} diff --git a/modules/authmodule-eIDAS-v2/src/test/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/test/validation/EidasRequestPreProcessingSecondTest.java b/modules/authmodule-eIDAS-v2/src/test/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/test/validation/EidasRequestPreProcessingSecondTest.java new file mode 100644 index 00000000..9ee38296 --- /dev/null +++ b/modules/authmodule-eIDAS-v2/src/test/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/test/validation/EidasRequestPreProcessingSecondTest.java @@ -0,0 +1,157 @@ +/* + * Copyright 2018 A-SIT Plus GmbH + * AT-specific eIDAS Connector has been developed in a cooperation between EGIZ, + * A-SIT Plus GmbH, A-SIT, and Graz University of Technology. + * + * Licensed under the EUPL, Version 1.2 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "License"); + * You may not use this work except in compliance with the License. + * You may obtain a copy of the License at: + * https://joinup.ec.europa.eu/news/understanding-eupl-v12 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. +*/ + +package at.asitplus.eidas.specific.modules.auth.eidas.v2.test.validation; + +import java.util.HashMap; +import java.util.Map; +import java.util.UUID; + +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.test.annotation.DirtiesContext; +import org.springframework.test.annotation.DirtiesContext.ClassMode; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; + +import at.asitplus.eidas.specific.core.test.config.dummy.MsConnectorDummyConfigMap; +import at.asitplus.eidas.specific.modules.auth.eidas.v2.exception.EidPostProcessingException; +import at.asitplus.eidas.specific.modules.auth.eidas.v2.service.CcSpecificEidProcessingService; +import at.gv.egiz.eaaf.core.api.data.EaafConfigConstants; +import at.gv.egiz.eaaf.core.api.data.EaafConstants; +import at.gv.egiz.eaaf.core.impl.idp.module.test.DummySpConfiguration; +import at.gv.egiz.eaaf.core.impl.idp.module.test.TestRequestImpl; +import eu.eidas.auth.commons.light.impl.LightRequest; +import eu.eidas.auth.commons.light.impl.LightRequest.Builder; + +@RunWith(SpringJUnit4ClassRunner.class) +@ContextConfiguration(locations = { + "/SpringTest-context_tasks_test.xml", + "/SpringTest-context_basic_mapConfig.xml"}) +@DirtiesContext(classMode = ClassMode.AFTER_CLASS) +public class EidasRequestPreProcessingSecondTest { + + @Autowired + private MsConnectorDummyConfigMap basicConfig; + @Autowired + private CcSpecificEidProcessingService preProcessor; + + private TestRequestImpl pendingReq; + private DummySpConfiguration oaParam; + private Builder authnRequestBuilder; + + + /** + * jUnit test set-up. + * + */ + @Before + public void setUp() { + + final Map spConfig = new HashMap<>(); + spConfig.put(EaafConfigConstants.SERVICE_UNIQUEIDENTIFIER, "testSp"); + spConfig.put("target", "urn:publicid:gv.at:cdid+XX"); + oaParam = new DummySpConfiguration(spConfig, basicConfig); + + pendingReq = new TestRequestImpl(); + pendingReq.setSpConfig(oaParam); + pendingReq.setPendingReqId(at.gv.egiz.eaaf.core.impl.utils.Random.nextProcessReferenceValue()); + pendingReq.setAuthUrl("http://test.com/"); + + authnRequestBuilder = LightRequest.builder(); + authnRequestBuilder.id(UUID.randomUUID().toString()); + authnRequestBuilder.issuer("Test"); + authnRequestBuilder.levelOfAssurance(EaafConstants.EIDAS_LOA_HIGH); + + basicConfig.putConfigValue( + "eidas.ms.auth.eIDAS.node_v2.requesterId.lu.useStaticRequesterForAll", "true"); + + } + + @Test + public void prePreProcessDeUnknownAttribute() throws EidPostProcessingException { + basicConfig.putConfigValue("eidas.ms.auth.eIDAS.node_v2.staticProviderNameForPublicSPs", "myNode"); + basicConfig.putConfigValue( + "eidas.ms.auth.eIDAS.node_v2.workarounds.useStaticProviderNameForPublicSPs", "true"); + + final String testCountry = "DE"; + authnRequestBuilder.citizenCountryCode(testCountry); + preProcessor.preProcess(testCountry, pendingReq, authnRequestBuilder); + + final LightRequest lightReq = authnRequestBuilder.build(); + + Assert.assertEquals("ProviderName is not Static", "myNode", lightReq.getProviderName()); + Assert.assertEquals("no PublicSP", "public", lightReq.getSpType()); + Assert.assertEquals("Requested attribute size not match", 8, lightReq.getRequestedAttributes().size()); + + } + + + /* + * Set ProviderName according to general configuration + */ + @Test + public void prePreProcessLuPublicSpWithoutRequestId() throws EidPostProcessingException { + + basicConfig.putConfigValue( + "eidas.ms.auth.eIDAS.node_v2.requesterId.lu.useStaticRequesterForAll", "false"); + + final String testCountry = "LU"; + authnRequestBuilder.citizenCountryCode(testCountry); + preProcessor.preProcess(testCountry, pendingReq, authnRequestBuilder); + + final LightRequest lightReq = authnRequestBuilder.build(); + + Assert.assertEquals("ProviderName is not Static", "myNode", lightReq.getProviderName()); + Assert.assertNull("RequesterId", lightReq.getRequesterId()); + Assert.assertEquals("no PublicSP", "public", lightReq.getSpType()); + Assert.assertEquals("Requested attribute size not match", 4, lightReq.getRequestedAttributes().size()); + + } + + /* + * Always set requesterId and providername in case of country LU + */ + @Test + public void prePreProcessLuPublicSpWithStaticRequesterId() throws EidPostProcessingException { + + + final String testCountry = "LU"; + authnRequestBuilder.citizenCountryCode(testCountry); + preProcessor.preProcess(testCountry, pendingReq, authnRequestBuilder); + + final LightRequest lightReq = authnRequestBuilder.build(); + + Assert.assertEquals("ProviderName is not Static", + "myNode", lightReq.getProviderName()); + Assert.assertEquals("RequesterId is not Static", + "myNode", lightReq.getRequesterId()); + Assert.assertEquals("no PublicSP", "public", lightReq.getSpType()); + Assert.assertEquals("Requested attribute size not match", 4, lightReq.getRequestedAttributes().size()); + + } + +} diff --git a/modules/authmodule-eIDAS-v2/src/test/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/test/validation/EidasResponseValidatorTest.java b/modules/authmodule-eIDAS-v2/src/test/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/test/validation/EidasResponseValidatorTest.java new file mode 100644 index 00000000..b1f1b164 --- /dev/null +++ b/modules/authmodule-eIDAS-v2/src/test/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/test/validation/EidasResponseValidatorTest.java @@ -0,0 +1,333 @@ +package at.asitplus.eidas.specific.modules.auth.eidas.v2.test.validation; + +import static at.asitplus.eidas.specific.core.MsEidasNodeConstants.PROP_CONFIG_SP_NEW_EID_MODE; + +import java.net.URISyntaxException; +import java.util.Arrays; +import java.util.HashMap; +import java.util.Map; + +import org.apache.commons.lang3.RandomStringUtils; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.powermock.core.classloader.annotations.PrepareForTest; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.test.annotation.DirtiesContext; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; + +import com.google.common.collect.ImmutableSet; + +import at.asitplus.eidas.specific.core.test.config.dummy.MsConnectorDummyConfigMap; +import at.asitplus.eidas.specific.core.test.config.dummy.MsConnectorDummySpConfiguration; +import at.asitplus.eidas.specific.modules.auth.eidas.v2.Constants; +import at.asitplus.eidas.specific.modules.auth.eidas.v2.exception.EidasValidationException; +import at.asitplus.eidas.specific.modules.auth.eidas.v2.service.EidasAttributeRegistry; +import at.asitplus.eidas.specific.modules.auth.eidas.v2.tasks.CreateIdentityLinkTask; +import at.asitplus.eidas.specific.modules.auth.eidas.v2.validator.EidasResponseValidator; +import at.gv.egiz.eaaf.core.api.data.EaafConfigConstants; +import at.gv.egiz.eaaf.core.api.data.EaafConstants; +import at.gv.egiz.eaaf.core.exceptions.EaafStorageException; +import at.gv.egiz.eaaf.core.impl.idp.module.test.TestRequestImpl; +import at.gv.egiz.eaaf.core.impl.utils.Random; +import eu.eidas.auth.commons.attribute.AttributeDefinition; +import eu.eidas.auth.commons.attribute.ImmutableAttributeMap; +import eu.eidas.auth.commons.attribute.ImmutableAttributeMap.Builder; +import eu.eidas.auth.commons.attribute.impl.StringAttributeValue; +import eu.eidas.auth.commons.light.ILightResponse; +import eu.eidas.auth.commons.protocol.impl.AuthenticationResponse; +import lombok.val; + +@RunWith(SpringJUnit4ClassRunner.class) +@PrepareForTest(CreateIdentityLinkTask.class) +@DirtiesContext(classMode = DirtiesContext.ClassMode.BEFORE_CLASS) +@ContextConfiguration(locations = { + "/SpringTest-context_tasks_test.xml", + "/SpringTest-context_basic_mapConfig.xml"}) +public class EidasResponseValidatorTest { + + @Autowired private MsConnectorDummyConfigMap basicConfig; + @Autowired protected EidasAttributeRegistry attrRegistry; + + private TestRequestImpl pendingReq; + private MsConnectorDummySpConfiguration oaParam; + + + /** + * jUnit test set-up. + */ + @Before + public void setUp() throws EaafStorageException, URISyntaxException { + + final Map spConfig = new HashMap<>(); + spConfig.put(EaafConfigConstants.SERVICE_UNIQUEIDENTIFIER, "testSp"); + spConfig.put("target", "urn:publicid:gv.at:cdid+XX"); + spConfig.put(PROP_CONFIG_SP_NEW_EID_MODE, "true"); + oaParam = new MsConnectorDummySpConfiguration(spConfig, basicConfig); + oaParam.setLoa(Arrays.asList(EaafConstants.EIDAS_LOA_HIGH)); + pendingReq = new TestRequestImpl(); + + pendingReq.setSpConfig(oaParam); + pendingReq.setPendingReqId(at.gv.egiz.eaaf.core.impl.utils.Random.nextProcessReferenceValue()); + pendingReq.setAuthUrl("http://test.com/"); + pendingReq.setTransactionId("avaasbav"); + pendingReq.setPiiTransactionId(RandomStringUtils.randomAlphanumeric(10)); + + } + + + @Test + public void loaFromResponseToLow() throws URISyntaxException { + //set-up + ILightResponse eidasResponse = buildDummyAuthResponse( + "LU/AT/" + RandomStringUtils.randomNumeric(10), + EaafConstants.EIDAS_LOA_LOW, + false); + String spCountry = "AT"; + String citizenCountryCode = "XX"; + + //execute test + try { + EidasResponseValidator.validateResponse(pendingReq, eidasResponse, spCountry, citizenCountryCode, attrRegistry); + Assert.fail("Wrong eIDAS response not detected"); + + } catch (EidasValidationException e) { + Assert.assertEquals("ErrorId", "eidas.06", e.getErrorId()); + Assert.assertEquals("wrong parameter size", 1, e.getParams().length); + Assert.assertEquals("wrong errorMsg", "http://eidas.europa.eu/LoA/low", + e.getParams()[0]); + + } + } + + @Test + public void noEidasSpCountry() throws URISyntaxException { + //set-up + ILightResponse eidasResponse = buildDummyAuthResponse( + "LU/AT/" + RandomStringUtils.randomNumeric(10), + EaafConstants.EIDAS_LOA_SUBSTANTIAL, + false); + String spCountry = null; + String citizenCountryCode = "LU"; + + oaParam.setLoa(Arrays.asList(EaafConstants.EIDAS_LOA_HIGH, EaafConstants.EIDAS_LOA_SUBSTANTIAL)); + + + //execute test + try { + EidasResponseValidator.validateResponse(pendingReq, eidasResponse, spCountry, citizenCountryCode, attrRegistry); + Assert.fail("Wrong eIDAS response not detected"); + + } catch (EidasValidationException e) { + Assert.assertEquals("ErrorId", "eidas.07", e.getErrorId()); + Assert.assertEquals("wrong parameter size", 2, e.getParams().length); + Assert.assertEquals("wrong errorMsg", "PersonIdentifier", + e.getParams()[0]); + Assert.assertEquals("wrong errorMsg", + "Destination country does not match to SP country", + e.getParams()[1]); + + } + } + + @Test + public void noEidasResponseCountry() throws URISyntaxException { + //set-up + ILightResponse eidasResponse = buildDummyAuthResponse( + "LU/AT/" + RandomStringUtils.randomNumeric(10), + EaafConstants.EIDAS_LOA_SUBSTANTIAL, + false); + String spCountry = "AT"; + String citizenCountryCode = null; + + oaParam.setLoa(Arrays.asList(EaafConstants.EIDAS_LOA_HIGH, EaafConstants.EIDAS_LOA_SUBSTANTIAL)); + + + //execute test + try { + EidasResponseValidator.validateResponse(pendingReq, eidasResponse, spCountry, citizenCountryCode, attrRegistry); + Assert.fail("Wrong eIDAS response not detected"); + + } catch (EidasValidationException e) { + Assert.assertEquals("ErrorId", "eidas.07", e.getErrorId()); + Assert.assertEquals("wrong parameter size", 2, e.getParams().length); + Assert.assertEquals("wrong errorMsg", "PersonIdentifier", + e.getParams()[0]); + Assert.assertEquals("wrong errorMsg", + "Citizen country does not match to eIDAS-node country that generates the response", + e.getParams()[1]); + + } + } + + @Test + public void wrongEidasResponseCountry() throws URISyntaxException { + //set-up + ILightResponse eidasResponse = buildDummyAuthResponse( + "LU/AT/" + RandomStringUtils.randomNumeric(10), + EaafConstants.EIDAS_LOA_SUBSTANTIAL, + false); + String spCountry = "AT"; + String citizenCountryCode = "XX"; + + oaParam.setLoa(Arrays.asList(EaafConstants.EIDAS_LOA_HIGH, EaafConstants.EIDAS_LOA_SUBSTANTIAL)); + + + //execute test + try { + EidasResponseValidator.validateResponse(pendingReq, eidasResponse, spCountry, citizenCountryCode, attrRegistry); + Assert.fail("Wrong eIDAS response not detected"); + + } catch (EidasValidationException e) { + Assert.assertEquals("ErrorId", "eidas.07", e.getErrorId()); + Assert.assertEquals("wrong parameter size", 2, e.getParams().length); + Assert.assertEquals("wrong errorMsg", "PersonIdentifier", + e.getParams()[0]); + Assert.assertEquals("wrong errorMsg", + "Citizen country does not match to eIDAS-node country that generates the response", + e.getParams()[1]); + + } + } + + @Test + public void missingPersonalIdentifier() throws URISyntaxException { + //set-up + ILightResponse eidasResponse = buildDummyAuthResponse( + null, + EaafConstants.EIDAS_LOA_SUBSTANTIAL, + false); + String spCountry = "AT"; + String citizenCountryCode = "LU"; + + oaParam.setLoa(Arrays.asList(EaafConstants.EIDAS_LOA_HIGH, EaafConstants.EIDAS_LOA_SUBSTANTIAL)); + + + //execute test + try { + EidasResponseValidator.validateResponse(pendingReq, eidasResponse, spCountry, citizenCountryCode, attrRegistry); + Assert.fail("Wrong eIDAS response not detected"); + + } catch (EidasValidationException e) { + Assert.assertEquals("ErrorId", "eidas.05", e.getErrorId()); + Assert.assertEquals("wrong parameter size", 1, e.getParams().length); + Assert.assertEquals("wrong errorMsg", "NO 'PersonalIdentifier' attriubte", + e.getParams()[0]); + + } + } + + @Test + public void moreThanOnePersonalIdentifier() throws URISyntaxException { + //set-up + ILightResponse eidasResponse = buildDummyAuthResponse( + null, + EaafConstants.EIDAS_LOA_SUBSTANTIAL, + true); + String spCountry = "AT"; + String citizenCountryCode = "LU"; + + oaParam.setLoa(Arrays.asList(EaafConstants.EIDAS_LOA_HIGH, EaafConstants.EIDAS_LOA_SUBSTANTIAL)); + + + //execute test + try { + EidasResponseValidator.validateResponse(pendingReq, eidasResponse, spCountry, citizenCountryCode, attrRegistry); + Assert.fail("Wrong eIDAS response not detected"); + + } catch (EidasValidationException e) { + Assert.assertEquals("ErrorId", "eidas.05", e.getErrorId()); + Assert.assertEquals("wrong parameter size", 1, e.getParams().length); + Assert.assertEquals("wrong errorMsg", "NO 'PersonalIdentifier' attriubte", + e.getParams()[0]); + + } + } + + @Test + public void emptyPersonalIdentifier() throws URISyntaxException { + //set-up + ILightResponse eidasResponse = buildDummyAuthResponse( + "", + EaafConstants.EIDAS_LOA_SUBSTANTIAL, + false); + String spCountry = "AT"; + String citizenCountryCode = "LU"; + + oaParam.setLoa(Arrays.asList(EaafConstants.EIDAS_LOA_HIGH, EaafConstants.EIDAS_LOA_SUBSTANTIAL)); + + + //execute test + try { + EidasResponseValidator.validateResponse(pendingReq, eidasResponse, spCountry, citizenCountryCode, attrRegistry); + Assert.fail("Wrong eIDAS response not detected"); + + } catch (EidasValidationException e) { + Assert.assertEquals("ErrorId", "eidas.07", e.getErrorId()); + Assert.assertEquals("wrong parameter size", 2, e.getParams().length); + Assert.assertEquals("wrong errorMsg", "PersonIdentifier", + e.getParams()[0]); + Assert.assertEquals("wrong errorMsg", + "Wrong identifier format", + e.getParams()[1]); + + } + } + + @Test + public void validResponse() throws URISyntaxException, EidasValidationException { + //set-up + + String spCountry = RandomStringUtils.randomAlphabetic(2).toUpperCase(); + String cCountry = RandomStringUtils.randomAlphabetic(2).toUpperCase(); + + ILightResponse eidasResponse = buildDummyAuthResponse( + cCountry + "/" + spCountry + "/" + RandomStringUtils.randomAlphanumeric(20), + EaafConstants.EIDAS_LOA_SUBSTANTIAL, + false); + + oaParam.setLoa(Arrays.asList(EaafConstants.EIDAS_LOA_HIGH, EaafConstants.EIDAS_LOA_SUBSTANTIAL)); + + + //execute test + + EidasResponseValidator.validateResponse(pendingReq, eidasResponse, spCountry, cCountry, attrRegistry); + + } + + + private AuthenticationResponse buildDummyAuthResponse(String personalId, String loa, boolean moreThanOnePersonalId) + throws URISyntaxException { + + + final AttributeDefinition personIdattributeDef = attrRegistry.getCoreAttributeRegistry().getByFriendlyName( + Constants.eIDAS_ATTR_PERSONALIDENTIFIER).first(); + + final Builder attributeMap = ImmutableAttributeMap.builder(); + if (personalId != null) { + if (moreThanOnePersonalId) { + ImmutableSet values = ImmutableSet.of(new StringAttributeValue(personalId), + new StringAttributeValue("XX/YY/" + RandomStringUtils.randomAlphanumeric(10))); + attributeMap.put(personIdattributeDef, values); + + } else { + attributeMap.put(personIdattributeDef, personalId); + + } + } + + val b = new AuthenticationResponse.Builder(); + return b.id("_".concat(Random.nextHexRandom16())) + .issuer(RandomStringUtils.randomAlphabetic(10)) + .subject(RandomStringUtils.randomAlphabetic(10)) + .statusCode(Constants.SUCCESS_URI) + .inResponseTo("_".concat(Random.nextHexRandom16())) + .subjectNameIdFormat("afaf") + .levelOfAssurance(loa) + .attributes(attributeMap.build()) + .build(); + } +} + diff --git a/modules/authmodule-eIDAS-v2/src/test/resources/SpringTest-context_basic_mapConfig.xml b/modules/authmodule-eIDAS-v2/src/test/resources/SpringTest-context_basic_mapConfig.xml new file mode 100644 index 00000000..fe9ff441 --- /dev/null +++ b/modules/authmodule-eIDAS-v2/src/test/resources/SpringTest-context_basic_mapConfig.xml @@ -0,0 +1,20 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/modules/authmodule-eIDAS-v2/src/test/resources/SpringTest-context_basic_realConfig.xml b/modules/authmodule-eIDAS-v2/src/test/resources/SpringTest-context_basic_realConfig.xml new file mode 100644 index 00000000..79695f69 --- /dev/null +++ b/modules/authmodule-eIDAS-v2/src/test/resources/SpringTest-context_basic_realConfig.xml @@ -0,0 +1,25 @@ + + + + + + + + + + \ No newline at end of file diff --git a/modules/authmodule-eIDAS-v2/src/test/resources/SpringTest-context_basic_test.xml b/modules/authmodule-eIDAS-v2/src/test/resources/SpringTest-context_basic_test.xml new file mode 100644 index 00000000..f31e5063 --- /dev/null +++ b/modules/authmodule-eIDAS-v2/src/test/resources/SpringTest-context_basic_test.xml @@ -0,0 +1,73 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/modules/authmodule-eIDAS-v2/src/test/resources/SpringTest-context_tasks_test.xml b/modules/authmodule-eIDAS-v2/src/test/resources/SpringTest-context_tasks_test.xml new file mode 100644 index 00000000..6d6bb51e --- /dev/null +++ b/modules/authmodule-eIDAS-v2/src/test/resources/SpringTest-context_tasks_test.xml @@ -0,0 +1,67 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/modules/authmodule-eIDAS-v2/src/test/resources/config/additional-attributes.xml b/modules/authmodule-eIDAS-v2/src/test/resources/config/additional-attributes.xml new file mode 100644 index 00000000..6510546e --- /dev/null +++ b/modules/authmodule-eIDAS-v2/src/test/resources/config/additional-attributes.xml @@ -0,0 +1,39 @@ + + + + + + Dynamic attributes + + http://eidas.europa.eu/attributes/naturalperson/AdditionalAttribute + AdditionalAttribute + NaturalPerson + false + http://www.w3.org/2001/XMLSchema + string + xs + eu.eidas.auth.commons.attribute.impl.LiteralStringAttributeValueMarshaller + + http://eidas.europa.eu/attributes/legalperson/LegalAdditionalAttribute + LegalAdditionalAttribute + LegalPerson + false + http://www.w3.org/2001/XMLSchema + string + xs + eu.eidas.auth.commons.attribute.impl.LiteralStringAttributeValueMarshaller + + diff --git a/modules/authmodule-eIDAS-v2/src/test/resources/config/eidas-attributes.xml b/modules/authmodule-eIDAS-v2/src/test/resources/config/eidas-attributes.xml new file mode 100644 index 00000000..cbae35db --- /dev/null +++ b/modules/authmodule-eIDAS-v2/src/test/resources/config/eidas-attributes.xml @@ -0,0 +1,376 @@ + + + + + + eIDAS attributes + + http://eidas.europa.eu/attributes/naturalperson/PersonIdentifier + PersonIdentifier + NaturalPerson + true + true + http://eidas.europa.eu/attributes/naturalperson + PersonIdentifierType + eidas-natural + eu.eidas.auth.commons.attribute.impl.LiteralStringAttributeValueMarshaller + + http://eidas.europa.eu/attributes/naturalperson/CurrentFamilyName + FamilyName + NaturalPerson + true + true + http://eidas.europa.eu/attributes/naturalperson + CurrentFamilyNameType + eidas-natural + eu.eidas.auth.commons.attribute.impl.LiteralStringAttributeValueMarshaller + + http://eidas.europa.eu/attributes/naturalperson/CurrentGivenName + FirstName + NaturalPerson + true + true + http://eidas.europa.eu/attributes/naturalperson + CurrentGivenNameType + eidas-natural + eu.eidas.auth.commons.attribute.impl.LiteralStringAttributeValueMarshaller + + http://eidas.europa.eu/attributes/naturalperson/DateOfBirth + DateOfBirth + NaturalPerson + true + http://eidas.europa.eu/attributes/naturalperson + DateOfBirthType + eidas-natural + eu.eidas.auth.commons.attribute.impl.DateTimeAttributeValueMarshaller + + http://eidas.europa.eu/attributes/naturalperson/BirthName + BirthName + NaturalPerson + false + true + http://eidas.europa.eu/attributes/naturalperson + BirthNameType + eidas-natural + eu.eidas.auth.commons.attribute.impl.LiteralStringAttributeValueMarshaller + + http://eidas.europa.eu/attributes/naturalperson/PlaceOfBirth + PlaceOfBirth + NaturalPerson + false + http://eidas.europa.eu/attributes/naturalperson + PlaceOfBirthType + eidas-natural + eu.eidas.auth.commons.attribute.impl.LiteralStringAttributeValueMarshaller + + http://eidas.europa.eu/attributes/naturalperson/CurrentAddress + CurrentAddress + NaturalPerson + false + http://eidas.europa.eu/attributes/naturalperson + CurrentAddressType + eidas-natural + eu.eidas.auth.commons.protocol.eidas.impl.CurrentAddressAttributeValueMarshaller + + http://eidas.europa.eu/attributes/naturalperson/Gender + Gender + NaturalPerson + false + http://eidas.europa.eu/attributes/naturalperson + GenderType + eidas-natural + eu.eidas.auth.commons.protocol.eidas.impl.GenderAttributeValueMarshaller + + http://eidas.europa.eu/attributes/legalperson/LegalPersonIdentifier + LegalPersonIdentifier + LegalPerson + true + true + http://eidas.europa.eu/attributes/legalperson + LegalPersonIdentifierType + eidas-legal + eu.eidas.auth.commons.attribute.impl.LiteralStringAttributeValueMarshaller + + http://eidas.europa.eu/attributes/legalperson/LegalName + LegalName + LegalPerson + true + true + http://eidas.europa.eu/attributes/legalperson + LegalNameType + eidas-legal + eu.eidas.auth.commons.attribute.impl.LiteralStringAttributeValueMarshaller + + http://eidas.europa.eu/attributes/legalperson/LegalPersonAddress + LegalAddress + LegalPerson + false + http://eidas.europa.eu/attributes/legalperson + LegalPersonAddressType + eidas-legal + eu.eidas.auth.commons.protocol.eidas.impl.LegalAddressAttributeValueMarshaller + + http://eidas.europa.eu/attributes/legalperson/VATRegistrationNumber + VATRegistration + LegalPerson + false + http://eidas.europa.eu/attributes/legalperson + VATRegistrationNumberType + eidas-legal + eu.eidas.auth.commons.attribute.impl.LiteralStringAttributeValueMarshaller + + http://eidas.europa.eu/attributes/legalperson/TaxReference + TaxReference + LegalPerson + false + http://eidas.europa.eu/attributes/legalperson + TaxReferenceType + eidas-legal + eu.eidas.auth.commons.attribute.impl.LiteralStringAttributeValueMarshaller + + http://eidas.europa.eu/attributes/legalperson/D-2012-17-EUIdentifier + D-2012-17-EUIdentifier + LegalPerson + false + http://eidas.europa.eu/attributes/legalperson + D-2012-17-EUIdentifierType + eidas-legal + eu.eidas.auth.commons.attribute.impl.LiteralStringAttributeValueMarshaller + + http://eidas.europa.eu/attributes/legalperson/LEI + LEI + LegalPerson + false + http://eidas.europa.eu/attributes/legalperson + LEIType + eidas-legal + eu.eidas.auth.commons.attribute.impl.LiteralStringAttributeValueMarshaller + + http://eidas.europa.eu/attributes/legalperson/EORI + EORI + LegalPerson + false + http://eidas.europa.eu/attributes/legalperson + EORIType + eidas-legal + eu.eidas.auth.commons.attribute.impl.LiteralStringAttributeValueMarshaller + + http://eidas.europa.eu/attributes/legalperson/SEED + SEED + LegalPerson + false + http://eidas.europa.eu/attributes/legalperson + SEEDType + eidas-legal + eu.eidas.auth.commons.attribute.impl.LiteralStringAttributeValueMarshaller + + http://eidas.europa.eu/attributes/legalperson/SIC + SIC + LegalPerson + false + http://eidas.europa.eu/attributes/legalperson + SICType + eidas-legal + eu.eidas.auth.commons.attribute.impl.LiteralStringAttributeValueMarshaller + + http://eidas.europa.eu/attributes/naturalperson/representative/PersonIdentifier + RepresentativePersonIdentifier + RepresentativeNaturalPerson + false + true + http://eidas.europa.eu/attributes/naturalperson/representative + PersonIdentifierType + eidas-natural + eu.eidas.auth.commons.attribute.impl.LiteralStringAttributeValueMarshaller + + http://eidas.europa.eu/attributes/naturalperson/representative/CurrentFamilyName + RepresentativeFamilyName + RepresentativeNaturalPerson + false + true + http://eidas.europa.eu/attributes/naturalperson/representative + CurrentFamilyNameType + eidas-reprentative-natural + eu.eidas.auth.commons.attribute.impl.LiteralStringAttributeValueMarshaller + + http://eidas.europa.eu/attributes/naturalperson/representative/CurrentGivenName + RepresentativeFirstName + RepresentativeNaturalPerson + false + true + http://eidas.europa.eu/attributes/naturalperson/representative + CurrentGivenNameType + eidas-reprentative-natural + eu.eidas.auth.commons.attribute.impl.LiteralStringAttributeValueMarshaller + + http://eidas.europa.eu/attributes/naturalperson/representative/DateOfBirth + RepresentativeDateOfBirth + RepresentativeNaturalPerson + false + http://eidas.europa.eu/attributes/naturalperson/representative + DateOfBirthType + eidas-reprentative-natural + eu.eidas.auth.commons.attribute.impl.DateTimeAttributeValueMarshaller + + http://eidas.europa.eu/attributes/naturalperson/representative/BirthName + RepresentativeBirthName + RepresentativeNaturalPerson + false + true + http://eidas.europa.eu/attributes/naturalperson/representative + BirthNameType + eidas-reprentative-natural + eu.eidas.auth.commons.attribute.impl.LiteralStringAttributeValueMarshaller + + http://eidas.europa.eu/attributes/naturalperson/representative/PlaceOfBirth + RepresentativePlaceOfBirth + RepresentativeNaturalPerson + false + http://eidas.europa.eu/attributes/naturalperson/representative + PlaceOfBirthType + eidas-reprentative-natural + eu.eidas.auth.commons.attribute.impl.LiteralStringAttributeValueMarshaller + + http://eidas.europa.eu/attributes/naturalperson/representative/CurrentAddress + RepresentativeCurrentAddress + RepresentativeNaturalPerson + false + http://eidas.europa.eu/attributes/naturalperson/representative + CurrentAddressType + eidas-reprentative-natural + eu.eidas.auth.commons.protocol.eidas.impl.RepvCurrentAddressAttributeValueMarshaller + + http://eidas.europa.eu/attributes/naturalperson/representative/Gender + RepresentativeGender + RepresentativeNaturalPerson + false + http://eidas.europa.eu/attributes/naturalperson/representative + GenderType + eidas-reprentative-natural + eu.eidas.auth.commons.protocol.eidas.impl.GenderAttributeValueMarshaller + + http://eidas.europa.eu/attributes/legalperson/representative/LegalPersonIdentifier + RepresentativeLegalPersonIdentifier + RepresentativeLegalPerson + false + true + http://eidas.europa.eu/attributes/legalperson/representative + LegalPersonIdentifierType + eidas-reprentative-legal + eu.eidas.auth.commons.attribute.impl.LiteralStringAttributeValueMarshaller + + http://eidas.europa.eu/attributes/legalperson/representative/LegalName + RepresentativeLegalName + RepresentativeLegalPerson + false + true + http://eidas.europa.eu/attributes/legalperson/representative + LegalNameType + eidas-reprentative-legal + eu.eidas.auth.commons.attribute.impl.LiteralStringAttributeValueMarshaller + + http://eidas.europa.eu/attributes/legalperson/representative/LegalPersonAddress + RepresentativeLegalAddress + RepresentativeLegalPerson + false + http://eidas.europa.eu/attributes/legalperson/representative + LegalPersonAddressType + eidas-reprentative-legal + eu.eidas.auth.commons.protocol.eidas.impl.RepvLegalAddressAttributeValueMarshaller + + http://eidas.europa.eu/attributes/legalperson/representative/VATRegistrationNumber + RepresentativeVATRegistration + RepresentativeLegalPerson + false + http://eidas.europa.eu/attributes/legalperson/representative + VATRegistrationNumberType + eidas-reprentative-legal + eu.eidas.auth.commons.attribute.impl.LiteralStringAttributeValueMarshaller + + http://eidas.europa.eu/attributes/legalperson/representative/TaxReference + RepresentativeTaxReference + RepresentativeLegalPerson + false + http://eidas.europa.eu/attributes/legalperson/representative + TaxReferenceType + eidas-reprentative-legal + eu.eidas.auth.commons.attribute.impl.LiteralStringAttributeValueMarshaller + + http://eidas.europa.eu/attributes/legalperson/representative/D-2012-17-EUIdentifier + RepresentativeD-2012-17-EUIdentifier + RepresentativeLegalPerson + false + http://eidas.europa.eu/attributes/legalperson/representative + D-2012-17-EUIdentifierType + eidas-reprentative-legal + eu.eidas.auth.commons.attribute.impl.LiteralStringAttributeValueMarshaller + + http://eidas.europa.eu/attributes/legalperson/representative/LEI + RepresentativeLEI + RepresentativeLegalPerson + false + http://eidas.europa.eu/attributes/legalperson/representative + LEIType + eidas-reprentative-legal + eu.eidas.auth.commons.attribute.impl.LiteralStringAttributeValueMarshaller + + http://eidas.europa.eu/attributes/legalperson/representative/EORI + RepresentativeEORI + RepresentativeLegalPerson + false + http://eidas.europa.eu/attributes/legalperson/representative + EORIType + eidas-reprentative-legal + eu.eidas.auth.commons.attribute.impl.LiteralStringAttributeValueMarshaller + + http://eidas.europa.eu/attributes/legalperson/representative/SEED + RepresentativeSEED + RepresentativeLegalPerson + false + http://eidas.europa.eu/attributes/legalperson/representative + SEEDType + eidas-reprentative-legal + eu.eidas.auth.commons.attribute.impl.LiteralStringAttributeValueMarshaller + + http://eidas.europa.eu/attributes/legalperson/representative/SIC + RepresentativeSIC + RepresentativeLegalPerson + false + http://eidas.europa.eu/attributes/legalperson/representative + SICType + eidas-reprentative-legal + eu.eidas.auth.commons.attribute.impl.LiteralStringAttributeValueMarshaller + + http://eidas.europa.eu/attributes/legalperson/representative/LegalPersonAddress + RepresentativeLegalAddress + RepresentativeLegalPerson + false + http://eidas.europa.eu/attributes/legalperson/representative + LegalPersonAddressType + eidas-reprentative-legal + eu.eidas.auth.commons.protocol.eidas.impl.RepvLegalAddressAttributeValueMarshaller + + http://eidas.europa.eu/attributes/legalperson/representative/VATRegistrationNumber + RepresentativeVATRegistration + RepresentativeLegalPerson + false + http://eidas.europa.eu/attributes/legalperson/representative + VATRegistrationNumberType + eidas-reprentative-legal + eu.eidas.auth.commons.attribute.impl.LiteralStringAttributeValueMarshaller + + + diff --git a/modules/authmodule-eIDAS-v2/src/test/resources/config/junit_config_1.properties b/modules/authmodule-eIDAS-v2/src/test/resources/config/junit_config_1.properties new file mode 100644 index 00000000..a662379c --- /dev/null +++ b/modules/authmodule-eIDAS-v2/src/test/resources/config/junit_config_1.properties @@ -0,0 +1,117 @@ +## Basic service configuration +eidas.ms.context.url.prefix= +eidas.ms.context.url.request.validation=false + +eidas.ms.context.use.clustermode=true + +##Monitoring +eidas.ms.monitoring.eIDASNode.metadata.url= + + +##Specific logger configuration +eidas.ms.technicallog.write.MDS.into.techlog=true +eidas.ms.revisionlog.write.MDS.into.revisionlog=true +eidas.ms.revisionlog.logIPAddressOfUser=true + +##Directory for static Web content +eidas.ms.webcontent.static.directory=webcontent/ +eidas.ms.webcontent.templates=templates/ +eidas.ms.webcontent.properties=properties/messages + +## extended validation of pending-request Id's +eidas.ms.core.pendingrequestid.maxlifetime=300 +eidas.ms.core.pendingrequestid.digist.algorithm=HmacSHA256 +eidas.ms.core.pendingrequestid.digist.secret=pendingReqIdSecret + +## eIDAS Ref. Implementation connector ### +eidas.ms.auth.eIDAS.node_v2.entityId=ownSpecificConnector +eidas.ms.auth.eIDAS.node_v2.forward.endpoint= +eidas.ms.auth.eIDAS.node_v2.forward.method=POST +eidas.ms.auth.eIDAS.node_v2.countrycode=AT +eidas.ms.auth.eIDAS.node_v2.publicSectorTargets=.* +eidas.ms.auth.eIDAS.node_v2.workarounds.addAlwaysProviderName=true +eidas.ms.auth.eIDAS.node_v2.workarounds.useRequestIdAsTransactionIdentifier=true +eidas.ms.auth.eIDAS.node_v2.workarounds.useStaticProviderNameForPublicSPs=true +eidas.ms.auth.eIDAS.node_v2.staticProviderNameForPublicSPs=myNode + +eidas.ms.auth.eIDAS.node_v2.loa.requested.minimum=http://eidas.europa.eu/LoA/high + +eidas.ms.auth.eIDAS.szrclient.useTestService=true +eidas.ms.auth.eIDAS.szrclient.endpoint.prod= +eidas.ms.auth.eIDAS.szrclient.endpoint.test=http://localhost:1234/demoszr +eidas.ms.auth.eIDAS.szrclient.ssl.keyStore.path=keys/..... +eidas.ms.auth.eIDAS.szrclient.ssl.keyStore.password= +eidas.ms.auth.eIDAS.szrclient.ssl.trustStore.path= +eidas.ms.auth.eIDAS.szrclient.ssl.trustStore.password= +eidas.ms.auth.eIDAS.szrclient.timeout.connection=15 +eidas.ms.auth.eIDAS.szrclient.timeout.response=30 +eidas.ms.auth.eIDAS.szrclient.params.vkz= + +eidas.ms.auth.eIDAS.szrclient.params.useSZRForbPKCalculation=false + + +eidas.ms.auth.eIDAS.authblock.keystore.password=f/+saJBc3a}*/T^s +eidas.ms.auth.eIDAS.authblock.keystore.friendlyName=connectorkeypair +eidas.ms.auth.eIDAS.authblock.keystore.path=./../keystore/teststore.jks +eidas.ms.auth.eIDAS.authblock.keystore.type=jks +eidas.ms.auth.eIDAS.authblock.key.alias=connectorkeypair +eidas.ms.auth.eIDAS.authblock.key.password=f/+saJBc3a}*/T^s + + +#Raw eIDAS Id data storage +eidas.ms.auth.eIDAS.szrclient.workarounds.eidmapping.revisionlog.active=true + +eidas.ms.auth.eIDAS.szrclient.params.setPlaceOfBirthIfAvailable=true +eidas.ms.auth.eIDAS.szrclient.params.setBirthNameIfAvailable=true + +eidas.ms.auth.eIDAS.szrclient.debug.logfullmessages=true +eidas.ms.auth.eIDAS.szrclient.debug.useDummySolution=true + +##without mandates +eidas.ms.auth.eIDAS.node_v2.attributes.requested.onlynatural.0=PersonIdentifier,true +eidas.ms.auth.eIDAS.node_v2.attributes.requested.onlynatural.1=FamilyName,true +eidas.ms.auth.eIDAS.node_v2.attributes.requested.onlynatural.2=FirstName,true +eidas.ms.auth.eIDAS.node_v2.attributes.requested.onlynatural.3=DateOfBirth,true + +eidas.ms.auth.eIDAS.node_v2.attributes.requested.de.onlynatural.4=PlaceOfBirth,false +eidas.ms.auth.eIDAS.node_v2.attributes.requested.de.onlynatural.5=BirthName,false +eidas.ms.auth.eIDAS.node_v2.attributes.requested.de.onlynatural.6=Gender,false +eidas.ms.auth.eIDAS.node_v2.attributes.requested.de.onlynatural.7=CurrentAddress,false +eidas.ms.auth.eIDAS.node_v2.attributes.requested.de.onlynatural.8=testtest,false + +##with mandates ---- NOT FULLY SUPPORTED AT THE MOMENT ----- +eidas.ms.auth.eIDAS.node_v2.attributes.requested.representation.0=PersonIdentifier,true +eidas.ms.auth.eIDAS.node_v2.attributes.requested.representation.1=FamilyName,true +eidas.ms.auth.eIDAS.node_v2.attributes.requested.representation.2=FirstName,true +eidas.ms.auth.eIDAS.node_v2.attributes.requested.representation.3=DateOfBirth,true +eidas.ms.auth.eIDAS.node_v2.attributes.requested.representation.4=LegalPerson,true +eidas.ms.auth.eIDAS.node_v2.attributes.requested.representation.5=LegalName,true + + +## PVP2 S-Profile end-point configuration +eidas.ms.pvp2.keystore.path=keys/..... +eidas.ms.pvp2.keystore.password= +eidas.ms.pvp2.key.metadata.alias= +eidas.ms.pvp2.key.metadata.password= +eidas.ms.pvp2.key.signing.alias= +eidas.ms.pvp2.key.signing.password= +eidas.ms.pvp2.metadata.validity=24 + +## Service Provider configuration +eidas.ms.sp.0.uniqueID= +eidas.ms.sp.0.pvp2.metadata.truststore= +eidas.ms.sp.0.pvp2.metadata.truststore.password= +eidas.ms.sp.0.newEidMode=true + +#eidas.ms.sp.0.friendlyName= +#eidas.ms.sp.0.pvp2.metadata.url= +#eidas.ms.sp.0.policy.allowed.requested.targets=.* +#eidas.ms.sp.0.policy.hasBaseIdTransferRestriction=false + + +##only for advanced config +eidas.ms.configuration.sp.disableRegistrationRequirement= +eidas.ms.configuration.restrictions.baseID.spTransmission= +eidas.ms.configuration.auth.default.countrycode= +eidas.ms.configuration.pvp.scheme.validation= +eidas.ms.configuration.pvp.enable.entitycategories= \ No newline at end of file diff --git a/modules/authmodule-eIDAS-v2/src/test/resources/config/junit_config_2.properties b/modules/authmodule-eIDAS-v2/src/test/resources/config/junit_config_2.properties new file mode 100644 index 00000000..7c5e5a40 --- /dev/null +++ b/modules/authmodule-eIDAS-v2/src/test/resources/config/junit_config_2.properties @@ -0,0 +1,114 @@ +## Basic service configuration +eidas.ms.context.url.prefix= +eidas.ms.context.url.request.validation=false + +eidas.ms.context.use.clustermode=true + +##Monitoring +eidas.ms.monitoring.eIDASNode.metadata.url= + + +##Specific logger configuration +eidas.ms.technicallog.write.MDS.into.techlog=true +eidas.ms.revisionlog.write.MDS.into.revisionlog=true +eidas.ms.revisionlog.logIPAddressOfUser=true + +##Directory for static Web content +eidas.ms.webcontent.static.directory=webcontent/ +eidas.ms.webcontent.templates=templates/ +eidas.ms.webcontent.properties=properties/messages + +## extended validation of pending-request Id's +eidas.ms.core.pendingrequestid.maxlifetime=300 +eidas.ms.core.pendingrequestid.digist.algorithm=HmacSHA256 +eidas.ms.core.pendingrequestid.digist.secret=pendingReqIdSecret + +## eIDAS Ref. Implementation connector ### +eidas.ms.auth.eIDAS.node_v2.entityId=ownSpecificConnector +eidas.ms.auth.eIDAS.node_v2.forward.endpoint=http://test +eidas.ms.auth.eIDAS.node_v2.forward.method=GET +eidas.ms.auth.eIDAS.node_v2.countrycode=AT +#eidas.ms.auth.eIDAS.node_v2.publicSectorTargets=.* +eidas.ms.auth.eIDAS.node_v2.workarounds.addAlwaysProviderName=true +eidas.ms.auth.eIDAS.node_v2.workarounds.useRequestIdAsTransactionIdentifier=true +eidas.ms.auth.eIDAS.node_v2.workarounds.useStaticProviderNameForPublicSPs=false + +eidas.ms.auth.eIDAS.node_v2.loa.requested.minimum=http://eidas.europa.eu/LoA/high + +eidas.ms.auth.eIDAS.szrclient.useTestService=true +eidas.ms.auth.eIDAS.szrclient.endpoint.prod= +eidas.ms.auth.eIDAS.szrclient.endpoint.test=http://localhost:1234/demoszr +eidas.ms.auth.eIDAS.szrclient.ssl.keyStore.path=keys/..... +eidas.ms.auth.eIDAS.szrclient.ssl.keyStore.password= +eidas.ms.auth.eIDAS.szrclient.ssl.trustStore.path= +eidas.ms.auth.eIDAS.szrclient.ssl.trustStore.password= +eidas.ms.auth.eIDAS.szrclient.timeout.connection=15 +eidas.ms.auth.eIDAS.szrclient.timeout.response=30 +eidas.ms.auth.eIDAS.szrclient.params.vkz= + +eidas.ms.auth.eIDAS.szrclient.params.useSZRForbPKCalculation=false + + +eidas.ms.auth.eIDAS.authblock.keystore.password=f/+saJBc3a}*/T^s +eidas.ms.auth.eIDAS.authblock.keystore.friendlyName=connectorkeypair +eidas.ms.auth.eIDAS.authblock.keystore.path=./../keystore/teststore.jks +eidas.ms.auth.eIDAS.authblock.keystore.type=jks +eidas.ms.auth.eIDAS.authblock.key.alias=connectorkeypair +eidas.ms.auth.eIDAS.authblock.key.password=f/+saJBc3a}*/T^s + + +#Raw eIDAS Id data storage +eidas.ms.auth.eIDAS.szrclient.workarounds.eidmapping.revisionlog.active=true + +eidas.ms.auth.eIDAS.szrclient.params.setPlaceOfBirthIfAvailable=true +eidas.ms.auth.eIDAS.szrclient.params.setBirthNameIfAvailable=true + +eidas.ms.auth.eIDAS.szrclient.debug.logfullmessages=true +eidas.ms.auth.eIDAS.szrclient.debug.useDummySolution=true + +##without mandates +eidas.ms.auth.eIDAS.node_v2.attributes.requested.onlynatural.0=PersonIdentifier,true +eidas.ms.auth.eIDAS.node_v2.attributes.requested.onlynatural.1=FamilyName,true +eidas.ms.auth.eIDAS.node_v2.attributes.requested.onlynatural.2=FirstName,true +eidas.ms.auth.eIDAS.node_v2.attributes.requested.onlynatural.3=DateOfBirth,true + +eidas.ms.auth.eIDAS.node_v2.attributes.requested.onlynatural.4=PlaceOfBirth,false +eidas.ms.auth.eIDAS.node_v2.attributes.requested.onlynatural.5=BirthName,false +eidas.ms.auth.eIDAS.node_v2.attributes.requested.onlynatural.6=Gender,false +eidas.ms.auth.eIDAS.node_v2.attributes.requested.onlynatural.7=CurrentAddress,false + +##with mandates ---- NOT FULLY SUPPORTED AT THE MOMENT ----- +eidas.ms.auth.eIDAS.node_v2.attributes.requested.representation.0=PersonIdentifier,true +eidas.ms.auth.eIDAS.node_v2.attributes.requested.representation.1=FamilyName,true +eidas.ms.auth.eIDAS.node_v2.attributes.requested.representation.2=FirstName,true +eidas.ms.auth.eIDAS.node_v2.attributes.requested.representation.3=DateOfBirth,true +eidas.ms.auth.eIDAS.node_v2.attributes.requested.representation.4=LegalPerson,true +eidas.ms.auth.eIDAS.node_v2.attributes.requested.representation.5=LegalName,true + + +## PVP2 S-Profile end-point configuration +eidas.ms.pvp2.keystore.path=keys/..... +eidas.ms.pvp2.keystore.password= +eidas.ms.pvp2.key.metadata.alias= +eidas.ms.pvp2.key.metadata.password= +eidas.ms.pvp2.key.signing.alias= +eidas.ms.pvp2.key.signing.password= +eidas.ms.pvp2.metadata.validity=24 + +## Service Provider configuration +eidas.ms.sp.0.uniqueID= +eidas.ms.sp.0.pvp2.metadata.truststore= +eidas.ms.sp.0.pvp2.metadata.truststore.password= + +#eidas.ms.sp.0.friendlyName= +#eidas.ms.sp.0.pvp2.metadata.url= +#eidas.ms.sp.0.policy.allowed.requested.targets=.* +#eidas.ms.sp.0.policy.hasBaseIdTransferRestriction=false + + +##only for advanced config +eidas.ms.configuration.sp.disableRegistrationRequirement= +eidas.ms.configuration.restrictions.baseID.spTransmission= +eidas.ms.configuration.auth.default.countrycode= +eidas.ms.configuration.pvp.scheme.validation= +eidas.ms.configuration.pvp.enable.entitycategories= \ No newline at end of file diff --git a/modules/authmodule-eIDAS-v2/src/test/resources/config/junit_config_3.properties b/modules/authmodule-eIDAS-v2/src/test/resources/config/junit_config_3.properties new file mode 100644 index 00000000..c830d447 --- /dev/null +++ b/modules/authmodule-eIDAS-v2/src/test/resources/config/junit_config_3.properties @@ -0,0 +1,118 @@ +## Basic service configuration +eidas.ms.context.url.prefix= +eidas.ms.context.url.request.validation=false + +eidas.ms.context.use.clustermode=true + +##Monitoring +eidas.ms.monitoring.eIDASNode.metadata.url= + + +##Specific logger configuration +eidas.ms.technicallog.write.MDS.into.techlog=true +eidas.ms.revisionlog.write.MDS.into.revisionlog=true +eidas.ms.revisionlog.logIPAddressOfUser=true + +##Directory for static Web content +eidas.ms.webcontent.static.directory=webcontent/ +eidas.ms.webcontent.templates=templates/ +eidas.ms.webcontent.properties=properties/messages + +## extended validation of pending-request Id's +eidas.ms.core.pendingrequestid.maxlifetime=300 +eidas.ms.core.pendingrequestid.digist.algorithm=HmacSHA256 +eidas.ms.core.pendingrequestid.digist.secret=pendingReqIdSecret + +## eIDAS Ref. Implementation connector ### +eidas.ms.auth.eIDAS.node_v2.entityId=ownSpecificConnector +eidas.ms.auth.eIDAS.node_v2.forward.endpoint=http://test.com/ +eidas.ms.auth.eIDAS.node_v2.forward.method=POST +eidas.ms.auth.eIDAS.node_v2.countrycode=AT +eidas.ms.auth.eIDAS.node_v2.publicSectorTargets=.* +eidas.ms.auth.eIDAS.node_v2.workarounds.addAlwaysProviderName=true +eidas.ms.auth.eIDAS.node_v2.workarounds.useRequestIdAsTransactionIdentifier=true +eidas.ms.auth.eIDAS.node_v2.workarounds.useStaticProviderNameForPublicSPs=true +eidas.ms.auth.eIDAS.node_v2.staticProviderNameForPublicSPs=myNode + +eidas.ms.auth.eIDAS.node_v2.loa.requested.minimum=http://eidas.europa.eu/LoA/high + +eidas.ms.auth.eIDAS.szrclient.useTestService=true +eidas.ms.auth.eIDAS.szrclient.endpoint.prod= +eidas.ms.auth.eIDAS.szrclient.endpoint.test=http://localhost:1234/demoszr +eidas.ms.auth.eIDAS.szrclient.ssl.keyStore.path=keys/..... +eidas.ms.auth.eIDAS.szrclient.ssl.keyStore.password= +eidas.ms.auth.eIDAS.szrclient.ssl.trustStore.path= +eidas.ms.auth.eIDAS.szrclient.ssl.trustStore.password= +eidas.ms.auth.eIDAS.szrclient.timeout.connection=15 +eidas.ms.auth.eIDAS.szrclient.timeout.response=30 +eidas.ms.auth.eIDAS.szrclient.params.vkz= + +eidas.ms.auth.eIDAS.authblock.keystore.password=f/+saJBc3a}*/T^s +eidas.ms.auth.eIDAS.authblock.keystore.friendlyName=connectorkeypair +eidas.ms.auth.eIDAS.authblock.keystore.path=./../keystore/teststore.jks +eidas.ms.auth.eIDAS.authblock.keystore.type=jks +eidas.ms.auth.eIDAS.authblock.key.alias=connectorkeypair +eidas.ms.auth.eIDAS.authblock.key.password=f/+saJBc3a}*/T^s + + +eidas.ms.auth.eIDAS.szrclient.params.useSZRForbPKCalculation=false + + +#Raw eIDAS Id data storage +eidas.ms.auth.eIDAS.szrclient.workarounds.eidmapping.revisionlog.active=true + +eidas.ms.auth.eIDAS.szrclient.params.setPlaceOfBirthIfAvailable=true +eidas.ms.auth.eIDAS.szrclient.params.setBirthNameIfAvailable=true + +eidas.ms.auth.eIDAS.szrclient.debug.logfullmessages=true +eidas.ms.auth.eIDAS.szrclient.debug.useDummySolution=false + +##without mandates +eidas.ms.auth.eIDAS.node_v2.attributes.requested.onlynatural.0=PersonIdentifier,true +eidas.ms.auth.eIDAS.node_v2.attributes.requested.onlynatural.1=FamilyName,true +eidas.ms.auth.eIDAS.node_v2.attributes.requested.onlynatural.2=FirstName,true +eidas.ms.auth.eIDAS.node_v2.attributes.requested.onlynatural.3=DateOfBirth,true + +eidas.ms.auth.eIDAS.node_v2.attributes.requested.de.onlynatural.4=PlaceOfBirth,false +eidas.ms.auth.eIDAS.node_v2.attributes.requested.de.onlynatural.5=BirthName,false +eidas.ms.auth.eIDAS.node_v2.attributes.requested.de.onlynatural.6=Gender,false +eidas.ms.auth.eIDAS.node_v2.attributes.requested.de.onlynatural.7=CurrentAddress,false +eidas.ms.auth.eIDAS.node_v2.attributes.requested.de.onlynatural.8=testtest,false + +##with mandates ---- NOT FULLY SUPPORTED AT THE MOMENT ----- +eidas.ms.auth.eIDAS.node_v2.attributes.requested.representation.0=PersonIdentifier,true +eidas.ms.auth.eIDAS.node_v2.attributes.requested.representation.1=FamilyName,true +eidas.ms.auth.eIDAS.node_v2.attributes.requested.representation.2=FirstName,true +eidas.ms.auth.eIDAS.node_v2.attributes.requested.representation.3=DateOfBirth,true +eidas.ms.auth.eIDAS.node_v2.attributes.requested.representation.4=LegalPerson,true +eidas.ms.auth.eIDAS.node_v2.attributes.requested.representation.5=LegalName,true + + +## PVP2 S-Profile end-point configuration +eidas.ms.pvp2.keystore.path=keys/..... +eidas.ms.pvp2.keystore.password= +eidas.ms.pvp2.key.metadata.alias= +eidas.ms.pvp2.key.metadata.password= +eidas.ms.pvp2.key.signing.alias= +eidas.ms.pvp2.key.signing.password= +eidas.ms.pvp2.metadata.validity=24 + +## Service Provider configuration +eidas.ms.sp.0.uniqueID= +eidas.ms.sp.0.pvp2.metadata.truststore= +eidas.ms.sp.0.pvp2.metadata.truststore.password= +eidas.ms.sp.0.newEidMode=true + + +#eidas.ms.sp.0.friendlyName= +#eidas.ms.sp.0.pvp2.metadata.url= +#eidas.ms.sp.0.policy.allowed.requested.targets=.* +#eidas.ms.sp.0.policy.hasBaseIdTransferRestriction=false + + +##only for advanced config +eidas.ms.configuration.sp.disableRegistrationRequirement= +eidas.ms.configuration.restrictions.baseID.spTransmission= +eidas.ms.configuration.auth.default.countrycode= +eidas.ms.configuration.pvp.scheme.validation= +eidas.ms.configuration.pvp.enable.entitycategories= \ No newline at end of file diff --git a/modules/authmodule-eIDAS-v2/src/test/resources/config/junit_config_4.properties b/modules/authmodule-eIDAS-v2/src/test/resources/config/junit_config_4.properties new file mode 100644 index 00000000..01e72069 --- /dev/null +++ b/modules/authmodule-eIDAS-v2/src/test/resources/config/junit_config_4.properties @@ -0,0 +1,114 @@ +## Basic service configuration +eidas.ms.context.url.prefix= +eidas.ms.context.url.request.validation=false + +eidas.ms.context.use.clustermode=true + +##Monitoring +eidas.ms.monitoring.eIDASNode.metadata.url= + + +##Specific logger configuration +eidas.ms.technicallog.write.MDS.into.techlog=true +eidas.ms.revisionlog.write.MDS.into.revisionlog=true +eidas.ms.revisionlog.logIPAddressOfUser=true + +##Directory for static Web content +eidas.ms.webcontent.static.directory=webcontent/ +eidas.ms.webcontent.templates=templates/ +eidas.ms.webcontent.properties=properties/messages + +## extended validation of pending-request Id's +eidas.ms.core.pendingrequestid.maxlifetime=300 +eidas.ms.core.pendingrequestid.digist.algorithm=HmacSHA256 +eidas.ms.core.pendingrequestid.digist.secret=pendingReqIdSecret + +## eIDAS Ref. Implementation connector ### +eidas.ms.auth.eIDAS.node_v2.entityId=ownSpecificConnector +eidas.ms.auth.eIDAS.node_v2.forward.endpoint=http://test +eidas.ms.auth.eIDAS.node_v2.forward.method=GET +eidas.ms.auth.eIDAS.node_v2.countrycode=AT +#eidas.ms.auth.eIDAS.node_v2.publicSectorTargets=.* +eidas.ms.auth.eIDAS.node_v2.workarounds.addAlwaysProviderName=false +eidas.ms.auth.eIDAS.node_v2.workarounds.useRequestIdAsTransactionIdentifier=true +eidas.ms.auth.eIDAS.node_v2.workarounds.useStaticProviderNameForPublicSPs=false + +eidas.ms.auth.eIDAS.node_v2.loa.requested.minimum=http://eidas.europa.eu/LoA/high + +eidas.ms.auth.eIDAS.szrclient.useTestService=true +eidas.ms.auth.eIDAS.szrclient.endpoint.prod= +eidas.ms.auth.eIDAS.szrclient.endpoint.test=http://localhost:1234/demoszr +eidas.ms.auth.eIDAS.szrclient.ssl.keyStore.path=keys/..... +eidas.ms.auth.eIDAS.szrclient.ssl.keyStore.password= +eidas.ms.auth.eIDAS.szrclient.ssl.trustStore.path= +eidas.ms.auth.eIDAS.szrclient.ssl.trustStore.password= +eidas.ms.auth.eIDAS.szrclient.timeout.connection=15 +eidas.ms.auth.eIDAS.szrclient.timeout.response=30 +eidas.ms.auth.eIDAS.szrclient.params.vkz= + +eidas.ms.auth.eIDAS.szrclient.params.useSZRForbPKCalculation=false + + +eidas.ms.auth.eIDAS.authblock.keystore.password=f/+saJBc3a}*/T^s +eidas.ms.auth.eIDAS.authblock.keystore.friendlyName=connectorkeypair +eidas.ms.auth.eIDAS.authblock.keystore.path=./../keystore/teststore.jks +eidas.ms.auth.eIDAS.authblock.keystore.type=jks +eidas.ms.auth.eIDAS.authblock.key.alias=connectorkeypair +eidas.ms.auth.eIDAS.authblock.key.password=f/+saJBc3a}*/T^s + + +#Raw eIDAS Id data storage +eidas.ms.auth.eIDAS.szrclient.workarounds.eidmapping.revisionlog.active=true + +eidas.ms.auth.eIDAS.szrclient.params.setPlaceOfBirthIfAvailable=true +eidas.ms.auth.eIDAS.szrclient.params.setBirthNameIfAvailable=true + +eidas.ms.auth.eIDAS.szrclient.debug.logfullmessages=true +eidas.ms.auth.eIDAS.szrclient.debug.useDummySolution=true + +##without mandates +eidas.ms.auth.eIDAS.node_v2.attributes.requested.onlynatural.0=PersonIdentifier,true +eidas.ms.auth.eIDAS.node_v2.attributes.requested.onlynatural.1=FamilyName,true +eidas.ms.auth.eIDAS.node_v2.attributes.requested.onlynatural.2=FirstName,true +eidas.ms.auth.eIDAS.node_v2.attributes.requested.onlynatural.3=DateOfBirth,true + +eidas.ms.auth.eIDAS.node_v2.attributes.requested.onlynatural.4=PlaceOfBirth,false +eidas.ms.auth.eIDAS.node_v2.attributes.requested.onlynatural.5=BirthName,false +eidas.ms.auth.eIDAS.node_v2.attributes.requested.onlynatural.6=Gender,false +eidas.ms.auth.eIDAS.node_v2.attributes.requested.onlynatural.7=CurrentAddress,false + +##with mandates ---- NOT FULLY SUPPORTED AT THE MOMENT ----- +eidas.ms.auth.eIDAS.node_v2.attributes.requested.representation.0=PersonIdentifier,true +eidas.ms.auth.eIDAS.node_v2.attributes.requested.representation.1=FamilyName,true +eidas.ms.auth.eIDAS.node_v2.attributes.requested.representation.2=FirstName,true +eidas.ms.auth.eIDAS.node_v2.attributes.requested.representation.3=DateOfBirth,true +eidas.ms.auth.eIDAS.node_v2.attributes.requested.representation.4=LegalPerson,true +eidas.ms.auth.eIDAS.node_v2.attributes.requested.representation.5=LegalName,true + + +## PVP2 S-Profile end-point configuration +eidas.ms.pvp2.keystore.path=keys/..... +eidas.ms.pvp2.keystore.password= +eidas.ms.pvp2.key.metadata.alias= +eidas.ms.pvp2.key.metadata.password= +eidas.ms.pvp2.key.signing.alias= +eidas.ms.pvp2.key.signing.password= +eidas.ms.pvp2.metadata.validity=24 + +## Service Provider configuration +eidas.ms.sp.0.uniqueID= +eidas.ms.sp.0.pvp2.metadata.truststore= +eidas.ms.sp.0.pvp2.metadata.truststore.password= + +#eidas.ms.sp.0.friendlyName= +#eidas.ms.sp.0.pvp2.metadata.url= +#eidas.ms.sp.0.policy.allowed.requested.targets=.* +#eidas.ms.sp.0.policy.hasBaseIdTransferRestriction=false + + +##only for advanced config +eidas.ms.configuration.sp.disableRegistrationRequirement= +eidas.ms.configuration.restrictions.baseID.spTransmission= +eidas.ms.configuration.auth.default.countrycode= +eidas.ms.configuration.pvp.scheme.validation= +eidas.ms.configuration.pvp.enable.entitycategories= \ No newline at end of file diff --git a/modules/authmodule-eIDAS-v2/src/test/resources/config/junit_config_de_attributes.properties b/modules/authmodule-eIDAS-v2/src/test/resources/config/junit_config_de_attributes.properties new file mode 100644 index 00000000..6b235667 --- /dev/null +++ b/modules/authmodule-eIDAS-v2/src/test/resources/config/junit_config_de_attributes.properties @@ -0,0 +1,116 @@ +## Basic service configuration +eidas.ms.context.url.prefix= +eidas.ms.context.url.request.validation=false +eidas.ms.core.configRootDir=file:./src/test/resources/config/ + + +eidas.ms.context.use.clustermode=true + +##Monitoring +eidas.ms.monitoring.eIDASNode.metadata.url= + + +##Specific logger configuration +eidas.ms.technicallog.write.MDS.into.techlog=true +eidas.ms.revisionlog.write.MDS.into.revisionlog=true +eidas.ms.revisionlog.logIPAddressOfUser=true + +##Directory for static Web content +eidas.ms.webcontent.static.directory=webcontent/ +eidas.ms.webcontent.templates=templates/ +eidas.ms.webcontent.properties=properties/messages + +## extended validation of pending-request Id's +eidas.ms.core.pendingrequestid.maxlifetime=300 +eidas.ms.core.pendingrequestid.digist.algorithm=HmacSHA256 +eidas.ms.core.pendingrequestid.digist.secret=pendingReqIdSecret + +## eIDAS Ref. Implementation connector ### +eidas.ms.auth.eIDAS.node_v2.entityId=ownSpecificConnector +eidas.ms.auth.eIDAS.node_v2.forward.endpoint=http://test +eidas.ms.auth.eIDAS.node_v2.forward.method=GET +eidas.ms.auth.eIDAS.node_v2.countrycode=AT +#eidas.ms.auth.eIDAS.node_v2.publicSectorTargets=.* +eidas.ms.auth.eIDAS.node_v2.workarounds.addAlwaysProviderName=true +eidas.ms.auth.eIDAS.node_v2.workarounds.useRequestIdAsTransactionIdentifier=true +eidas.ms.auth.eIDAS.node_v2.workarounds.useStaticProviderNameForPublicSPs=true + +eidas.ms.auth.eIDAS.node_v2.loa.requested.minimum=http://eidas.europa.eu/LoA/high + +eidas.ms.auth.eIDAS.szrclient.useTestService=true +eidas.ms.auth.eIDAS.szrclient.endpoint.prod= +eidas.ms.auth.eIDAS.szrclient.endpoint.test=http://localhost:1234/demoszr +eidas.ms.auth.eIDAS.szrclient.ssl.keyStore.path=keys/..... +eidas.ms.auth.eIDAS.szrclient.ssl.keyStore.password= +eidas.ms.auth.eIDAS.szrclient.ssl.trustStore.path= +eidas.ms.auth.eIDAS.szrclient.ssl.trustStore.password= +eidas.ms.auth.eIDAS.szrclient.timeout.connection=15 +eidas.ms.auth.eIDAS.szrclient.timeout.response=30 +eidas.ms.auth.eIDAS.szrclient.params.vkz= + +eidas.ms.auth.eIDAS.szrclient.params.useSZRForbPKCalculation=false + + +eidas.ms.auth.eIDAS.authblock.keystore.password=f/+saJBc3a}*/T^s +eidas.ms.auth.eIDAS.authblock.keystore.friendlyName=connectorkeypair +eidas.ms.auth.eIDAS.authblock.keystore.path=./../keystore/teststore.jks +eidas.ms.auth.eIDAS.authblock.keystore.type=jks +eidas.ms.auth.eIDAS.authblock.key.alias=connectorkeypair +eidas.ms.auth.eIDAS.authblock.key.password=f/+saJBc3a}*/T^s + + +#Raw eIDAS Id data storage +eidas.ms.auth.eIDAS.szrclient.workarounds.eidmapping.revisionlog.active=true + +eidas.ms.auth.eIDAS.szrclient.params.setPlaceOfBirthIfAvailable=true +eidas.ms.auth.eIDAS.szrclient.params.setBirthNameIfAvailable=true + +eidas.ms.auth.eIDAS.szrclient.debug.logfullmessages=true +eidas.ms.auth.eIDAS.szrclient.debug.useDummySolution=true + +##without mandates +eidas.ms.auth.eIDAS.node_v2.attributes.requested.onlynatural.0=PersonIdentifier,true +eidas.ms.auth.eIDAS.node_v2.attributes.requested.onlynatural.1=FamilyName,true +eidas.ms.auth.eIDAS.node_v2.attributes.requested.onlynatural.2=FirstName,true +eidas.ms.auth.eIDAS.node_v2.attributes.requested.onlynatural.3=DateOfBirth,true + +eidas.ms.auth.eIDAS.node_v2.attributes.requested.de.onlynatural.4=PlaceOfBirth,false +eidas.ms.auth.eIDAS.node_v2.attributes.requested.de.onlynatural.5=BirthName,false +eidas.ms.auth.eIDAS.node_v2.attributes.requested.de.onlynatural.6=Gender,false +eidas.ms.auth.eIDAS.node_v2.attributes.requested.de.onlynatural.7=CurrentAddress,false + +##with mandates ---- NOT FULLY SUPPORTED AT THE MOMENT ----- +eidas.ms.auth.eIDAS.node_v2.attributes.requested.representation.0=PersonIdentifier,true +eidas.ms.auth.eIDAS.node_v2.attributes.requested.representation.1=FamilyName,true +eidas.ms.auth.eIDAS.node_v2.attributes.requested.representation.2=FirstName,true +eidas.ms.auth.eIDAS.node_v2.attributes.requested.representation.3=DateOfBirth,true +eidas.ms.auth.eIDAS.node_v2.attributes.requested.representation.4=LegalPerson,true +eidas.ms.auth.eIDAS.node_v2.attributes.requested.representation.5=LegalName,true + + +## PVP2 S-Profile end-point configuration +eidas.ms.pvp2.keystore.path=keys/..... +eidas.ms.pvp2.keystore.password= +eidas.ms.pvp2.key.metadata.alias= +eidas.ms.pvp2.key.metadata.password= +eidas.ms.pvp2.key.signing.alias= +eidas.ms.pvp2.key.signing.password= +eidas.ms.pvp2.metadata.validity=24 + +## Service Provider configuration +eidas.ms.sp.0.uniqueID= +eidas.ms.sp.0.pvp2.metadata.truststore= +eidas.ms.sp.0.pvp2.metadata.truststore.password= + +#eidas.ms.sp.0.friendlyName= +#eidas.ms.sp.0.pvp2.metadata.url= +#eidas.ms.sp.0.policy.allowed.requested.targets=.* +#eidas.ms.sp.0.policy.hasBaseIdTransferRestriction=false + + +##only for advanced config +eidas.ms.configuration.sp.disableRegistrationRequirement= +eidas.ms.configuration.restrictions.baseID.spTransmission= +eidas.ms.configuration.auth.default.countrycode= +eidas.ms.configuration.pvp.scheme.validation= +eidas.ms.configuration.pvp.enable.entitycategories= \ No newline at end of file diff --git a/modules/authmodule-eIDAS-v2/src/test/resources/data/junit.jks b/modules/authmodule-eIDAS-v2/src/test/resources/data/junit.jks new file mode 100644 index 00000000..a18df332 Binary files /dev/null and b/modules/authmodule-eIDAS-v2/src/test/resources/data/junit.jks differ diff --git a/modules/authmodule-eIDAS-v2/src/test/resources/data/szr/signed_eidasBind.jws b/modules/authmodule-eIDAS-v2/src/test/resources/data/szr/signed_eidasBind.jws new file mode 100644 index 00000000..f7c9a1c7 --- /dev/null +++ b/modules/authmodule-eIDAS-v2/src/test/resources/data/szr/signed_eidasBind.jws @@ -0,0 +1 @@ +eyJ1cm46YXQuZ3YuZWlkOmJpbmR0eXBlIjoidXJuOmF0Lmd2LmVpZDplaWRhc0JpbmQiLCJhbGciOiJSUzUxMiIsIng1dCNTMjU2IjoiY3FtcXBHdWlnS0NRelVWX1doWURHU1EyNEx6Zkxtd0ZtUlNYQlNYR3o3byJ9.eyJ1cm46ZWlkZ3ZhdDphdHRyaWJ1dGVzLnZzei52YWx1ZSI6IjhEYWNBTUxVSFEiLCJ1cm46ZWlkZ3ZhdDphdHRyaWJ1dGVzLnVzZXIucHVia2V5cyI6WyI1NDZ5OEtXZ3R1V3F1dXVNdC9DUWhKem1pWXZ3bzR1QzhLZWxxdUtMc2VLbG1mQ2dtcnpscGFQd3A1K3Q2NjI4Il0sInVybjplaWRndmF0OmF0dHJpYnV0ZXMuZWlkLnN0YXR1cyI6InVybjplaWRndmF0OmVpZC5zdGF0dXMuZWlkYXMifQ.WiECS-E5RB-zQV3JW6-3B7op093QErqq3yS2S4YVFQq9XmYzTD8UKo63yaHa-2U2WFUbiwNI3OOkwNZIAedMZHHblZ0jzjGTb58zL4Yvm6sPSlq3TP5u0emiQdjIJNQmILE5ZYVOgSA-4MWLXAgRQEl2A1w8lHxptE6ya83GdhA0gP51-rY_536qvVuaZHrQ2Lpahl-lTIY1Zi6Knqj1yFdH-auqkLxB44l-XvMv9QryBZMAkkmiu8J598rzIJ2ifGyw4UqHDJZ53GKUpBbU_X23ZjsZ8B5ZapRTO9JGoEEW3rMDEO5_9cjWYOCn87-CA3bMNVbo1KN146UZGuZbyXuevLPznRkbCtXS--IE0SuuLBaowcktX2ggeeSzaq6UZW7hSmQnErVgxxfP16ijBu8yylo-PFbqgYFNT-Ca2rS8i1Cs0KdPTahYIRm4xLARahYLQbqA15medm7JSoz4tA468c_hcNzyG9aGoXYuw1F5kUrJkHl0IWdHkvSR8RWw \ No newline at end of file diff --git a/modules/authmodule-eIDAS-v2/src/test/resources/data/szr/szr_resp_error_travelerdocexists.xml b/modules/authmodule-eIDAS-v2/src/test/resources/data/szr/szr_resp_error_travelerdocexists.xml new file mode 100644 index 00000000..d627ded2 --- /dev/null +++ b/modules/authmodule-eIDAS-v2/src/test/resources/data/szr/szr_resp_error_travelerdocexists.xml @@ -0,0 +1,6 @@ + + + p344:F455 + The travel document you sent to insert a person already exists for another person. Either check the document or have the person altered accordingly + urn:SZRServices + diff --git a/modules/authmodule-eIDAS-v2/src/test/resources/data/szr/szr_resp_valid_1.xml b/modules/authmodule-eIDAS-v2/src/test/resources/data/szr/szr_resp_valid_1.xml new file mode 100644 index 00000000..c376caef --- /dev/null +++ b/modules/authmodule-eIDAS-v2/src/test/resources/data/szr/szr_resp_valid_1.xml @@ -0,0 +1,50 @@ +k+zDM1BVpN1WJO4x7ZQ3ng==urn:publicid:gv.at:baseidFranzMustermannunknown1989-05-05 + + + + urn:oasis:names:tc:SAML:1.0:cm:sender-vouches + + k+zDM1BVpN1WJO4x7ZQ3ng==urn:publicid:gv.at:baseidHansMustermann1989-05-05 + + + + + + + + + + + + not(ancestor-or-self::pr:Identification) + + + + + GZjlsEXIhUPBSbOR1R8P4dzRJHE= + + + + lCnWsFICFg0ogj0Ha7++Y9gyOQg= + + + + a6tPfkdriEzAyQh2jU3/4j48baaPnY/i510OHx0vwHRvXLz80UyZzffdmtaRuk3iHVxgUMd9 + Ld0DLsRt6tFJiPLyBCo0QCuqaOwgTcuUI3Ku/oySpqMjqug3AMdrhxW2j41yQlzvkjiZTT4j + zQ9GHFnZnnob0+bBflqIjZOl4xc= + MIICTzCCAbigAwIBAgIBADANBgkqhkiG9w0BAQUFADATMREwDwYDVQQDEwhTWlJQRVJTQjAeFw0wNTA3MDEwMDAwMDBaFw00MDEyMzEyMzU5NTlaMBMxETAPBgNVBAMTCFNaUlBFUlNCMIIBHzANBgkqhkiG9w0BAQEFAAOCAQwAMIIBBwKBgQDGNmo9LOohefioGreKU6j6R05jUwHuddziSOQPolmMSXQG6NnnlLQaITv7BEmFj+EBqaOc+891wgZCRvNA2h+fHdJ69QXi/xjCovJI5SHh9jA+ssqhZ68iXOZHPq4WeegtYiYyJaRxWF+iPLqSm+bknS/KuBUcZol9SM3r6CMf0wKBgHytGrIelzc9ZN97VYXLkOJxi4TNSSj3Q/1TIC0s+HSzjbD694Y6ufINpR+IQm5epLTdXx9Dxv19bYnsLEIt0niMd2Cnm1DxXe8iNaDzpWec7fbRT6vDBwtTnyQkGfu2GGF3nSvVZ5AUDbLdAfZLOlbwsZmPnWU1zktSkLgKnT2XozIwMDAuBglghkgBhvhCAQ0EIRMfQ3JlYXRlZCBieSB6L09TIElDU0YgLSBIQ1I3NzgwIDANBgkqhkiG9w0BAQUFAAOBgQBwPc3l/Qf4myH8rsAAM5HqdCR68bMegWgNVxlPNl5DNJEE2hbPhIJ/K6TF6cjROYKDVuQ/+drtsZcrEOaqhqD3qw7MXAiT9GurV99YM/qTBsMy13yjU3LqeFX25Om8JlccGF5G+iHrVjfNQEUocGnGxCAPMlBvGwia4JjJcIPx7Q== + + + + + + not(ancestor-or-self::dsig:Signature) + + + + SbpaaSlLolEX5D9P7HyTPnImvns= + + + + +ERN \ No newline at end of file diff --git a/modules/authmodule-eIDAS-v2/src/test/resources/data/szr/szr_resp_valid_2.xml b/modules/authmodule-eIDAS-v2/src/test/resources/data/szr/szr_resp_valid_2.xml new file mode 100644 index 00000000..f07c67d6 --- /dev/null +++ b/modules/authmodule-eIDAS-v2/src/test/resources/data/szr/szr_resp_valid_2.xml @@ -0,0 +1,50 @@ +k+zDM1BVpN1WJO4x7ZQ3ng==urn:publicid:gv.at:baseidFranzMustermannunknown1989-05-05 + + + + urn:oasis:names:tc:SAML:1.0:cm:sender-vouches + + k+zDM1BV1312312332x7ZQ3ng==urn:publicid:gv.at:baseidMartinaMusterfrau1991-04-15 + + + + + + + + + + + + not(ancestor-or-self::pr:Identification) + + + + + GZjlsEXIhUPBSbOR1R8P4dzRJHE= + + + + lCnWsFICFg0ogj0Ha7++Y9gyOQg= + + + + a6tPfkdriEzAyQh2jU3/4j48baaPnY/i510OHx0vwHRvXLz80UyZzffdmtaRuk3iHVxgUMd9 + Ld0DLsRt6tFJiPLyBCo0QCuqaOwgTcuUI3Ku/oySpqMjqug3AMdrhxW2j41yQlzvkjiZTT4j + zQ9GHFnZnnob0+bBflqIjZOl4xc= + MIICTzCCAbigAwIBAgIBADANBgkqhkiG9w0BAQUFADATMREwDwYDVQQDEwhTWlJQRVJTQjAeFw0wNTA3MDEwMDAwMDBaFw00MDEyMzEyMzU5NTlaMBMxETAPBgNVBAMTCFNaUlBFUlNCMIIBHzANBgkqhkiG9w0BAQEFAAOCAQwAMIIBBwKBgQDGNmo9LOohefioGreKU6j6R05jUwHuddziSOQPolmMSXQG6NnnlLQaITv7BEmFj+EBqaOc+891wgZCRvNA2h+fHdJ69QXi/xjCovJI5SHh9jA+ssqhZ68iXOZHPq4WeegtYiYyJaRxWF+iPLqSm+bknS/KuBUcZol9SM3r6CMf0wKBgHytGrIelzc9ZN97VYXLkOJxi4TNSSj3Q/1TIC0s+HSzjbD694Y6ufINpR+IQm5epLTdXx9Dxv19bYnsLEIt0niMd2Cnm1DxXe8iNaDzpWec7fbRT6vDBwtTnyQkGfu2GGF3nSvVZ5AUDbLdAfZLOlbwsZmPnWU1zktSkLgKnT2XozIwMDAuBglghkgBhvhCAQ0EIRMfQ3JlYXRlZCBieSB6L09TIElDU0YgLSBIQ1I3NzgwIDANBgkqhkiG9w0BAQUFAAOBgQBwPc3l/Qf4myH8rsAAM5HqdCR68bMegWgNVxlPNl5DNJEE2hbPhIJ/K6TF6cjROYKDVuQ/+drtsZcrEOaqhqD3qw7MXAiT9GurV99YM/qTBsMy13yjU3LqeFX25Om8JlccGF5G+iHrVjfNQEUocGnGxCAPMlBvGwia4JjJcIPx7Q== + + + + + + not(ancestor-or-self::dsig:Signature) + + + + SbpaaSlLolEX5D9P7HyTPnImvns= + + + + +ERN \ No newline at end of file diff --git a/modules/authmodule-eIDAS-v2/src/test/resources/keystore/teststore.jks b/modules/authmodule-eIDAS-v2/src/test/resources/keystore/teststore.jks new file mode 100644 index 00000000..fcc6400c Binary files /dev/null and b/modules/authmodule-eIDAS-v2/src/test/resources/keystore/teststore.jks differ diff --git a/modules/authmodule_id-austria/checks/spotbugs-exclude.xml b/modules/authmodule_id-austria/checks/spotbugs-exclude.xml new file mode 100644 index 00000000..366c7aca --- /dev/null +++ b/modules/authmodule_id-austria/checks/spotbugs-exclude.xml @@ -0,0 +1,29 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/modules/authmodule_id-austria/pom.xml b/modules/authmodule_id-austria/pom.xml new file mode 100644 index 00000000..1afa71df --- /dev/null +++ b/modules/authmodule_id-austria/pom.xml @@ -0,0 +1,171 @@ + + 4.0.0 + + at.asitplus.eidas.ms_specific + modules + 1.2.4-SNAPSHOT + + at.asitplus.eidas.ms_specific.modules + authmodule_id-austria + ID-Austria authentication + User authentication forwarding user to ID Austria system + + + + at.gv.egiz.components + egiz-spring-api + + + at.asitplus.eidas.ms_specific + core_common_lib + + + at.asitplus.eidas.ms_specific.modules + eidas_proxy-sevice + + + at.gv.egiz.eaaf + eaaf-core + + + at.gv.egiz.eaaf + eaaf_module_pvp2_sp + + + + org.apache.commons + commons-lang3 + + + com.google.guava + guava + + + org.apache.commons + commons-text + + + + javax.servlet + javax.servlet-api + provided + + + + + junit + junit + test + + + org.springframework + spring-test + test + + + org.powermock + powermock-module-junit4 + test + + + org.powermock + powermock-api-mockito2 + test + + + com.squareup.okhttp3 + mockwebserver + test + + + at.asitplus.eidas.ms_specific + core_common_lib + test + test-jar + + + + at.gv.egiz.eaaf + eaaf_core_utils + test + test-jar + + + at.gv.egiz.eaaf + eaaf-core + test + test-jar + + + at.gv.egiz.eaaf + eaaf_module_pvp2_core + test + test-jar + + + at.gv.egiz.eaaf + eaaf_module_pvp2_idp + test + test-jar + + + + + + + src/main/resources + + + + + + org.apache.maven.plugins + maven-compiler-plugin + + + + com.github.spotbugs + spotbugs-maven-plugin + ${spotbugs-maven-plugin.version} + + checks/spotbugs-exclude.xml + + + + + org.jacoco + jacoco-maven-plugin + + + post-unit-check + test + + check + report + + + true + + + + + + + + maven-surefire-plugin + + 1 + + + + org.apache.maven.surefire + surefire-junit47 + ${surefire.version} + + + + + + + + \ No newline at end of file diff --git a/modules/authmodule_id-austria/src/main/java/at/asitplus/eidas/specific/modules/auth/idaustria/IdAustriaAuthConstants.java b/modules/authmodule_id-austria/src/main/java/at/asitplus/eidas/specific/modules/auth/idaustria/IdAustriaAuthConstants.java new file mode 100644 index 00000000..57e5c706 --- /dev/null +++ b/modules/authmodule_id-austria/src/main/java/at/asitplus/eidas/specific/modules/auth/idaustria/IdAustriaAuthConstants.java @@ -0,0 +1,123 @@ +package at.asitplus.eidas.specific.modules.auth.idaustria; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Set; +import java.util.stream.Collectors; + +import at.asitplus.eidas.specific.core.MsEidasNodeConstants; +import at.gv.egiz.eaaf.core.api.data.PvpAttributeDefinitions; +import at.gv.egiz.eaaf.core.impl.data.Triple; + +/** + * Constant values for ID Austria authentication module. + * + * @author tlenz + * + */ +public class IdAustriaAuthConstants { + + private IdAustriaAuthConstants() { + + } + + public static final String ERRORTYPE_00 = "module.idaustria.00"; + public static final String ERRORTYPE_01 = "module.idaustria.01"; + public static final String ERRORTYPE_02 = "module.idaustria.02"; + public static final String ERRORTYPE_03 = "module.idaustria.03"; + public static final String ERRORTYPE_04 = "module.idaustria.04"; + public static final String ERRORTYPE_05 = "module.idaustria.05"; + public static final String ERRORTYPE_06 = "module.idaustria.06"; + public static final String ERRORTYPE_98 = "module.idaustria.98"; + public static final String ERRORTYPE_99 = "module.idaustria.99"; + + + public static final String SAML2_STATUSCODE_USERSTOP = "1005"; + + public static final int METADATA_VALIDUNTIL_IN_HOURS = 24 * 365; + public static final String MODULE_NAME_FOR_LOGGING = "ID Austria based eIDAS authentication"; + + public static final String ENDPOINT_POST = "/sp/idaustria/eidas/post"; + public static final String ENDPOINT_REDIRECT = "/sp/idaustria/eidas/redirect"; + public static final String ENDPOINT_METADATA = "/sp/idaustria/eidas/metadata"; + + public static final String CONFIG_PROPS_PREFIX = "modules.idaustriaauth."; + + public static final String CONFIG_PROPS_IDAUSTRIA_ENTITYID = CONFIG_PROPS_PREFIX + "idp.entityId"; + public static final String CONFIG_PROPS_IDAUSTRIA_METADATAURL = CONFIG_PROPS_PREFIX + "idp.metadataUrl"; + + public static final String CONFIG_PROPS_KEYSTORE_TYPE = CONFIG_PROPS_PREFIX + "keystore.type"; + public static final String CONFIG_PROPS_KEYSTORE_NAME = CONFIG_PROPS_PREFIX + "keystore.name"; + public static final String CONFIG_PROPS_KEYSTORE_PATH = CONFIG_PROPS_PREFIX + "keystore.path"; + public static final String CONFIG_PROPS_KEYSTOREPASSWORD = CONFIG_PROPS_PREFIX + "keystore.password"; + public static final String CONFIG_PROPS_SIGN_METADATA_KEY_PASSWORD = CONFIG_PROPS_PREFIX + + "metadata.sign.password"; + public static final String CONFIG_PROPS_SIGN_METADATA_ALIAS = CONFIG_PROPS_PREFIX + + "metadata.sign.alias"; + public static final String CONFIG_PROPS_SIGN_SIGNING_KEY_PASSWORD = CONFIG_PROPS_PREFIX + + "request.sign.password"; + public static final String CONFIG_PROPS_SIGN_SIGNING_ALIAS = CONFIG_PROPS_PREFIX + + "request.sign.alias"; + public static final String CONFIG_PROPS_ENCRYPTION_KEY_PASSWORD = CONFIG_PROPS_PREFIX + + "response.encryption.password"; + public static final String CONFIG_PROPS_ENCRYPTION_ALIAS = CONFIG_PROPS_PREFIX + + "response.encryption.alias"; + + public static final String CONFIG_PROPS_TRUSTSTORE_TYPE = CONFIG_PROPS_PREFIX + "truststore.type"; + public static final String CONFIG_PROPS_TRUSTSTORE_NAME = CONFIG_PROPS_PREFIX + "truststore.name"; + public static final String CONFIG_PROPS_TRUSTSTORE_PATH = CONFIG_PROPS_PREFIX + "truststore.path"; + public static final String CONFIG_PROPS_TRUSTSTORE_PASSWORD = CONFIG_PROPS_PREFIX + "truststore.password"; + + public static final String CONFIG_PROPS_REQUIRED_PVP_ATTRIBUTES_LIST = CONFIG_PROPS_PREFIX + + "required.additional.attributes"; + + + /** + * SP specific EntityId of the ID Austria. + */ + public static final String CONFIG_PROPS_APPSPECIFIC_IDAUSTRIA_NODE_URL = "auth.idaustria.entityId"; + + + public static final List> DEFAULT_REQUIRED_PVP_ATTRIBUTES = + Collections.unmodifiableList(new ArrayList>() { + private static final long serialVersionUID = 1L; + { + // add PVP Version attribute + add(Triple.newInstance(PvpAttributeDefinitions.PVP_VERSION_NAME, + PvpAttributeDefinitions.PVP_VERSION_FRIENDLY_NAME, false)); + + // entity information + add(Triple.newInstance(PvpAttributeDefinitions.GIVEN_NAME_NAME, + PvpAttributeDefinitions.GIVEN_NAME_FRIENDLY_NAME, true)); + add(Triple.newInstance(PvpAttributeDefinitions.PRINCIPAL_NAME_NAME, + PvpAttributeDefinitions.PRINCIPAL_NAME_FRIENDLY_NAME, true)); + add(Triple.newInstance(PvpAttributeDefinitions.BIRTHDATE_NAME, + PvpAttributeDefinitions.BIRTHDATE_FRIENDLY_NAME, true)); + add(Triple.newInstance(PvpAttributeDefinitions.BPK_NAME, + PvpAttributeDefinitions.BPK_FRIENDLY_NAME, true)); + + // entity metadata information + add(Triple.newInstance(PvpAttributeDefinitions.EID_ISSUING_NATION_NAME, + PvpAttributeDefinitions.EID_ISSUING_NATION_FRIENDLY_NAME, true)); + add(Triple.newInstance(PvpAttributeDefinitions.EID_CITIZEN_EIDAS_QAA_LEVEL_NAME, + PvpAttributeDefinitions.EID_CITIZEN_EIDAS_QAA_LEVEL_FRIENDLY_NAME, false)); + + // mandate attributes + add(Triple.newInstance(PvpAttributeDefinitions.MANDATE_TYPE_NAME, + PvpAttributeDefinitions.MANDATE_TYPE_FRIENDLY_NAME, false)); + add(Triple.newInstance(PvpAttributeDefinitions.MANDATE_TYPE_OID_NAME, + PvpAttributeDefinitions.MANDATE_TYPE_OID_FRIENDLY_NAME, false)); + addAll(MsEidasNodeConstants.DEFAULT_REQUIRED_MANDATE_JUR_PVP_ATTRIBUTES); + addAll(MsEidasNodeConstants.DEFAULT_REQUIRED_MANDATE_NAT_PVP_ATTRIBUTES); + + } + }); + + public static final Set DEFAULT_REQUIRED_PVP_ATTRIBUTE_NAMES = + DEFAULT_REQUIRED_PVP_ATTRIBUTES.stream() + .filter(el -> el.getThird()) + .map(el -> el.getFirst()) + .collect(Collectors.toSet()); + +} diff --git a/modules/authmodule_id-austria/src/main/java/at/asitplus/eidas/specific/modules/auth/idaustria/IdAustriaAuthenticationSpringResourceProvider.java b/modules/authmodule_id-austria/src/main/java/at/asitplus/eidas/specific/modules/auth/idaustria/IdAustriaAuthenticationSpringResourceProvider.java new file mode 100644 index 00000000..2240b843 --- /dev/null +++ b/modules/authmodule_id-austria/src/main/java/at/asitplus/eidas/specific/modules/auth/idaustria/IdAustriaAuthenticationSpringResourceProvider.java @@ -0,0 +1,56 @@ +/* + * Copyright 2018 A-SIT Plus GmbH + * AT-specific eIDAS Connector has been developed in a cooperation between EGIZ, + * A-SIT Plus GmbH, A-SIT, and Graz University of Technology. + * + * Licensed under the EUPL, Version 1.2 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "License"); + * You may not use this work except in compliance with the License. + * You may obtain a copy of the License at: + * https://joinup.ec.europa.eu/news/understanding-eupl-v12 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. +*/ + +package at.asitplus.eidas.specific.modules.auth.idaustria; + +import org.springframework.core.io.ClassPathResource; +import org.springframework.core.io.Resource; + +import at.gv.egiz.components.spring.api.SpringResourceProvider; + +public class IdAustriaAuthenticationSpringResourceProvider implements SpringResourceProvider { + + @Override + public String getName() { + return "Auth. module for ID Austria based authentication"; + } + + @Override + public String[] getPackagesToScan() { + return null; + + } + + @Override + public Resource[] getResourcesToLoad() { + final ClassPathResource idAustriaAuthConfig = + new ClassPathResource("/spring/id_austria_auth.beans.xml", + IdAustriaAuthenticationSpringResourceProvider.class); + final ClassPathResource idAustriaTaskConfig = + new ClassPathResource("/spring/id_austria_task.beans.xml", + IdAustriaAuthenticationSpringResourceProvider.class); + + return new Resource[] { idAustriaAuthConfig, idAustriaTaskConfig }; + } + +} diff --git a/modules/authmodule_id-austria/src/main/java/at/asitplus/eidas/specific/modules/auth/idaustria/IdAustriaEidasProxyAuthenticationModulImpl.java b/modules/authmodule_id-austria/src/main/java/at/asitplus/eidas/specific/modules/auth/idaustria/IdAustriaEidasProxyAuthenticationModulImpl.java new file mode 100644 index 00000000..6f90569c --- /dev/null +++ b/modules/authmodule_id-austria/src/main/java/at/asitplus/eidas/specific/modules/auth/idaustria/IdAustriaEidasProxyAuthenticationModulImpl.java @@ -0,0 +1,91 @@ +/* + * Copyright 2018 A-SIT Plus GmbH + * AT-specific eIDAS Connector has been developed in a cooperation between EGIZ, + * A-SIT Plus GmbH, A-SIT, and Graz University of Technology. + * + * Licensed under the EUPL, Version 1.2 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "License"); + * You may not use this work except in compliance with the License. + * You may obtain a copy of the License at: + * https://joinup.ec.europa.eu/news/understanding-eupl-v12 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. +*/ + +package at.asitplus.eidas.specific.modules.auth.idaustria; + +import at.asitplus.eidas.specific.modules.msproxyservice.protocol.ProxyServicePendingRequest; +import at.gv.egiz.eaaf.core.api.IRequest; +import at.gv.egiz.eaaf.core.api.idp.auth.modules.AuthModule; +import at.gv.egiz.eaaf.core.api.idp.process.ExecutionContext; +import lombok.extern.slf4j.Slf4j; + +/** + * Authentication-process selection to start ID Austria authentication for eIDAS Proxy-Service requests. + * + * @author tlenz + * + */ +@Slf4j +public class IdAustriaEidasProxyAuthenticationModulImpl implements AuthModule { + + private static final String ID_AUSTRIA_EIDAS_PROXY_AUTHPROCESS_NAME = "idAustriaForEidasProxyService"; + + private int priority = 1; + + @Override + public int getPriority() { + return priority; + } + + /** + * Sets the priority of this module. Default value is {@code 0}. + * + * @param priority The priority. + */ + public void setPriority(int priority) { + this.priority = priority; + } + + /* + * (non-Javadoc) + * + * @see at.gv.egovernment.moa.id.auth.modules.AuthModule#selectProcess(at.gv. + * egovernment.moa.id.process.api.ExecutionContext) + */ + @Override + public String selectProcess(ExecutionContext context, IRequest pendingReq) { + if (pendingReq instanceof ProxyServicePendingRequest) { + log.info("Find eIDAS Proxy-Service request. Starting ID Austria based user authentication ... "); + return ID_AUSTRIA_EIDAS_PROXY_AUTHPROCESS_NAME; + + } else { + log.trace("No {} request. Ignore it for ID Austria authentication", + ProxyServicePendingRequest.class.getName()); + + } + + return null; + + } + + /* + * (non-Javadoc) + * + * @see at.gv.egovernment.moa.id.auth.modules.AuthModule#getProcessDefinitions() + */ + @Override + public String[] getProcessDefinitions() { + return new String[] { "classpath:/process/id_austria.Authentication.process.xml" }; + } + +} diff --git a/modules/authmodule_id-austria/src/main/java/at/asitplus/eidas/specific/modules/auth/idaustria/builder/attributes/EidasConnecorUniqueIdAttributeBuilder.java b/modules/authmodule_id-austria/src/main/java/at/asitplus/eidas/specific/modules/auth/idaustria/builder/attributes/EidasConnecorUniqueIdAttributeBuilder.java new file mode 100644 index 00000000..89e06991 --- /dev/null +++ b/modules/authmodule_id-austria/src/main/java/at/asitplus/eidas/specific/modules/auth/idaustria/builder/attributes/EidasConnecorUniqueIdAttributeBuilder.java @@ -0,0 +1,52 @@ +/* + * Copyright 2017 Graz University of Technology EAAF-Core Components has been developed in a + * cooperation between EGIZ, A-SIT Plus, A-SIT, and Graz University of Technology. + * + * Licensed under the EUPL, Version 1.2 or - as soon they will be approved by the European + * Commission - subsequent versions of the EUPL (the "Licence"); You may not use this work except in + * compliance with the Licence. You may obtain a copy of the Licence at: + * https://joinup.ec.europa.eu/news/understanding-eupl-v12 + * + * Unless required by applicable law or agreed to in writing, software distributed under the Licence + * is distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the Licence for the specific language governing permissions and limitations under + * the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text file for details on the + * various modules and licenses. The "NOTICE" text file is part of the distribution. Any derivative + * works that you distribute must include a readable copy of the "NOTICE" text file. +*/ + +package at.asitplus.eidas.specific.modules.auth.idaustria.builder.attributes; + +import at.gv.egiz.eaaf.core.api.data.ExtendedPvpAttributeDefinitions; +import at.gv.egiz.eaaf.core.api.idp.IAttributeBuilder; +import at.gv.egiz.eaaf.core.api.idp.IAttributeGenerator; +import at.gv.egiz.eaaf.core.api.idp.IAuthData; +import at.gv.egiz.eaaf.core.api.idp.ISpConfiguration; +import at.gv.egiz.eaaf.core.exceptions.AttributeBuilderException; + +public class EidasConnecorUniqueIdAttributeBuilder + implements IAttributeBuilder, ExtendedPvpAttributeDefinitions { + + @Override + public String getName() { + return EIDAS_CONNECTOR_UNIQUEID_NAME; + } + + @Override + public ATT build(final ISpConfiguration oaParam, final IAuthData authData, + final IAttributeGenerator g) + throws AttributeBuilderException { + return g.buildStringAttribute(EIDAS_CONNECTOR_UNIQUEID_FRIENDLY_NAME, EIDAS_CONNECTOR_UNIQUEID_NAME, + oaParam.getUniqueIdentifier()); + + } + + @Override + public ATT buildEmpty(final IAttributeGenerator g) { + return g.buildEmptyAttribute(EIDAS_CONNECTOR_UNIQUEID_FRIENDLY_NAME, EIDAS_CONNECTOR_UNIQUEID_NAME); + + } + +} diff --git a/modules/authmodule_id-austria/src/main/java/at/asitplus/eidas/specific/modules/auth/idaustria/config/IdAustriaAuthMessageSource.java b/modules/authmodule_id-austria/src/main/java/at/asitplus/eidas/specific/modules/auth/idaustria/config/IdAustriaAuthMessageSource.java new file mode 100644 index 00000000..697c4496 --- /dev/null +++ b/modules/authmodule_id-austria/src/main/java/at/asitplus/eidas/specific/modules/auth/idaustria/config/IdAustriaAuthMessageSource.java @@ -0,0 +1,22 @@ +package at.asitplus.eidas.specific.modules.auth.idaustria.config; + +import java.util.Arrays; +import java.util.List; + +import at.gv.egiz.eaaf.core.api.logging.IMessageSourceLocation; + +/** + * i18n message-source for ID Austria authentication errors. + * + * @author tlenz + * + */ +public class IdAustriaAuthMessageSource implements IMessageSourceLocation { + + @Override + public List getMessageSourceLocation() { + return Arrays.asList("classpath:messages/idaustria_auth_messages"); + + } + +} diff --git a/modules/authmodule_id-austria/src/main/java/at/asitplus/eidas/specific/modules/auth/idaustria/config/IdAustriaAuthMetadataConfiguration.java b/modules/authmodule_id-austria/src/main/java/at/asitplus/eidas/specific/modules/auth/idaustria/config/IdAustriaAuthMetadataConfiguration.java new file mode 100644 index 00000000..41990363 --- /dev/null +++ b/modules/authmodule_id-austria/src/main/java/at/asitplus/eidas/specific/modules/auth/idaustria/config/IdAustriaAuthMetadataConfiguration.java @@ -0,0 +1,462 @@ +package at.asitplus.eidas.specific.modules.auth.idaustria.config; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.opensaml.saml.saml2.core.Attribute; +import org.opensaml.saml.saml2.core.NameIDType; +import org.opensaml.saml.saml2.metadata.ContactPerson; +import org.opensaml.saml.saml2.metadata.Organization; +import org.opensaml.saml.saml2.metadata.RequestedAttribute; +import org.opensaml.security.credential.Credential; + +import at.asitplus.eidas.specific.modules.auth.idaustria.IdAustriaAuthConstants; +import at.asitplus.eidas.specific.modules.auth.idaustria.utils.IdAustriaAuthCredentialProvider; +import at.gv.egiz.eaaf.core.exceptions.EaafException; +import at.gv.egiz.eaaf.core.impl.data.Pair; +import at.gv.egiz.eaaf.core.impl.data.Triple; +import at.gv.egiz.eaaf.modules.pvp2.api.IPvp2BasicConfiguration; +import at.gv.egiz.eaaf.modules.pvp2.api.credential.EaafX509Credential; +import at.gv.egiz.eaaf.modules.pvp2.api.metadata.IPvpMetadataBuilderConfiguration; +import at.gv.egiz.eaaf.modules.pvp2.exception.CredentialsNotAvailableException; +import at.gv.egiz.eaaf.modules.pvp2.impl.builder.PvpAttributeBuilder; +import lombok.extern.slf4j.Slf4j; + +/** + * Configuration object to generate PVP S-Profile metadata for SAML2 client. + * + * @author tlenz + * + */ +@Slf4j +public class IdAustriaAuthMetadataConfiguration implements IPvpMetadataBuilderConfiguration { + + private Collection additionalAttributes = null; + + private final String authUrl; + private final IdAustriaAuthCredentialProvider credentialProvider; + private final IPvp2BasicConfiguration pvpConfiguration; + + /** + * Configuration object to create PVP2 S-Profile metadata information. + * + * @param authUrl Public URL prefix of the application + * @param credentialProvider Credentials used by PVP2 S-Profile end-point + * @param pvpConfiguration Basic PVP2 S-Profile end-point configuration + */ + public IdAustriaAuthMetadataConfiguration(String authUrl, + IdAustriaAuthCredentialProvider credentialProvider, + IPvp2BasicConfiguration pvpConfiguration) { + this.authUrl = authUrl; + this.credentialProvider = credentialProvider; + this.pvpConfiguration = pvpConfiguration; + } + + /* + * (non-Javadoc) + * + * @see + * at.gv.egovernment.moa.id.protocols.pvp2x.builder.AbstractPVPMetadataBuilder# + * getMetadataValidUntil() + */ + @Override + public int getMetadataValidUntil() { + return IdAustriaAuthConstants.METADATA_VALIDUNTIL_IN_HOURS; + + } + + /* + * (non-Javadoc) + * + * @see + * at.gv.egovernment.moa.id.protocols.pvp2x.builder.AbstractPVPMetadataBuilder# + * buildEntitiesDescriptorAsRootElement() + */ + @Override + public boolean buildEntitiesDescriptorAsRootElement() { + return false; + + } + + /* + * (non-Javadoc) + * + * @see + * at.gv.egovernment.moa.id.protocols.pvp2x.builder.AbstractPVPMetadataBuilder# + * buildIDPSSODescriptor() + */ + @Override + public boolean buildIdpSsoDescriptor() { + return false; + + } + + /* + * (non-Javadoc) + * + * @see + * at.gv.egovernment.moa.id.protocols.pvp2x.builder.AbstractPVPMetadataBuilder# + * buildSPSSODescriptor() + */ + @Override + public boolean buildSpSsoDescriptor() { + return true; + + } + + /* + * (non-Javadoc) + * + * @see + * at.gv.egovernment.moa.id.protocols.pvp2x.builder.AbstractPVPMetadataBuilder# + * getEntityIDPostfix() + */ + @Override + public String getEntityID() { + return authUrl + IdAustriaAuthConstants.ENDPOINT_METADATA; + + } + + /* + * (non-Javadoc) + * + * @see + * at.gv.egovernment.moa.id.protocols.pvp2x.builder.AbstractPVPMetadataBuilder# + * getEntityFriendlyName() + */ + @Override + public String getEntityFriendlyName() { + return null; + } + + /* + * (non-Javadoc) + * + * @see + * at.gv.egovernment.moa.id.protocols.pvp2x.builder.AbstractPVPMetadataBuilder# + * getContactPersonInformation() + */ + @Override + public List getContactPersonInformation() { + try { + return pvpConfiguration.getIdpContacts(); + + } catch (final EaafException e) { + log.warn("Can not load Metadata entry: Contect Person", e); + return null; + + } + + } + + /* + * (non-Javadoc) + * + * @see + * at.gv.egovernment.moa.id.protocols.pvp2x.builder.AbstractPVPMetadataBuilder# + * getOrgansiationInformation() + */ + @Override + public Organization getOrgansiationInformation() { + try { + return pvpConfiguration.getIdpOrganisation(); + + } catch (final EaafException e) { + log.warn("Can not load Metadata entry: Organisation", e); + return null; + + } + } + + /* + * (non-Javadoc) + * + * @see + * at.gv.egovernment.moa.id.protocols.pvp2x.builder.AbstractPVPMetadataBuilder# + * getMetadataSigningCredentials() + */ + @Override + public EaafX509Credential getMetadataSigningCredentials() throws CredentialsNotAvailableException { + return credentialProvider.getMetaDataSigningCredential(); + + } + + /* + * (non-Javadoc) + * + * @see + * at.gv.egovernment.moa.id.protocols.pvp2x.builder.AbstractPVPMetadataBuilder# + * getRequestorResponseSigningCredentials() + */ + @Override + public Credential getRequestorResponseSigningCredentials() throws CredentialsNotAvailableException { + return credentialProvider.getMessageSigningCredential(); + + } + + /* + * (non-Javadoc) + * + * @see + * at.gv.egovernment.moa.id.protocols.pvp2x.builder.AbstractPVPMetadataBuilder# + * getEncryptionCredentials() + */ + @Override + public Credential getEncryptionCredentials() throws CredentialsNotAvailableException { + return credentialProvider.getMessageEncryptionCredential(); + + } + + /* + * (non-Javadoc) + * + * @see + * at.gv.egovernment.moa.id.protocols.pvp2x.builder.AbstractPVPMetadataBuilder# + * getIDPWebSSOPostBindingURL() + */ + @Override + public String getIdpWebSsoPostBindingUrl() { + return null; + } + + /* + * (non-Javadoc) + * + * @see + * at.gv.egovernment.moa.id.protocols.pvp2x.builder.AbstractPVPMetadataBuilder# + * getIDPWebSSORedirectBindingURL() + */ + @Override + public String getIdpWebSsoRedirectBindingUrl() { + return null; + } + + /* + * (non-Javadoc) + * + * @see + * at.gv.egovernment.moa.id.protocols.pvp2x.builder.AbstractPVPMetadataBuilder# + * getIDPSLOPostBindingURL() + */ + @Override + public String getIdpSloPostBindingUrl() { + return null; + } + + /* + * (non-Javadoc) + * + * @see + * at.gv.egovernment.moa.id.protocols.pvp2x.builder.AbstractPVPMetadataBuilder# + * getIDPSLORedirectBindingURL() + */ + @Override + public String getIdpSloRedirectBindingUrl() { + return null; + } + + /* + * (non-Javadoc) + * + * @see + * at.gv.egovernment.moa.id.protocols.pvp2x.builder.AbstractPVPMetadataBuilder# + * getSPAssertionConsumerServicePostBindingURL() + */ + @Override + public String getSpAssertionConsumerServicePostBindingUrl() { + return authUrl + IdAustriaAuthConstants.ENDPOINT_POST; + } + + /* + * (non-Javadoc) + * + * @see + * at.gv.egovernment.moa.id.protocols.pvp2x.builder.AbstractPVPMetadataBuilder# + * getSPAssertionConsumerServiceRedirectBindingURL() + */ + @Override + public String getSpAssertionConsumerServiceRedirectBindingUrl() { + return authUrl + IdAustriaAuthConstants.ENDPOINT_REDIRECT; + } + + /* + * (non-Javadoc) + * + * @see + * at.gv.egovernment.moa.id.protocols.pvp2x.builder.AbstractPVPMetadataBuilder# + * getSPSLOPostBindingURL() + */ + @Override + public String getSpSloPostBindingUrl() { + return null; + } + + /* + * (non-Javadoc) + * + * @see + * at.gv.egovernment.moa.id.protocols.pvp2x.builder.AbstractPVPMetadataBuilder# + * getSPSLORedirectBindingURL() + */ + @Override + public String getSpSloRedirectBindingUrl() { + return null; + } + + /* + * (non-Javadoc) + * + * @see + * at.gv.egovernment.moa.id.protocols.pvp2x.builder.AbstractPVPMetadataBuilder# + * getSPSLOSOAPBindingURL() + */ + @Override + public String getSpSloSoapBindingUrl() { + return null; + } + + /* + * (non-Javadoc) + * + * @see + * at.gv.egovernment.moa.id.protocols.pvp2x.builder.AbstractPVPMetadataBuilder# + * getIDPPossibleAttributes() + */ + @Override + public List getIdpPossibleAttributes() { + return null; + } + + /* + * (non-Javadoc) + * + * @see + * at.gv.egovernment.moa.id.protocols.pvp2x.builder.AbstractPVPMetadataBuilder# + * getIDPPossibleNameITTypes() + */ + @Override + public List getIdpPossibleNameIdTypes() { + return null; + } + + + + /* + * (non-Javadoc) + * + * @see + * at.gv.egovernment.moa.id.protocols.pvp2x.builder.AbstractPVPMetadataBuilder# + * getSPRequiredAttributes() + */ + @Override + public Collection getSpRequiredAttributes() { + final Map requestedAttributes = new HashMap<>(); + log.trace("Build required attributes for ID Austria operaton ... "); + injectDefinedAttributes(requestedAttributes, + IdAustriaAuthConstants.DEFAULT_REQUIRED_PVP_ATTRIBUTES); + + + if (additionalAttributes != null) { + log.trace("Add additional PVP attributes into metadata ... "); + for (final RequestedAttribute el : additionalAttributes) { + if (requestedAttributes.containsKey(el.getName())) { + log.debug("Attribute " + el.getName() + + " is already added by default configuration. Overwrite it by user configuration"); + } + + requestedAttributes.put(el.getName(), el); + + } + } + + return requestedAttributes.values(); + + } + + + + /* + * (non-Javadoc) + * + * @see + * at.gv.egovernment.moa.id.protocols.pvp2x.builder.AbstractPVPMetadataBuilder# + * getSPAllowedNameITTypes() + */ + @Override + public List getSpAllowedNameIdTypes() { + return Arrays.asList(NameIDType.PERSISTENT); + + } + + /* + * (non-Javadoc) + * + * @see at.gv.egovernment.moa.id.protocols.pvp2x.config. + * IPVPMetadataBuilderConfiguration#getSPNameForLogging() + */ + @Override + public String getSpNameForLogging() { + return IdAustriaAuthConstants.MODULE_NAME_FOR_LOGGING; + } + + /* + * (non-Javadoc) + * + * @see at.gv.egovernment.moa.id.protocols.pvp2x.config. + * IPVPMetadataBuilderConfiguration#wantAssertionSigned() + */ + @Override + public boolean wantAssertionSigned() { + return false; + } + + /* + * (non-Javadoc) + * + * @see at.gv.egovernment.moa.id.protocols.pvp2x.config. + * IPVPMetadataBuilderConfiguration#wantAuthnRequestSigned() + */ + @Override + public boolean wantAuthnRequestSigned() { + return true; + } + + /** + * Add additonal PVP attributes that are required by this deployment. + * + * @param additionalAttr List of PVP attribute name and isRequired flag + */ + public void setAdditionalRequiredAttributes(List> additionalAttr) { + if (additionalAttr != null && !additionalAttr.isEmpty()) { + additionalAttributes = new ArrayList<>(); + for (final Pair el : additionalAttr) { + final Attribute attributBuilder = PvpAttributeBuilder.buildEmptyAttribute(el.getFirst()); + if (attributBuilder != null) { + additionalAttributes.add( + PvpAttributeBuilder.buildReqAttribute( + attributBuilder.getName(), + attributBuilder.getFriendlyName(), + el.getSecond())); + + } else { + log.info("NO PVP attribute with name: " + el.getFirst()); + } + + } + } + } + + private void injectDefinedAttributes(Map requestedAttributes, + List> attributes) { + for (final Triple el : attributes) { + requestedAttributes.put(el.getFirst(), PvpAttributeBuilder.buildReqAttribute(el.getFirst(), el + .getSecond(), el.getThird())); + + } + } + +} diff --git a/modules/authmodule_id-austria/src/main/java/at/asitplus/eidas/specific/modules/auth/idaustria/config/IdAustriaAuthRequestBuilderConfiguration.java b/modules/authmodule_id-austria/src/main/java/at/asitplus/eidas/specific/modules/auth/idaustria/config/IdAustriaAuthRequestBuilderConfiguration.java new file mode 100644 index 00000000..52bd1c5f --- /dev/null +++ b/modules/authmodule_id-austria/src/main/java/at/asitplus/eidas/specific/modules/auth/idaustria/config/IdAustriaAuthRequestBuilderConfiguration.java @@ -0,0 +1,307 @@ +package at.asitplus.eidas.specific.modules.auth.idaustria.config; + +import java.util.List; + +import org.opensaml.saml.saml2.core.AuthnContextComparisonTypeEnumeration; +import org.opensaml.saml.saml2.core.NameIDType; +import org.opensaml.saml.saml2.metadata.EntityDescriptor; +import org.w3c.dom.Element; + +import at.asitplus.eidas.specific.modules.auth.idaustria.IdAustriaAuthConstants; +import at.gv.egiz.eaaf.modules.pvp2.api.credential.EaafX509Credential; +import at.gv.egiz.eaaf.modules.pvp2.api.reqattr.EaafRequestedAttribute; +import at.gv.egiz.eaaf.modules.pvp2.sp.api.IPvpAuthnRequestBuilderConfiguruation; + +/** + * ID Austria client-specific implementation of an {@link IPvpAuthnRequestBuilderConfiguruation}. + * + * @author tlenz + * + */ +public class IdAustriaAuthRequestBuilderConfiguration implements IPvpAuthnRequestBuilderConfiguruation { + + private boolean isPassive; + private String spEntityId; + private String qaaLevel; + private EntityDescriptor idpEntity; + private EaafX509Credential signCred; + private String scopeRequesterId; + private String providerName; + private List requestedAttributes; + private String reqId; + + /* + * (non-Javadoc) + * + * @see at.gv.egovernment.moa.id.protocols.pvp2x.config. + * IPVPAuthnRequestBuilderConfiguruation#isPassivRequest() + */ + @Override + public Boolean isPassivRequest() { + return this.isPassive; + } + + /* + * (non-Javadoc) + * + * @see at.gv.egovernment.moa.id.protocols.pvp2x.config. + * IPVPAuthnRequestBuilderConfiguruation#getAssertionConsumerServiceId() + */ + @Override + public Integer getAssertionConsumerServiceId() { + return 0; + } + + /* + * (non-Javadoc) + * + * @see at.gv.egovernment.moa.id.protocols.pvp2x.config. + * IPVPAuthnRequestBuilderConfiguruation#getEntityID() + */ + @Override + public String getSpEntityID() { + return this.spEntityId; + } + + /* + * (non-Javadoc) + * + * @see at.gv.egovernment.moa.id.protocols.pvp2x.config. + * IPVPAuthnRequestBuilderConfiguruation#getNameIDPolicy() + */ + @Override + public String getNameIdPolicyFormat() { + return NameIDType.PERSISTENT; + } + + /* + * (non-Javadoc) + * + * @see at.gv.egovernment.moa.id.protocols.pvp2x.config. + * IPVPAuthnRequestBuilderConfiguruation#getNameIDPolicy() + */ + @Override + public boolean getNameIdPolicyAllowCreation() { + return true; + } + + /* + * (non-Javadoc) + * + * @see at.gv.egovernment.moa.id.protocols.pvp2x.config. + * IPVPAuthnRequestBuilderConfiguruation#getAuthnContextClassRef() + */ + @Override + public String getAuthnContextClassRef() { + return this.qaaLevel; + } + + /* + * (non-Javadoc) + * + * @see at.gv.egovernment.moa.id.protocols.pvp2x.config. + * IPVPAuthnRequestBuilderConfiguruation#getAuthnContextComparison() + */ + @Override + public AuthnContextComparisonTypeEnumeration getAuthnContextComparison() { + return AuthnContextComparisonTypeEnumeration.MINIMUM; + } + + /** + * Set isPassive flag in SAML2 request. + * + * @param isPassive the isPassive to set. + */ + public void setPassive(boolean isPassive) { + this.isPassive = isPassive; + } + + /** + * Set the requester EntityId. + * + * @param spEntityId EntityId of SP + */ + public void setSpEntityID(String spEntityId) { + this.spEntityId = spEntityId; + } + + /** + * Set required LoA. + * + * @param loa the LoA to set. + */ + public void setRequestedLoA(String loa) { + qaaLevel = loa; + } + + /** + * Set EntityId of IDP. + * + * @param idpEntity the idpEntity to set. + */ + public void setIdpEntity(EntityDescriptor idpEntity) { + this.idpEntity = idpEntity; + } + + /** + * Set message signing credentials. + * + * @param signCred the signCred to set. + */ + public void setSignCred(EaafX509Credential signCred) { + this.signCred = signCred; + } + + /* + * (non-Javadoc) + * + * @see at.gv.egovernment.moa.id.protocols.pvp2x.config. + * IPVPAuthnRequestBuilderConfiguruation#getAuthnRequestSigningCredential() + */ + @Override + public EaafX509Credential getAuthnRequestSigningCredential() { + return this.signCred; + } + + /* + * (non-Javadoc) + * + * @see at.gv.egovernment.moa.id.protocols.pvp2x.config. + * IPVPAuthnRequestBuilderConfiguruation#getIDPEntityDescriptor() + */ + @Override + public EntityDescriptor getIdpEntityDescriptor() { + return this.idpEntity; + } + + /* + * (non-Javadoc) + * + * @see at.gv.egovernment.moa.id.protocols.pvp2x.config. + * IPVPAuthnRequestBuilderConfiguruation#getSubjectNameID() + */ + @Override + public String getSubjectNameID() { + return null; + } + + /* + * (non-Javadoc) + * + * @see at.gv.egovernment.moa.id.protocols.pvp2x.config. + * IPVPAuthnRequestBuilderConfiguruation#getSPNameForLogging() + */ + @Override + public String getSpNameForLogging() { + return IdAustriaAuthConstants.MODULE_NAME_FOR_LOGGING; + } + + /* + * (non-Javadoc) + * + * @see at.gv.egovernment.moa.id.protocols.pvp2x.config. + * IPVPAuthnRequestBuilderConfiguruation#getSubjectNameIDFormat() + */ + @Override + public String getSubjectNameIdFormat() { + return null; + } + + /* + * (non-Javadoc) + * + * @see at.gv.egovernment.moa.id.protocols.pvp2x.config. + * IPVPAuthnRequestBuilderConfiguruation#getRequestID() + */ + @Override + public String getRequestID() { + return this.reqId; + } + + /* + * (non-Javadoc) + * + * @see at.gv.egovernment.moa.id.protocols.pvp2x.config. + * IPVPAuthnRequestBuilderConfiguruation#getSubjectNameIDQualifier() + */ + @Override + public String getSubjectNameIdQualifier() { + return null; + } + + /* + * (non-Javadoc) + * + * @see at.gv.egovernment.moa.id.protocols.pvp2x.config. + * IPVPAuthnRequestBuilderConfiguruation#getSubjectConformationMethode() + */ + @Override + public String getSubjectConformationMethode() { + return null; + } + + /* + * (non-Javadoc) + * + * @see at.gv.egovernment.moa.id.protocols.pvp2x.config. + * IPVPAuthnRequestBuilderConfiguruation#getSubjectConformationDate() + */ + @Override + public Element getSubjectConformationDate() { + return null; + } + + @Override + public List getRequestedAttributes() { + return this.requestedAttributes; + + } + + @Override + public String getProviderName() { + return this.providerName; + } + + @Override + public String getScopeRequesterId() { + return this.scopeRequesterId; + } + + /** + * Set the entityId of the SP that requests the proxy for eIDAS authentication. + * + * @param scopeRequesterId RequestId in SAML2 Proxy extension + */ + public void setScopeRequesterId(String scopeRequesterId) { + this.scopeRequesterId = scopeRequesterId; + } + + /** + * Set a friendlyName for the SP that requests the proxy for eIDAS + * authentication. + * + * @param providerName SAML2 provider-name attribute-value + */ + public void setProviderName(String providerName) { + this.providerName = providerName; + } + + /** + * Set a Set of PVP attributes that a requested by using requested attributes. + * + * @param requestedAttributes Requested SAML2 attributes + */ + public void setRequestedAttributes(List requestedAttributes) { + this.requestedAttributes = requestedAttributes; + } + + /** + * Set a RequestId for this Authn. Request. + * + * @param reqId SAML2 message requestId + */ + public void setRequestId(String reqId) { + this.reqId = reqId; + } + +} diff --git a/modules/authmodule_id-austria/src/main/java/at/asitplus/eidas/specific/modules/auth/idaustria/controller/IdAustriaAuthMetadataController.java b/modules/authmodule_id-austria/src/main/java/at/asitplus/eidas/specific/modules/auth/idaustria/controller/IdAustriaAuthMetadataController.java new file mode 100644 index 00000000..ad708d30 --- /dev/null +++ b/modules/authmodule_id-austria/src/main/java/at/asitplus/eidas/specific/modules/auth/idaustria/controller/IdAustriaAuthMetadataController.java @@ -0,0 +1,150 @@ +package at.asitplus.eidas.specific.modules.auth.idaustria.controller; + +import java.io.IOException; +import java.net.MalformedURLException; +import java.net.URL; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.apache.commons.lang3.StringUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Controller; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; + +import com.google.common.net.MediaType; + +import at.asitplus.eidas.specific.modules.auth.idaustria.IdAustriaAuthConstants; +import at.asitplus.eidas.specific.modules.auth.idaustria.config.IdAustriaAuthMetadataConfiguration; +import at.asitplus.eidas.specific.modules.auth.idaustria.utils.IdAustriaAuthCredentialProvider; +import at.gv.egiz.eaaf.core.exceptions.EaafAuthenticationException; +import at.gv.egiz.eaaf.core.exceptions.EaafException; +import at.gv.egiz.eaaf.core.impl.data.Pair; +import at.gv.egiz.eaaf.core.impl.http.HttpUtils; +import at.gv.egiz.eaaf.core.impl.idp.controller.AbstractController; +import at.gv.egiz.eaaf.core.impl.utils.KeyValueUtils; +import at.gv.egiz.eaaf.modules.pvp2.api.IPvp2BasicConfiguration; +import at.gv.egiz.eaaf.modules.pvp2.impl.builder.PvpMetadataBuilder; +import lombok.extern.slf4j.Slf4j; + +/** + * Controller that generates SAML2 metadata for ID Austria authentication client. + * + * @author tlenz + * + */ +@Slf4j +@Controller +public class IdAustriaAuthMetadataController extends AbstractController { + + private static final String ERROR_CODE_INTERNAL_00 = "eaaf.core.00"; + + @Autowired + PvpMetadataBuilder metadatabuilder; + @Autowired + IdAustriaAuthCredentialProvider credentialProvider; + @Autowired + IPvp2BasicConfiguration pvpConfiguration; + + /** + * Default construction with logging. + * + */ + public IdAustriaAuthMetadataController() { + super(); + log.debug("Registering servlet " + getClass().getName() + + " with mappings '" + IdAustriaAuthConstants.ENDPOINT_METADATA + + "'."); + + } + + /** + * End-point that produce PVP2 metadata for ID Austria authentication client. + * + * @param req http Request + * @param resp http Response + * @throws IOException In case of an I/O error + * @throws EaafException In case of a metadata generation error + */ + @RequestMapping(value = IdAustriaAuthConstants.ENDPOINT_METADATA, + method = { RequestMethod.GET }) + public void getSpMetadata(HttpServletRequest req, HttpServletResponse resp) throws IOException, + EaafException { + // check PublicURL prefix + try { + final String authUrl = getAuthUrlFromHttpContext(req); + + // initialize metadata builder configuration + final IdAustriaAuthMetadataConfiguration metadataConfig = + new IdAustriaAuthMetadataConfiguration(authUrl, credentialProvider, pvpConfiguration); + metadataConfig.setAdditionalRequiredAttributes(getAdditonalRequiredAttributes()); + + // build metadata + final String xmlMetadata = metadatabuilder.buildPvpMetadata(metadataConfig); + + // write response + final byte[] content = xmlMetadata.getBytes("UTF-8"); + resp.setStatus(HttpServletResponse.SC_OK); + resp.setContentLength(content.length); + resp.setContentType(MediaType.XML_UTF_8.toString()); + resp.getOutputStream().write(content); + + } catch (final Exception e) { + log.warn("Build PVP metadata for ID Austria client FAILED.", e); + protAuthService.handleErrorNoRedirect(e, req, resp, false); + + } + + } + + private String getAuthUrlFromHttpContext(HttpServletRequest req) throws EaafException { + // check if End-Point is valid + final String authUrlString = HttpUtils.extractAuthUrlFromRequest(req); + URL authReqUrl; + try { + authReqUrl = new URL(authUrlString); + + } catch (final MalformedURLException e) { + log.warn("Requested URL: {} is not a valid URL.", authUrlString); + throw new EaafAuthenticationException(ERROR_CODE_INTERNAL_00, new Object[] { authUrlString }, e); + + } + + final String idpAuthUrl = authConfig.validateIdpUrl(authReqUrl); + if (idpAuthUrl == null) { + log.warn("Requested URL: {} is NOT found in configuration.", authReqUrl); + throw new EaafAuthenticationException(ERROR_CODE_INTERNAL_00, new Object[] { authUrlString }); + + } + + return idpAuthUrl; + } + + private List> getAdditonalRequiredAttributes() { + final List> result = new ArrayList<>(); + // load attributes from configuration + final Map addReqAttributes = authConfig.getBasicConfigurationWithPrefix( + IdAustriaAuthConstants.CONFIG_PROPS_REQUIRED_PVP_ATTRIBUTES_LIST); + for (final String el : addReqAttributes.values()) { + if (StringUtils.isNotEmpty(el)) { + log.trace("Parse additional attr. definition: " + el); + final List attr = KeyValueUtils.getListOfCsvValues(el.trim()); + if (attr.size() == 2) { + result.add(Pair.newInstance(attr.get(0), Boolean.parseBoolean(attr.get(1)))); + + } else { + log.info("IGNORE additional attr. definition: " + el + + " Reason: Format not valid"); + } + } + } + + return result; + + } + +} diff --git a/modules/authmodule_id-austria/src/main/java/at/asitplus/eidas/specific/modules/auth/idaustria/controller/IdAustriaAuthSignalController.java b/modules/authmodule_id-austria/src/main/java/at/asitplus/eidas/specific/modules/auth/idaustria/controller/IdAustriaAuthSignalController.java new file mode 100644 index 00000000..2e7868fd --- /dev/null +++ b/modules/authmodule_id-austria/src/main/java/at/asitplus/eidas/specific/modules/auth/idaustria/controller/IdAustriaAuthSignalController.java @@ -0,0 +1,94 @@ +package at.asitplus.eidas.specific.modules.auth.idaustria.controller; + +import java.io.IOException; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.apache.commons.lang3.StringUtils; +import org.apache.commons.text.StringEscapeUtils; +import org.springframework.stereotype.Controller; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; + +import at.asitplus.eidas.specific.modules.auth.idaustria.IdAustriaAuthConstants; +import at.gv.egiz.eaaf.core.exceptions.EaafException; +import at.gv.egiz.eaaf.core.impl.idp.controller.AbstractProcessEngineSignalController; +import lombok.extern.slf4j.Slf4j; + +/** + * Controller that receives the response from ID Austria system. + * + * @author tlenz + * + */ +@Slf4j +@Controller +public class IdAustriaAuthSignalController extends AbstractProcessEngineSignalController { + + public static final String HTTP_PARAM_RELAYSTATE = "RelayState"; + + /** + * Default constructor with logging. + * + */ + public IdAustriaAuthSignalController() { + super(); + log.debug("Registering servlet " + getClass().getName() + + " with mappings '" + IdAustriaAuthConstants.ENDPOINT_POST + + "' and '" + IdAustriaAuthConstants.ENDPOINT_REDIRECT + "'."); + + } + + /** + * HTTP end-point for incoming SAML2 Respone from ID Austrian System. + * + * @param req HTTP request + * @param resp HTTP response + * @throws IOException In case of a HTTP communication error + * @throws EaafException In case of a state-validation problem + */ + @RequestMapping(value = { IdAustriaAuthConstants.ENDPOINT_POST, + IdAustriaAuthConstants.ENDPOINT_REDIRECT }, + method = { RequestMethod.POST, RequestMethod.GET }) + public void performEidasAuthentication(HttpServletRequest req, HttpServletResponse resp) + throws IOException, EaafException { + signalProcessManagement(req, resp); + + } + + /** + * Read the PendingRequestId from SAML2 RelayState parameter. + */ + @Override + public String getPendingRequestId(HttpServletRequest request) { + String relayState = StringEscapeUtils.escapeHtml4(request.getParameter(HTTP_PARAM_RELAYSTATE)); + if (StringUtils.isNotEmpty(relayState)) { + try { + String pendingReqId = transactionStorage.get(relayState, String.class); + if (StringUtils.isNotEmpty(pendingReqId)) { + + return pendingReqId; + + } else { + log.info("SAML2 RelayState from request is unknown. Can NOT restore session ... "); + + } + + } catch (EaafException e) { + log.error("Can NOT map SAML2 RelayState to pendingRequestId", e); + + } finally { + transactionStorage.remove(relayState); + + } + + } else { + log.info("No SAML2 relaystate. Can NOT restore session ... "); + + } + + return null; + + } +} 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 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 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 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 true if mandate was used, otherwise false + */ + 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 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 null. + * + * @param samlResp SAML2 response + * @return Sub-StatusCode or null 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 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 + 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 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 attributs, String attributeName, String attributeValue) { + final Attribute requesterIdAttr = PvpAttributeBuilder.buildEmptyAttribute(attributeName); + final EaafRequestedAttribute requesterIdReqAttr = Saml2Utils.generateReqAuthnAttributeSimple( + requesterIdAttr, + true, + attributeValue); + attributs.add(requesterIdReqAttr); + + } + +} diff --git a/modules/authmodule_id-austria/src/main/java/at/asitplus/eidas/specific/modules/auth/idaustria/utils/IdAustriaAuthCredentialProvider.java b/modules/authmodule_id-austria/src/main/java/at/asitplus/eidas/specific/modules/auth/idaustria/utils/IdAustriaAuthCredentialProvider.java new file mode 100644 index 00000000..7da306b5 --- /dev/null +++ b/modules/authmodule_id-austria/src/main/java/at/asitplus/eidas/specific/modules/auth/idaustria/utils/IdAustriaAuthCredentialProvider.java @@ -0,0 +1,130 @@ +package at.asitplus.eidas.specific.modules.auth.idaustria.utils; + +import org.springframework.beans.factory.annotation.Autowired; + +import at.asitplus.eidas.specific.modules.auth.idaustria.IdAustriaAuthConstants; +import at.gv.egiz.eaaf.core.api.idp.IConfiguration; +import at.gv.egiz.eaaf.core.exceptions.EaafConfigurationException; +import at.gv.egiz.eaaf.core.impl.credential.KeyStoreConfiguration; +import at.gv.egiz.eaaf.core.impl.credential.KeyStoreConfiguration.KeyStoreType; +import at.gv.egiz.eaaf.modules.pvp2.impl.utils.AbstractCredentialProvider; + +/** + * Credential provider for ID Austria PVP S-Profile client. + * + * @author tlenz + * + */ +public class IdAustriaAuthCredentialProvider extends AbstractCredentialProvider { + + @Autowired + IConfiguration authConfig; + + + @Override + public KeyStoreConfiguration getBasicKeyStoreConfig() throws EaafConfigurationException { + final KeyStoreConfiguration keyStoreConfig = new KeyStoreConfiguration(); + keyStoreConfig.setFriendlyName(IdAustriaAuthConstants.MODULE_NAME_FOR_LOGGING); + keyStoreConfig.setKeyStoreType( + authConfig.getBasicConfiguration(IdAustriaAuthConstants.CONFIG_PROPS_KEYSTORE_TYPE, + KeyStoreType.PKCS12.getKeyStoreType())); + keyStoreConfig.setKeyStoreName( + authConfig.getBasicConfiguration(IdAustriaAuthConstants.CONFIG_PROPS_KEYSTORE_NAME)); + keyStoreConfig.setSoftKeyStoreFilePath(getKeyStoreFilePath()); + keyStoreConfig.setSoftKeyStorePassword( + authConfig.getBasicConfiguration(IdAustriaAuthConstants.CONFIG_PROPS_KEYSTOREPASSWORD)); + + return keyStoreConfig; + + } + + private String getKeyStoreFilePath() throws EaafConfigurationException { + final String path = authConfig.getBasicConfiguration( + IdAustriaAuthConstants.CONFIG_PROPS_KEYSTORE_PATH); + if (path == null) { + throw new EaafConfigurationException(IdAustriaAuthConstants.ERRORTYPE_00, + new Object[] { IdAustriaAuthConstants.CONFIG_PROPS_KEYSTORE_PATH }); + + } + return path; + } + + /* + * (non-Javadoc) + * + * @see + * at.gv.egovernment.moa.id.protocols.pvp2x.signer.AbstractCredentialProvider# + * getMetadataKeyAlias() + */ + @Override + public String getMetadataKeyAlias() { + return authConfig.getBasicConfiguration( + IdAustriaAuthConstants.CONFIG_PROPS_SIGN_METADATA_ALIAS); + } + + /* + * (non-Javadoc) + * + * @see + * at.gv.egovernment.moa.id.protocols.pvp2x.signer.AbstractCredentialProvider# + * getMetadataKeyPassword() + */ + @Override + public String getMetadataKeyPassword() { + return authConfig.getBasicConfiguration( + IdAustriaAuthConstants.CONFIG_PROPS_SIGN_METADATA_KEY_PASSWORD); + } + + /* + * (non-Javadoc) + * + * @see + * at.gv.egovernment.moa.id.protocols.pvp2x.signer.AbstractCredentialProvider# + * getSignatureKeyAlias() + */ + @Override + public String getSignatureKeyAlias() { + return authConfig.getBasicConfiguration( + IdAustriaAuthConstants.CONFIG_PROPS_SIGN_SIGNING_ALIAS); + } + + /* + * (non-Javadoc) + * + * @see + * at.gv.egovernment.moa.id.protocols.pvp2x.signer.AbstractCredentialProvider# + * getSignatureKeyPassword() + */ + @Override + public String getSignatureKeyPassword() { + return authConfig.getBasicConfiguration( + IdAustriaAuthConstants.CONFIG_PROPS_SIGN_SIGNING_KEY_PASSWORD); + } + + /* + * (non-Javadoc) + * + * @see + * at.gv.egovernment.moa.id.protocols.pvp2x.signer.AbstractCredentialProvider# + * getEncryptionKeyAlias() + */ + @Override + public String getEncryptionKeyAlias() { + return authConfig.getBasicConfiguration( + IdAustriaAuthConstants.CONFIG_PROPS_ENCRYPTION_ALIAS); + } + + /* + * (non-Javadoc) + * + * @see + * at.gv.egovernment.moa.id.protocols.pvp2x.signer.AbstractCredentialProvider# + * getEncryptionKeyPassword() + */ + @Override + public String getEncryptionKeyPassword() { + return authConfig.getBasicConfiguration( + IdAustriaAuthConstants.CONFIG_PROPS_ENCRYPTION_KEY_PASSWORD); + } + +} diff --git a/modules/authmodule_id-austria/src/main/java/at/asitplus/eidas/specific/modules/auth/idaustria/utils/IdAustriaAuthMetadataProvider.java b/modules/authmodule_id-austria/src/main/java/at/asitplus/eidas/specific/modules/auth/idaustria/utils/IdAustriaAuthMetadataProvider.java new file mode 100644 index 00000000..72c52488 --- /dev/null +++ b/modules/authmodule_id-austria/src/main/java/at/asitplus/eidas/specific/modules/auth/idaustria/utils/IdAustriaAuthMetadataProvider.java @@ -0,0 +1,168 @@ +package at.asitplus.eidas.specific.modules.auth.idaustria.utils; + +import java.io.IOException; +import java.security.KeyStore; +import java.security.Provider; +import java.security.cert.CertificateException; +import java.text.MessageFormat; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +import javax.annotation.PostConstruct; + +import org.apache.commons.lang3.StringUtils; +import org.opensaml.saml.metadata.resolver.MetadataResolver; +import org.opensaml.saml.metadata.resolver.filter.MetadataFilter; +import org.opensaml.saml.metadata.resolver.filter.MetadataFilterChain; +import org.springframework.beans.factory.annotation.Autowired; + +import at.asitplus.eidas.specific.modules.auth.idaustria.IdAustriaAuthConstants; +import at.gv.egiz.eaaf.core.api.idp.IConfiguration; +import at.gv.egiz.eaaf.core.exceptions.EaafConfigurationException; +import at.gv.egiz.eaaf.core.exceptions.EaafException; +import at.gv.egiz.eaaf.core.impl.credential.EaafKeyStoreFactory; +import at.gv.egiz.eaaf.core.impl.credential.KeyStoreConfiguration; +import at.gv.egiz.eaaf.core.impl.credential.KeyStoreConfiguration.KeyStoreType; +import at.gv.egiz.eaaf.core.impl.data.Pair; +import at.gv.egiz.eaaf.core.impl.http.IHttpClientFactory; +import at.gv.egiz.eaaf.modules.pvp2.exception.Pvp2MetadataException; +import at.gv.egiz.eaaf.modules.pvp2.impl.metadata.AbstractChainingMetadataProvider; +import at.gv.egiz.eaaf.modules.pvp2.impl.metadata.PvpMetadataResolverFactory; +import at.gv.egiz.eaaf.modules.pvp2.impl.validation.metadata.SchemaValidationFilter; +import at.gv.egiz.eaaf.modules.pvp2.impl.validation.metadata.SimpleMetadataSignatureVerificationFilter; +import lombok.extern.slf4j.Slf4j; + +/** + * SAML2 metadata-provider implementation for ID Austria client. + * + * @author tlenz + * + */ +@Slf4j +public class IdAustriaAuthMetadataProvider extends AbstractChainingMetadataProvider { + + private static final String FRIENDLYNAME_METADATA_TRUSTSTORE = "'ID Austria client-metadata truststore'"; + private static final String PROVIDER_ID_PATTERN = "ID Austria resolver: {0}"; + public static final String PROVIDER_ID = "ID Austria_client metadata provider'"; + + @Autowired + private IConfiguration basicConfig; + + @Autowired + private PvpMetadataResolverFactory metadataProviderFactory; + @Autowired + private IHttpClientFactory httpClientFactory; + + @Autowired + private EaafKeyStoreFactory keyStoreFactory; + + private Pair metadataSigningTrustStore; + + @Override + protected String getMetadataUrl(String entityId) throws EaafConfigurationException { + log.trace("ID Austria uses SAML2 well-known location approach. EntityId is Metadata-URL"); + return entityId; + + } + + @Override + protected MetadataResolver createNewMetadataProvider(String entityId) throws EaafConfigurationException, + IOException, CertificateException { + final List filterList = new ArrayList<>(); + filterList.add(new SchemaValidationFilter(true)); + filterList.add(new SimpleMetadataSignatureVerificationFilter( + metadataSigningTrustStore.getFirst(), entityId)); + + final MetadataFilterChain filter = new MetadataFilterChain(); + filter.setFilters(filterList); + + try { + return metadataProviderFactory.createMetadataProvider(getMetadataUrl(entityId), + filter, + MessageFormat.format(PROVIDER_ID_PATTERN, entityId), + httpClientFactory.getHttpClient()); + + } catch (final Pvp2MetadataException e) { + log.info("Can NOT build metadata provider for entityId: {}", entityId); + throw new EaafConfigurationException(IdAustriaAuthConstants.ERRORTYPE_04, + new Object[] { entityId, e.getMessage() }, e); + + } + } + + @Override + protected List getAllMetadataUrlsFromConfiguration() throws EaafConfigurationException { + return Collections.emptyList(); + + } + + @Override + protected String getMetadataProviderId() { + return PROVIDER_ID; + + } + + @Override + public void runGarbageCollector() { + log.trace("Garbage collection is NOT supported by: {}", getId()); + } + + @Override + public void doDestroy() { + super.fullyDestroy(); + + } + + @PostConstruct + private void initialize() throws EaafException { + // initialize truststore to validate metadata signing certificates + initializeTrustStore(); + + // load metadata with metadataURL, as backup + initializeFileSystemMetadata(); + + } + + private void initializeFileSystemMetadata() { + try { + final String metadataUrl = basicConfig.getBasicConfiguration( + IdAustriaAuthConstants.CONFIG_PROPS_IDAUSTRIA_METADATAURL); + if (StringUtils.isNotEmpty(metadataUrl)) { + log.info("Use not recommended metadata-provider initialization!" + + " SAML2 'Well-Known-Location' is the preferred methode."); + log.info("Initialize 'ID Austria' metadata-provider with URL: {}", metadataUrl); + + addMetadataResolverIntoChain(createNewMetadataProvider(metadataUrl)); + } + + } catch (final EaafConfigurationException | CertificateException | IOException e) { + log.warn("Can NOT inject static eIDAS Node metadata-soure.", e); + log.warn("Communication with ID Austria can be FAIL."); + + } + } + + private void initializeTrustStore() throws EaafException { + // set configuration + final KeyStoreConfiguration trustStoreConfig = new KeyStoreConfiguration(); + trustStoreConfig.setFriendlyName(FRIENDLYNAME_METADATA_TRUSTSTORE); + trustStoreConfig.setKeyStoreType(basicConfig.getBasicConfiguration( + IdAustriaAuthConstants.CONFIG_PROPS_TRUSTSTORE_TYPE, + KeyStoreType.JKS.getKeyStoreType())); + trustStoreConfig.setKeyStoreName(basicConfig.getBasicConfiguration( + IdAustriaAuthConstants.CONFIG_PROPS_TRUSTSTORE_NAME)); + trustStoreConfig.setSoftKeyStoreFilePath(basicConfig.getBasicConfiguration( + IdAustriaAuthConstants.CONFIG_PROPS_TRUSTSTORE_PATH)); + trustStoreConfig.setSoftKeyStorePassword(basicConfig.getBasicConfiguration( + IdAustriaAuthConstants.CONFIG_PROPS_TRUSTSTORE_PASSWORD)); + + // validate configuration + trustStoreConfig.validate(); + + // open new TrustStore + metadataSigningTrustStore = keyStoreFactory.buildNewKeyStore(trustStoreConfig); + + } + +} diff --git a/modules/authmodule_id-austria/src/main/java/at/asitplus/eidas/specific/modules/auth/idaustria/utils/Utils.java b/modules/authmodule_id-austria/src/main/java/at/asitplus/eidas/specific/modules/auth/idaustria/utils/Utils.java new file mode 100644 index 00000000..1de6c33f --- /dev/null +++ b/modules/authmodule_id-austria/src/main/java/at/asitplus/eidas/specific/modules/auth/idaustria/utils/Utils.java @@ -0,0 +1,44 @@ +package at.asitplus.eidas.specific.modules.auth.idaustria.utils; + +import javax.annotation.Nullable; + +import org.apache.commons.lang3.StringUtils; + +import at.asitplus.eidas.specific.modules.auth.idaustria.IdAustriaAuthConstants; +import at.gv.egiz.eaaf.core.api.idp.IConfiguration; +import at.gv.egiz.eaaf.core.api.idp.ISpConfiguration; + +public class Utils { + + /** + * Get the EntityId of the ID Austria system that + * should be used in this process. + * + * @param spConfiguration Service-Provider configuration that can include + * {@linkplain IdAustriaAuthConstants.CONFIG_PROPS_APPSPECIFIC_IDAUSTRIA_NODE_URL} + * @param authConfig Basic application configuration that include + * {@linkplain IdAustriaAuthConstants.CONFIG_PROPS_IDAUSTRIA_ENTITYID} + * @return EntityId, or null if no EntityId was found in configuration + */ + @Nullable + public static String getIdAustriaEntityId( + ISpConfiguration spConfiguration, IConfiguration authConfig) { + // load from service-provider configuration + String msNodeEntityID = spConfiguration.getConfigurationValue( + IdAustriaAuthConstants.CONFIG_PROPS_APPSPECIFIC_IDAUSTRIA_NODE_URL); + + if (StringUtils.isEmpty(msNodeEntityID)) { + msNodeEntityID = authConfig.getBasicConfiguration( + IdAustriaAuthConstants.CONFIG_PROPS_IDAUSTRIA_ENTITYID); + + } + + return msNodeEntityID; + } + + private Utils() { + //hide constructor of private class + + } + +} diff --git a/modules/authmodule_id-austria/src/main/resources/META-INF/services/at.gv.egiz.components.spring.api.SpringResourceProvider b/modules/authmodule_id-austria/src/main/resources/META-INF/services/at.gv.egiz.components.spring.api.SpringResourceProvider new file mode 100644 index 00000000..6bf41f6f --- /dev/null +++ b/modules/authmodule_id-austria/src/main/resources/META-INF/services/at.gv.egiz.components.spring.api.SpringResourceProvider @@ -0,0 +1 @@ +at.asitplus.eidas.specific.modules.auth.idaustria.IdAustriaAuthenticationSpringResourceProvider \ No newline at end of file diff --git a/modules/authmodule_id-austria/src/main/resources/META-INF/services/at.gv.egiz.eaaf.core.api.idp.IAttributeBuilder b/modules/authmodule_id-austria/src/main/resources/META-INF/services/at.gv.egiz.eaaf.core.api.idp.IAttributeBuilder new file mode 100644 index 00000000..65e9482c --- /dev/null +++ b/modules/authmodule_id-austria/src/main/resources/META-INF/services/at.gv.egiz.eaaf.core.api.idp.IAttributeBuilder @@ -0,0 +1 @@ +at.asitplus.eidas.specific.modules.auth.idaustria.builder.attributes.EidasConnecorUniqueIdAttributeBuilder diff --git a/modules/authmodule_id-austria/src/main/resources/messages/idaustria_auth_messages.properties b/modules/authmodule_id-austria/src/main/resources/messages/idaustria_auth_messages.properties new file mode 100644 index 00000000..6de6e0dc --- /dev/null +++ b/modules/authmodule_id-austria/src/main/resources/messages/idaustria_auth_messages.properties @@ -0,0 +1,10 @@ +module.idaustria.00=ID Austria authentication-module has an error in configuration. Missing: {0} +module.idaustria.01=ID Austria authentication-module has an error in configuration: {0}. Reason: {1} +module.idaustria.02=ID Austria authentication-module has an error in configuration. Reason: {0} +module.idaustria.03=ID Austria authentication-module has a general error during request pre-processing. Reason: {0} +module.idaustria.04=ID Austria authentication-module has a general error during response post-processing. +module.idaustria.05=ID Austria authentication-module can not initialize SAML2 metadata provider for entityId: {0}. Reason: {1} +module.idaustria.06=ID Austria authentication-module receives an invalid eIDAS bPK, which does NOT match to country-code of eIDAS Proxy-Service + +module.idaustria.98=ID Austria authentication-module has an internal error. Reason: {0} +module.idaustria.99=ID Austria authentication-module has an generic internal error. \ No newline at end of file diff --git a/modules/authmodule_id-austria/src/main/resources/process/id_austria.Authentication.process.xml b/modules/authmodule_id-austria/src/main/resources/process/id_austria.Authentication.process.xml new file mode 100644 index 00000000..e8a83e68 --- /dev/null +++ b/modules/authmodule_id-austria/src/main/resources/process/id_austria.Authentication.process.xml @@ -0,0 +1,18 @@ + + + + + + + + + + + + + + + + + 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 new file mode 100644 index 00000000..d2d16bf9 --- /dev/null +++ b/modules/authmodule_id-austria/src/main/resources/spring/id_austria_auth.beans.xml @@ -0,0 +1,36 @@ + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/modules/authmodule_id-austria/src/main/resources/spring/id_austria_task.beans.xml b/modules/authmodule_id-austria/src/main/resources/spring/id_austria_task.beans.xml new file mode 100644 index 00000000..9da9145d --- /dev/null +++ b/modules/authmodule_id-austria/src/main/resources/spring/id_austria_task.beans.xml @@ -0,0 +1,23 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/modules/authmodule_id-austria/src/test/java/at/asitplus/eidas/specific/modules/auth/idaustria/test/IdAustriaAuthSpringResourceProviderTest.java b/modules/authmodule_id-austria/src/test/java/at/asitplus/eidas/specific/modules/auth/idaustria/test/IdAustriaAuthSpringResourceProviderTest.java new file mode 100644 index 00000000..478a3ad4 --- /dev/null +++ b/modules/authmodule_id-austria/src/test/java/at/asitplus/eidas/specific/modules/auth/idaustria/test/IdAustriaAuthSpringResourceProviderTest.java @@ -0,0 +1,56 @@ +package at.asitplus.eidas.specific.modules.auth.idaustria.test; + +import java.io.IOException; +import java.io.InputStream; + +import org.apache.commons.io.IOUtils; +import org.junit.Assert; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.BlockJUnit4ClassRunner; +import org.springframework.core.io.Resource; + +import at.asitplus.eidas.specific.modules.auth.idaustria.IdAustriaAuthenticationSpringResourceProvider; +import at.gv.egiz.eaaf.core.test.TestConstants; + + + +@RunWith(BlockJUnit4ClassRunner.class) +public class IdAustriaAuthSpringResourceProviderTest { + + @Test + public void testSpringConfig() { + final IdAustriaAuthenticationSpringResourceProvider test = + new IdAustriaAuthenticationSpringResourceProvider(); + for (final Resource el : test.getResourcesToLoad()) { + try { + IOUtils.toByteArray(el.getInputStream()); + + } catch (final IOException e) { + Assert.fail("Ressouce: " + el.getFilename() + " not found"); + } + + } + + Assert.assertNotNull("no Name", test.getName()); + Assert.assertNull("Find package definitions", test.getPackagesToScan()); + + } + + @Test + public void testSpILoaderConfig() { + final InputStream el = this.getClass().getResourceAsStream(TestConstants.TEST_SPI_LOADER_PATH); + try { + final String spiFile = IOUtils.toString(el, "UTF-8"); + + Assert.assertEquals("Wrong classpath in SPI file", + IdAustriaAuthenticationSpringResourceProvider.class.getName(), spiFile); + + + } catch (final IOException e) { + Assert.fail("Ressouce: " + TestConstants.TEST_SPI_LOADER_PATH + " not found"); + + } + } + +} diff --git a/modules/authmodule_id-austria/src/test/java/at/asitplus/eidas/specific/modules/auth/idaustria/test/IdAustriaEidasProxyAuthenticationModulImplTest.java b/modules/authmodule_id-austria/src/test/java/at/asitplus/eidas/specific/modules/auth/idaustria/test/IdAustriaEidasProxyAuthenticationModulImplTest.java new file mode 100644 index 00000000..5a4c8b7e --- /dev/null +++ b/modules/authmodule_id-austria/src/test/java/at/asitplus/eidas/specific/modules/auth/idaustria/test/IdAustriaEidasProxyAuthenticationModulImplTest.java @@ -0,0 +1,102 @@ +package at.asitplus.eidas.specific.modules.auth.idaustria.test; + +import java.util.HashMap; +import java.util.Map; + +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.core.io.Resource; +import org.springframework.core.io.ResourceLoader; +import org.springframework.test.annotation.DirtiesContext; +import org.springframework.test.annotation.DirtiesContext.ClassMode; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; + +import at.asitplus.eidas.specific.modules.auth.idaustria.IdAustriaEidasProxyAuthenticationModulImpl; +import at.asitplus.eidas.specific.modules.msproxyservice.protocol.ProxyServicePendingRequest; +import at.gv.egiz.eaaf.core.api.data.EaafConfigConstants; +import at.gv.egiz.eaaf.core.api.idp.IConfiguration; +import at.gv.egiz.eaaf.core.api.idp.process.ExecutionContext; +import at.gv.egiz.eaaf.core.api.idp.process.ProcessEngine; +import at.gv.egiz.eaaf.core.impl.idp.auth.modules.ModuleRegistration; +import at.gv.egiz.eaaf.core.impl.idp.module.test.DummyConfiguration; +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; + +@RunWith(SpringJUnit4ClassRunner.class) +@ContextConfiguration(locations = { + "/spring/SpringTest-context_basic_test.xml", + "/spring/SpringTest-context_basic_mapConfig.xml"}) +@DirtiesContext(classMode = ClassMode.BEFORE_CLASS) +public class IdAustriaEidasProxyAuthenticationModulImplTest { + + @Autowired ModuleRegistration moduleReg; + @Autowired ResourceLoader loader; + @Autowired ProcessEngine processEngine; + + + private final ExecutionContext executionContext = new ExecutionContextImpl(); + private DummySpConfiguration oaParam; + private IdAustriaEidasProxyAuthenticationModulImpl authProcess = + new IdAustriaEidasProxyAuthenticationModulImpl(); + + + /** + * jUnit test set-up. + * + */ + @Before + public void initialize() { + Map configMap = new HashMap(); + configMap.put(EaafConfigConstants.SERVICE_UNIQUEIDENTIFIER, "http://test.com/test"); + IConfiguration basicConfig = new DummyConfiguration(); + oaParam = new DummySpConfiguration(configMap, basicConfig); + + } + + @Test + public void checkProcessDefinition() { + Assert.assertNotNull("AuthModule is null", authProcess); + Assert.assertNotNull("AuthModule process is null", authProcess.getProcessDefinitions()); + + for (String el : authProcess.getProcessDefinitions()) { + Resource res = loader.getResource(el); + Assert.assertTrue("AuthProcess description not extist", res.exists()); + + } + } + + @Test + public void idAustriaAuthSelected() throws Exception { + ProxyServicePendingRequest pendingReq = new ProxyServicePendingRequest(); + pendingReq.setOnlineApplicationConfiguration(oaParam); + + //execute test + final String result = moduleReg.selectProcess(executionContext, pendingReq); + + //validate state + Assert.assertNotNull("Process is null", result); + Assert.assertEquals("Process Id not match", "idAustriaForEidasProxyService", result); + + Assert.assertNotNull("Can not initalize process", processEngine.createProcessInstance(result)); + + } + + @Test + public void wrongPendingRequestType() throws Exception { + TestRequestImpl pendingReq = new TestRequestImpl(); + pendingReq.setSpConfig(oaParam); + + //execute test + final String result = moduleReg.selectProcess(executionContext, pendingReq); + + //validate state + Assert.assertNull("AuthProcessName", result); + + } + +} diff --git a/modules/authmodule_id-austria/src/test/java/at/asitplus/eidas/specific/modules/auth/idaustria/test/builder/attributes/EidasConnecorUniqueIdAttributeBuilderTest.java b/modules/authmodule_id-austria/src/test/java/at/asitplus/eidas/specific/modules/auth/idaustria/test/builder/attributes/EidasConnecorUniqueIdAttributeBuilderTest.java new file mode 100644 index 00000000..9f42f5e5 --- /dev/null +++ b/modules/authmodule_id-austria/src/test/java/at/asitplus/eidas/specific/modules/auth/idaustria/test/builder/attributes/EidasConnecorUniqueIdAttributeBuilderTest.java @@ -0,0 +1,54 @@ +package at.asitplus.eidas.specific.modules.auth.idaustria.test.builder.attributes; + +import org.junit.Assert; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; + +import at.asitplus.eidas.specific.modules.auth.idaustria.builder.attributes.EidasConnecorUniqueIdAttributeBuilder; +import at.gv.egiz.eaaf.core.api.idp.IAttributeBuilder; +import at.gv.egiz.eaaf.core.api.idp.ISpConfiguration; +import at.gv.egiz.eaaf.core.exceptions.AttributeBuilderException; +import at.gv.egiz.eaaf.core.impl.idp.auth.attributes.AbstractAttributeBuilderTest; + +/** + * Attribute builder to generate an attribute that holds the unique eIDSA-Connector identifier for this process. + *
+ * The attribute-value is read from {@link ISpConfiguration} with method getUniqueIdentifier() + * + * @author tlenz + * + */ +@RunWith(SpringJUnit4ClassRunner.class) +@ContextConfiguration(locations = { + "/spring/SpringTest-context_basic_mapConfig.xml", + "/spring/SpringTest-context_basic_test.xml", +}) +public class EidasConnecorUniqueIdAttributeBuilderTest extends AbstractAttributeBuilderTest { + + private final IAttributeBuilder attrBuilder = new EidasConnecorUniqueIdAttributeBuilder(); + + @Test + public void attributeName() { + Assert.assertEquals("Wrong attribute name", + "urn:eidgvat:attributes.eidas.uniqueId", attrBuilder.getName()); + + } + + @Test + public void checkEmptyAttribute() { + String value = attrBuilder.buildEmpty(gen); + Assert.assertNull("Attr. not null", value); + + } + + + @Test + public void withAttributeValue() throws AttributeBuilderException, Exception { + String value = attrBuilder.build(spConfig, buildAuthData(), gen); + Assert.assertEquals("wrong attributeValue", spConfig.getUniqueIdentifier(), value); + + } + +} diff --git a/modules/authmodule_id-austria/src/test/java/at/asitplus/eidas/specific/modules/auth/idaustria/test/config/IdAustriaAuthMessageSourceTest.java b/modules/authmodule_id-austria/src/test/java/at/asitplus/eidas/specific/modules/auth/idaustria/test/config/IdAustriaAuthMessageSourceTest.java new file mode 100644 index 00000000..2a92c01e --- /dev/null +++ b/modules/authmodule_id-austria/src/test/java/at/asitplus/eidas/specific/modules/auth/idaustria/test/config/IdAustriaAuthMessageSourceTest.java @@ -0,0 +1,50 @@ +package at.asitplus.eidas.specific.modules.auth.idaustria.test.config; + +import java.util.List; + +import org.junit.Assert; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.core.io.Resource; +import org.springframework.core.io.ResourceLoader; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; + +import at.asitplus.eidas.specific.modules.auth.idaustria.config.IdAustriaAuthMessageSource; +import at.gv.egiz.eaaf.core.api.logging.IMessageSourceLocation; + +@RunWith(SpringJUnit4ClassRunner.class) +@ContextConfiguration(locations = { + "/spring/SpringTest-context_basic_test.xml", + "/spring/SpringTest-context_basic_mapConfig.xml", + }) +public class IdAustriaAuthMessageSourceTest { + + @Autowired + private ResourceLoader loader; + @Autowired(required = false) + private List messageSources; + + @Test + public void checkMessageSources() { + Assert.assertNotNull("No messageSource", messageSources); + Assert.assertFalse("No message source", messageSources.isEmpty()); + + boolean found = false; + + for (final IMessageSourceLocation messageSource : messageSources) { + found = found ? found : messageSource instanceof IdAustriaAuthMessageSource; + + Assert.assertNotNull("No sourcePath", messageSource.getMessageSourceLocation()); + for (final String el : messageSource.getMessageSourceLocation()) { + final Resource messages = loader.getResource(el + ".properties"); + Assert.assertTrue("Source not exist", messages.exists()); + + } + } + + Assert.assertTrue("Internal messagesource not found", found); + + } +} diff --git a/modules/authmodule_id-austria/src/test/java/at/asitplus/eidas/specific/modules/auth/idaustria/test/controller/IdAustriaAuthMetadataControllerFirstTest.java b/modules/authmodule_id-austria/src/test/java/at/asitplus/eidas/specific/modules/auth/idaustria/test/controller/IdAustriaAuthMetadataControllerFirstTest.java new file mode 100644 index 00000000..0df74f7b --- /dev/null +++ b/modules/authmodule_id-austria/src/test/java/at/asitplus/eidas/specific/modules/auth/idaustria/test/controller/IdAustriaAuthMetadataControllerFirstTest.java @@ -0,0 +1,186 @@ +package at.asitplus.eidas.specific.modules.auth.idaustria.test.controller; + +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.io.UnsupportedEncodingException; +import java.security.cert.X509Certificate; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +import org.junit.Assert; +import org.junit.Before; +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.UnmarshallingException; +import org.opensaml.core.xml.util.XMLObjectSupport; +import org.opensaml.saml.common.xml.SAMLConstants; +import org.opensaml.saml.metadata.resolver.filter.FilterException; +import org.opensaml.saml.metadata.resolver.filter.MetadataFilterContext; +import org.opensaml.saml.saml2.metadata.EntityDescriptor; +import org.opensaml.saml.saml2.metadata.SPSSODescriptor; +import org.opensaml.security.x509.BasicX509Credential; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.mock.web.MockHttpServletRequest; +import org.springframework.mock.web.MockHttpServletResponse; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; +import org.springframework.web.servlet.config.annotation.EnableWebMvc; + +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.controller.IdAustriaAuthMetadataController; +import at.asitplus.eidas.specific.modules.auth.idaustria.utils.IdAustriaAuthCredentialProvider; +import at.gv.egiz.eaaf.core.api.data.PvpAttributeDefinitions; +import at.gv.egiz.eaaf.core.exceptions.EaafException; +import at.gv.egiz.eaaf.modules.pvp2.exception.CredentialsNotAvailableException; +import at.gv.egiz.eaaf.modules.pvp2.impl.opensaml.initialize.EaafOpenSaml3xInitializer; +import at.gv.egiz.eaaf.modules.pvp2.impl.validation.metadata.SchemaValidationFilter; +import at.gv.egiz.eaaf.modules.pvp2.impl.validation.metadata.SimpleMetadataSignatureVerificationFilter; +import net.shibboleth.utilities.java.support.xml.XMLParserException; + +@RunWith(SpringJUnit4ClassRunner.class) +@ContextConfiguration(locations = { + "/spring/SpringTest-context_basic_mapConfig.xml", + "/spring/SpringTest-context_basic_test.xml" +}) +@EnableWebMvc +public class IdAustriaAuthMetadataControllerFirstTest { + + private MockHttpServletRequest httpReq; + private MockHttpServletResponse httpResp; + + @Autowired private IdAustriaAuthMetadataController controller; + @Autowired private IdAustriaAuthCredentialProvider credProvider; + @Autowired private MsConnectorDummyConfigMap config; + + /** + * JUnit class initializer. + * + * @throws Exception In case of an OpenSAML3 initialization error + */ + @BeforeClass + public static void initialize() throws Exception { + EaafOpenSaml3xInitializer.eaafInitialize(); + + } + + /** + * Single jUnit-test set-up. + */ + @Before + public void testSetup() { + httpReq = new MockHttpServletRequest("GET", "https://localhost/authhandler"); + httpReq.setContextPath("/authhandler"); + httpResp = new MockHttpServletResponse(); + + //remove additional attributes + Map attr = config.getBasicConfigurationWithPrefix( + "eidas.ms.modules.idaustriaauth.required.additional.attributes."); + for (String el : attr.keySet()) { + config.removeConfigValue("eidas.ms.modules.idaustriaauth.required.additional.attributes." + el); + + } + + + } + + @Test + public void buildMetadataValid() throws IOException, EaafException, + XMLParserException, UnmarshallingException, FilterException { + + //build metdata + controller.getSpMetadata(httpReq, httpResp); + + //check result + validateResponse(16); + + } + + @Test + public void buildMetadataValidWithAdditionalAttributes() throws IOException, EaafException, + XMLParserException, UnmarshallingException, FilterException { + config.putConfigValue("eidas.ms.modules.idaustriaauth.required.additional.attributes.1", + PvpAttributeDefinitions.BPK_LIST_NAME + ",true"); + config.putConfigValue("eidas.ms.modules.idaustriaauth.required.additional.attributes.2", + PvpAttributeDefinitions.PVP_VERSION_NAME + ",false"); + config.putConfigValue("eidas.ms.modules.idaustriaauth.required.additional.attributes.7", + PvpAttributeDefinitions.EID_SIGNER_CERTIFICATE_NAME + ",true"); + + config.putConfigValue("eidas.ms.modules.idaustriaauth.required.additional.attributes.3", "bbbbb"); + config.putConfigValue("eidas.ms.modules.idaustriaauth.required.additional.attributes.4", "bbbbb,false,test"); + config.putConfigValue("eidas.ms.modules.idaustriaauth.required.additional.attributes.5", "bbbbb,nichts"); + config.putConfigValue("eidas.ms.modules.idaustriaauth.required.additional.attributes.6", ""); + + //build metdata + controller.getSpMetadata(httpReq, httpResp); + + //check result + validateResponse(17); + + } + + private void validateResponse(int numberOfRequestedAttributes) throws UnsupportedEncodingException, + XMLParserException, UnmarshallingException, FilterException, CredentialsNotAvailableException { + Assert.assertEquals("HTTP Statuscode", 200, httpResp.getStatus()); + Assert.assertEquals("ContentType", "text/xml; charset=utf-8", httpResp.getContentType()); + Assert.assertEquals("ContentEncoding", "UTF-8", httpResp.getCharacterEncoding()); + + final String metadataXml = httpResp.getContentAsString(); + Assert.assertNotNull("XML Metadata", metadataXml); + + final EntityDescriptor metadata = (EntityDescriptor) XMLObjectSupport.unmarshallFromInputStream( + XMLObjectProviderRegistrySupport.getParserPool(), new ByteArrayInputStream(metadataXml.getBytes("UTF-8"))); + + Assert.assertEquals("EntityId", + "http://localhost/authhandler" + IdAustriaAuthConstants.ENDPOINT_METADATA, + metadata.getEntityID()); + + MetadataFilterContext filterContext = new MetadataFilterContext(); + + //check XML scheme + final SchemaValidationFilter schemaFilter = new SchemaValidationFilter(); + schemaFilter.filter(metadata, filterContext); + + //check signature + final SimpleMetadataSignatureVerificationFilter sigFilter = + new SimpleMetadataSignatureVerificationFilter(credProvider.getKeyStore().getFirst(), + metadata.getEntityID()); + sigFilter.filter(metadata, filterContext); + + //check content + final SPSSODescriptor spSsoDesc = metadata.getSPSSODescriptor(SAMLConstants.SAML20P_NS); + Assert.assertNotNull("SPSSODescr.", spSsoDesc); + + Assert.assertFalse("AssertionConsumerServices", + spSsoDesc.getAssertionConsumerServices().isEmpty()); + Assert.assertTrue("ContactPersons", metadata.getContactPersons().isEmpty()); + Assert.assertNull("ContactPersons", metadata.getOrganization()); + + Assert.assertFalse("KeyDescriptors", + spSsoDesc.getKeyDescriptors().isEmpty()); + Assert.assertEquals("#KeyDescriptors", 2, spSsoDesc.getKeyDescriptors().size()); + + Assert.assertFalse("NameIDFormats", + spSsoDesc.getNameIDFormats().isEmpty()); + Assert.assertEquals("wrong NameIDFormats", "urn:oasis:names:tc:SAML:2.0:nameid-format:persistent", + spSsoDesc.getNameIDFormats().get(0).getURI()); + + Assert.assertFalse("AttributeConsumingServices", + spSsoDesc.getAttributeConsumingServices().isEmpty()); + Assert.assertEquals("#RequestAttributes", numberOfRequestedAttributes, + spSsoDesc.getAttributeConsumingServices().get(0).getRequestedAttributes().size()); + + } + + private List convertX509Certs(List certs) { + final List result = new ArrayList<>(); + for (final X509Certificate cert : certs) { + result.add(new BasicX509Credential(cert)); + + } + return result; + } +} diff --git a/modules/authmodule_id-austria/src/test/java/at/asitplus/eidas/specific/modules/auth/idaustria/test/controller/IdAustriaAuthSignalControllerTest.java b/modules/authmodule_id-austria/src/test/java/at/asitplus/eidas/specific/modules/auth/idaustria/test/controller/IdAustriaAuthSignalControllerTest.java new file mode 100644 index 00000000..e9ecbc58 --- /dev/null +++ b/modules/authmodule_id-austria/src/test/java/at/asitplus/eidas/specific/modules/auth/idaustria/test/controller/IdAustriaAuthSignalControllerTest.java @@ -0,0 +1,200 @@ +package at.asitplus.eidas.specific.modules.auth.idaustria.test.controller; + +import java.io.IOException; +import java.util.HashMap; +import java.util.Map; + +import org.apache.commons.lang3.RandomStringUtils; +import org.junit.Assert; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.mock.web.MockHttpServletRequest; +import org.springframework.mock.web.MockHttpServletResponse; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; +import org.springframework.util.SerializationUtils; +import org.springframework.web.servlet.config.annotation.EnableWebMvc; + +import at.asitplus.eidas.specific.modules.auth.idaustria.controller.IdAustriaAuthSignalController; +import at.gv.egiz.eaaf.core.api.IRequestStorage; +import at.gv.egiz.eaaf.core.api.data.EaafConfigConstants; +import at.gv.egiz.eaaf.core.api.data.ExceptionContainer; +import at.gv.egiz.eaaf.core.api.idp.IConfiguration; +import at.gv.egiz.eaaf.core.api.storage.ITransactionStorage; +import at.gv.egiz.eaaf.core.api.utils.IPendingRequestIdGenerationStrategy; +import at.gv.egiz.eaaf.core.exceptions.EaafException; +import at.gv.egiz.eaaf.core.impl.idp.module.test.DummyProtocolAuthService; +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.spring.test.DummyTransactionStorage.DummyDbEntry; + +@RunWith(SpringJUnit4ClassRunner.class) +@ContextConfiguration(locations = { + "/spring/SpringTest-context_basic_mapConfig.xml", + "/spring/SpringTest-context_basic_test.xml" +}) +@EnableWebMvc +public class IdAustriaAuthSignalControllerTest { + + @Autowired(required = true) + private IdAustriaAuthSignalController controller; + @Autowired(required = true) + private ITransactionStorage cache; + @Autowired(required = true) + private IPendingRequestIdGenerationStrategy pendingReqGeneration; + @Autowired(required = true) + private IRequestStorage reqStorage; + @Autowired(required = true) + private IConfiguration basicConfig; + @Autowired private ITransactionStorage transactionStorage; + + @Autowired private DummyProtocolAuthService protAuthService; + + @Test + public void noRelayState() throws IOException, EaafException { + final MockHttpServletRequest httpReq = + new MockHttpServletRequest("POST", "https://localhost/ms_connectoror"); + final MockHttpServletResponse httpResp = new MockHttpServletResponse(); + + controller.performEidasAuthentication(httpReq, httpResp); + Assert.assertEquals("httpStausCode", 200, httpResp.getStatus()); + + final String errorId = protAuthService.getErrorKey(); + final Object error = cache.get(errorId); + Assert.assertNotNull("Error is null", error); + org.springframework.util.Assert.isInstanceOf(byte[].class, + ((DummyDbEntry) error).getObj()); + final Object errorObj = SerializationUtils.deserialize((byte[]) ((DummyDbEntry) error).getObj()); + org.springframework.util.Assert.isInstanceOf(ExceptionContainer.class, errorObj); + org.springframework.util.Assert.isInstanceOf(EaafException.class, + ((ExceptionContainer) errorObj).getExceptionThrown()); + + } + + @Test + public void validRelayStateNoPendingReqId() throws EaafException, IOException { + final String pendingReqId = pendingReqGeneration.generateExternalPendingRequestId(); + final MockHttpServletRequest httpReq = + new MockHttpServletRequest("POST", "https://localhost/ms_connectoror"); + httpReq.addParameter(IdAustriaAuthSignalController.HTTP_PARAM_RELAYSTATE, pendingReqId); + final MockHttpServletResponse httpResp = new MockHttpServletResponse(); + + controller.performEidasAuthentication(httpReq, httpResp); + Assert.assertEquals("httpStausCode", 200, httpResp.getStatus()); + + final String errorId = protAuthService.getErrorKey(); + final Object error = cache.get(errorId); + Assert.assertNotNull("Error is null", error); + org.springframework.util.Assert.isInstanceOf(byte[].class, + ((DummyDbEntry) error).getObj()); + final Object errorObj = SerializationUtils.deserialize((byte[]) ((DummyDbEntry) error).getObj()); + org.springframework.util.Assert.isInstanceOf(ExceptionContainer.class, errorObj); + org.springframework.util.Assert.isInstanceOf(EaafException.class, + ((ExceptionContainer) errorObj).getExceptionThrown()); + //TODO: + Assert.assertEquals("ErrorCode not match", "auth.26", + ((EaafException) ((ExceptionContainer) errorObj).getExceptionThrown()).getErrorId()); + + } + + @Test + public void validRelayStateSuspectPendingReqId() throws EaafException, IOException { + String relayState = RandomStringUtils.randomAlphanumeric(10); + transactionStorage.put(relayState, false, -1); + + final MockHttpServletRequest httpReq = + new MockHttpServletRequest("POST", "https://localhost/ms_connectoror"); + httpReq.addParameter(IdAustriaAuthSignalController.HTTP_PARAM_RELAYSTATE, relayState); + final MockHttpServletResponse httpResp = new MockHttpServletResponse(); + + controller.performEidasAuthentication(httpReq, httpResp); + Assert.assertEquals("httpStausCode", 200, httpResp.getStatus()); + + final String errorId = protAuthService.getErrorKey(); + final Object error = cache.get(errorId); + Assert.assertNotNull("Error is null", error); + org.springframework.util.Assert.isInstanceOf(byte[].class, + ((DummyDbEntry) error).getObj()); + final Object errorObj = SerializationUtils.deserialize((byte[]) ((DummyDbEntry) error).getObj()); + org.springframework.util.Assert.isInstanceOf(ExceptionContainer.class, errorObj); + org.springframework.util.Assert.isInstanceOf(EaafException.class, + ((ExceptionContainer) errorObj).getExceptionThrown()); + //TODO: + Assert.assertEquals("ErrorCode not match", "auth.26", + ((EaafException) ((ExceptionContainer) errorObj).getExceptionThrown()).getErrorId()); + + Assert.assertNull("RelayState was not removed", transactionStorage.get(relayState)); + + } + + @Test + public void validRelayStateNoPendingReq() throws EaafException, IOException { + final String pendingReqId = pendingReqGeneration.generateExternalPendingRequestId(); + String relayState = RandomStringUtils.randomAlphanumeric(10); + transactionStorage.put(relayState, pendingReqId, -1); + + final MockHttpServletRequest httpReq = + new MockHttpServletRequest("POST", "https://localhost/ms_connectoror"); + httpReq.addParameter(IdAustriaAuthSignalController.HTTP_PARAM_RELAYSTATE, relayState); + final MockHttpServletResponse httpResp = new MockHttpServletResponse(); + + controller.performEidasAuthentication(httpReq, httpResp); + Assert.assertEquals("httpStausCode", 200, httpResp.getStatus()); + + final String errorId = protAuthService.getErrorKey(); + final Object error = cache.get(errorId); + Assert.assertNotNull("Error is null", error); + org.springframework.util.Assert.isInstanceOf(byte[].class, + ((DummyDbEntry) error).getObj()); + final Object errorObj = SerializationUtils.deserialize((byte[]) ((DummyDbEntry) error).getObj()); + org.springframework.util.Assert.isInstanceOf(ExceptionContainer.class, errorObj); + org.springframework.util.Assert.isInstanceOf(EaafException.class, + ((ExceptionContainer) errorObj).getExceptionThrown()); + //TODO: + Assert.assertEquals("ErrorCode not match", "auth.28", + ((EaafException) ((ExceptionContainer) errorObj).getExceptionThrown()).getErrorId()); + + Assert.assertNull("RelayState was not removed", transactionStorage.get(relayState)); + + } + + @Test + public void validRelayStateWithPendingReq() throws EaafException, IOException { + final String pendingReqId = pendingReqGeneration.generateExternalPendingRequestId(); + + String relayState = RandomStringUtils.randomAlphanumeric(10); + transactionStorage.put(relayState, pendingReqId, -1); + + final TestRequestImpl pendingReq = new TestRequestImpl(); + pendingReq.setPendingReqId(pendingReqId); + pendingReq.setAuthUrl("http://localhost/idp"); + final Map spConfigMap = new HashMap<>(); + spConfigMap.put(EaafConfigConstants.SERVICE_UNIQUEIDENTIFIER, "http://test.sp"); + final DummySpConfiguration spConfig = new DummySpConfiguration(spConfigMap, basicConfig); + pendingReq.setSpConfig(spConfig); + reqStorage.storePendingRequest(pendingReq); + + final MockHttpServletRequest httpReq = + new MockHttpServletRequest("POST", "https://localhost/ms_connectoror"); + httpReq.addParameter(IdAustriaAuthSignalController.HTTP_PARAM_RELAYSTATE, relayState); + final MockHttpServletResponse httpResp = new MockHttpServletResponse(); + + controller.performEidasAuthentication(httpReq, httpResp); + + Assert.assertEquals("httpStausCode", 200, httpResp.getStatus()); + + final String errorId = protAuthService.getErrorKey(); + final Object error = cache.get(errorId); + Assert.assertNotNull("Error is null", error); + org.springframework.util.Assert.isInstanceOf(byte[].class, + ((DummyDbEntry) error).getObj()); + final Object errorObj = SerializationUtils.deserialize((byte[]) ((DummyDbEntry) error).getObj()); + org.springframework.util.Assert.isInstanceOf(ExceptionContainer.class, errorObj); + org.springframework.util.Assert.isInstanceOf(EaafException.class, + ((ExceptionContainer) errorObj).getExceptionThrown()); + Assert.assertEquals("ErrorCode not match", + "PendingRequest object is not of type 'RequestImpl.class'", + ((EaafException) ((ExceptionContainer) errorObj).getExceptionThrown()).getErrorId()); + } +} diff --git a/modules/authmodule_id-austria/src/test/java/at/asitplus/eidas/specific/modules/auth/idaustria/test/task/ReceiveAuthnResponseTaskTest.java b/modules/authmodule_id-austria/src/test/java/at/asitplus/eidas/specific/modules/auth/idaustria/test/task/ReceiveAuthnResponseTaskTest.java new file mode 100644 index 00000000..c452fe22 --- /dev/null +++ b/modules/authmodule_id-austria/src/test/java/at/asitplus/eidas/specific/modules/auth/idaustria/test/task/ReceiveAuthnResponseTaskTest.java @@ -0,0 +1,792 @@ +package at.asitplus.eidas.specific.modules.auth.idaustria.test.task; + +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertThrows; +import static org.junit.Assert.assertTrue; + +import java.io.IOException; +import java.time.Instant; +import java.util.Arrays; +import java.util.Base64; +import java.util.HashMap; +import java.util.Map; + +import javax.xml.transform.TransformerException; + +import org.apache.commons.io.IOUtils; +import org.apache.commons.lang3.RandomStringUtils; +import org.junit.Assert; +import org.junit.Before; +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.core.Issuer; +import org.opensaml.saml.saml2.core.Response; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.ApplicationContext; +import org.springframework.mock.web.MockHttpServletRequest; +import org.springframework.mock.web.MockHttpServletResponse; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; +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.config.ServiceProviderConfiguration; +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.tasks.ReceiveFromIdAustriaSystemTask; +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.IRequestStorage; +import at.gv.egiz.eaaf.core.api.data.EaafConfigConstants; +import at.gv.egiz.eaaf.core.api.data.EaafConstants; +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.EaafException; +import at.gv.egiz.eaaf.core.exceptions.TaskExecutionException; +import at.gv.egiz.eaaf.core.impl.idp.auth.data.AuthProcessDataWrapper; +import at.gv.egiz.eaaf.core.impl.idp.process.ExecutionContextImpl; +import at.gv.egiz.eaaf.core.impl.utils.DomUtils; +import at.gv.egiz.eaaf.modules.pvp2.api.credential.EaafX509Credential; +import at.gv.egiz.eaaf.modules.pvp2.exception.CredentialsNotAvailableException; +import at.gv.egiz.eaaf.modules.pvp2.exception.Pvp2MetadataException; +import at.gv.egiz.eaaf.modules.pvp2.exception.SamlSigningException; +import at.gv.egiz.eaaf.modules.pvp2.impl.metadata.PvpMetadataResolverFactory; +import at.gv.egiz.eaaf.modules.pvp2.impl.opensaml.initialize.EaafOpenSaml3xInitializer; +import at.gv.egiz.eaaf.modules.pvp2.impl.utils.Saml2Utils; +import at.gv.egiz.eaaf.modules.pvp2.sp.exception.AuthnResponseValidationException; +import net.shibboleth.utilities.java.support.xml.XMLParserException; + +@RunWith(SpringJUnit4ClassRunner.class) +@ContextConfiguration(locations = { + "/spring/SpringTest-context_basic_mapConfig.xml", + "/spring/SpringTest-context_basic_test.xml", +}) +public class ReceiveAuthnResponseTaskTest { + + private static final String METADATA_PATH = "classpath:/data/idp_metadata_classpath_entity.xml"; + + @Autowired ApplicationContext context; + @Autowired MsConnectorDummyConfigMap config; + + @Autowired IdAustriaAuthMetadataProvider metadataProvider; + @Autowired IdAustriaAuthCredentialProvider credentialProvider; + @Autowired PvpMetadataResolverFactory metadataFactory; + @Autowired IRequestStorage storage; + + final ExecutionContext executionContext = new ExecutionContextImpl(); + private MockHttpServletRequest httpReq; + private MockHttpServletResponse httpResp; + + private ProxyServicePendingRequest pendingReq; + private ServiceProviderConfiguration oaParam; + private Map spConfig; + + private ReceiveFromIdAustriaSystemTask task; + + /** + * JUnit class initializer. + * + * @throws Exception In case of an OpenSAML3 initialization error + */ + @BeforeClass + public static void initialize() throws Exception { + EaafOpenSaml3xInitializer.eaafInitialize(); + + } + + /** + * jUnit test set-up. + * + * @throws Exception In case of an set-up error + */ + @Before + public void setUp() throws Exception { + task = (ReceiveFromIdAustriaSystemTask) context.getBean("receiveIdAustriaAuthnResponseTask"); + + httpReq = new MockHttpServletRequest("POST", "https://localhost/ms_connector"); + httpReq.setScheme("https"); + httpReq.setServerPort(443); + httpReq.setContextPath("/authhandler"); + httpResp = new MockHttpServletResponse(); + RequestContextHolder.resetRequestAttributes(); + RequestContextHolder.setRequestAttributes(new ServletRequestAttributes(httpReq, httpResp)); + + config.putConfigValue(IdAustriaAuthConstants.CONFIG_PROPS_IDAUSTRIA_ENTITYID, + "classpath:/data/idp_metadata_classpath_entity.xml"); + config.putConfigValue(IdAustriaAuthConstants.CONFIG_PROPS_SIGN_SIGNING_ALIAS, "sig"); + + spConfig = new HashMap<>(); + spConfig.put(EaafConfigConstants.SERVICE_UNIQUEIDENTIFIER, "http://test.com/test"); + oaParam = new ServiceProviderConfiguration(spConfig, config); + oaParam.setRequiredLoA(Arrays.asList(EaafConstants.EIDAS_LOA_HIGH)); + + pendingReq = new ProxyServicePendingRequest(); + pendingReq.initialize(httpReq, config); + pendingReq.setPendingRequestId(RandomStringUtils.randomAlphanumeric(10)); + pendingReq.setOnlineApplicationConfiguration(oaParam); + + metadataProvider.fullyDestroy(); + + } + + @Test + public void unsupportedHttpMethode() { + httpReq = new MockHttpServletRequest("PUT", "https://localhost/ms_connector"); + RequestContextHolder.resetRequestAttributes(); + RequestContextHolder.setRequestAttributes(new ServletRequestAttributes(httpReq, httpResp)); + + final TaskExecutionException e = assertThrows(TaskExecutionException.class, + () -> task.execute(pendingReq, executionContext)); + + Assert.assertNotNull(e.getPendingRequestID()); + Assert.assertEquals(pendingReq.getPendingRequestId(), e.getPendingRequestID()); + Assert.assertNotNull(e.getOriginalException()); + org.springframework.util.Assert.isInstanceOf(AuthnResponseValidationException.class, + e.getOriginalException()); + Assert.assertEquals("sp.pvp2.03", + ((AuthnResponseValidationException) e.getOriginalException()).getErrorId()); + + } + + @Test + public void httpGetNoMessage() { + httpReq = new MockHttpServletRequest("GET", "https://localhost/ms_connector"); + RequestContextHolder.resetRequestAttributes(); + RequestContextHolder.setRequestAttributes(new ServletRequestAttributes(httpReq, httpResp)); + + final TaskExecutionException e = assertThrows(TaskExecutionException.class, + () -> task.execute(pendingReq, executionContext)); + + Assert.assertNotNull(e.getPendingRequestID()); + Assert.assertEquals(pendingReq.getPendingRequestId(), e.getPendingRequestID()); + Assert.assertNotNull(e.getOriginalException()); + org.springframework.util.Assert.isInstanceOf(AuthnResponseValidationException.class, + e.getOriginalException()); + Assert.assertEquals("sp.pvp2.12", + ((AuthnResponseValidationException) e.getOriginalException()).getErrorId()); + + } + + @Test + public void httpPostNoMessage() { + + final TaskExecutionException e = assertThrows(TaskExecutionException.class, + () -> task.execute(pendingReq, executionContext)); + + Assert.assertNotNull(e.getPendingRequestID()); + Assert.assertEquals(pendingReq.getPendingRequestId(), e.getPendingRequestID()); + Assert.assertNotNull(e.getOriginalException()); + org.springframework.util.Assert.isInstanceOf(AuthnResponseValidationException.class, + e.getOriginalException()); + Assert.assertEquals("sp.pvp2.12", + ((AuthnResponseValidationException) e.getOriginalException()).getErrorId()); + + } + + @Test + public void httpPostMessageNotSigned() throws IOException { + + httpReq.addParameter("SAMLResponse", Base64.getEncoder().encodeToString( + IOUtils.toByteArray(ReceiveAuthnResponseTaskTest.class.getResourceAsStream( + "/data/Response_without_sig_classpath_entityid.xml")))); + + final TaskExecutionException e = assertThrows(TaskExecutionException.class, + () -> task.execute(pendingReq, executionContext)); + + Assert.assertNotNull(e.getPendingRequestID()); + Assert.assertEquals(pendingReq.getPendingRequestId(), e.getPendingRequestID()); + Assert.assertNotNull(e.getOriginalException()); + org.springframework.util.Assert.isInstanceOf(AuthnResponseValidationException.class, + e.getOriginalException()); + Assert.assertEquals("sp.pvp2.12", + ((AuthnResponseValidationException) e.getOriginalException()).getErrorId()); + + } + + @Test + public void httpPostMessageWrongDestinationEndpoint() throws IOException, SamlSigningException, + Pvp2MetadataException, CredentialsNotAvailableException, XMLParserException, UnmarshallingException, + TransformerException, MarshallingException { + + final Response response = initializeResponse( + "classpath:/data/idp_metadata_classpath_entity.xml", + "/data/Response_with_wrong_destination_endpoint.xml", + credentialProvider.getMessageSigningCredential(), true); + httpReq.addParameter("SAMLResponse", Base64.getEncoder().encodeToString( + DomUtils.serializeNode(XMLObjectSupport.getMarshaller(response).marshall(response)).getBytes( + "UTF-8"))); + + final TaskExecutionException e = assertThrows(TaskExecutionException.class, + () -> task.execute(pendingReq, executionContext)); + + Assert.assertNotNull(e.getPendingRequestID()); + Assert.assertEquals(pendingReq.getPendingRequestId(), e.getPendingRequestID()); + Assert.assertNotNull(e.getOriginalException()); + org.springframework.util.Assert.isInstanceOf(AuthnResponseValidationException.class, + e.getOriginalException()); + Assert.assertEquals("sp.pvp2.12", + ((AuthnResponseValidationException) e.getOriginalException()).getErrorId()); + + } + + @Test + public void httpPostValidSignedNoMetadata() throws IOException, SamlSigningException, + Pvp2MetadataException, CredentialsNotAvailableException, XMLParserException, UnmarshallingException, + MarshallingException, TransformerException { + + final Response response = initializeResponse( + "classpath:/data/idp_metadata_classpath_entity.xml", + "/data/Response_without_sig_classpath_entityid.xml", + credentialProvider.getMessageSigningCredential(), true); + httpReq.addParameter("SAMLResponse", Base64.getEncoder().encodeToString( + DomUtils.serializeNode(XMLObjectSupport.getMarshaller(response).marshall(response)).getBytes( + "UTF-8"))); + + final TaskExecutionException e = assertThrows(TaskExecutionException.class, + () -> task.execute(pendingReq, executionContext)); + + Assert.assertNotNull(e.getPendingRequestID()); + Assert.assertEquals(pendingReq.getPendingRequestId(), e.getPendingRequestID()); + Assert.assertNotNull(e.getOriginalException()); + org.springframework.util.Assert.isInstanceOf(AuthnResponseValidationException.class, + e.getOriginalException()); + Assert.assertEquals("sp.pvp2.11", + ((EaafException) e.getOriginalException()).getErrorId()); + + } + + @Test + public void httpPostValidSignedAssertionOutDated() throws IOException, SamlSigningException, + Pvp2MetadataException, CredentialsNotAvailableException, XMLParserException, UnmarshallingException, + MarshallingException, TransformerException { + + metadataProvider.addMetadataResolverIntoChain(metadataFactory.createMetadataProvider( + METADATA_PATH, null, "jUnit IDP", null)); + + final Response response = initializeResponse( + "classpath:/data/idp_metadata_classpath_entity.xml", + "/data/Response_without_sig_classpath_entityid.xml", + credentialProvider.getMessageSigningCredential(), false); + httpReq.addParameter("SAMLResponse", Base64.getEncoder().encodeToString( + DomUtils.serializeNode(XMLObjectSupport.getMarshaller(response).marshall(response)).getBytes( + "UTF-8"))); + + final TaskExecutionException e = assertThrows(TaskExecutionException.class, + () -> task.execute(pendingReq, executionContext)); + + Assert.assertNotNull(e.getPendingRequestID()); + Assert.assertEquals(pendingReq.getPendingRequestId(), e.getPendingRequestID()); + Assert.assertNotNull(e.getOriginalException()); + org.springframework.util.Assert.isInstanceOf(AuthnResponseValidationException.class, + e.getOriginalException()); + Assert.assertEquals("sp.pvp2.12", + ((EaafException) e.getOriginalException()).getErrorId()); + + } + + @Test + public void httpPostValidSignedAssertionFromWrongIdp() throws IOException, SamlSigningException, + Pvp2MetadataException, CredentialsNotAvailableException, XMLParserException, UnmarshallingException, + MarshallingException, TransformerException { + + metadataProvider.addMetadataResolverIntoChain(metadataFactory.createMetadataProvider( + METADATA_PATH, null, "jUnit IDP", null)); + + config.putConfigValue(IdAustriaAuthConstants.CONFIG_PROPS_IDAUSTRIA_ENTITYID, + RandomStringUtils.randomAlphabetic(10)); + + final Response response = initializeResponse( + "classpath:/data/idp_metadata_classpath_entity.xml", + "/data/Response_without_sig_classpath_entityid.xml", + credentialProvider.getMessageSigningCredential(), + true); + httpReq.addParameter("SAMLResponse", Base64.getEncoder().encodeToString( + DomUtils.serializeNode(XMLObjectSupport.getMarshaller(response).marshall(response)).getBytes( + "UTF-8"))); + + final TaskExecutionException e = assertThrows(TaskExecutionException.class, + () -> task.execute(pendingReq, executionContext)); + + Assert.assertNotNull(e.getPendingRequestID()); + Assert.assertEquals(pendingReq.getPendingRequestId(), e.getPendingRequestID()); + Assert.assertNotNull(e.getOriginalException()); + org.springframework.util.Assert.isInstanceOf(AuthnResponseValidationException.class, + e.getOriginalException()); + Assert.assertEquals("sp.pvp2.08", + ((EaafException) e.getOriginalException()).getErrorId()); + + } + + @Test + public void httpPostValidSignedWitError() throws IOException, SamlSigningException, + Pvp2MetadataException, CredentialsNotAvailableException, XMLParserException, UnmarshallingException, + MarshallingException, TransformerException { + + metadataProvider.addMetadataResolverIntoChain(metadataFactory.createMetadataProvider( + METADATA_PATH, null, "jUnit IDP", null)); + + final Response response = initializeResponse( + "classpath:/data/idp_metadata_classpath_entity.xml", + "/data/Response_without_sig_with_error.xml", + credentialProvider.getMessageSigningCredential(), + true); + httpReq.addParameter("SAMLResponse", Base64.getEncoder().encodeToString( + DomUtils.serializeNode(XMLObjectSupport.getMarshaller(response).marshall(response)).getBytes( + "UTF-8"))); + + final TaskExecutionException e = assertThrows(TaskExecutionException.class, + () -> task.execute(pendingReq, executionContext)); + + Assert.assertNotNull(e.getPendingRequestID()); + Assert.assertEquals(pendingReq.getPendingRequestId(), e.getPendingRequestID()); + Assert.assertNotNull(e.getOriginalException()); + org.springframework.util.Assert.isInstanceOf(AuthnResponseValidationException.class, + e.getOriginalException()); + Assert.assertEquals("sp.pvp2.05", + ((EaafException) e.getOriginalException()).getErrorId()); + + } + + @Test + public void httpPostValidSignedWitUserStopErrorCode() throws IOException, SamlSigningException, + Pvp2MetadataException, CredentialsNotAvailableException, XMLParserException, UnmarshallingException, + MarshallingException, TransformerException, TaskExecutionException { + + metadataProvider.addMetadataResolverIntoChain(metadataFactory.createMetadataProvider( + METADATA_PATH, null, "jUnit IDP", null)); + + final Response response = initializeResponse( + "classpath:/data/idp_metadata_classpath_entity.xml", + "/data/Response_without_sig_with_error_userstop.xml", + credentialProvider.getMessageSigningCredential(), + true); + httpReq.addParameter("SAMLResponse", Base64.getEncoder().encodeToString( + DomUtils.serializeNode(XMLObjectSupport.getMarshaller(response).marshall(response)).getBytes( + "UTF-8"))); + + // perform test + task.execute(pendingReq, executionContext); + + // validate state + Assert.assertTrue("process not cancelled", executionContext.isProcessCancelled()); + Assert.assertTrue("process not stopped by user", pendingReq.isAbortedByUser()); + Assert.assertFalse("should not authenticated", pendingReq.isAuthenticated()); + + } + + @Test + public void httpPostValidSignedWithErrorAndNoSubCode() throws IOException, SamlSigningException, + Pvp2MetadataException, CredentialsNotAvailableException, XMLParserException, UnmarshallingException, + MarshallingException, TransformerException { + + metadataProvider.addMetadataResolverIntoChain(metadataFactory.createMetadataProvider( + METADATA_PATH, null, "jUnit IDP", null)); + + final Response response = initializeResponse( + "classpath:/data/idp_metadata_classpath_entity.xml", + "/data/Response_without_sig_with_error_without_subcode.xml", + credentialProvider.getMessageSigningCredential(), + true); + httpReq.addParameter("SAMLResponse", Base64.getEncoder().encodeToString( + DomUtils.serializeNode(XMLObjectSupport.getMarshaller(response).marshall(response)).getBytes( + "UTF-8"))); + + final TaskExecutionException e = assertThrows(TaskExecutionException.class, + () -> task.execute(pendingReq, executionContext)); + + Assert.assertNotNull(e.getPendingRequestID()); + Assert.assertEquals(pendingReq.getPendingRequestId(), e.getPendingRequestID()); + Assert.assertNotNull(e.getOriginalException()); + org.springframework.util.Assert.isInstanceOf(AuthnResponseValidationException.class, + e.getOriginalException()); + Assert.assertEquals("sp.pvp2.05", + ((EaafException) e.getOriginalException()).getErrorId()); + + } + + @Test + public void httpPostValidSignedWithErrorAndEmptySubCode() throws IOException, SamlSigningException, + Pvp2MetadataException, CredentialsNotAvailableException, XMLParserException, UnmarshallingException, + MarshallingException, TransformerException { + + metadataProvider.addMetadataResolverIntoChain(metadataFactory.createMetadataProvider( + METADATA_PATH, null, "jUnit IDP", null)); + + final Response response = initializeResponse( + "classpath:/data/idp_metadata_classpath_entity.xml", + "/data/Response_without_sig_with_error_empty_subcode.xml", + credentialProvider.getMessageSigningCredential(), + true); + httpReq.addParameter("SAMLResponse", Base64.getEncoder().encodeToString( + DomUtils.serializeNode(XMLObjectSupport.getMarshaller(response).marshall(response)).getBytes( + "UTF-8"))); + + final TaskExecutionException e = assertThrows(TaskExecutionException.class, + () -> task.execute(pendingReq, executionContext)); + + Assert.assertNotNull(e.getPendingRequestID()); + Assert.assertEquals(pendingReq.getPendingRequestId(), e.getPendingRequestID()); + Assert.assertNotNull(e.getOriginalException()); + org.springframework.util.Assert.isInstanceOf(AuthnResponseValidationException.class, + e.getOriginalException()); + Assert.assertEquals("sp.pvp2.05", + ((EaafException) e.getOriginalException()).getErrorId()); + + } + + @Test + public void httpPostValidSignedAssertionMissingAttributes() throws IOException, SamlSigningException, + Pvp2MetadataException, CredentialsNotAvailableException, XMLParserException, UnmarshallingException, + MarshallingException, TransformerException, TaskExecutionException { + + metadataProvider.addMetadataResolverIntoChain(metadataFactory.createMetadataProvider( + METADATA_PATH, null, "jUnit IDP", null)); + + final Response response = initializeResponse( + "classpath:/data/idp_metadata_classpath_entity.xml", + "/data/Response_with_EID_wrong_data.xml", + credentialProvider.getMessageSigningCredential(), + true); + httpReq.addParameter("SAMLResponse", Base64.getEncoder().encodeToString( + DomUtils.serializeNode(XMLObjectSupport.getMarshaller(response).marshall(response)).getBytes( + "UTF-8"))); + + // perform task + final TaskExecutionException e = assertThrows(TaskExecutionException.class, + () -> task.execute(pendingReq, executionContext)); + + Assert.assertNotNull(e.getPendingRequestID()); + Assert.assertEquals(pendingReq.getPendingRequestId(), e.getPendingRequestID()); + Assert.assertNotNull(e.getOriginalException()); + org.springframework.util.Assert.isInstanceOf(AuthnResponseValidationException.class, + e.getOriginalException()); + Assert.assertEquals("sp.pvp2.12", + ((EaafException) e.getOriginalException()).getErrorId()); + Assert.assertEquals("sp.pvp2.06", + ((EaafException) ((EaafException) e.getOriginalException()).getCause()).getErrorId()); + + } + + @Test + public void httpPostValidSignedAssertionWrongBpkTarget() throws IOException, XMLParserException, UnmarshallingException, + MarshallingException, TransformerException, TaskExecutionException, EaafException { + + oaParam.setBpkTargetIdentifier(EaafConstants.URN_PREFIX_EIDAS + "AT+ZZ"); + + metadataProvider.addMetadataResolverIntoChain(metadataFactory.createMetadataProvider( + METADATA_PATH, null, "jUnit IDP", null)); + + final Response response = initializeResponse( + "classpath:/data/idp_metadata_classpath_entity.xml", + "/data/Response_with_EID.xml", + credentialProvider.getMessageSigningCredential(), + true); + httpReq.addParameter("SAMLResponse", Base64.getEncoder().encodeToString( + DomUtils.serializeNode(XMLObjectSupport.getMarshaller(response).marshall(response)).getBytes( + "UTF-8"))); + + // perform task + final TaskExecutionException e = assertThrows(TaskExecutionException.class, + () -> task.execute(pendingReq, executionContext)); + + Assert.assertNotNull(e.getPendingRequestID()); + Assert.assertEquals(pendingReq.getPendingRequestId(), e.getPendingRequestID()); + Assert.assertNotNull(e.getOriginalException()); + org.springframework.util.Assert.isInstanceOf(AuthnResponseValidationException.class, + e.getOriginalException()); + Assert.assertEquals("sp.pvp2.12", + ((EaafException) e.getOriginalException()).getErrorId()); + Assert.assertEquals("sp.pvp2.06", + ((EaafException) ((EaafException) e.getOriginalException()).getCause()).getErrorId()); + Assert.assertEquals("module.idaustria.06", + ((EaafException) ((EaafException) ((EaafException) e.getOriginalException()) + .getCause()).getCause()).getErrorId()); + + } + + @Test + public void httpPostValidSignedAssertionEidValid() throws IOException, XMLParserException, UnmarshallingException, + MarshallingException, TransformerException, TaskExecutionException, EaafException { + + oaParam.setBpkTargetIdentifier(EaafConstants.URN_PREFIX_EIDAS + "AT+XX"); + + metadataProvider.addMetadataResolverIntoChain(metadataFactory.createMetadataProvider( + METADATA_PATH, null, "jUnit IDP", null)); + + final Response response = initializeResponse( + "classpath:/data/idp_metadata_classpath_entity.xml", + "/data/Response_with_EID.xml", + credentialProvider.getMessageSigningCredential(), + true); + httpReq.addParameter("SAMLResponse", Base64.getEncoder().encodeToString( + DomUtils.serializeNode(XMLObjectSupport.getMarshaller(response).marshall(response)).getBytes( + "UTF-8"))); + + // perform task + task.execute(pendingReq, executionContext); + + // validate state + IRequest storedReq = storage.getPendingRequest(pendingReq.getPendingRequestId()); + Assert.assertNotNull("pendingReq not stored", storedReq); + final AuthProcessDataWrapper session = pendingReq.getSessionData(AuthProcessDataWrapper.class); + Assert.assertFalse("foreigner flag", session.isForeigner()); + assertTrue("eidProcess flag", session.isEidProcess()); + assertFalse("useMandate flag", session.isMandateUsed()); + + checkAttributeInSession(session,PvpAttributeDefinitions.GIVEN_NAME_NAME, "Max"); + checkAttributeInSession(session,PvpAttributeDefinitions.PRINCIPAL_NAME_NAME, "Mustermann"); + checkAttributeInSession(session,PvpAttributeDefinitions.BIRTHDATE_NAME, "1940-01-01"); + checkAttributeInSession(session,PvpAttributeDefinitions.EID_CITIZEN_EIDAS_QAA_LEVEL_NAME, "http://eidas.europa.eu/LoA/high"); + checkAttributeInSession(session,PvpAttributeDefinitions.EID_ISSUING_NATION_NAME, "AT"); + + //pre-generated eIDAS identifer + checkAttributeInSession(session, MsEidasNodeConstants.ATTR_EIDAS_PERSONAL_IDENTIFIER, "QVGm48cqcM4UcyhDTNGYmVdrIoY="); + + } + + + + @Test + public void httpPostValidSignedAssertionMinimumAttributes() throws IOException, XMLParserException, UnmarshallingException, + MarshallingException, TransformerException, TaskExecutionException, EaafException { + + oaParam.setBpkTargetIdentifier(EaafConstants.URN_PREFIX_EIDAS + "AT+CC"); + + metadataProvider.addMetadataResolverIntoChain(metadataFactory.createMetadataProvider( + METADATA_PATH, null, "jUnit IDP", null)); + + final Response response = initializeResponse( + "classpath:/data/idp_metadata_classpath_entity.xml", + "/data/Response_with_EID_minimum.xml", + credentialProvider.getMessageSigningCredential(), + true); + httpReq.addParameter("SAMLResponse", Base64.getEncoder().encodeToString( + DomUtils.serializeNode(XMLObjectSupport.getMarshaller(response).marshall(response)).getBytes( + "UTF-8"))); + + // perform task + task.execute(pendingReq, executionContext); + + // validate state + IRequest storedReq = storage.getPendingRequest(pendingReq.getPendingRequestId()); + Assert.assertNotNull("pendingReq not stored", storedReq); + final AuthProcessDataWrapper session = pendingReq.getSessionData(AuthProcessDataWrapper.class); + Assert.assertFalse("foreigner flag", session.isForeigner()); + + checkAttributeInSession(session,PvpAttributeDefinitions.GIVEN_NAME_NAME, "Max"); + checkAttributeInSession(session,PvpAttributeDefinitions.PRINCIPAL_NAME_NAME, "Mustermann"); + checkAttributeInSession(session,PvpAttributeDefinitions.BIRTHDATE_NAME, "1940-01-01"); + checkAttributeInSession(session,PvpAttributeDefinitions.EID_ISSUING_NATION_NAME, "AT"); + + checkAttributeInSession(session,MsEidasNodeConstants.ATTR_EIDAS_PERSONAL_IDENTIFIER, "QVGm48cqcM4UcyhDTNGYmVdrIoY="); + + } + + @Test + public void httpPostValidSignedAssertionEidBpkWithoutPrefix() throws IOException, XMLParserException, UnmarshallingException, + MarshallingException, TransformerException, TaskExecutionException, EaafException { + + oaParam.setBpkTargetIdentifier(EaafConstants.URN_PREFIX_EIDAS + "AT+XX"); + + metadataProvider.addMetadataResolverIntoChain(metadataFactory.createMetadataProvider( + METADATA_PATH, null, "jUnit IDP", null)); + + final Response response = initializeResponse( + "classpath:/data/idp_metadata_classpath_entity.xml", + "/data/Response_with_EID_bpk_without_prefix.xml", + credentialProvider.getMessageSigningCredential(), + true); + httpReq.addParameter("SAMLResponse", Base64.getEncoder().encodeToString( + DomUtils.serializeNode(XMLObjectSupport.getMarshaller(response).marshall(response)).getBytes( + "UTF-8"))); + + // perform task + task.execute(pendingReq, executionContext); + + // validate state + IRequest storedReq = storage.getPendingRequest(pendingReq.getPendingRequestId()); + Assert.assertNotNull("pendingReq not stored", storedReq); + final AuthProcessDataWrapper session = pendingReq.getSessionData(AuthProcessDataWrapper.class); + Assert.assertFalse("foreigner flag", session.isForeigner()); + + checkAttributeInSession(session,PvpAttributeDefinitions.GIVEN_NAME_NAME, "Susi"); + checkAttributeInSession(session,PvpAttributeDefinitions.PRINCIPAL_NAME_NAME, "Heinz"); + checkAttributeInSession(session,PvpAttributeDefinitions.BIRTHDATE_NAME, "1955-01-01"); + checkAttributeInSession(session,PvpAttributeDefinitions.EID_CITIZEN_EIDAS_QAA_LEVEL_NAME, "http://eidas.europa.eu/LoA/aabbcc"); + checkAttributeInSession(session,PvpAttributeDefinitions.EID_ISSUING_NATION_NAME, "AT"); + + //pre-generated eIDAS identifer + checkAttributeInSession(session,MsEidasNodeConstants.ATTR_EIDAS_PERSONAL_IDENTIFIER, "QVGm48cqcasfasfsafsafdM4UcyhDTNGYmVdrIoY="); + + } + + @Test + public void httpPostValidSignedAssertionEidWithEidSectorAttr() throws IOException, XMLParserException, UnmarshallingException, + MarshallingException, TransformerException, TaskExecutionException, EaafException { + + oaParam.setBpkTargetIdentifier(EaafConstants.URN_PREFIX_EIDAS + "AT+AB"); + + metadataProvider.addMetadataResolverIntoChain(metadataFactory.createMetadataProvider( + METADATA_PATH, null, "jUnit IDP", null)); + + final Response response = initializeResponse( + "classpath:/data/idp_metadata_classpath_entity.xml", + "/data/Response_with_EID_with_eid_sector_attr.xml", + credentialProvider.getMessageSigningCredential(), + true); + httpReq.addParameter("SAMLResponse", Base64.getEncoder().encodeToString( + DomUtils.serializeNode(XMLObjectSupport.getMarshaller(response).marshall(response)).getBytes( + "UTF-8"))); + + // perform task + task.execute(pendingReq, executionContext); + + // validate state + IRequest storedReq = storage.getPendingRequest(pendingReq.getPendingRequestId()); + Assert.assertNotNull("pendingReq not stored", storedReq); + final AuthProcessDataWrapper session = pendingReq.getSessionData(AuthProcessDataWrapper.class); + Assert.assertFalse("foreigner flag", session.isForeigner()); + + checkAttributeInSession(session,PvpAttributeDefinitions.GIVEN_NAME_NAME, "Susi"); + checkAttributeInSession(session,PvpAttributeDefinitions.PRINCIPAL_NAME_NAME, "Heinz"); + checkAttributeInSession(session,PvpAttributeDefinitions.BIRTHDATE_NAME, "1955-01-01"); + checkAttributeInSession(session,PvpAttributeDefinitions.EID_CITIZEN_EIDAS_QAA_LEVEL_NAME, "http://eidas.europa.eu/LoA/aabbcc"); + checkAttributeInSession(session,PvpAttributeDefinitions.EID_ISSUING_NATION_NAME, "AT"); + + //pre-generated eIDAS identifer + checkAttributeInSession(session,MsEidasNodeConstants.ATTR_EIDAS_PERSONAL_IDENTIFIER, "QVGm48cqcasfasfsafsafdM4UcyhDTNGYmVdrIoY="); + + } + + @Test + public void httpPostValidSignedAssertionEidValidWithJurMandate() throws IOException, XMLParserException, UnmarshallingException, + MarshallingException, TransformerException, TaskExecutionException, EaafException { + + oaParam.setBpkTargetIdentifier(EaafConstants.URN_PREFIX_EIDAS + "AT+XX"); + + metadataProvider.addMetadataResolverIntoChain(metadataFactory.createMetadataProvider( + METADATA_PATH, null, "jUnit IDP", null)); + + final Response response = initializeResponse( + "classpath:/data/idp_metadata_classpath_entity.xml", + "/data/Response_with_EID_with_mandate_jur.xml", + credentialProvider.getMessageSigningCredential(), + true); + httpReq.addParameter("SAMLResponse", Base64.getEncoder().encodeToString( + DomUtils.serializeNode(XMLObjectSupport.getMarshaller(response).marshall(response)).getBytes( + "UTF-8"))); + + // perform task + task.execute(pendingReq, executionContext); + + // validate state + IRequest storedReq = storage.getPendingRequest(pendingReq.getPendingRequestId()); + Assert.assertNotNull("pendingReq not stored", storedReq); + final AuthProcessDataWrapper session = pendingReq.getSessionData(AuthProcessDataWrapper.class); + Assert.assertFalse("foreigner flag", session.isForeigner()); + assertTrue("eidProcess flag", session.isEidProcess()); + assertTrue("useMandate flag", session.isMandateUsed()); + + checkAttributeInSession(session, PvpAttributeDefinitions.GIVEN_NAME_NAME, "Max"); + checkAttributeInSession(session, PvpAttributeDefinitions.PRINCIPAL_NAME_NAME, "Mustermann"); + checkAttributeInSession(session, PvpAttributeDefinitions.BIRTHDATE_NAME, "1940-01-01"); + checkAttributeInSession(session, PvpAttributeDefinitions.EID_CITIZEN_EIDAS_QAA_LEVEL_NAME, "http://eidas.europa.eu/LoA/high"); + checkAttributeInSession(session, PvpAttributeDefinitions.EID_ISSUING_NATION_NAME, "AT"); + + checkAttributeInSession(session, PvpAttributeDefinitions.MANDATE_TYPE_NAME, "Generalvollmacht"); + checkAttributeInSession(session, PvpAttributeDefinitions.MANDATE_LEG_PER_FULL_NAME_NAME, "Testfirma"); + checkAttributeInSession(session, PvpAttributeDefinitions.MANDATE_LEG_PER_SOURCE_PIN_NAME, "999999m"); + checkAttributeInSession(session, PvpAttributeDefinitions.MANDATE_LEG_PER_SOURCE_PIN_TYPE_NAME, "urn:publicid:gv.at:baseid+XERSB"); + + //pre-generated eIDAS identifer + checkAttributeInSession(session, MsEidasNodeConstants.ATTR_EIDAS_PERSONAL_IDENTIFIER, "QVGm48cqcM4UcyhDTNGYmVdrIoY="); + assertNull("find nat. person bpk for mandator", session.getGenericDataFromSession( + PvpAttributeDefinitions.MANDATE_NAT_PER_BPK_NAME, String.class)); + + + } + + @Test + public void httpPostValidSignedAssertionEidValidWithNatMandate() throws IOException, XMLParserException, UnmarshallingException, + MarshallingException, TransformerException, TaskExecutionException, EaafException { + + oaParam.setBpkTargetIdentifier(EaafConstants.URN_PREFIX_EIDAS + "AT+XX"); + + metadataProvider.addMetadataResolverIntoChain(metadataFactory.createMetadataProvider( + METADATA_PATH, null, "jUnit IDP", null)); + + final Response response = initializeResponse( + "classpath:/data/idp_metadata_classpath_entity.xml", + "/data/Response_with_EID_with_mandate_nat.xml", + credentialProvider.getMessageSigningCredential(), + true); + httpReq.addParameter("SAMLResponse", Base64.getEncoder().encodeToString( + DomUtils.serializeNode(XMLObjectSupport.getMarshaller(response).marshall(response)).getBytes( + "UTF-8"))); + + // perform task + task.execute(pendingReq, executionContext); + + // validate state + IRequest storedReq = storage.getPendingRequest(pendingReq.getPendingRequestId()); + Assert.assertNotNull("pendingReq not stored", storedReq); + final AuthProcessDataWrapper session = pendingReq.getSessionData(AuthProcessDataWrapper.class); + Assert.assertFalse("foreigner flag", session.isForeigner()); + assertTrue("eidProcess flag", session.isEidProcess()); + assertTrue("useMandate flag", session.isMandateUsed()); + + checkAttributeInSession(session, PvpAttributeDefinitions.GIVEN_NAME_NAME, "Max"); + checkAttributeInSession(session, PvpAttributeDefinitions.PRINCIPAL_NAME_NAME, "Mustermann"); + checkAttributeInSession(session, PvpAttributeDefinitions.BIRTHDATE_NAME, "1940-01-01"); + checkAttributeInSession(session, PvpAttributeDefinitions.EID_CITIZEN_EIDAS_QAA_LEVEL_NAME, "http://eidas.europa.eu/LoA/high"); + checkAttributeInSession(session, PvpAttributeDefinitions.EID_ISSUING_NATION_NAME, "AT"); + + checkAttributeInSession(session, PvpAttributeDefinitions.MANDATE_TYPE_NAME, "GeneralvollmachtBilateral"); + checkAttributeInSession(session, PvpAttributeDefinitions.MANDATE_NAT_PER_GIVEN_NAME_NAME, "Gerti"); + checkAttributeInSession(session, PvpAttributeDefinitions.MANDATE_NAT_PER_FAMILY_NAME_NAME, "Musterfrau"); + checkAttributeInSession(session, PvpAttributeDefinitions.MANDATE_NAT_PER_BIRTHDATE_NAME, "01-02-1941"); + checkAttributeInSession(session, PvpAttributeDefinitions.MANDATE_NAT_PER_BPK_NAME, "AT+XX:AFSDAFSDFDSFCSDAFASDF="); + + + //pre-generated eIDAS identifer + checkAttributeInSession(session, MsEidasNodeConstants.ATTR_EIDAS_PERSONAL_IDENTIFIER, + "QVGm48cqcM4UcyhDTNGYmVdrIoY="); + + + } + + private void checkAttributeInSession(AuthProcessDataWrapper session, String attrName, String expected) { + String value = session.getGenericDataFromSession(attrName, String.class); + Assert.assertEquals("wrong attr. value", expected, value); + + } + + private Response initializeResponse(String idpEntityId, String responsePath, EaafX509Credential credential, + boolean validConditions) throws SamlSigningException, XMLParserException, UnmarshallingException, + Pvp2MetadataException { + + final Response response = (Response) XMLObjectSupport.unmarshallFromInputStream( + XMLObjectProviderRegistrySupport.getParserPool(), + ReceiveAuthnResponseTaskTest.class.getResourceAsStream(responsePath)); + response.setIssueInstant(Instant.now()); + final Issuer issuer = Saml2Utils.createSamlObject(Issuer.class); + issuer.setValue(idpEntityId); + response.setIssuer(issuer); + + if (validConditions) { + response.getAssertions().get(0).getConditions().setNotOnOrAfter(Instant.now().plusSeconds(5*60)); + + } + + return Saml2Utils.signSamlObject(response, credential, true); + } +} diff --git a/modules/authmodule_id-austria/src/test/java/at/asitplus/eidas/specific/modules/auth/idaustria/test/task/RequestIdAustriaSystemTaskTest.java b/modules/authmodule_id-austria/src/test/java/at/asitplus/eidas/specific/modules/auth/idaustria/test/task/RequestIdAustriaSystemTaskTest.java new file mode 100644 index 00000000..54b019eb --- /dev/null +++ b/modules/authmodule_id-austria/src/test/java/at/asitplus/eidas/specific/modules/auth/idaustria/test/task/RequestIdAustriaSystemTaskTest.java @@ -0,0 +1,455 @@ +package at.asitplus.eidas.specific.modules.auth.idaustria.test.task; + +import static org.junit.Assert.assertThrows; +import static org.junit.Assert.assertTrue; + +import java.io.ByteArrayInputStream; +import java.io.InputStream; +import java.util.Arrays; +import java.util.Base64; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.UUID; + +import org.apache.commons.lang3.RandomStringUtils; +import org.junit.Assert; +import org.junit.Before; +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.schema.XSString; +import org.opensaml.core.xml.util.XMLObjectSupport; +import org.opensaml.saml.common.xml.SAMLConstants; +import org.opensaml.saml.saml2.core.AuthnRequest; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.ApplicationContext; +import org.springframework.mock.web.MockHttpServletRequest; +import org.springframework.mock.web.MockHttpServletResponse; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; +import org.springframework.web.context.request.RequestContextHolder; +import org.springframework.web.context.request.ServletRequestAttributes; + +import at.asitplus.eidas.specific.core.config.ServiceProviderConfiguration; +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.tasks.RequestIdAustriaSystemTask; +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.data.EaafConfigConstants; +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.gui.IVelocityGuiBuilderConfiguration; +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.TaskExecutionException; +import at.gv.egiz.eaaf.core.impl.idp.module.gui.DummyGuiBuilderConfigurationFactory; +import at.gv.egiz.eaaf.core.impl.idp.process.ExecutionContextImpl; +import at.gv.egiz.eaaf.core.impl.utils.KeyValueUtils; +import at.gv.egiz.eaaf.modules.pvp2.api.reqattr.EaafRequestedAttributes; +import at.gv.egiz.eaaf.modules.pvp2.exception.CredentialsNotAvailableException; +import at.gv.egiz.eaaf.modules.pvp2.exception.Pvp2InternalErrorException; +import at.gv.egiz.eaaf.modules.pvp2.exception.Pvp2MetadataException; +import at.gv.egiz.eaaf.modules.pvp2.impl.message.PvpSProfileRequest; +import at.gv.egiz.eaaf.modules.pvp2.impl.metadata.PvpMetadataResolverFactory; +import at.gv.egiz.eaaf.modules.pvp2.impl.opensaml.initialize.EaafOpenSaml3xInitializer; +import at.gv.egiz.eaaf.modules.pvp2.impl.utils.Saml2Utils; +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.test.binding.PostBindingTest; +import eu.eidas.auth.commons.light.impl.LightRequest; + +@RunWith(SpringJUnit4ClassRunner.class) +@ContextConfiguration(locations = { + "/spring/SpringTest-context_basic_mapConfig.xml", + "/spring/SpringTest-context_basic_test.xml", +}) +public class RequestIdAustriaSystemTaskTest { + + private static final String METADATA_PATH = "classpath:/data/idp_metadata_classpath_entity.xml"; + private static final String METADATA_SP_PATH = "classpath:/data/sp_metadata_junit.xml"; + + @Autowired ApplicationContext context; + @Autowired MsConnectorDummyConfigMap config; + @Autowired IdAustriaAuthMetadataProvider metadataProvider; + @Autowired PvpMetadataResolverFactory metadataFactory; + @Autowired DummyGuiBuilderConfigurationFactory guiBuilderConfigFactory; + @Autowired SamlVerificationEngine samlVerifyEngine; + @Autowired ITransactionStorage transactionStorage; + + final ExecutionContext executionContext = new ExecutionContextImpl(); + private MockHttpServletRequest httpReq; + private MockHttpServletResponse httpResp; + private ProxyServicePendingRequest pendingReq; + private ServiceProviderConfiguration oaParam; + private Map spConfig; + + private RequestIdAustriaSystemTask task; + + /** + * JUnit class initializer. + * + * @throws Exception In case of an OpenSAML3 initialization error + */ + @BeforeClass + public static void initialize() throws Exception { + EaafOpenSaml3xInitializer.eaafInitialize(); + + } + + /** + * jUnit test set-up. + * + * @throws Exception In case of an set-up error + */ + @Before + public void setUp() throws Exception { + task = (RequestIdAustriaSystemTask) context.getBean("createIdAustriaAuthnRequestTask"); + + httpReq = new MockHttpServletRequest("POST", "https://localhost/authhandler"); + httpResp = new MockHttpServletResponse(); + RequestContextHolder.resetRequestAttributes(); + RequestContextHolder.setRequestAttributes(new ServletRequestAttributes(httpReq, httpResp)); + + config.putConfigValue(IdAustriaAuthConstants.CONFIG_PROPS_SIGN_SIGNING_ALIAS, "sig"); + config.putConfigValue(IdAustriaAuthConstants.CONFIG_PROPS_IDAUSTRIA_ENTITYID, METADATA_PATH); + + spConfig = new HashMap<>(); + spConfig.put(EaafConfigConstants.SERVICE_UNIQUEIDENTIFIER, "http://test.com/test"); + oaParam = new ServiceProviderConfiguration(spConfig, config); + oaParam.setRequiredLoA(Arrays.asList(EaafConstants.EIDAS_LOA_HIGH)); + + String spCountryCode = RandomStringUtils.randomAlphabetic(2).toUpperCase(); + oaParam.setBpkTargetIdentifier(EaafConstants.URN_PREFIX_EIDAS + "AT+" + + spCountryCode); + + pendingReq = new ProxyServicePendingRequest(); + pendingReq.initialize(httpReq, config); + pendingReq.setPendingRequestId(RandomStringUtils.randomAlphanumeric(10)); + pendingReq.setOnlineApplicationConfiguration(oaParam); + + metadataProvider.fullyDestroy(); + guiBuilderConfigFactory.setVelocityBuilderConfig(createDummyGuiConfig()); + + } + + @Test + public void missingIdAustriaSystemEntiryId() { + config.removeConfigValue(IdAustriaAuthConstants.CONFIG_PROPS_IDAUSTRIA_ENTITYID); + + + TaskExecutionException e = assertThrows(TaskExecutionException.class, + () -> task.execute(pendingReq, executionContext)); + + Assert.assertNotNull(e.getPendingRequestID()); + Assert.assertEquals(pendingReq.getPendingRequestId(), e.getPendingRequestID()); + Assert.assertNotNull(e.getOriginalException()); + org.springframework.util.Assert.isInstanceOf(EaafConfigurationException.class, + e.getOriginalException()); + Assert.assertEquals("module.idaustria.00", + ((EaafConfigurationException) e.getOriginalException()).getErrorId()); + + + } + + @Test + public void noMetadataAvailableOnGlobalConfig() { + config.putConfigValue(IdAustriaAuthConstants.CONFIG_PROPS_IDAUSTRIA_ENTITYID, + RandomStringUtils.randomAlphabetic(10)); + + + TaskExecutionException e = assertThrows(TaskExecutionException.class, + () -> task.execute(pendingReq, executionContext)); + + Assert.assertNotNull(e.getPendingRequestID()); + Assert.assertEquals(pendingReq.getPendingRequestId(), e.getPendingRequestID()); + Assert.assertNotNull(e.getOriginalException()); + org.springframework.util.Assert.isInstanceOf(EaafConfigurationException.class, + e.getOriginalException()); + Assert.assertEquals("module.idaustria.05", + ((EaafConfigurationException) e.getOriginalException()).getErrorId()); + + + } + + @Test + public void noMetadataSigningKeyStore() throws Pvp2MetadataException { + config.removeConfigValue("eidas.ms.modules.idaustriaauth.request.sign.alias"); + + metadataProvider.addMetadataResolverIntoChain( + metadataFactory.createMetadataProvider(METADATA_PATH, null, "jUnitTest", null)); + + TaskExecutionException e = assertThrows(TaskExecutionException.class, + () -> task.execute(pendingReq, executionContext)); + + Assert.assertNotNull(e.getPendingRequestID()); + Assert.assertEquals(pendingReq.getPendingRequestId(), e.getPendingRequestID()); + Assert.assertNotNull(e.getOriginalException()); + org.springframework.util.Assert.isInstanceOf(CredentialsNotAvailableException.class, + e.getOriginalException()); + Assert.assertEquals("internal.pvp.01", + ((CredentialsNotAvailableException) e.getOriginalException()).getErrorId()); + + } + + @Test + public void successWithoutSpInfos() throws Pvp2InternalErrorException, SecurityException, Exception { + metadataProvider.addMetadataResolverIntoChain( + metadataFactory.createMetadataProvider(METADATA_PATH, null, "jUnitTest", null)); + + 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"); + pendingReq.setEidasRequest(eidasRequestBuilder.build()); + + //execute test + task.execute(pendingReq, executionContext); + + //validate state + final EaafRequestedAttributes reqAttr = validate(); + Assert.assertEquals("#Req Attribute", 4, reqAttr.getAttributes().size()); + + Assert.assertEquals("Wrong req attr.", "urn:eidgvat:attributes.eidas.uniqueId", + reqAttr.getAttributes().get(0).getName()); + Assert.assertNotNull("Req. Attr value element", reqAttr.getAttributes().get(0).getAttributeValues()); + Assert.assertEquals("#Req. Attr value", 1, + reqAttr.getAttributes().get(0).getAttributeValues().size()); + org.springframework.util.Assert.isInstanceOf(XSString.class, + reqAttr.getAttributes().get(0).getAttributeValues().get(0), "Wrong requested Attributes Value type"); + Assert.assertEquals("Req. Attr. Value", pendingReq.getServiceProviderConfiguration().getUniqueIdentifier(), + ((XSString)reqAttr.getAttributes().get(0).getAttributeValues().get(0)).getValue()); + + Assert.assertEquals("Wrong req attr.", "urn:oid:1.2.40.0.10.2.1.1.261.34", + reqAttr.getAttributes().get(1).getName()); + Assert.assertNotNull("Req. Attr value element", reqAttr.getAttributes().get(1).getAttributeValues()); + Assert.assertEquals("#Req. Attr value", 1, + reqAttr.getAttributes().get(1).getAttributeValues().size()); + org.springframework.util.Assert.isInstanceOf(XSString.class, + reqAttr.getAttributes().get(1).getAttributeValues().get(0), "Wrong requested Attributes Value type"); + Assert.assertEquals("Req. Attr. Value", oaParam.getAreaSpecificTargetIdentifier(), + ((XSString)reqAttr.getAttributes().get(1).getAttributeValues().get(0)).getValue()); + + Assert.assertEquals("Wrong req attr.", "urn:oid:1.2.40.0.10.2.1.1.261.108", + reqAttr.getAttributes().get(2).getName()); + Assert.assertNotNull("Req. Attr value element", reqAttr.getAttributes().get(1).getAttributeValues()); + Assert.assertEquals("#Req. Attr value", 1, + reqAttr.getAttributes().get(2).getAttributeValues().size()); + org.springframework.util.Assert.isInstanceOf(XSString.class, + reqAttr.getAttributes().get(2).getAttributeValues().get(0), "Wrong requested Attributes Value type"); + Assert.assertEquals("Req. Attr. Value", "http://eidas.europa.eu/LoA/high", + ((XSString)reqAttr.getAttributes().get(2).getAttributeValues().get(0)).getValue()); + + Assert.assertEquals("Wrong req attr.", "urn:eidgvat:attributes.ServiceProviderMandateType", + reqAttr.getAttributes().get(3).getName()); + Assert.assertNotNull("Req. Attr value element", reqAttr.getAttributes().get(3).getAttributeValues()); + Assert.assertEquals("#Req. Attr value", 1, + reqAttr.getAttributes().get(3).getAttributeValues().size()); + org.springframework.util.Assert.isInstanceOf(XSString.class, + reqAttr.getAttributes().get(3).getAttributeValues().get(0), "Wrong requested Attributes Value type"); + Assert.assertEquals("Req. Attr. Value", + pendingReq.getServiceProviderConfiguration(ServiceProviderConfiguration.class).getMandateMode().getMode(), + ((XSString)reqAttr.getAttributes().get(3).getAttributeValues().get(0)).getValue()); + + } + + @Test + public void successWithSpInfos() throws Pvp2InternalErrorException, SecurityException, Exception { + metadataProvider.addMetadataResolverIntoChain( + metadataFactory.createMetadataProvider(METADATA_PATH, null, "jUnitTest", null)); + + 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)); + LightRequest eidasReq = eidasRequestBuilder.build(); + pendingReq.setEidasRequest(eidasReq); + + //execute test + task.execute(pendingReq, executionContext); + + //validate state + final EaafRequestedAttributes reqAttr = validate(); + Assert.assertEquals("#Req Attribute", 6, reqAttr.getAttributes().size()); + + Assert.assertEquals("Wrong req attr.", "urn:eidgvat:attributes.ServiceProviderFriendlyName", + reqAttr.getAttributes().get(3).getName()); + Assert.assertNotNull("Req. Attr value element", reqAttr.getAttributes().get(1).getAttributeValues()); + Assert.assertEquals("#Req. Attr value", 1, + reqAttr.getAttributes().get(3).getAttributeValues().size()); + org.springframework.util.Assert.isInstanceOf(XSString.class, + reqAttr.getAttributes().get(3).getAttributeValues().get(0), "Wrong requested Attributes Value type"); + Assert.assertEquals("Req. Attr. Value", eidasReq.getProviderName(), + ((XSString)reqAttr.getAttributes().get(3).getAttributeValues().get(0)).getValue()); + + Assert.assertEquals("Wrong req attr.", "urn:eidgvat:attributes.ServiceProviderUniqueId", + reqAttr.getAttributes().get(4).getName()); + Assert.assertNotNull("Req. Attr value element", reqAttr.getAttributes().get(1).getAttributeValues()); + Assert.assertEquals("#Req. Attr value", 1, + reqAttr.getAttributes().get(4).getAttributeValues().size()); + org.springframework.util.Assert.isInstanceOf(XSString.class, + reqAttr.getAttributes().get(4).getAttributeValues().get(0), "Wrong requested Attributes Value type"); + Assert.assertEquals("Req. Attr. Value", eidasReq.getRequesterId(), + ((XSString)reqAttr.getAttributes().get(4).getAttributeValues().get(0)).getValue()); + + } + + @Test + public void successWithMandates() throws Pvp2InternalErrorException, SecurityException, Exception { + metadataProvider.addMetadataResolverIntoChain( + metadataFactory.createMetadataProvider(METADATA_PATH, null, "jUnitTest", null)); + + 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)); + LightRequest eidasReq = eidasRequestBuilder.build(); + pendingReq.setEidasRequest(eidasReq); + + List mandateProfiles = Arrays.asList( + RandomStringUtils.randomAlphabetic(5), RandomStringUtils.randomAlphabetic(5)); + oaParam.setMandateProfiles(mandateProfiles); + oaParam.setMandateMode(SpMandateModes.LEGAL_FORCE); + //execute test + task.execute(pendingReq, executionContext); + + //validate state + final EaafRequestedAttributes reqAttr = validate(); + Assert.assertEquals("#Req Attribute", 7, reqAttr.getAttributes().size()); + + Assert.assertEquals("Wrong req attr.", "urn:eidgvat:attributes.ServiceProviderMandateProfiles", + reqAttr.getAttributes().get(5).getName()); + Assert.assertNotNull("Req. Attr value element", reqAttr.getAttributes().get(1).getAttributeValues()); + Assert.assertEquals("#Req. Attr value", 1, + reqAttr.getAttributes().get(5).getAttributeValues().size()); + org.springframework.util.Assert.isInstanceOf(XSString.class, + reqAttr.getAttributes().get(5).getAttributeValues().get(0), "Wrong requested Attributes Value type"); + + List reqProfiles = KeyValueUtils.getListOfCsvValues( + ((XSString)reqAttr.getAttributes().get(5).getAttributeValues().get(0)).getValue()); + reqProfiles.stream().forEach(el -> assertTrue("missing profile: " + el, mandateProfiles.contains(el))); + + + Assert.assertEquals("Wrong req attr.", "urn:eidgvat:attributes.ServiceProviderMandateType", + reqAttr.getAttributes().get(6).getName()); + Assert.assertNotNull("Req. Attr value element", reqAttr.getAttributes().get(6).getAttributeValues()); + Assert.assertEquals("#Req. Attr value", 1, + reqAttr.getAttributes().get(6).getAttributeValues().size()); + org.springframework.util.Assert.isInstanceOf(XSString.class, + reqAttr.getAttributes().get(6).getAttributeValues().get(0), "Wrong requested Attributes Value type"); + Assert.assertEquals("Req. Attr. Value", + SpMandateModes.LEGAL_FORCE.getMode(), + ((XSString)reqAttr.getAttributes().get(6).getAttributeValues().get(0)).getValue()); + + } + + private EaafRequestedAttributes validate() throws Pvp2InternalErrorException, SecurityException, Exception { + Assert.assertEquals("HTTP Statuscode", 200, httpResp.getStatus()); + Assert.assertEquals("ContentType", "text/html;charset=UTF-8", httpResp.getContentType()); + Assert.assertEquals("ContentEncoding", "UTF-8", httpResp.getCharacterEncoding()); + + final String html = httpResp.getContentAsString(); + Assert.assertNotNull("XML Metadata", html); + + final int startIndex = html.indexOf("SAMLRequest="); + Assert.assertTrue("No SAMLRequest in html", startIndex >= 0); + final String authnXml = html.substring(startIndex + "SAMLRequest=".length()); + + //check if relaystate was stored + final int startIndexRelayState = html.indexOf("RelayState="); + Assert.assertTrue("wrong RelayState in HTML", + startIndexRelayState >= 0); + String relayState = html.substring(startIndexRelayState + "RelayState=".length(), startIndex); + String storedPendingReqId = transactionStorage.get(relayState, String.class); + Assert.assertEquals("relayStore not map to pendingRequestId", + pendingReq.getPendingRequestId(), storedPendingReqId); + + + final AuthnRequest authnRequest = (AuthnRequest) XMLObjectSupport.unmarshallFromInputStream( + XMLObjectProviderRegistrySupport.getParserPool(), new ByteArrayInputStream( + Base64.getDecoder().decode(authnXml))); + + Assert.assertNotNull("AuthnReq", authnRequest); + Assert.assertNotNull("Issuer", authnRequest.getIssuer()); + Assert.assertEquals("EntityId", + "http://localhost" + IdAustriaAuthConstants.ENDPOINT_METADATA, + authnRequest.getIssuer().getValue()); + + //check XML scheme + Saml2Utils.schemeValidation(authnRequest); + + //check signature + final PvpSProfileRequest msg = new PvpSProfileRequest( + authnRequest, + SAMLConstants.SAML2_POST_BINDING_URI); + msg.setEntityID(authnRequest.getIssuer().getValue()); + metadataProvider.addMetadataResolverIntoChain( + metadataFactory.createMetadataProvider(METADATA_SP_PATH, null, "jUnit SP", null)); + samlVerifyEngine.verify(msg, TrustEngineFactory.getSignatureKnownKeysTrustEngine(metadataProvider)); + + //check other elements + Assert.assertNotNull("Extensions", authnRequest.getExtensions()); + Assert.assertFalse("No Requested attributes", + authnRequest.getExtensions().getUnknownXMLObjects().isEmpty()); + + Assert.assertEquals("#ReqAttributes", 1, authnRequest.getExtensions().getUnknownXMLObjects().size()); + org.springframework.util.Assert.isInstanceOf(EaafRequestedAttributes.class, + authnRequest.getExtensions().getUnknownXMLObjects().get(0), "No Requested Attributes object"); + + return (EaafRequestedAttributes) authnRequest.getExtensions().getUnknownXMLObjects().get(0); + + } + + private IVelocityGuiBuilderConfiguration createDummyGuiConfig() { + return new IVelocityGuiBuilderConfiguration() { + + @Override + public Map getViewParameters() { + return null; + } + + @Override + public String getViewName() { + return "SAML2 Post-Binding"; + } + + @Override + public String getDefaultContentType() { + return null; + } + + @Override + public InputStream getTemplate(String viewName) { + return PostBindingTest.class.getResourceAsStream("/data/pvp_postbinding_template.html"); + } + + @Override + public String getClasspathTemplateDir() { + return null; + + } + + @Override + public boolean isWriteAsynch() { + return false; + + } + }; + } +} diff --git a/modules/authmodule_id-austria/src/test/java/at/asitplus/eidas/specific/modules/auth/idaustria/test/utils/IdAustriaAuthCredentialProviderTest.java b/modules/authmodule_id-austria/src/test/java/at/asitplus/eidas/specific/modules/auth/idaustria/test/utils/IdAustriaAuthCredentialProviderTest.java new file mode 100644 index 00000000..a0d6c988 --- /dev/null +++ b/modules/authmodule_id-austria/src/test/java/at/asitplus/eidas/specific/modules/auth/idaustria/test/utils/IdAustriaAuthCredentialProviderTest.java @@ -0,0 +1,413 @@ +package at.asitplus.eidas.specific.modules.auth.idaustria.test.utils; + +import org.apache.commons.lang3.RandomStringUtils; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.beans.BeansException; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.ApplicationContext; +import org.springframework.test.annotation.DirtiesContext; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; + +import com.google.common.base.Optional; +import com.google.common.base.Predicates; +import com.google.common.base.Throwables; +import com.google.common.collect.FluentIterable; + +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.IdAustriaAuthCredentialProvider; +import at.gv.egiz.eaaf.core.exceptions.EaafConfigurationException; +import at.gv.egiz.eaaf.core.exceptions.EaafException; +import at.gv.egiz.eaaf.core.exceptions.EaafFactoryException; +import at.gv.egiz.eaaf.modules.pvp2.api.credential.EaafX509Credential; +import at.gv.egiz.eaaf.modules.pvp2.exception.CredentialsNotAvailableException; + +@RunWith(SpringJUnit4ClassRunner.class) +@ContextConfiguration(locations = { + "/spring/SpringTest-context_basic_mapConfig.xml", + "/spring/SpringTest-context_lazy.xml" + }) +@DirtiesContext +public class IdAustriaAuthCredentialProviderTest { + + private static final String PATH_JKS = "pvp.jks"; + private static final String ALIAS_METADATA = "metadata"; + private static final String ALIAS_SIGN = "signing"; + private static final String ALIAS_ENC = "encryption"; + private static final String PASSWORD = "password"; + + @Autowired + private ApplicationContext context; + @Autowired + private MsConnectorDummyConfigMap config; + + /** + * jUnit test initializer. + */ + @Before + public void initialize() { + config.putConfigValue(IdAustriaAuthConstants.CONFIG_PROPS_KEYSTORE_PATH, PATH_JKS); + config.putConfigValue(IdAustriaAuthConstants.CONFIG_PROPS_KEYSTOREPASSWORD, PASSWORD); + + config.removeConfigValue(IdAustriaAuthConstants.CONFIG_PROPS_SIGN_METADATA_ALIAS); + config.removeConfigValue(IdAustriaAuthConstants.CONFIG_PROPS_SIGN_METADATA_KEY_PASSWORD); + + config.removeConfigValue(IdAustriaAuthConstants.CONFIG_PROPS_SIGN_SIGNING_ALIAS); + config.removeConfigValue(IdAustriaAuthConstants.CONFIG_PROPS_SIGN_SIGNING_KEY_PASSWORD); + + config.removeConfigValue(IdAustriaAuthConstants.CONFIG_PROPS_ENCRYPTION_ALIAS); + config.removeConfigValue(IdAustriaAuthConstants.CONFIG_PROPS_ENCRYPTION_KEY_PASSWORD); + + } + + @Test + @DirtiesContext + public void noKeyStoreUrl() { + config.removeConfigValue(IdAustriaAuthConstants.CONFIG_PROPS_KEYSTORE_PATH); + try { + context.getBean(IdAustriaAuthCredentialProvider.class); + Assert.fail("No KeyStore not detected"); + + } catch (final BeansException e) { + org.springframework.util.Assert.isInstanceOf(EaafConfigurationException.class, + e.getCause(), "Wrong exception"); + } + + } + + @Test + @DirtiesContext + public void noKeyStore() { + config.putConfigValue(IdAustriaAuthConstants.CONFIG_PROPS_KEYSTORE_PATH, + "src/test/resources/config/notExist.p12"); + try { + context.getBean(IdAustriaAuthCredentialProvider.class); + Assert.fail("No KeyStore not detected"); + + } catch (final BeansException e) { + final Optional eaafException = FluentIterable.from( + Throwables.getCausalChain(e)).filter( + Predicates.instanceOf(EaafConfigurationException.class)).first(); + Assert.assertTrue("Wrong exception", eaafException.isPresent()); + Assert.assertEquals("Wrong errorId", "internal.keystore.06", + ((EaafException) eaafException.get()).getErrorId()); + + } + + } + + @Test + @DirtiesContext + public void noWrongKeyStorePassword() { + config.putConfigValue(IdAustriaAuthConstants.CONFIG_PROPS_KEYSTOREPASSWORD, "test"); + try { + context.getBean(IdAustriaAuthCredentialProvider.class); + Assert.fail("No KeyStore not detected"); + + } catch (final BeansException e) { + final Optional eaafException = FluentIterable.from( + Throwables.getCausalChain(e)).filter( + Predicates.instanceOf(EaafFactoryException.class)).first(); + Assert.assertTrue("Wrong exception", eaafException.isPresent()); + Assert.assertEquals("Wrong errorId", "internal.keystore.06", + ((EaafException) eaafException.get()).getErrorId()); + + } + + } + + @Test + @DirtiesContext + public void notKeyConfigurationWrongAlias() { + final IdAustriaAuthCredentialProvider credential = context.getBean( + IdAustriaAuthCredentialProvider.class); + + Assert.assertNotNull("Credetialprovider", credential); + Assert.assertNotNull("Friendlyname", credential.getFriendlyName()); + + try { + config.putConfigValue(IdAustriaAuthConstants.CONFIG_PROPS_SIGN_METADATA_ALIAS, + RandomStringUtils.randomAlphabetic(5)); + credential.getMetaDataSigningCredential(); + Assert.fail("No Metadata signing credentials not detected"); + + } catch (final CredentialsNotAvailableException e) { + Assert.assertTrue("Wrong errorCode", e.getMessage().contains("internal.pvp.01")); + + } + + try { + config.putConfigValue(IdAustriaAuthConstants.CONFIG_PROPS_SIGN_SIGNING_ALIAS, + RandomStringUtils.randomAlphabetic(5)); + credential.getMessageSigningCredential(); + Assert.fail("No Metadata signing credentials not detected"); + + } catch (final CredentialsNotAvailableException e) { + Assert.assertTrue("Wrong errorCode", e.getMessage().contains("internal.pvp.01")); + + } + + try { + config.putConfigValue(IdAustriaAuthConstants.CONFIG_PROPS_ENCRYPTION_ALIAS, + RandomStringUtils.randomAlphabetic(5)); + credential.getMessageEncryptionCredential(); + Assert.fail("No Metadata signing credentials not detected"); + + } catch (final CredentialsNotAvailableException e) { + Assert.assertTrue("Wrong errorCode", e.getMessage().contains("internal.pvp.01")); + + } + + } + + @Test + @DirtiesContext + public void notKeyConfigurationWrongPassword() { + final IdAustriaAuthCredentialProvider credential = context.getBean( + IdAustriaAuthCredentialProvider.class); + + Assert.assertNotNull("Credetialprovider", credential); + Assert.assertNotNull("Friendlyname", credential.getFriendlyName()); + + try { + config.putConfigValue(IdAustriaAuthConstants.CONFIG_PROPS_SIGN_METADATA_KEY_PASSWORD, + RandomStringUtils.randomAlphabetic(5)); + credential.getMetaDataSigningCredential(); + Assert.fail("No Metadata signing credentials not detected"); + + } catch (final CredentialsNotAvailableException e) { + Assert.assertTrue("Wrong errorCode", e.getMessage().contains("internal.pvp.01")); + + } + + try { + config.putConfigValue(IdAustriaAuthConstants.CONFIG_PROPS_SIGN_SIGNING_KEY_PASSWORD, + RandomStringUtils.randomAlphabetic(5)); + credential.getMessageSigningCredential(); + Assert.fail("No message signing credentials not detected"); + + } catch (final CredentialsNotAvailableException e) { + Assert.assertTrue("Wrong errorCode", e.getMessage().contains("internal.pvp.01")); + + } + + try { + config.putConfigValue(IdAustriaAuthConstants.CONFIG_PROPS_ENCRYPTION_KEY_PASSWORD, + RandomStringUtils.randomAlphabetic(5)); + final EaafX509Credential encCred = credential.getMessageEncryptionCredential(); + Assert.assertNull("No encryption signing credentials not detected", encCred); + + } catch (final CredentialsNotAvailableException e) { + Assert.assertTrue("Wrong errorCode", e.getMessage().contains("internal.pvp.01")); + + } + + } + + @Test + @DirtiesContext + public void notKeyConfigurationValidAliasWrongPassword() { + final IdAustriaAuthCredentialProvider credential = context.getBean( + IdAustriaAuthCredentialProvider.class); + + Assert.assertNotNull("Credetialprovider", credential); + Assert.assertNotNull("Friendlyname", credential.getFriendlyName()); + + try { + config.putConfigValue(IdAustriaAuthConstants.CONFIG_PROPS_SIGN_METADATA_ALIAS, + ALIAS_METADATA); + config.putConfigValue(IdAustriaAuthConstants.CONFIG_PROPS_SIGN_METADATA_KEY_PASSWORD, + RandomStringUtils.randomAlphabetic(5)); + credential.getMetaDataSigningCredential(); + Assert.fail("No Metadata signing credentials not detected"); + + } catch (final CredentialsNotAvailableException e) { + Assert.assertTrue("Wrong errorCode", e.getMessage().contains("internal.pvp.01")); + + } + + try { + config.putConfigValue(IdAustriaAuthConstants.CONFIG_PROPS_SIGN_SIGNING_ALIAS, + ALIAS_SIGN); + config.putConfigValue(IdAustriaAuthConstants.CONFIG_PROPS_SIGN_SIGNING_KEY_PASSWORD, + RandomStringUtils.randomAlphabetic(5)); + credential.getMessageSigningCredential(); + Assert.fail("No Metadata signing credentials not detected"); + + } catch (final CredentialsNotAvailableException e) { + Assert.assertTrue("Wrong errorCode", e.getMessage().contains("internal.pvp.01")); + + } + + try { + config.putConfigValue(IdAustriaAuthConstants.CONFIG_PROPS_ENCRYPTION_ALIAS, + ALIAS_ENC); + config.putConfigValue(IdAustriaAuthConstants.CONFIG_PROPS_ENCRYPTION_KEY_PASSWORD, + RandomStringUtils.randomAlphabetic(5)); + credential.getMessageEncryptionCredential(); + Assert.fail("No Metadata signing credentials not detected"); + + } catch (final CredentialsNotAvailableException e) { + Assert.assertTrue("Wrong errorCode", e.getMessage().contains("internal.pvp.01")); + + } + } + + @Test + @DirtiesContext + public void notKeyConfigurationWrongAliasValidPassword() { + final IdAustriaAuthCredentialProvider credential = context.getBean( + IdAustriaAuthCredentialProvider.class); + + Assert.assertNotNull("Credetialprovider", credential); + Assert.assertNotNull("Friendlyname", credential.getFriendlyName()); + + try { + config.putConfigValue(IdAustriaAuthConstants.CONFIG_PROPS_SIGN_METADATA_ALIAS, + RandomStringUtils.randomAlphabetic(5)); + config.putConfigValue(IdAustriaAuthConstants.CONFIG_PROPS_SIGN_METADATA_KEY_PASSWORD, + PASSWORD); + credential.getMetaDataSigningCredential(); + Assert.fail("No Metadata signing credentials not detected"); + + } catch (final CredentialsNotAvailableException e) { + Assert.assertTrue("Wrong errorCode", e.getMessage().contains("internal.pvp.01")); + + } + + try { + config.putConfigValue(IdAustriaAuthConstants.CONFIG_PROPS_SIGN_SIGNING_ALIAS, + RandomStringUtils.randomAlphabetic(5)); + config.putConfigValue(IdAustriaAuthConstants.CONFIG_PROPS_SIGN_SIGNING_KEY_PASSWORD, + PASSWORD); + credential.getMessageSigningCredential(); + Assert.fail("No Metadata signing credentials not detected"); + + } catch (final CredentialsNotAvailableException e) { + Assert.assertTrue("Wrong errorCode", e.getMessage().contains("internal.pvp.01")); + + } + + try { + config.putConfigValue(IdAustriaAuthConstants.CONFIG_PROPS_ENCRYPTION_ALIAS, + RandomStringUtils.randomAlphabetic(5)); + config.putConfigValue(IdAustriaAuthConstants.CONFIG_PROPS_ENCRYPTION_KEY_PASSWORD, + PASSWORD); + credential.getMessageEncryptionCredential(); + Assert.fail("No Metadata signing credentials not detected"); + + } catch (final CredentialsNotAvailableException e) { + Assert.assertTrue("Wrong errorCode", e.getMessage().contains("internal.pvp.01")); + + } + } + + @Test + @DirtiesContext + public void validonfiguration() throws CredentialsNotAvailableException { + final IdAustriaAuthCredentialProvider credential = context.getBean( + IdAustriaAuthCredentialProvider.class); + + Assert.assertNotNull("Credetialprovider", credential); + Assert.assertNotNull("Friendlyname", credential.getFriendlyName()); + + config.putConfigValue(IdAustriaAuthConstants.CONFIG_PROPS_SIGN_METADATA_ALIAS, + ALIAS_METADATA); + config.putConfigValue(IdAustriaAuthConstants.CONFIG_PROPS_SIGN_METADATA_KEY_PASSWORD, + PASSWORD); + credential.getMetaDataSigningCredential(); + + config.putConfigValue(IdAustriaAuthConstants.CONFIG_PROPS_SIGN_SIGNING_ALIAS, + ALIAS_SIGN); + config.putConfigValue(IdAustriaAuthConstants.CONFIG_PROPS_SIGN_SIGNING_KEY_PASSWORD, + PASSWORD); + credential.getMessageSigningCredential(); + + config.putConfigValue(IdAustriaAuthConstants.CONFIG_PROPS_ENCRYPTION_ALIAS, + ALIAS_ENC); + config.putConfigValue(IdAustriaAuthConstants.CONFIG_PROPS_ENCRYPTION_KEY_PASSWORD, + PASSWORD); + credential.getMessageEncryptionCredential(); + + } + + @Test + @DirtiesContext + public void notKeyConfiguration() { + final IdAustriaAuthCredentialProvider credential = context.getBean( + IdAustriaAuthCredentialProvider.class); + + Assert.assertNotNull("Credetialprovider", credential); + Assert.assertNotNull("Friendlyname", credential.getFriendlyName()); + + try { + credential.getMetaDataSigningCredential(); + Assert.fail("No Metadata signing credentials not detected"); + + } catch (final CredentialsNotAvailableException e) { + Assert.assertTrue("Wrong errorCode", e.getMessage().contains("internal.pvp.01")); + + } + + try { + credential.getMessageSigningCredential(); + Assert.fail("No message signing credentials not detected"); + + } catch (final CredentialsNotAvailableException e) { + Assert.assertTrue("Wrong errorCode", e.getMessage().contains("internal.pvp.01")); + + } + + try { + final EaafX509Credential encCred = credential.getMessageEncryptionCredential(); + Assert.assertNull("No encryption signing credentials not detected", encCred); + + } catch (final CredentialsNotAvailableException e) { + Assert.assertTrue("Wrong errorCode", e.getMessage().contains("internal.pvp.01")); + + } + + } + + @Test + @DirtiesContext + public void notKeyConfigurationPkcs12() { + config.putConfigValue(IdAustriaAuthConstants.CONFIG_PROPS_KEYSTORE_PATH, "pvp.p12"); + final IdAustriaAuthCredentialProvider credential = context.getBean( + IdAustriaAuthCredentialProvider.class); + + Assert.assertNotNull("Credetialprovider", credential); + Assert.assertNotNull("Friendlyname", credential.getFriendlyName()); + + try { + credential.getMetaDataSigningCredential(); + Assert.fail("No Metadata signing credentials not detected"); + + } catch (final CredentialsNotAvailableException e) { + Assert.assertTrue("Wrong errorCode", e.getMessage().contains("internal.pvp.01")); + + } + + try { + credential.getMessageSigningCredential(); + Assert.fail("No message signing credentials not detected"); + + } catch (final CredentialsNotAvailableException e) { + Assert.assertTrue("Wrong errorCode", e.getMessage().contains("internal.pvp.01")); + + } + + try { + final EaafX509Credential encCred = credential.getMessageEncryptionCredential(); + Assert.assertNull("No encryption signing credentials not detected", encCred); + + } catch (final CredentialsNotAvailableException e) { + Assert.assertTrue("Wrong errorCode", e.getMessage().contains("internal.pvp.01")); + + } + } +} diff --git a/modules/authmodule_id-austria/src/test/java/at/asitplus/eidas/specific/modules/auth/idaustria/test/utils/IdAustriaAuthMetadataProviderFirstTest.java b/modules/authmodule_id-austria/src/test/java/at/asitplus/eidas/specific/modules/auth/idaustria/test/utils/IdAustriaAuthMetadataProviderFirstTest.java new file mode 100644 index 00000000..d9e73db1 --- /dev/null +++ b/modules/authmodule_id-austria/src/test/java/at/asitplus/eidas/specific/modules/auth/idaustria/test/utils/IdAustriaAuthMetadataProviderFirstTest.java @@ -0,0 +1,236 @@ +package at.asitplus.eidas.specific.modules.auth.idaustria.test.utils; + +import java.io.IOException; +import java.time.Instant; +import java.time.temporal.ChronoUnit; + +import org.apache.commons.lang3.RandomStringUtils; +import org.junit.Assert; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.opensaml.core.criterion.EntityIdCriterion; +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.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.utils.IdAustriaAuthMetadataProvider; +import at.gv.egiz.eaaf.modules.pvp2.api.metadata.IPvp2MetadataProvider; +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.Pvp2MetadataException; +import at.gv.egiz.eaaf.modules.pvp2.exception.SamlSigningException; +import at.gv.egiz.eaaf.modules.pvp2.impl.metadata.PvpMetadataResolverFactory; +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.CriteriaSet; +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 IdAustriaAuthMetadataProviderFirstTest { + + @Autowired IPvp2CredentialProvider credentialProvider; + @Autowired IdAustriaAuthMetadataProvider provider; + @Autowired PvpMetadataResolverFactory resolverFactory; + @Autowired MsConnectorDummyConfigMap config; + + 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"); + + } + + /** + * jUnit test set-up. + * + * @throws ResolverException + * + */ + @Before + public void testSetup() { + provider.fullyDestroy(); + + } + + @Test + public void simpleManuelAddingTest() throws Pvp2MetadataException, ResolverException { + final IPvp2MetadataProvider resolver1 = resolverFactory.createMetadataProvider( + "classpath:/data/idp_metadata_sig_notvalid.xml", + null, "junit", null); + Assert.assertNotNull("Resolver 1 is null", resolver1); + provider.addMetadataResolverIntoChain(resolver1); + + final IPvp2MetadataProvider resolver2 = resolverFactory.createMetadataProvider( + "classpath:/data/idp_metadata_sig_valid_wrong_alg.xml", + null, "junit", null); + Assert.assertNotNull("Resolver 2 is null", resolver2); + provider.addMetadataResolverIntoChain(resolver2); + + final EntityDescriptor entity1 = provider.getEntityDescriptor("https://localEntity"); + Assert.assertNotNull("Entity 1 not found", entity1); + + final EntityDescriptor entity2 = provider.getEntityDescriptor( + "https://vidp.gv.at/ms_connector/pvp/metadata"); + Assert.assertNotNull("Entity 2 not found", entity2); + + final EntityDescriptor entity3 = provider.getEntityDescriptor("https://egiz.gv.at/abababa"); + Assert.assertNull("Entity 3 found", entity3); + + } + + @Test + public void dynamicLoadingNoValidSignature() throws ResolverException { + final EntityDescriptor entity = provider.getEntityDescriptor("classpath:/data/idp_metadata_no_sig2.xml"); + Assert.assertNull("Entity found", entity); + + } + + @Test + public void dynamicLoadingValidSignature() throws XMLParserException, UnmarshallingException, + SamlSigningException, CredentialsNotAvailableException, MarshallingException, ResolverException { + + final String entityId = injectValidHttpMetadata(); + final EntityDescriptor entity = provider.getEntityDescriptor(entityId); + Assert.assertNotNull("Entity not found", entity); + + } + + @Test + public void reloadNotPossible() throws XMLParserException, UnmarshallingException, + SamlSigningException, CredentialsNotAvailableException, MarshallingException, ResolverException { + + final String entityId = injectValidHttpMetadata(); + final EntityDescriptor entity = provider.getEntityDescriptor(entityId); + Assert.assertNotNull("Entity not found", entity); + Assert.assertNotNull("Entity not found", + provider.resolveSingle(generateEntityIdCreteria(entityId))); + + Assert.assertFalse("Refresh should not be possible", + provider.refreshMetadataProvider(entityId)); + + final EntityDescriptor entity2 = provider.getEntityDescriptor(entityId); + Assert.assertNull("Entity not found", entity2); + Assert.assertNull("Entity not found", + provider.resolveSingle(generateEntityIdCreteria(entityId))); + + Assert.assertFalse("Last refresh", provider.wasLastRefreshSuccess()); + + } + + @Test + public void refeshTest() throws Pvp2MetadataException, ResolverException { + Assert.assertFalse("Last refresh", provider.wasLastRefreshSuccess()); + Assert.assertNull("LastRefresh", provider.getLastRefresh()); + Assert.assertNull("LastSuccessfulRefresh", provider.getLastSuccessfulRefresh()); + Assert.assertNull("LastUpdate", provider.getLastUpdate()); + + final IPvp2MetadataProvider resolver1 = resolverFactory.createMetadataProvider( + "classpath:/data/idp_metadata_sig_notvalid.xml", + null, "junit", null); + Assert.assertNotNull("Resolver 1 is null", resolver1); + provider.addMetadataResolverIntoChain(resolver1); + + final IPvp2MetadataProvider resolver2 = resolverFactory.createMetadataProvider( + "classpath:/data/idp_metadata_sig_valid_wrong_alg.xml", + null, "junit", null); + Assert.assertNotNull("Resolver 2 is null", resolver2); + provider.addMetadataResolverIntoChain(resolver2); + + provider.refresh(); + + Assert.assertTrue("Last refresh", provider.wasLastRefreshSuccess()); + Assert.assertNotNull("LastRefresh", provider.getLastRefresh()); + Assert.assertNotNull("LastSuccessfulRefresh", provider.getLastSuccessfulRefresh()); + Assert.assertNotNull("LastUpdate", provider.getLastUpdate()); + + } + + @Test + public void reloadPossible() throws XMLParserException, UnmarshallingException, + SamlSigningException, CredentialsNotAvailableException, MarshallingException, ResolverException, + IOException { + + mockWebServer.shutdown(); + mockWebServer = new MockWebServer(); + mockServerUrl = mockWebServer.url("/sp/metadata"); + + final String entityId = injectValidHttpMetadata(); + final EntityDescriptor entity = provider.getEntityDescriptor(entityId); + Assert.assertNotNull("Entity not found", entity); + Assert.assertNotNull("Entity not found", + provider.resolveSingle(generateEntityIdCreteria(entityId))); + + Assert.assertFalse("Last refresh", provider.wasLastRefreshSuccess()); + + injectValidHttpMetadata(entityId); + Assert.assertTrue("Refresh should not be possible", + provider.refreshMetadataProvider(entityId)); + + final EntityDescriptor entity2 = provider.getEntityDescriptor(entityId); + Assert.assertNotNull("Entity not found", entity2); + Assert.assertNotNull("Entity not found", + provider.resolveSingle(generateEntityIdCreteria(entityId))); + + Assert.assertFalse("Last refresh", provider.wasLastRefreshSuccess()); + + } + + private String injectValidHttpMetadata() throws SamlSigningException, CredentialsNotAvailableException, + XMLParserException, UnmarshallingException, MarshallingException { + return injectValidHttpMetadata(mockServerUrl.url().toString() + + "/" + RandomStringUtils.randomAlphabetic(5)); + } + + private String injectValidHttpMetadata(String dynEntityId) throws XMLParserException, + UnmarshallingException, + MarshallingException, SamlSigningException, CredentialsNotAvailableException { + final EntityDescriptor metadata = (EntityDescriptor) XMLObjectSupport.unmarshallFromInputStream( + XMLObjectProviderRegistrySupport.getParserPool(), + IdAustriaAuthMetadataProviderFirstTest.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; + + } + + private CriteriaSet generateEntityIdCreteria(String entityId) { + final CriteriaSet result = new CriteriaSet(); + result.add(new EntityIdCriterion(entityId)); + return result; + + } +} diff --git a/modules/authmodule_id-austria/src/test/java/at/asitplus/eidas/specific/modules/auth/idaustria/test/utils/IdAustriaAuthMetadataProviderSecondTest.java b/modules/authmodule_id-austria/src/test/java/at/asitplus/eidas/specific/modules/auth/idaustria/test/utils/IdAustriaAuthMetadataProviderSecondTest.java new file mode 100644 index 00000000..9b3c1a34 --- /dev/null +++ b/modules/authmodule_id-austria/src/test/java/at/asitplus/eidas/specific/modules/auth/idaustria/test/utils/IdAustriaAuthMetadataProviderSecondTest.java @@ -0,0 +1,65 @@ +package at.asitplus.eidas.specific.modules.auth.idaustria.test.utils; + +import org.junit.Assert; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.opensaml.saml.saml2.metadata.EntityDescriptor; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; + +import at.asitplus.eidas.specific.modules.auth.idaustria.utils.IdAustriaAuthMetadataProvider; +import at.gv.egiz.eaaf.modules.pvp2.impl.opensaml.initialize.EaafOpenSaml3xInitializer; +import net.shibboleth.utilities.java.support.resolver.ResolverException; + +@RunWith(SpringJUnit4ClassRunner.class) +@ContextConfiguration(locations = { + "/spring/SpringTest-context_basic_test.xml", + "/spring/SpringTest-context_basic_mapConfig.xml" }) +public class IdAustriaAuthMetadataProviderSecondTest { + + @Autowired + IdAustriaAuthMetadataProvider provider; + + /** + * JUnit class initializer. + * + * @throws Exception In case of an OpenSAML3 initialization error + */ + @BeforeClass + public static void classInitializer() throws Exception { + EaafOpenSaml3xInitializer.eaafInitialize(); + + } + + /** + * jUnit test set-up. + * + * @throws ResolverException + * + */ + @Before + public void testSetup() { + provider.fullyDestroy(); + + } + + @Test + public void notTrustedX509CertsInTrustStore() throws ResolverException { + final EntityDescriptor entity = provider.getEntityDescriptor("classpath:/data/idp_metadata_no_sig2.xml"); + Assert.assertNull("Entity found", entity); + + } + + @Test + public void readStaticInfos() { + Assert.assertEquals("wrong providerId", + IdAustriaAuthMetadataProvider.PROVIDER_ID, provider.getId()); + + provider.runGarbageCollector(); + + } + +} diff --git a/modules/authmodule_id-austria/src/test/resources/config/junit.jks b/modules/authmodule_id-austria/src/test/resources/config/junit.jks new file mode 100644 index 00000000..59e6ad13 Binary files /dev/null and b/modules/authmodule_id-austria/src/test/resources/config/junit.jks differ diff --git a/modules/authmodule_id-austria/src/test/resources/config/junit_config_1.properties b/modules/authmodule_id-austria/src/test/resources/config/junit_config_1.properties new file mode 100644 index 00000000..66c13dbc --- /dev/null +++ b/modules/authmodule_id-austria/src/test/resources/config/junit_config_1.properties @@ -0,0 +1,44 @@ +## HTTP-client defaults +eidas.ms.client.http.connection.timeout.socket=1 +eidas.ms.client.http.connection.timeout.connection=1 +eidas.ms.client.http.connection.timeout.request=1 + + +## PVP2 S-Profile communication with ID Austria System +# EntityId and optional metadata of ID Austria System +eidas.ms.modules.idaustriaauth.idp.entityId=http://junit.idaustria.at/idp +#eidas.ms.modules.idaustriaauth.idp.metadataUrl=http://junit.idaustria.at/idp/metadata + +# SAML2 client configuration +eidas.ms.modules.idaustriaauth.keystore.type=jks +#eidas.ms.modules.idaustriaauth.keystore.name= +eidas.ms.modules.idaustriaauth.keystore.path=junit_test.jks +eidas.ms.modules.idaustriaauth.keystore.password=password +eidas.ms.modules.idaustriaauth.metadata.sign.alias=meta +eidas.ms.modules.idaustriaauth.metadata.sign.password=password +eidas.ms.modules.idaustriaauth.request.sign.alias=sig +eidas.ms.modules.idaustriaauth.request.sign.password=password +eidas.ms.modules.idaustriaauth.response.encryption.alias=enc +eidas.ms.modules.idaustriaauth.response.encryption.password=password + +# TrustStore to validate SAML2 metadata from ID Austria +eidas.ms.modules.idaustriaauth.truststore.type=jks +eidas.ms.modules.idaustriaauth.truststore.name= +eidas.ms.modules.idaustriaauth.truststore.path=junit_test.jks +eidas.ms.modules.idaustriaauth.truststore.password=password + +# Additional requested attributes in SAML2 metadata +#eidas.ms.modules.idaustriaauth.required.additional.attributes.1= +#eidas.ms.modules.idaustriaauth.required.additional.attributes.2= +#eidas.ms.modules.idaustriaauth.required.additional.attributes.3= +#eidas.ms.modules.idaustriaauth.required.additional.attributes.4= + + + +## General PVP2 metadata configuration +eidas.ms.pvp2.metadata.organisation.name=JUnit +eidas.ms.pvp2.metadata.organisation.friendyname=For testing with jUnit +eidas.ms.pvp2.metadata.organisation.url=http://junit.test +eidas.ms.pvp2.metadata.contact.givenname=Max +eidas.ms.pvp2.metadata.contact.surname=Mustermann +eidas.ms.pvp2.metadata.contact.email=max@junit.test \ No newline at end of file diff --git a/modules/authmodule_id-austria/src/test/resources/config/junit_test.jks b/modules/authmodule_id-austria/src/test/resources/config/junit_test.jks new file mode 100644 index 00000000..ee6254a9 Binary files /dev/null and b/modules/authmodule_id-austria/src/test/resources/config/junit_test.jks differ diff --git a/modules/authmodule_id-austria/src/test/resources/config/junit_test_no_trust_certs.jks b/modules/authmodule_id-austria/src/test/resources/config/junit_test_no_trust_certs.jks new file mode 100644 index 00000000..8fe3b03c Binary files /dev/null and b/modules/authmodule_id-austria/src/test/resources/config/junit_test_no_trust_certs.jks differ diff --git a/modules/authmodule_id-austria/src/test/resources/config/pvp.jks b/modules/authmodule_id-austria/src/test/resources/config/pvp.jks new file mode 100644 index 00000000..f0a5a09a Binary files /dev/null and b/modules/authmodule_id-austria/src/test/resources/config/pvp.jks differ diff --git a/modules/authmodule_id-austria/src/test/resources/config/pvp.p12 b/modules/authmodule_id-austria/src/test/resources/config/pvp.p12 new file mode 100644 index 00000000..183342f7 Binary files /dev/null and b/modules/authmodule_id-austria/src/test/resources/config/pvp.p12 differ diff --git a/modules/authmodule_id-austria/src/test/resources/data/Response_with_EID.xml b/modules/authmodule_id-austria/src/test/resources/data/Response_with_EID.xml new file mode 100644 index 00000000..8d3c1c66 --- /dev/null +++ b/modules/authmodule_id-austria/src/test/resources/data/Response_with_EID.xml @@ -0,0 +1,49 @@ + + + classpath:/data/idp_metadata_classpath_entity.xml + + + + + https://demo.egiz.gv.at/demoportal_moaid-2.0/pvp/metadata + + QVGm48cqcM4UcyhDTNGYmVdrIoY= + + + + + + + https://localhost/authhandler/sp/idaustria/eidas/metadata + + + + + http://eidas.europa.eu/LoA/high + + + + + 2.1 + + + http://eidas.europa.eu/LoA/high + + + AT + + + Mustermann + + + Max + + + 1940-01-01 + + + AT+XX:QVGm48cqcM4UcyhDTNGYmVdrIoY= + + + + diff --git a/modules/authmodule_id-austria/src/test/resources/data/Response_with_EID_bpk_without_prefix.xml b/modules/authmodule_id-austria/src/test/resources/data/Response_with_EID_bpk_without_prefix.xml new file mode 100644 index 00000000..ec4f451e --- /dev/null +++ b/modules/authmodule_id-austria/src/test/resources/data/Response_with_EID_bpk_without_prefix.xml @@ -0,0 +1,49 @@ + + + classpath:/data/idp_metadata_classpath_entity.xml + + + + + https://demo.egiz.gv.at/demoportal_moaid-2.0/pvp/metadata + + QVGm48cqcM4UcyhDTNGYmVdrIoY= + + + + + + + https://localhost/authhandler/sp/idaustria/eidas/metadata + + + + + http://eidas.europa.eu/LoA/high + + + + + 2.1 + + + http://eidas.europa.eu/LoA/aabbcc + + + AT + + + Heinz + + + Susi + + + 1955-01-01 + + + QVGm48cqcasfasfsafsafdM4UcyhDTNGYmVdrIoY= + + + + diff --git a/modules/authmodule_id-austria/src/test/resources/data/Response_with_EID_minimum.xml b/modules/authmodule_id-austria/src/test/resources/data/Response_with_EID_minimum.xml new file mode 100644 index 00000000..be8e7cc3 --- /dev/null +++ b/modules/authmodule_id-austria/src/test/resources/data/Response_with_EID_minimum.xml @@ -0,0 +1,43 @@ + + + classpath:/data/idp_metadata_classpath_entity.xml + + + + + https://demo.egiz.gv.at/demoportal_moaid-2.0/pvp/metadata + + QVGm48cqcM4UcyhDTNGYmVdrIoY= + + + + + + + https://localhost/authhandler/sp/idaustria/eidas/metadata + + + + + http://eidas.europa.eu/LoA/high + + + + + AT + + + Mustermann + + + Max + + + 1940-01-01 + + + AT+CC:QVGm48cqcM4UcyhDTNGYmVdrIoY= + + + + diff --git a/modules/authmodule_id-austria/src/test/resources/data/Response_with_EID_with_eid_sector_attr.xml b/modules/authmodule_id-austria/src/test/resources/data/Response_with_EID_with_eid_sector_attr.xml new file mode 100644 index 00000000..6b86c6f1 --- /dev/null +++ b/modules/authmodule_id-austria/src/test/resources/data/Response_with_EID_with_eid_sector_attr.xml @@ -0,0 +1,52 @@ + + + classpath:/data/idp_metadata_classpath_entity.xml + + + + + https://demo.egiz.gv.at/demoportal_moaid-2.0/pvp/metadata + + QVGm48cqcM4UcyhDTNGYmVdrIoY= + + + + + + + https://localhost/authhandler/sp/idaustria/eidas/metadata + + + + + http://eidas.europa.eu/LoA/high + + + + + 2.1 + + + http://eidas.europa.eu/LoA/aabbcc + + + AT + + + Heinz + + + Susi + + + 1955-01-01 + + + AT+AB:QVGm48cqcasfasfsafsafdM4UcyhDTNGYmVdrIoY= + + + urn:publicid:gv.at:eidasid+AT+AB + + + + diff --git a/modules/authmodule_id-austria/src/test/resources/data/Response_with_EID_with_mandate_jur.xml b/modules/authmodule_id-austria/src/test/resources/data/Response_with_EID_with_mandate_jur.xml new file mode 100644 index 00000000..da97bbf4 --- /dev/null +++ b/modules/authmodule_id-austria/src/test/resources/data/Response_with_EID_with_mandate_jur.xml @@ -0,0 +1,63 @@ + + + classpath:/data/idp_metadata_classpath_entity.xml + + + + + https://demo.egiz.gv.at/demoportal_moaid-2.0/pvp/metadata + + QVGm48cqcM4UcyhDTNGYmVdrIoY= + + + + + + + https://localhost/authhandler/sp/idaustria/eidas/metadata + + + + + http://eidas.europa.eu/LoA/high + + + + + 2.1 + + + http://eidas.europa.eu/LoA/high + + + AT + + + Mustermann + + + Max + + + 1940-01-01 + + + AT+XX:QVGm48cqcM4UcyhDTNGYmVdrIoY= + + + + Generalvollmacht + + + 999999m + + + urn:publicid:gv.at:baseid+XERSB + + + Testfirma + + + + + diff --git a/modules/authmodule_id-austria/src/test/resources/data/Response_with_EID_with_mandate_nat.xml b/modules/authmodule_id-austria/src/test/resources/data/Response_with_EID_with_mandate_nat.xml new file mode 100644 index 00000000..8a84503d --- /dev/null +++ b/modules/authmodule_id-austria/src/test/resources/data/Response_with_EID_with_mandate_nat.xml @@ -0,0 +1,66 @@ + + + classpath:/data/idp_metadata_classpath_entity.xml + + + + + https://demo.egiz.gv.at/demoportal_moaid-2.0/pvp/metadata + + QVGm48cqcM4UcyhDTNGYmVdrIoY= + + + + + + + https://localhost/authhandler/sp/idaustria/eidas/metadata + + + + + http://eidas.europa.eu/LoA/high + + + + + 2.1 + + + http://eidas.europa.eu/LoA/high + + + AT + + + Mustermann + + + Max + + + 1940-01-01 + + + AT+XX:QVGm48cqcM4UcyhDTNGYmVdrIoY= + + + + GeneralvollmachtBilateral + + + AT+XX:AFSDAFSDFDSFCSDAFASDF= + + + Gerti + + + Musterfrau + + + 01-02-1941 + + + + + diff --git a/modules/authmodule_id-austria/src/test/resources/data/Response_with_EID_wrong_data.xml b/modules/authmodule_id-austria/src/test/resources/data/Response_with_EID_wrong_data.xml new file mode 100644 index 00000000..cc534d09 --- /dev/null +++ b/modules/authmodule_id-austria/src/test/resources/data/Response_with_EID_wrong_data.xml @@ -0,0 +1,46 @@ + + + classpath:/data/idp_metadata_classpath_entity.xml + + + + + https://demo.egiz.gv.at/demoportal_moaid-2.0/pvp/metadata + + QVGm48cqcM4UcyhDTNGYmVdrIoY= + + + + + + + https://localhost/authhandler/sp/idaustria/eidas/metadata + + + + + http://eidas.europa.eu/LoA/high + + + + + piiId_112233445566 + + + 2.1 + + + http://eidas.europa.eu/LoA/low + + + IT + + + aabbccddeeffgghh + + + MIIBbjCCARSgAwIBAgIEXh7TNzAKBggqhkjOPQQDAjA/MQswCQYDVQQGEwJBVDENMAsGA1UECgwERUdJWjEOMAwGA1UECwwFalVuaXQxETAPBgNVBAMMCG1ldGFkYXRhMB4XDTIwMDExNTA4NTQxNVoXDTMwMDExNDA4NTQxNVowPzELMAkGA1UEBhMCQVQxDTALBgNVBAoMBEVHSVoxDjAMBgNVBAsMBWpVbml0MREwDwYDVQQDDAhtZXRhZGF0YTBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABBdBkaxt31p++aZeP3SmlWITj9SYO4McV2ccXFsH4X4QMHuKAMUvjxPm1kdU01eTOWdiQX0GpDIBspYMZh8ZKcwwCgYIKoZIzj0EAwIDSAAwRQIhAJ3QKlk9cd90s+i8y62fvmGF6LtfNO+JvkWqDUBeQImnAiA2KwFtzO7STAp9MEwQGe0vt0F8mO1ttrLE+rr6YxdwGA== + + + + diff --git a/modules/authmodule_id-austria/src/test/resources/data/Response_with_wrong_destination_endpoint.xml b/modules/authmodule_id-austria/src/test/resources/data/Response_with_wrong_destination_endpoint.xml new file mode 100644 index 00000000..2ae05ca1 --- /dev/null +++ b/modules/authmodule_id-austria/src/test/resources/data/Response_with_wrong_destination_endpoint.xml @@ -0,0 +1,52 @@ + + + classpath:/data/idp_metadata_classpath_entity.xml + + + + + https://demo.egiz.gv.at/demoportal_moaid-2.0/pvp/metadata + + QVGm48cqcM4UcyhDTNGYmVdrIoY= + + + + + + + https://localhost/authhandler/sp/idaustria/eidas/metadata + + + + + http://www.stork.gov.eu/1.0/citizenQAALevel/4 + + + + + 2.1 + + + Mustermann + + + Max + + + 1940-01-01 + + + BF:QVGm48cqcM4UcyhDTNGYmVdrIoY= + + + 4 + + + AT + + + urn:publicid:gv.at:cdid+BF + + + + diff --git a/modules/authmodule_id-austria/src/test/resources/data/Response_without_sig_classpath_entityid.xml b/modules/authmodule_id-austria/src/test/resources/data/Response_without_sig_classpath_entityid.xml new file mode 100644 index 00000000..0fd675e2 --- /dev/null +++ b/modules/authmodule_id-austria/src/test/resources/data/Response_without_sig_classpath_entityid.xml @@ -0,0 +1,52 @@ + + + classpath:/data/idp_metadata_classpath_entity.xml + + + + + https://demo.egiz.gv.at/demoportal_moaid-2.0/pvp/metadata + + QVGm48cqcM4UcyhDTNGYmVdrIoY= + + + + + + + https://localhost/authhandler/sp/idaustria/eidas/metadata + + + + + http://eidas.europa.eu/LoA/high + + + + + 2.1 + + + Mustermann + + + Max + + + 1940-01-01 + + + BF:QVGm48cqcM4UcyhDTNGYmVdrIoY= + + + http://eidas.europa.eu/LoA/high + + + IT + + + urn:publicid:gv.at:cdid+BF + + + + diff --git a/modules/authmodule_id-austria/src/test/resources/data/Response_without_sig_with_error.xml b/modules/authmodule_id-austria/src/test/resources/data/Response_without_sig_with_error.xml new file mode 100644 index 00000000..ee5920dc --- /dev/null +++ b/modules/authmodule_id-austria/src/test/resources/data/Response_without_sig_with_error.xml @@ -0,0 +1,46 @@ + + + classpath:/data/idp_metadata_classpath_entity.xml + + + + + Der Anmeldevorgang wurde durch den Benutzer abgebrochen. + + + https://demo.egiz.gv.at/demoportal_moaid-2.0/pvp/metadata + + QVGm48cqcM4UcyhDTNGYmVdrIoY= + + + + + + + https://localhost/authhandler/sp/idaustria/eidas/metadata + + + + + http://eidas.europa.eu/LoA/high + + + + + 2.1 + + + http://eidas.europa.eu/LoA/low + + + IT + + + aabbccddeeffgghh + + + MIIBbjCCARSgAwIBAgIEXh7TNzAKBggqhkjOPQQDAjA/MQswCQYDVQQGEwJBVDENMAsGA1UECgwERUdJWjEOMAwGA1UECwwFalVuaXQxETAPBgNVBAMMCG1ldGFkYXRhMB4XDTIwMDExNTA4NTQxNVoXDTMwMDExNDA4NTQxNVowPzELMAkGA1UEBhMCQVQxDTALBgNVBAoMBEVHSVoxDjAMBgNVBAsMBWpVbml0MREwDwYDVQQDDAhtZXRhZGF0YTBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABBdBkaxt31p++aZeP3SmlWITj9SYO4McV2ccXFsH4X4QMHuKAMUvjxPm1kdU01eTOWdiQX0GpDIBspYMZh8ZKcwwCgYIKoZIzj0EAwIDSAAwRQIhAJ3QKlk9cd90s+i8y62fvmGF6LtfNO+JvkWqDUBeQImnAiA2KwFtzO7STAp9MEwQGe0vt0F8mO1ttrLE+rr6YxdwGA== + + + + diff --git a/modules/authmodule_id-austria/src/test/resources/data/Response_without_sig_with_error_empty_subcode.xml b/modules/authmodule_id-austria/src/test/resources/data/Response_without_sig_with_error_empty_subcode.xml new file mode 100644 index 00000000..dd3f7908 --- /dev/null +++ b/modules/authmodule_id-austria/src/test/resources/data/Response_without_sig_with_error_empty_subcode.xml @@ -0,0 +1,46 @@ + + + classpath:/data/idp_metadata_classpath_entity.xml + + + + + Der Anmeldevorgang wurde durch den Benutzer abgebrochen. + + + https://demo.egiz.gv.at/demoportal_moaid-2.0/pvp/metadata + + QVGm48cqcM4UcyhDTNGYmVdrIoY= + + + + + + + https://localhost/authhandler/sp/idaustria/eidas/metadata + + + + + http://eidas.europa.eu/LoA/high + + + + + 2.1 + + + http://eidas.europa.eu/LoA/low + + + IT + + + aabbccddeeffgghh + + + MIIBbjCCARSgAwIBAgIEXh7TNzAKBggqhkjOPQQDAjA/MQswCQYDVQQGEwJBVDENMAsGA1UECgwERUdJWjEOMAwGA1UECwwFalVuaXQxETAPBgNVBAMMCG1ldGFkYXRhMB4XDTIwMDExNTA4NTQxNVoXDTMwMDExNDA4NTQxNVowPzELMAkGA1UEBhMCQVQxDTALBgNVBAoMBEVHSVoxDjAMBgNVBAsMBWpVbml0MREwDwYDVQQDDAhtZXRhZGF0YTBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABBdBkaxt31p++aZeP3SmlWITj9SYO4McV2ccXFsH4X4QMHuKAMUvjxPm1kdU01eTOWdiQX0GpDIBspYMZh8ZKcwwCgYIKoZIzj0EAwIDSAAwRQIhAJ3QKlk9cd90s+i8y62fvmGF6LtfNO+JvkWqDUBeQImnAiA2KwFtzO7STAp9MEwQGe0vt0F8mO1ttrLE+rr6YxdwGA== + + + + diff --git a/modules/authmodule_id-austria/src/test/resources/data/Response_without_sig_with_error_userstop.xml b/modules/authmodule_id-austria/src/test/resources/data/Response_without_sig_with_error_userstop.xml new file mode 100644 index 00000000..1783cbab --- /dev/null +++ b/modules/authmodule_id-austria/src/test/resources/data/Response_without_sig_with_error_userstop.xml @@ -0,0 +1,46 @@ + + + classpath:/data/idp_metadata_classpath_entity.xml + + + + + Der Anmeldevorgang wurde durch den Benutzer abgebrochen. + + + https://demo.egiz.gv.at/demoportal_moaid-2.0/pvp/metadata + + QVGm48cqcM4UcyhDTNGYmVdrIoY= + + + + + + + https://localhost/authhandler/sp/idaustria/eidas/metadata + + + + + http://eidas.europa.eu/LoA/high + + + + + 2.1 + + + http://eidas.europa.eu/LoA/low + + + IT + + + aabbccddeeffgghh + + + MIIBbjCCARSgAwIBAgIEXh7TNzAKBggqhkjOPQQDAjA/MQswCQYDVQQGEwJBVDENMAsGA1UECgwERUdJWjEOMAwGA1UECwwFalVuaXQxETAPBgNVBAMMCG1ldGFkYXRhMB4XDTIwMDExNTA4NTQxNVoXDTMwMDExNDA4NTQxNVowPzELMAkGA1UEBhMCQVQxDTALBgNVBAoMBEVHSVoxDjAMBgNVBAsMBWpVbml0MREwDwYDVQQDDAhtZXRhZGF0YTBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABBdBkaxt31p++aZeP3SmlWITj9SYO4McV2ccXFsH4X4QMHuKAMUvjxPm1kdU01eTOWdiQX0GpDIBspYMZh8ZKcwwCgYIKoZIzj0EAwIDSAAwRQIhAJ3QKlk9cd90s+i8y62fvmGF6LtfNO+JvkWqDUBeQImnAiA2KwFtzO7STAp9MEwQGe0vt0F8mO1ttrLE+rr6YxdwGA== + + + + diff --git a/modules/authmodule_id-austria/src/test/resources/data/Response_without_sig_with_error_without_subcode.xml b/modules/authmodule_id-austria/src/test/resources/data/Response_without_sig_with_error_without_subcode.xml new file mode 100644 index 00000000..1c7a8433 --- /dev/null +++ b/modules/authmodule_id-austria/src/test/resources/data/Response_without_sig_with_error_without_subcode.xml @@ -0,0 +1,45 @@ + + + classpath:/data/idp_metadata_classpath_entity.xml + + + + Der Anmeldevorgang wurde durch den Benutzer abgebrochen. + + + https://demo.egiz.gv.at/demoportal_moaid-2.0/pvp/metadata + + QVGm48cqcM4UcyhDTNGYmVdrIoY= + + + + + + + https://localhost/authhandler/sp/idaustria/eidas/metadata + + + + + http://eidas.europa.eu/LoA/high + + + + + 2.1 + + + http://eidas.europa.eu/LoA/low + + + IT + + + aabbccddeeffgghh + + + MIIBbjCCARSgAwIBAgIEXh7TNzAKBggqhkjOPQQDAjA/MQswCQYDVQQGEwJBVDENMAsGA1UECgwERUdJWjEOMAwGA1UECwwFalVuaXQxETAPBgNVBAMMCG1ldGFkYXRhMB4XDTIwMDExNTA4NTQxNVoXDTMwMDExNDA4NTQxNVowPzELMAkGA1UEBhMCQVQxDTALBgNVBAoMBEVHSVoxDjAMBgNVBAsMBWpVbml0MREwDwYDVQQDDAhtZXRhZGF0YTBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABBdBkaxt31p++aZeP3SmlWITj9SYO4McV2ccXFsH4X4QMHuKAMUvjxPm1kdU01eTOWdiQX0GpDIBspYMZh8ZKcwwCgYIKoZIzj0EAwIDSAAwRQIhAJ3QKlk9cd90s+i8y62fvmGF6LtfNO+JvkWqDUBeQImnAiA2KwFtzO7STAp9MEwQGe0vt0F8mO1ttrLE+rr6YxdwGA== + + + + diff --git a/modules/authmodule_id-austria/src/test/resources/data/eidas_node_siging.crt b/modules/authmodule_id-austria/src/test/resources/data/eidas_node_siging.crt new file mode 100644 index 00000000..95843ea9 --- /dev/null +++ b/modules/authmodule_id-austria/src/test/resources/data/eidas_node_siging.crt @@ -0,0 +1,21 @@ +-----BEGIN CERTIFICATE----- +MIIEFTCCAn0CBFtIcMwwDQYJKoZIhvcNAQELBQAwTzELMAkGA1UEBhMCQVQxDTALBgNVBAoMBEVH +SVoxMTAvBgNVBAMMKG5hdGlvbmFsIGNlbnRyYWwgZUlEQVMgbm9kZSAtIHRlc3RzeXN0ZW0wHhcN +MTgwNzEzMDkyODQ0WhcNMjEwNDA3MDkyODQ0WjBPMQswCQYDVQQGEwJBVDENMAsGA1UECgwERUdJ +WjExMC8GA1UEAwwobmF0aW9uYWwgY2VudHJhbCBlSURBUyBub2RlIC0gdGVzdHN5c3RlbTCCAaIw +DQYJKoZIhvcNAQEBBQADggGPADCCAYoCggGBALK4bdf5OremKkj0+xCjU0eN7RUd1A2VqoGnvFUs +t7xjLQ1PspHiDf9Pm2cwOIJabSnuZ01hYAGz9X+lU3Z3fwhVc+tEsuzsaAml/LPw3i3+ppoSTJDM +iDvhCoUKTzJ8HBQj2gTvXNlqPljyGneuCJ+uBMr7Okq/XjMTJj2xzvutrHS3qIO+/w+OkY967QLV +RXh0bdFqYqnyAnlYcWJPIwjanOJtE2difPYqers7ZW1F9djP0+IZRoyaook5rpLYvuQTHuvulgIE +3zGlTuOx3sk8zMyInMndqi75Eh+ROnndSZE7gN3u5CfFpuO5pxFa2jj1h/AnR39Tg8/sU+Se+AwH +rNvee3IWhxk5LkelYevfeCQos7Dv2ASE9XMCCs7FoE47w8fDalECh09MFKDiotpklbq3OrPg9NQ4 +D//k0GXlW5jYUKP/Wq/+suAI6mfhSnNkjOGMcMlzNTmwxGD/v7Py6OVA+YcJQsqYalLrqbvT2tXV +mYBVO3oqafg+kfevfwIDAQABMA0GCSqGSIb3DQEBCwUAA4IBgQCioM8k0EEBFtY4QyxOYFufPDLw +9PNPct01ltnTVjNEEt/L6/8zYlDwrDeULEkJS7mV9zV3657NPQ5IPT/Ib93Uk/RPi0iOA2CGWIMa +DQIODN3BUYr+zPUqhbKS6OWOhTgV8GiRCUbxrT1uc1AiacP63pga3TJX8k8WFnfW+Dqm2MfWWlxr +4X2YB9VUW55X5sBNy035jYhEpp8NCK/fTAhoEQNCG+rm3T9qhT6YyOnbW2kXU747+ZwXT2qA5o4y +a/9+6dDc+LUlHCEm4X7c6bcGvCfNezB4k56FzbAJlOLf2VDGzvEQBf0hsB+kElezm1VBlEkZ4Mjz +pBpHBMoR21SwTpcvrbR4ig0Bk1eEHNK44sw0F32K5yww3gnJftMIZtPhjhk8UdG2/H6vs9s/to2V +j4V6wN4o79RTULoQ8RjL6MPWEWzwOvOZXJAo2XJEECvDivSjIJvNC0lfrK3zI3LH3c1JR6q2EfeC +Z50wTJMFoChSaqunJQXKo81g6wNhP00= +-----END CERTIFICATE----- diff --git a/modules/authmodule_id-austria/src/test/resources/data/idp_metadata_classpath_entity.xml b/modules/authmodule_id-austria/src/test/resources/data/idp_metadata_classpath_entity.xml new file mode 100644 index 00000000..de565887 --- /dev/null +++ b/modules/authmodule_id-austria/src/test/resources/data/idp_metadata_classpath_entity.xml @@ -0,0 +1,146 @@ + + + + + + + MIIDMzCCAhsCBFtIcPowDQYJKoZIhvcNAQELBQAwXjELMAkGA1UEBhMCQVQxDTALBgNVBAoMBEVH + SVoxJDAiBgNVBAsMG2NlbnRyYWwgbmF0aW9uYWwgZUlEQVMgbm9kZTEaMBgGA1UEAwwRQXNzZXJ0 + aW9uIHNpZ25pbmcwHhcNMTgwNzEzMDkyOTMwWhcNMjEwNDA3MDkyOTMwWjBeMQswCQYDVQQGEwJB + VDENMAsGA1UECgwERUdJWjEkMCIGA1UECwwbY2VudHJhbCBuYXRpb25hbCBlSURBUyBub2RlMRow + GAYDVQQDDBFBc3NlcnRpb24gc2lnbmluZzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB + AJ5zDYxMPRcz6AHaev1tS46Tq8sdgbGFM56uxk6c7LmMDC+HTzNX/3Q5S/YwSzgL3ue5TSw1ltOf + yMXMZ6D0+buWWcsxGEkQ8M3adKRFdQrEwafzwTA7pguq5WiHOkr4qwR7dLMome9z5cc3LRcwdOPP + gq7ahb5jM3hRqc5xkMWIuvql0NFXPzlHrjDLwy5nIWPOhL5abhVt4YsXbpbjXxFSGkDEAZ32K3EU + LNBr9FSUmJfbrVX9AU2T+BKIwiqXP8e/3UJHgPHQ0l5ljWp5P6u5+tvM21o8sUM4eArRa8BkdRsP + C92GVuASSUz2ZJ3JhAK1cSM8bnvaZVLQtTvPMAcCAwEAATANBgkqhkiG9w0BAQsFAAOCAQEAAp7z + TubWXW6YMpyLSvWBdZiiQ3X66XpSZLZJDIAkoPzEY0DSBp8I5YASIx4JTR5XJt+6MI9acgNIAYW8 + DhtRwUMVaRWEtuCrfKhGLWm5KSxnhPcD3lzRZhY4ZcA7dUlirjf6hnqo2TFEmJ9fkM+rxwy1GkDD + 7j2YDSOFmSq9/Ud9/IbIfSnRu/lO0dh7iRrmg3y0Y/+plPxYmp4AHqehP11OchTz2FGGHVsSC2Vs + IVBQI6ANZYyOlicgfEEFHA06jP9OnA0EwEFr2P+di9caZg8vfibyzxMGeuf6CY0c0eLHokBCn2W8 + vkzvWiER3pozRvCmXFjCVZfRjUunaJf2ow== + + + + MIIC+DCCAeCgAwIBAgIEXh7TbTANBgkqhkiG9w0BAQsFADA+MQswCQYDVQQGEwJB + VDENMAsGA1UECgwERUdJWjEOMAwGA1UECwwFalVuaXQxEDAOBgNVBAMMB3NpZ25p + bmcwHhcNMjAwMTE1MDg1NTA5WhcNMjkwMTE0MDg1NTA5WjA+MQswCQYDVQQGEwJB + VDENMAsGA1UECgwERUdJWjEOMAwGA1UECwwFalVuaXQxEDAOBgNVBAMMB3NpZ25p + bmcwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCUSiRjnDvPafZfhJ+L + 1wM86FKJX3VIAV/8TD9qJ6HOBkn5WwYfpheyCfRb6XVDyIGpO8qnMWAgC17Ngbmh + zj8d8HXNQ2l3uppMv24oUTfXyYhQfZWAghx0sTlRIx/ZmlnduJilx2S53Sa7ruJw + lQcBFXj9h9B8dtyegc86Sx6D9BumP1xU7+mEBk8Gv9rR5Khg0Y7qGfZWB0t4aikg + aupWveVwiGifOOSfR8czqIg9qUpMYfZiTEBTSRmN6sPiNWhd4J0GyAI9Rn5C9jz/ + sSlQrxpN+4DXzsqSU5F6gzq3yRux6wyOzDlt2birf21VPQ9HIy4YCjZXwgDWG7AO + 821pAgMBAAEwDQYJKoZIhvcNAQELBQADggEBADnwdaxUtQU6SIpYwIb2c0ljTmQi + 7ryUcUpNHtK0M0E5Mw5Ex8zwrWbNQZ2sUyc4r07M66iOIqHsYZUQlRYvVKHifDpA + r8TCgD7iGGdB3By8Ou0RaNW+03w1fwmi98CufbHCGvpv0o2KxlejoHZminNdQ79i + bN+01nhocezJQATEQlnwHLiQSjilXpZeLYDk8HbrcUXNRxezN4ChdH+uU54vf+Ux + qcj9QHcmBe1+BM8EXfqS1DbTwZl+NTCnh5OYl8fvIFSOHMBxwFrI4pyY0faxg9Uc + rCogn/oQ+mV1gnVUDaDhvvEnVGZQtrlt7heVId2BeNellVgsrcmdW8j4U9U= + + + + MIIBbjCCARSgAwIBAgIEXh7TNzAKBggqhkjOPQQDAjA/MQswCQYDVQQGEwJBVDEN + MAsGA1UECgwERUdJWjEOMAwGA1UECwwFalVuaXQxETAPBgNVBAMMCG1ldGFkYXRh + MB4XDTIwMDExNTA4NTQxNVoXDTMwMDExNDA4NTQxNVowPzELMAkGA1UEBhMCQVQx + DTALBgNVBAoMBEVHSVoxDjAMBgNVBAsMBWpVbml0MREwDwYDVQQDDAhtZXRhZGF0 + YTBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABBdBkaxt31p++aZeP3SmlWITj9SY + O4McV2ccXFsH4X4QMHuKAMUvjxPm1kdU01eTOWdiQX0GpDIBspYMZh8ZKcwwCgYI + KoZIzj0EAwIDSAAwRQIhAJ3QKlk9cd90s+i8y62fvmGF6LtfNO+JvkWqDUBeQImn + AiA2KwFtzO7STAp9MEwQGe0vt0F8mO1ttrLE+rr6YxdwGA== + + + + + urn:oasis:names:tc:SAML:2.0:nameid-format:persistent + + urn:oasis:names:tc:SAML:2.0:nameid-format:transient + + urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified + + + + + + + + + + + + + + + + + + + + diff --git a/modules/authmodule_id-austria/src/test/resources/data/idp_metadata_no_sig.xml b/modules/authmodule_id-austria/src/test/resources/data/idp_metadata_no_sig.xml new file mode 100644 index 00000000..bc55fe62 --- /dev/null +++ b/modules/authmodule_id-austria/src/test/resources/data/idp_metadata_no_sig.xml @@ -0,0 +1,46 @@ + + + + + + + MIIDMzCCAhsCBFtIcPowDQYJKoZIhvcNAQELBQAwXjELMAkGA1UEBhMCQVQxDTALBgNVBAoMBEVH +SVoxJDAiBgNVBAsMG2NlbnRyYWwgbmF0aW9uYWwgZUlEQVMgbm9kZTEaMBgGA1UEAwwRQXNzZXJ0 +aW9uIHNpZ25pbmcwHhcNMTgwNzEzMDkyOTMwWhcNMjEwNDA3MDkyOTMwWjBeMQswCQYDVQQGEwJB +VDENMAsGA1UECgwERUdJWjEkMCIGA1UECwwbY2VudHJhbCBuYXRpb25hbCBlSURBUyBub2RlMRow +GAYDVQQDDBFBc3NlcnRpb24gc2lnbmluZzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB +AJ5zDYxMPRcz6AHaev1tS46Tq8sdgbGFM56uxk6c7LmMDC+HTzNX/3Q5S/YwSzgL3ue5TSw1ltOf +yMXMZ6D0+buWWcsxGEkQ8M3adKRFdQrEwafzwTA7pguq5WiHOkr4qwR7dLMome9z5cc3LRcwdOPP +gq7ahb5jM3hRqc5xkMWIuvql0NFXPzlHrjDLwy5nIWPOhL5abhVt4YsXbpbjXxFSGkDEAZ32K3EU +LNBr9FSUmJfbrVX9AU2T+BKIwiqXP8e/3UJHgPHQ0l5ljWp5P6u5+tvM21o8sUM4eArRa8BkdRsP +C92GVuASSUz2ZJ3JhAK1cSM8bnvaZVLQtTvPMAcCAwEAATANBgkqhkiG9w0BAQsFAAOCAQEAAp7z +TubWXW6YMpyLSvWBdZiiQ3X66XpSZLZJDIAkoPzEY0DSBp8I5YASIx4JTR5XJt+6MI9acgNIAYW8 +DhtRwUMVaRWEtuCrfKhGLWm5KSxnhPcD3lzRZhY4ZcA7dUlirjf6hnqo2TFEmJ9fkM+rxwy1GkDD +7j2YDSOFmSq9/Ud9/IbIfSnRu/lO0dh7iRrmg3y0Y/+plPxYmp4AHqehP11OchTz2FGGHVsSC2Vs +IVBQI6ANZYyOlicgfEEFHA06jP9OnA0EwEFr2P+di9caZg8vfibyzxMGeuf6CY0c0eLHokBCn2W8 +vkzvWiER3pozRvCmXFjCVZfRjUunaJf2ow== + + + + urn:oasis:names:tc:SAML:2.0:nameid-format:persistent + urn:oasis:names:tc:SAML:2.0:nameid-format:transient + urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified + + + + + + + + + + + + + + + + + + + diff --git a/modules/authmodule_id-austria/src/test/resources/data/idp_metadata_no_sig2.xml b/modules/authmodule_id-austria/src/test/resources/data/idp_metadata_no_sig2.xml new file mode 100644 index 00000000..bdc176a0 --- /dev/null +++ b/modules/authmodule_id-austria/src/test/resources/data/idp_metadata_no_sig2.xml @@ -0,0 +1,46 @@ + + + + + + + MIIDMzCCAhsCBFtIcPowDQYJKoZIhvcNAQELBQAwXjELMAkGA1UEBhMCQVQxDTALBgNVBAoMBEVH +SVoxJDAiBgNVBAsMG2NlbnRyYWwgbmF0aW9uYWwgZUlEQVMgbm9kZTEaMBgGA1UEAwwRQXNzZXJ0 +aW9uIHNpZ25pbmcwHhcNMTgwNzEzMDkyOTMwWhcNMjEwNDA3MDkyOTMwWjBeMQswCQYDVQQGEwJB +VDENMAsGA1UECgwERUdJWjEkMCIGA1UECwwbY2VudHJhbCBuYXRpb25hbCBlSURBUyBub2RlMRow +GAYDVQQDDBFBc3NlcnRpb24gc2lnbmluZzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB +AJ5zDYxMPRcz6AHaev1tS46Tq8sdgbGFM56uxk6c7LmMDC+HTzNX/3Q5S/YwSzgL3ue5TSw1ltOf +yMXMZ6D0+buWWcsxGEkQ8M3adKRFdQrEwafzwTA7pguq5WiHOkr4qwR7dLMome9z5cc3LRcwdOPP +gq7ahb5jM3hRqc5xkMWIuvql0NFXPzlHrjDLwy5nIWPOhL5abhVt4YsXbpbjXxFSGkDEAZ32K3EU +LNBr9FSUmJfbrVX9AU2T+BKIwiqXP8e/3UJHgPHQ0l5ljWp5P6u5+tvM21o8sUM4eArRa8BkdRsP +C92GVuASSUz2ZJ3JhAK1cSM8bnvaZVLQtTvPMAcCAwEAATANBgkqhkiG9w0BAQsFAAOCAQEAAp7z +TubWXW6YMpyLSvWBdZiiQ3X66XpSZLZJDIAkoPzEY0DSBp8I5YASIx4JTR5XJt+6MI9acgNIAYW8 +DhtRwUMVaRWEtuCrfKhGLWm5KSxnhPcD3lzRZhY4ZcA7dUlirjf6hnqo2TFEmJ9fkM+rxwy1GkDD +7j2YDSOFmSq9/Ud9/IbIfSnRu/lO0dh7iRrmg3y0Y/+plPxYmp4AHqehP11OchTz2FGGHVsSC2Vs +IVBQI6ANZYyOlicgfEEFHA06jP9OnA0EwEFr2P+di9caZg8vfibyzxMGeuf6CY0c0eLHokBCn2W8 +vkzvWiER3pozRvCmXFjCVZfRjUunaJf2ow== + + + + urn:oasis:names:tc:SAML:2.0:nameid-format:persistent + urn:oasis:names:tc:SAML:2.0:nameid-format:transient + urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified + + + + + + + + + + + + + + + + + + + diff --git a/modules/authmodule_id-austria/src/test/resources/data/idp_metadata_sig_notvalid.xml b/modules/authmodule_id-austria/src/test/resources/data/idp_metadata_sig_notvalid.xml new file mode 100644 index 00000000..86665a9c --- /dev/null +++ b/modules/authmodule_id-austria/src/test/resources/data/idp_metadata_sig_notvalid.xml @@ -0,0 +1,84 @@ + + + + + + + + + + + + + e6DiHa9scuvxJFBUipZ8PQcD4kAkmSIDZgZV+0/7glg= + + + Czr2EwhK/0ZUZ5blQpJfNoOFEscLlxlmHPjmOJUIsxlB2pUn+ApULrjVpR1ViUcGZ0PVi2KChSNoSn09YKjtgPFBiSY010VYdaACgqluxUt6AwESObaqcyHVBzMDUr/g6jkRFEJV4vqnZQQDdDfTH4MXNqunORegS1saBHw4nJSOX4YfoVmIuT5uOlRrxvoG7srnGShvF7DmvIHBUBF5Tq9FyeSgwTM8udxl8Yl9FB2pREuR83CcbgjPrYKtzi6TiSfrWkcD0L5BvmMxN/BdaGDAorxYOnk41sWDJjrkY8C2SC1YDy6XT4SM06uFwstUrRn8QPg1hfbLHAyQNoaR8ecgapk5DkxmbATMcGY+SM4yQWkBdYT7GtufNmF8sIVaL6JOOTKAE9qqX/1N6N4zOPmm8rpIqVEQZtQ5usN/ubxbxLxUoTdDeo8RwkktW6zQ3Zv9+Iyf0DASYmK1IxN+fMw/qyeVy9r6o15ITHTqTmT/7BidKZ58m4HxIK52E3DU + + + MIIEFTCCAn0CBFtIcMwwDQYJKoZIhvcNAQELBQAwTzELMAkGA1UEBhMCQVQxDTALBgNVBAoMBEVH +SVoxMTAvBgNVBAMMKG5hdGlvbmFsIGNlbnRyYWwgZUlEQVMgbm9kZSAtIHRlc3RzeXN0ZW0wHhcN +MTgwNzEzMDkyODQ0WhcNMjEwNDA3MDkyODQ0WjBPMQswCQYDVQQGEwJBVDENMAsGA1UECgwERUdJ +WjExMC8GA1UEAwwobmF0aW9uYWwgY2VudHJhbCBlSURBUyBub2RlIC0gdGVzdHN5c3RlbTCCAaIw +DQYJKoZIhvcNAQEBBQADggGPADCCAYoCggGBALK4bdf5OremKkj0+xCjU0eN7RUd1A2VqoGnvFUs +t7xjLQ1PspHiDf9Pm2cwOIJabSnuZ01hYAGz9X+lU3Z3fwhVc+tEsuzsaAml/LPw3i3+ppoSTJDM +iDvhCoUKTzJ8HBQj2gTvXNlqPljyGneuCJ+uBMr7Okq/XjMTJj2xzvutrHS3qIO+/w+OkY967QLV +RXh0bdFqYqnyAnlYcWJPIwjanOJtE2difPYqers7ZW1F9djP0+IZRoyaook5rpLYvuQTHuvulgIE +3zGlTuOx3sk8zMyInMndqi75Eh+ROnndSZE7gN3u5CfFpuO5pxFa2jj1h/AnR39Tg8/sU+Se+AwH +rNvee3IWhxk5LkelYevfeCQos7Dv2ASE9XMCCs7FoE47w8fDalECh09MFKDiotpklbq3OrPg9NQ4 +D//k0GXlW5jYUKP/Wq/+suAI6mfhSnNkjOGMcMlzNTmwxGD/v7Py6OVA+YcJQsqYalLrqbvT2tXV +mYBVO3oqafg+kfevfwIDAQABMA0GCSqGSIb3DQEBCwUAA4IBgQCioM8k0EEBFtY4QyxOYFufPDLw +9PNPct01ltnTVjNEEt/L6/8zYlDwrDeULEkJS7mV9zV3657NPQ5IPT/Ib93Uk/RPi0iOA2CGWIMa +DQIODN3BUYr+zPUqhbKS6OWOhTgV8GiRCUbxrT1uc1AiacP63pga3TJX8k8WFnfW+Dqm2MfWWlxr +4X2YB9VUW55X5sBNy035jYhEpp8NCK/fTAhoEQNCG+rm3T9qhT6YyOnbW2kXU747+ZwXT2qA5o4y +a/9+6dDc+LUlHCEm4X7c6bcGvCfNezB4k56FzbAJlOLf2VDGzvEQBf0hsB+kElezm1VBlEkZ4Mjz +pBpHBMoR21SwTpcvrbR4ig0Bk1eEHNK44sw0F32K5yww3gnJftMIZtPhjhk8UdG2/H6vs9s/to2V +j4V6wN4o79RTULoQ8RjL6MPWEWzwOvOZXJAo2XJEECvDivSjIJvNC0lfrK3zI3LH3c1JR6q2EfeC +Z50wTJMFoChSaqunJQXKo81g6wNhP00= + + + + + + + + MIIDMzCCAhsCBFtIcPowDQYJKoZIhvcNAQELBQAwXjELMAkGA1UEBhMCQVQxDTALBgNVBAoMBEVH +SVoxJDAiBgNVBAsMG2NlbnRyYWwgbmF0aW9uYWwgZUlEQVMgbm9kZTEaMBgGA1UEAwwRQXNzZXJ0 +aW9uIHNpZ25pbmcwHhcNMTgwNzEzMDkyOTMwWhcNMjEwNDA3MDkyOTMwWjBeMQswCQYDVQQGEwJB +VDENMAsGA1UECgwERUdJWjEkMCIGA1UECwwbY2VudHJhbCBuYXRpb25hbCBlSURBUyBub2RlMRow +GAYDVQQDDBFBc3NlcnRpb24gc2lnbmluZzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB +AJ5zDYxMPRcz6AHaev1tS46Tq8sdgbGFM56uxk6c7LmMDC+HTzNX/3Q5S/YwSzgL3ue5TSw1ltOf +yMXMZ6D0+buWWcsxGEkQ8M3adKRFdQrEwafzwTA7pguq5WiHOkr4qwR7dLMome9z5cc3LRcwdOPP +gq7ahb5jM3hRqc5xkMWIuvql0NFXPzlHrjDLwy5nIWPOhL5abhVt4YsXbpbjXxFSGkDEAZ32K3EU +LNBr9FSUmJfbrVX9AU2T+BKIwiqXP8e/3UJHgPHQ0l5ljWp5P6u5+tvM21o8sUM4eArRa8BkdRsP +C92GVuASSUz2ZJ3JhAK1cSM8bnvaZVLQtTvPMAcCAwEAATANBgkqhkiG9w0BAQsFAAOCAQEAAp7z +TubWXW6YMpyLSvWBdZiiQ3X66XpSZLZJDIAkoPzEY0DSBp8I5YASIx4JTR5XJt+6MI9acgNIAYW8 +DhtRwUMVaRWEtuCrfKhGLWm5KSxnhPcD3lzRZhY4ZcA7dUlirjf6hnqo2TFEmJ9fkM+rxwy1GkDD +7j2YDSOFmSq9/Ud9/IbIfSnRu/lO0dh7iRrmg3y0Y/+plPxYmp4AHqehP11OchTz2FGGHVsSC2Vs +IVBQI6ANZYyOlicgfEEFHA06jP9OnA0EwEFr2P+di9caZg8vfibyzxMGeuf6CY0c0eLHokBCn2W8 +vkzvWiER3pozRvCmXFjCVZfRjUunaJf2ow== + + + + urn:oasis:names:tc:SAML:2.0:nameid-format:persistent + urn:oasis:names:tc:SAML:2.0:nameid-format:transient + urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified + + + + + + + + + + + + + + + + + + + diff --git a/modules/authmodule_id-austria/src/test/resources/data/idp_metadata_sig_valid_wrong_alg.xml b/modules/authmodule_id-austria/src/test/resources/data/idp_metadata_sig_valid_wrong_alg.xml new file mode 100644 index 00000000..2187aa5f --- /dev/null +++ b/modules/authmodule_id-austria/src/test/resources/data/idp_metadata_sig_valid_wrong_alg.xml @@ -0,0 +1,74 @@ + + dhkHkgZ1OOHG0nYWiRXrpZhIAx41103CG6DKDbBra8o=AkxnEu9g3QgYC0JwuJXMYFrnNn6UMtrbtVn5YzkKBXxyYqZui4pEi/TRSM9r7Gt+ +4UqHrJVkYMbbuoO2kpiDnluPG+vHYzYFvF0agQ+gfGjpVQNRORN0FU7JPX+KPjpr +sMU8wVZITSPU0GBBccvzrcpq7DQt0VbV5U7/Vq3KM/fop4ytAkUbTltUj/XxvAd1 +XdhB/zyeTTR2dafJ6Z2CKyM7MMmxwXYD1NrPGciPvTJ9ASHAT0lJM1dxrRNbeAja +KTrNVj78MhSluRm5g7N1pMZzgMSpqN66AUg8pkSTvcRaNImPzYDcMQzHl2Tr362M +RudjSgaEljK98TbBdgLFTg==MIIEqzCCBBSgAwIBAgIHANux81oNezANBgkqhkiG9w0BAQUFADBAMSIwIAYDVQQD +ExlJQUlLIFRlc3QgSW50ZXJtZWRpYXRlIENBMQ0wCwYDVQQKEwRJQUlLMQswCQYD +VQQGEwJBVDAeFw0xMzA5MjcwNTMzMzdaFw0yMzA5MjcwNTMzMzdaMIHkMQswCQYD +VQQGEwJBVDENMAsGA1UEBxMER3JhejEmMCQGA1UEChMdR3JheiBVbml2ZXJzaXR5 +IG9mIFRlY2hub2xvZ3kxSDBGBgNVBAsTP0luc3RpdHV0ZSBmb3IgQXBwbGllZCBJ +bmZvcm1hdGlvbiBQcm9jZXNzaW5nIGFuZCBDb21tdW5pY2F0aW9uczEUMBIGA1UE +BBMLTU9BLVNTIFRlc3QxGDAWBgNVBCoTD0VHSVogVGVzdHBvcnRhbDEkMCIGA1UE +AxMbRUdJWiBUZXN0cG9ydGFsIE1PQS1TUyBUZXN0MIIBIjANBgkqhkiG9w0BAQEF +AAOCAQ8AMIIBCgKCAQEAuDjOyf+mY+oQL2FQzzuaiC8C23vVKbq/n2Zi7BqSibZH +mtqMJfmj4pT+hWSNHvVvWsaxFcx4KeNqdCMzwnw1r4P3Sf+2o5uFku5KHEMLMokR +yYQG9VqY/KkB94ye7Pv6zT8gvKqxGFg96UamECep4swPaSZrA8AOER5WAtyGDzKI +Tz+a5zfFaTXDoba7f98PCWR96yKiFjVOhzp38WVz4VJgz+b8ZSY7Xsv5Kn7DXjOL +STX4MevFLki3rFPup3+4vGToaMBW3PEj67HXBdqR855Le6+E6rVxORqsXqlVwhsI +6nuS0CO2LWYmBNR1IB0mXteeYH/HfxvuZc+7yDjdPQIDAQABo4IBhDCCAYAwDgYD +VR0PAQH/BAQDAgbAMAwGA1UdEwEB/wQCMAAwHQYDVR0OBBYEFEmcH6VY4BG1EAGB +TLoNR9vH/g6yMFAGA1UdHwRJMEcwRaBDoEGGP2h0dHA6Ly9jYS5pYWlrLnR1Z3Jh +ei5hdC9jYXBzby9jcmxzL0lBSUtUZXN0X0ludGVybWVkaWF0ZUNBLmNybDCBqgYI +KwYBBQUHAQEEgZ0wgZowSgYIKwYBBQUHMAGGPmh0dHA6Ly9jYS5pYWlrLnR1Z3Jh +ei5hdC9jYXBzby9PQ1NQP2NhPUlBSUtUZXN0X0ludGVybWVkaWF0ZUNBMEwGCCsG +AQUFBzAChkBodHRwOi8vY2EuaWFpay50dWdyYXouYXQvY2Fwc28vY2VydHMvSUFJ +S1Rlc3RfSW50ZXJtZWRpYXRlQ0EuY2VyMCEGA1UdEQQaMBiBFnRob21hcy5sZW56 +QGVnaXouZ3YuYXQwHwYDVR0jBBgwFoAUaKJeEdreL4BrRES/jfplNoEkp28wDQYJ +KoZIhvcNAQEFBQADgYEAlFGjUxXLs7SAT8NtXSrv2WrjlklaRnHTFHLQwyVo8JWb +gvRkHHDUv2o8ofXUY2R2WJ38dxeDoccgbXrJb/Qhi8IY7YhCwv/TuIZDisyAqo8W +ORKSip/6HWlGCSR/Vgoet1GtCmF0FoUxFUIGSAuQ2yyt4fIzt5GJrU1X5ujjI1w= + + + + MIIDMzCCAhsCBFtIcPowDQYJKoZIhvcNAQELBQAwXjELMAkGA1UEBhMCQVQxDTALBgNVBAoMBEVH +SVoxJDAiBgNVBAsMG2NlbnRyYWwgbmF0aW9uYWwgZUlEQVMgbm9kZTEaMBgGA1UEAwwRQXNzZXJ0 +aW9uIHNpZ25pbmcwHhcNMTgwNzEzMDkyOTMwWhcNMjEwNDA3MDkyOTMwWjBeMQswCQYDVQQGEwJB +VDENMAsGA1UECgwERUdJWjEkMCIGA1UECwwbY2VudHJhbCBuYXRpb25hbCBlSURBUyBub2RlMRow +GAYDVQQDDBFBc3NlcnRpb24gc2lnbmluZzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB +AJ5zDYxMPRcz6AHaev1tS46Tq8sdgbGFM56uxk6c7LmMDC+HTzNX/3Q5S/YwSzgL3ue5TSw1ltOf +yMXMZ6D0+buWWcsxGEkQ8M3adKRFdQrEwafzwTA7pguq5WiHOkr4qwR7dLMome9z5cc3LRcwdOPP +gq7ahb5jM3hRqc5xkMWIuvql0NFXPzlHrjDLwy5nIWPOhL5abhVt4YsXbpbjXxFSGkDEAZ32K3EU +LNBr9FSUmJfbrVX9AU2T+BKIwiqXP8e/3UJHgPHQ0l5ljWp5P6u5+tvM21o8sUM4eArRa8BkdRsP +C92GVuASSUz2ZJ3JhAK1cSM8bnvaZVLQtTvPMAcCAwEAATANBgkqhkiG9w0BAQsFAAOCAQEAAp7z +TubWXW6YMpyLSvWBdZiiQ3X66XpSZLZJDIAkoPzEY0DSBp8I5YASIx4JTR5XJt+6MI9acgNIAYW8 +DhtRwUMVaRWEtuCrfKhGLWm5KSxnhPcD3lzRZhY4ZcA7dUlirjf6hnqo2TFEmJ9fkM+rxwy1GkDD +7j2YDSOFmSq9/Ud9/IbIfSnRu/lO0dh7iRrmg3y0Y/+plPxYmp4AHqehP11OchTz2FGGHVsSC2Vs +IVBQI6ANZYyOlicgfEEFHA06jP9OnA0EwEFr2P+di9caZg8vfibyzxMGeuf6CY0c0eLHokBCn2W8 +vkzvWiER3pozRvCmXFjCVZfRjUunaJf2ow== + + + + urn:oasis:names:tc:SAML:2.0:nameid-format:persistent + urn:oasis:names:tc:SAML:2.0:nameid-format:transient + urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/modules/authmodule_id-austria/src/test/resources/data/junit_keystore_metadata.crt b/modules/authmodule_id-austria/src/test/resources/data/junit_keystore_metadata.crt new file mode 100644 index 00000000..35831d03 --- /dev/null +++ b/modules/authmodule_id-austria/src/test/resources/data/junit_keystore_metadata.crt @@ -0,0 +1,11 @@ +-----BEGIN CERTIFICATE----- +MIIBbjCCARSgAwIBAgIEXh7TNzAKBggqhkjOPQQDAjA/MQswCQYDVQQGEwJBVDEN +MAsGA1UECgwERUdJWjEOMAwGA1UECwwFalVuaXQxETAPBgNVBAMMCG1ldGFkYXRh +MB4XDTIwMDExNTA4NTQxNVoXDTMwMDExNDA4NTQxNVowPzELMAkGA1UEBhMCQVQx +DTALBgNVBAoMBEVHSVoxDjAMBgNVBAsMBWpVbml0MREwDwYDVQQDDAhtZXRhZGF0 +YTBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABBdBkaxt31p++aZeP3SmlWITj9SY +O4McV2ccXFsH4X4QMHuKAMUvjxPm1kdU01eTOWdiQX0GpDIBspYMZh8ZKcwwCgYI +KoZIzj0EAwIDSAAwRQIhAJ3QKlk9cd90s+i8y62fvmGF6LtfNO+JvkWqDUBeQImn +AiA2KwFtzO7STAp9MEwQGe0vt0F8mO1ttrLE+rr6YxdwGA== +-----END CERTIFICATE----- + diff --git a/modules/authmodule_id-austria/src/test/resources/data/junit_keystore_signing.crt b/modules/authmodule_id-austria/src/test/resources/data/junit_keystore_signing.crt new file mode 100644 index 00000000..35a82125 --- /dev/null +++ b/modules/authmodule_id-austria/src/test/resources/data/junit_keystore_signing.crt @@ -0,0 +1,18 @@ +-----BEGIN CERTIFICATE----- +MIIC+DCCAeCgAwIBAgIEXh7TbTANBgkqhkiG9w0BAQsFADA+MQswCQYDVQQGEwJB +VDENMAsGA1UECgwERUdJWjEOMAwGA1UECwwFalVuaXQxEDAOBgNVBAMMB3NpZ25p +bmcwHhcNMjAwMTE1MDg1NTA5WhcNMjkwMTE0MDg1NTA5WjA+MQswCQYDVQQGEwJB +VDENMAsGA1UECgwERUdJWjEOMAwGA1UECwwFalVuaXQxEDAOBgNVBAMMB3NpZ25p +bmcwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCUSiRjnDvPafZfhJ+L +1wM86FKJX3VIAV/8TD9qJ6HOBkn5WwYfpheyCfRb6XVDyIGpO8qnMWAgC17Ngbmh +zj8d8HXNQ2l3uppMv24oUTfXyYhQfZWAghx0sTlRIx/ZmlnduJilx2S53Sa7ruJw +lQcBFXj9h9B8dtyegc86Sx6D9BumP1xU7+mEBk8Gv9rR5Khg0Y7qGfZWB0t4aikg +aupWveVwiGifOOSfR8czqIg9qUpMYfZiTEBTSRmN6sPiNWhd4J0GyAI9Rn5C9jz/ +sSlQrxpN+4DXzsqSU5F6gzq3yRux6wyOzDlt2birf21VPQ9HIy4YCjZXwgDWG7AO +821pAgMBAAEwDQYJKoZIhvcNAQELBQADggEBADnwdaxUtQU6SIpYwIb2c0ljTmQi +7ryUcUpNHtK0M0E5Mw5Ex8zwrWbNQZ2sUyc4r07M66iOIqHsYZUQlRYvVKHifDpA +r8TCgD7iGGdB3By8Ou0RaNW+03w1fwmi98CufbHCGvpv0o2KxlejoHZminNdQ79i +bN+01nhocezJQATEQlnwHLiQSjilXpZeLYDk8HbrcUXNRxezN4ChdH+uU54vf+Ux +qcj9QHcmBe1+BM8EXfqS1DbTwZl+NTCnh5OYl8fvIFSOHMBxwFrI4pyY0faxg9Uc +rCogn/oQ+mV1gnVUDaDhvvEnVGZQtrlt7heVId2BeNellVgsrcmdW8j4U9U= +-----END CERTIFICATE----- diff --git a/modules/authmodule_id-austria/src/test/resources/data/moa_sig_signing.crt b/modules/authmodule_id-austria/src/test/resources/data/moa_sig_signing.crt new file mode 100644 index 00000000..fda99f2b --- /dev/null +++ b/modules/authmodule_id-austria/src/test/resources/data/moa_sig_signing.crt @@ -0,0 +1,27 @@ +-----BEGIN CERTIFICATE----- +MIIEqzCCBBSgAwIBAgIHANux81oNezANBgkqhkiG9w0BAQUFADBAMSIwIAYDVQQD +ExlJQUlLIFRlc3QgSW50ZXJtZWRpYXRlIENBMQ0wCwYDVQQKEwRJQUlLMQswCQYD +VQQGEwJBVDAeFw0xMzA5MjcwNTMzMzdaFw0yMzA5MjcwNTMzMzdaMIHkMQswCQYD +VQQGEwJBVDENMAsGA1UEBxMER3JhejEmMCQGA1UEChMdR3JheiBVbml2ZXJzaXR5 +IG9mIFRlY2hub2xvZ3kxSDBGBgNVBAsTP0luc3RpdHV0ZSBmb3IgQXBwbGllZCBJ +bmZvcm1hdGlvbiBQcm9jZXNzaW5nIGFuZCBDb21tdW5pY2F0aW9uczEUMBIGA1UE +BBMLTU9BLVNTIFRlc3QxGDAWBgNVBCoTD0VHSVogVGVzdHBvcnRhbDEkMCIGA1UE +AxMbRUdJWiBUZXN0cG9ydGFsIE1PQS1TUyBUZXN0MIIBIjANBgkqhkiG9w0BAQEF +AAOCAQ8AMIIBCgKCAQEAuDjOyf+mY+oQL2FQzzuaiC8C23vVKbq/n2Zi7BqSibZH +mtqMJfmj4pT+hWSNHvVvWsaxFcx4KeNqdCMzwnw1r4P3Sf+2o5uFku5KHEMLMokR +yYQG9VqY/KkB94ye7Pv6zT8gvKqxGFg96UamECep4swPaSZrA8AOER5WAtyGDzKI +Tz+a5zfFaTXDoba7f98PCWR96yKiFjVOhzp38WVz4VJgz+b8ZSY7Xsv5Kn7DXjOL +STX4MevFLki3rFPup3+4vGToaMBW3PEj67HXBdqR855Le6+E6rVxORqsXqlVwhsI +6nuS0CO2LWYmBNR1IB0mXteeYH/HfxvuZc+7yDjdPQIDAQABo4IBhDCCAYAwDgYD +VR0PAQH/BAQDAgbAMAwGA1UdEwEB/wQCMAAwHQYDVR0OBBYEFEmcH6VY4BG1EAGB +TLoNR9vH/g6yMFAGA1UdHwRJMEcwRaBDoEGGP2h0dHA6Ly9jYS5pYWlrLnR1Z3Jh +ei5hdC9jYXBzby9jcmxzL0lBSUtUZXN0X0ludGVybWVkaWF0ZUNBLmNybDCBqgYI +KwYBBQUHAQEEgZ0wgZowSgYIKwYBBQUHMAGGPmh0dHA6Ly9jYS5pYWlrLnR1Z3Jh +ei5hdC9jYXBzby9PQ1NQP2NhPUlBSUtUZXN0X0ludGVybWVkaWF0ZUNBMEwGCCsG +AQUFBzAChkBodHRwOi8vY2EuaWFpay50dWdyYXouYXQvY2Fwc28vY2VydHMvSUFJ +S1Rlc3RfSW50ZXJtZWRpYXRlQ0EuY2VyMCEGA1UdEQQaMBiBFnRob21hcy5sZW56 +QGVnaXouZ3YuYXQwHwYDVR0jBBgwFoAUaKJeEdreL4BrRES/jfplNoEkp28wDQYJ +KoZIhvcNAQEFBQADgYEAlFGjUxXLs7SAT8NtXSrv2WrjlklaRnHTFHLQwyVo8JWb +gvRkHHDUv2o8ofXUY2R2WJ38dxeDoccgbXrJb/Qhi8IY7YhCwv/TuIZDisyAqo8W +ORKSip/6HWlGCSR/Vgoet1GtCmF0FoUxFUIGSAuQ2yyt4fIzt5GJrU1X5ujjI1w= +-----END CERTIFICATE----- diff --git a/modules/authmodule_id-austria/src/test/resources/data/pvp_postbinding_template.html b/modules/authmodule_id-austria/src/test/resources/data/pvp_postbinding_template.html new file mode 100644 index 00000000..5c65e25a --- /dev/null +++ b/modules/authmodule_id-austria/src/test/resources/data/pvp_postbinding_template.html @@ -0,0 +1,3 @@ +#if($RelayState)RelayState=${RelayState}#end +#if($SAMLRequest)SAMLRequest=${SAMLRequest}#end +#if($SAMLResponse)SAMLResponse=${SAMLResponse}#end \ No newline at end of file diff --git a/modules/authmodule_id-austria/src/test/resources/data/sp_metadata_junit.xml b/modules/authmodule_id-austria/src/test/resources/data/sp_metadata_junit.xml new file mode 100644 index 00000000..32e90604 --- /dev/null +++ b/modules/authmodule_id-austria/src/test/resources/data/sp_metadata_junit.xml @@ -0,0 +1,66 @@ + + + + + + + MIIC+DCCAeCgAwIBAgIEXh7TbTANBgkqhkiG9w0BAQsFADA+MQswCQYDVQQGEwJBVDENMAsGA1UE +CgwERUdJWjEOMAwGA1UECwwFalVuaXQxEDAOBgNVBAMMB3NpZ25pbmcwHhcNMjAwMTE1MDg1NTA5 +WhcNMjkwMTE0MDg1NTA5WjA+MQswCQYDVQQGEwJBVDENMAsGA1UECgwERUdJWjEOMAwGA1UECwwF +alVuaXQxEDAOBgNVBAMMB3NpZ25pbmcwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCU +SiRjnDvPafZfhJ+L1wM86FKJX3VIAV/8TD9qJ6HOBkn5WwYfpheyCfRb6XVDyIGpO8qnMWAgC17N +gbmhzj8d8HXNQ2l3uppMv24oUTfXyYhQfZWAghx0sTlRIx/ZmlnduJilx2S53Sa7ruJwlQcBFXj9 +h9B8dtyegc86Sx6D9BumP1xU7+mEBk8Gv9rR5Khg0Y7qGfZWB0t4aikgaupWveVwiGifOOSfR8cz +qIg9qUpMYfZiTEBTSRmN6sPiNWhd4J0GyAI9Rn5C9jz/sSlQrxpN+4DXzsqSU5F6gzq3yRux6wyO +zDlt2birf21VPQ9HIy4YCjZXwgDWG7AO821pAgMBAAEwDQYJKoZIhvcNAQELBQADggEBADnwdaxU +tQU6SIpYwIb2c0ljTmQi7ryUcUpNHtK0M0E5Mw5Ex8zwrWbNQZ2sUyc4r07M66iOIqHsYZUQlRYv +VKHifDpAr8TCgD7iGGdB3By8Ou0RaNW+03w1fwmi98CufbHCGvpv0o2KxlejoHZminNdQ79ibN+0 +1nhocezJQATEQlnwHLiQSjilXpZeLYDk8HbrcUXNRxezN4ChdH+uU54vf+Uxqcj9QHcmBe1+BM8E +XfqS1DbTwZl+NTCnh5OYl8fvIFSOHMBxwFrI4pyY0faxg9UcrCogn/oQ+mV1gnVUDaDhvvEnVGZQ +trlt7heVId2BeNellVgsrcmdW8j4U9U= + + + + + + + MIIDKzCCAhMCBFrxKO4wDQYJKoZIhvcNAQELBQAwWjELMAkGA1UEBhMCQVQxDTALBgNVBAoMBEVH +SVoxGDAWBgNVBAsMD2RlbW8uZWdpei5ndi5hdDEiMCAGA1UEAwwZTU9BLUlEIElEUCAoVGVzdC1W +ZXJzaW9uKTAeFw0xODA1MDgwNDM0NTRaFw0yMTAxMzEwNDM0NTRaMFoxCzAJBgNVBAYTAkFUMQ0w +CwYDVQQKDARFR0laMRgwFgYDVQQLDA9kZW1vLmVnaXouZ3YuYXQxIjAgBgNVBAMMGU1PQS1JRCBJ +RFAgKFRlc3QtVmVyc2lvbikwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCaFnqoaYoq +UptenemC6FiVDg5F2hEjpjix8+ow6/6QhUl2cPOS0uwZHaIvwT/RVbJ9CPdil6+11qaCPfZ+FoY+ +M+ke7TRd2RS1DqFbe1KC0imEnwemyLQrYe5Pm7DNcaY/kHTTq+k0eeGbYH0U/Iopyi0VuN5OWl4F +Vg45pf7knhXkaimItdjnCXnKcYM91mmltCf6TDgUrz7US7PmgvinnhfBgdITAT4GRr4ehliT+/jt +1OzHEyWRHanBGIpXNeZNqxgnpnGtaDh4JZuYR8qfH+GRK6dtW2ziej6rGIiUElGVCkXsohgxMNzq +nWeD9JT8+yyp1XZlyQf+IxhhESQLAgMBAAEwDQYJKoZIhvcNAQELBQADggEBAIFejAFQepaEl/kC +VLvidMR+MXq5LCGHthUiI6eDTQZ+H7lZdHlj547XwEdX15b6Md3h7eSJ4hwlfV4go/0FaoLPzvVq +itwtYY5htywB3B6ZV34Eyi6C59Gl34XrV8CWxH4KKwLsVAjAy+/p/Xh0q2pzSBkeOChzBMBkjmyc +2Ue4MEKdL9guzp6+Yc/HL/phHAKYapkVyFwvsdqWOgyRzxAHINko8ExImMMB3xB5a52kfqLcui5O +fzEhjwLFJaGBMmFCmFGGOUwtIvl/6ZQ2LLzOE9+giVK9WsIgH11Pu+ejPFAbXf8cf4oWhbAfTkiy +4jpXrp77JXFRSDWddb0yePc= + + + + urn:oasis:names:tc:SAML:2.0:nameid-format:persistent + + + + Default Service + + + + + + + + + + + + + + + + + diff --git a/modules/authmodule_id-austria/src/test/resources/spring/SpringTest-context_basic_mapConfig.xml b/modules/authmodule_id-austria/src/test/resources/spring/SpringTest-context_basic_mapConfig.xml new file mode 100644 index 00000000..fe9ff441 --- /dev/null +++ b/modules/authmodule_id-austria/src/test/resources/spring/SpringTest-context_basic_mapConfig.xml @@ -0,0 +1,20 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/modules/authmodule_id-austria/src/test/resources/spring/SpringTest-context_basic_test.xml b/modules/authmodule_id-austria/src/test/resources/spring/SpringTest-context_basic_test.xml new file mode 100644 index 00000000..99778839 --- /dev/null +++ b/modules/authmodule_id-austria/src/test/resources/spring/SpringTest-context_basic_test.xml @@ -0,0 +1,32 @@ + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/modules/authmodule_id-austria/src/test/resources/spring/SpringTest-context_lazy.xml b/modules/authmodule_id-austria/src/test/resources/spring/SpringTest-context_lazy.xml new file mode 100644 index 00000000..5360960b --- /dev/null +++ b/modules/authmodule_id-austria/src/test/resources/spring/SpringTest-context_lazy.xml @@ -0,0 +1,24 @@ + + + + + + + + + + + + diff --git a/modules/core_common_lib/checks/spotbugs-exclude.xml b/modules/core_common_lib/checks/spotbugs-exclude.xml new file mode 100644 index 00000000..9700a0c0 --- /dev/null +++ b/modules/core_common_lib/checks/spotbugs-exclude.xml @@ -0,0 +1,20 @@ + + + + + + + + + + + + + + + + + + + + diff --git a/modules/core_common_lib/pom.xml b/modules/core_common_lib/pom.xml new file mode 100644 index 00000000..a27c20e3 --- /dev/null +++ b/modules/core_common_lib/pom.xml @@ -0,0 +1,106 @@ + + + 4.0.0 + + at.asitplus.eidas.ms_specific + modules + 1.2.4-SNAPSHOT + + core_common_lib + ms_specific_common_lib + jar + + http://maven.apache.org + + UTF-8 + + + + at.gv.egiz.eaaf + eaaf-core + + + org.springframework + spring-webmvc + + + javax.validation + validation-api + + + + javax.servlet + javax.servlet-api + provided + + + + + junit + junit + test + + + org.springframework + spring-test + test + + + at.gv.egiz.eaaf + eaaf_core_utils + test + test-jar + + + at.gv.egiz.eaaf + eaaf-core + test + test-jar + + + + + + core_common_lib + + + + org.apache.maven.plugins + maven-compiler-plugin + + 1.8 + 1.8 + + + + + + maven-surefire-plugin + + 1 + + + + org.apache.maven.surefire + surefire-junit47 + ${surefire.version} + + + + + + com.github.spotbugs + spotbugs-maven-plugin + ${spotbugs-maven-plugin.version} + + checks/spotbugs-exclude.xml + + + + + + + diff --git a/modules/core_common_lib/src/main/java/at/asitplus/eidas/specific/core/MsConnectorEventCodes.java b/modules/core_common_lib/src/main/java/at/asitplus/eidas/specific/core/MsConnectorEventCodes.java new file mode 100644 index 00000000..d15cf77c --- /dev/null +++ b/modules/core_common_lib/src/main/java/at/asitplus/eidas/specific/core/MsConnectorEventCodes.java @@ -0,0 +1,52 @@ +/* + * Copyright 2018 A-SIT Plus GmbH + * AT-specific eIDAS Connector has been developed in a cooperation between EGIZ, + * A-SIT Plus GmbH, A-SIT, and Graz University of Technology. + * + * Licensed under the EUPL, Version 1.2 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "License"); + * You may not use this work except in compliance with the License. + * You may obtain a copy of the License at: + * https://joinup.ec.europa.eu/news/understanding-eupl-v12 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + */ + +package at.asitplus.eidas.specific.core; + +public class MsConnectorEventCodes { + + public static final int STARTING_COUNTRY_SELECTION = 4100; + public static final int COUNTRY_SELECTED = 4101; + + public static final int PROCESS_STOPPED_BY_USER = 4102; + + public static final int EIDAS_NODE_CONNECTED = 6101; + public static final int RESPONSE_FROM_EIDAS_NODE = 6102; + public static final int RESPONSE_FROM_EIDAS_NODE_VALID = 6103; + public static final int RESPONSE_FROM_EIDAS_NODE_NOT_VALID = 6104; + public static final int RESPONSE_FROM_EIDAS_MDSDATA = 6105; + + public static final int SZR_IDL_RECEIVED = 6200; + public static final int SZR_BPK_RECEIVED = 6201; + public static final int SZR_VSZ_RECEIVED = 6202; + public static final int SZR_EIDASBIND_RECEIVED = 6203; + public static final int TECH_AUCHBLOCK_CREATED = 6204; + + public static final int SZR_ERNB_EIDAS_RAW_ID = 6210; + public static final int SZR_ERNB_EIDAS_ERNB_ID = 6211; + + + private MsConnectorEventCodes() { + // hidden constructor for class with static values only. + } +} diff --git a/modules/core_common_lib/src/main/java/at/asitplus/eidas/specific/core/MsEidasNodeConstants.java b/modules/core_common_lib/src/main/java/at/asitplus/eidas/specific/core/MsEidasNodeConstants.java new file mode 100644 index 00000000..ecf5cf67 --- /dev/null +++ b/modules/core_common_lib/src/main/java/at/asitplus/eidas/specific/core/MsEidasNodeConstants.java @@ -0,0 +1,229 @@ +/* + * Copyright 2018 A-SIT Plus GmbH + * AT-specific eIDAS Connector has been developed in a cooperation between EGIZ, + * A-SIT Plus GmbH, A-SIT, and Graz University of Technology. + * + * Licensed under the EUPL, Version 1.2 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "License"); + * You may not use this work except in compliance with the License. + * You may obtain a copy of the License at: + * https://joinup.ec.europa.eu/news/understanding-eupl-v12 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. +*/ + +package at.asitplus.eidas.specific.core; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; + +import at.gv.egiz.eaaf.core.api.data.EaafConfigConstants; +import at.gv.egiz.eaaf.core.api.data.PvpAttributeDefinitions; +import at.gv.egiz.eaaf.core.impl.data.Triple; +import at.gv.egiz.eaaf.core.impl.idp.auth.builder.AbstractAuthenticationDataBuilder; + +public class MsEidasNodeConstants { + // ************ configuration properties ************ + public static final String PROP_CONFIG_APPLICATION_PREFIX = "eidas.ms."; + public static final String PROP_CONFIG_APPLICATION_PUBLIC_URL_PREFIX = "context.url.prefix"; + public static final String PROP_CONFIG_APPLICATION_PUBLIC_URL_REQUEST_VALIDATION = + "context.url.request.validation"; + public static final String PROP_CONFIG_REVISIONLOG_LOG_IP_ADDRESS_OF_USER = + "revisionlog.logIPAddressOfUser"; + public static final String PROP_CONFIG_REVISIONLOG_WRITE_MDS_INTO_REVISION_LOG = + "revisionlog.write.MDS.into.revisionlog"; + public static final String PROP_CONFIG_TECHNICALLOG_WRITE_MDS_INTO_TECH_LOG = + "technicallog.write.MDS.into.techlog"; + + public static final String PROP_CONFIG_WEBCONTENT_STATIC_PATH = "webcontent.static.directory"; + public static final String PROP_CONFIG_WEBCONTENT_PROPERTIES_PATH = "webcontent.properties"; + public static final String PROP_CONFIG_WEBCONTENT_TEMPLATES_PATH = "webcontent.templates"; + + public static final String PROP_CONFIG_WEBCONTENT_TEMPLATES_CCSELECTION = "webcontent.templates.countryselection"; + + public static final String PROP_CONFIG_MONITORING_EIDASNODE_METADATAURL = + "monitoring.eIDASNode.metadata.url"; + + private static final String PROP_CONFIG_PVP2_PREFIX = "pvp2."; + public static final String CONFIG_PROPS_KEYSTORE_TYPE = PROP_CONFIG_PVP2_PREFIX + "keystore.type"; + public static final String CONFIG_PROPS_KEYSTORE_NAME = PROP_CONFIG_PVP2_PREFIX + "keystore.name"; + public static final String PROP_CONFIG_PVP2_KEYSTORE_PATH = PROP_CONFIG_PVP2_PREFIX + "keystore.path"; + public static final String PROP_CONFIG_PVP2_KEYSTORE_PASSWORD = PROP_CONFIG_PVP2_PREFIX + + "keystore.password"; + public static final String PROP_CONFIG_PVP2_KEY_METADATA_ALIAS = PROP_CONFIG_PVP2_PREFIX + + "key.metadata.alias"; + public static final String PROP_CONFIG_PVP2_KEY_METADATA_PASSWORD = PROP_CONFIG_PVP2_PREFIX + + "key.metadata.password"; + public static final String PROP_CONFIG_PVP2_KEY_SIGNING_ALIAS = PROP_CONFIG_PVP2_PREFIX + + "key.signing.alias"; + public static final String PROP_CONFIG_PVP2_KEY_SIGNING_PASSWORD = PROP_CONFIG_PVP2_PREFIX + + "key.signing.password"; + public static final String PROP_CONFIG_PVP2_METADATA_VALIDITY = PROP_CONFIG_PVP2_PREFIX + + "metadata.validity"; + + public static final String CONFIG_PROPS_METADATA_CONTACT_GIVENNAME = + PROP_CONFIG_PVP2_PREFIX + "metadata.contact.givenname"; + public static final String CONFIG_PROPS_METADATA_CONTACT_SURNAME = + PROP_CONFIG_PVP2_PREFIX + "metadata.contact.surname"; + public static final String CONFIG_PROPS_METADATA_CONTACT_EMAIL = + PROP_CONFIG_PVP2_PREFIX + "metadata.contact.email"; + public static final String CONFIG_PROPS_METADATA_ORGANISATION_NAME = + PROP_CONFIG_PVP2_PREFIX + "metadata.organisation.name"; + public static final String CONFIG_PROPS_METADATA_ORGANISATION_FRIENDLYNAME = + PROP_CONFIG_PVP2_PREFIX + "metadata.organisation.friendyname"; + public static final String CONFIG_PROPS_METADATA_ORGANISATION_URL = + PROP_CONFIG_PVP2_PREFIX + "metadata.organisation.url"; + + // TODO: is not implemented yet + public static final String PROP_CONFIG_SP_VALIDATION_DISABLED = + "configuration.sp.disableRegistrationRequirement"; + + public static final String PROP_EIDAS_REQUEST_LOA_MINIMUM_LEVEL = + "auth.eIDAS.node_v2.loa.requested.minimum"; + + public static final String PROP_CONFIG_AUTHBLOCK_KEYSTORE_TYPE = + "auth.eIDAS.authblock.keystore.type"; + public static final String PROP_CONFIG_AUTHBLOCK_KEYSTORE_PATH = + "auth.eIDAS.authblock.keystore.path"; + public static final String PROP_CONFIG_AUTHBLOCK_KEYSTORE_PASSWORD = + "auth.eIDAS.authblock.keystore.password"; + public static final String PROP_CONFIG_AUTHBLOCK_KEYSTORE_NAME = + "auth.eIDAS.authblock.keystore.name"; + public static final String PROP_CONFIG_AUTHBLOCK_KEY_ALIAS = + "auth.eIDAS.authblock.key.alias"; + public static final String PROP_CONFIG_AUTHBLOCK_KEY_PASSWORD = + "auth.eIDAS.authblock.key.password"; + + + + + public static final String PROP_CONFIG_SP_LIST_PREFIX = "sp"; + public static final String PROP_CONFIG_SP_UNIQUEIDENTIFIER = EaafConfigConstants.SERVICE_UNIQUEIDENTIFIER; + public static final String PROP_CONFIG_SP_FRIENDLYNAME = "friendlyName"; + public static final String PROP_CONFIG_SP_PVP2_METADATA_URL = "pvp2.metadata.url"; + public static final String PROP_CONFIG_SP_PVP2_METADATA_TRUSTSTORE = "pvp2.metadata.truststore"; + public static final String PROP_CONFIG_SP_PVP2_METADATA_TRUSTSTORE_PASSWORD = + "pvp2.metadata.truststore.password"; + public static final String PROP_CONFIG_SP_NEW_EID_MODE = + "newEidMode"; + + public static final String PROP_CONFIG_SP_POLICY_ALLOWED_TARGETS = "policy.allowed.requested.targets"; + public static final String PROP_CONFIG_SP_POLICY_BASEIDTRANSFER_RESTRICTION = + "policy.hasBaseIdTransferRestriction"; + + public static final String PROP_CONFIG_PVP_SCHEME_VALIDATION = "configuration.pvp.scheme.validation"; + public static final String PROP_CONFIG_PVP_ENABLE_ENTITYCATEGORIES = + "configuration.pvp.enable.entitycategories"; + + // ********** default values *************** + + // Default policy for SP-targets requested by MOA-ID to ms-specific eIDAS + // Connector + public static final String POLICY_DEFAULT_ALLOWED_TARGETS = ".*"; + // EAAFConstants.URN_PREFIX_CDID.replaceAll("\\.", "\\\\.").replaceAll("\\+", + // "\\\\+") + ".*"; + + public static final int METADATA_SOCKED_TIMEOUT = 20 * 1000; // 20 seconds metadata socked timeout + public static final int DEFAULT_PVP_METADATA_VALIDITY = 24; // 24 hours + public static final int DEFAULT_PVP_ASSERTION_VALIDITY = 5; // 5 minutes + + // ************ application end-points ************* + public static final String ENDPOINT_PVP_METADATA = "/pvp/metadata"; + public static final String ENDPOINT_PVP_POST = "/pvp/post"; + public static final String ENDPOINT_PVP_REDIRECT = "/pvp/redirect"; + + public static final String ENDPOINT_COUNTRYSELECTION = "/myHomeCountry"; + + public static final String ENDPOINT_MONITORING_MONITOR = "/monitoring"; + public static final String ENDPOINT_MONITORING_VERIFY = "/verify"; + + // ************ paths and templates ************ + public static final String CLASSPATH_TEMPLATE_DIR = "/templates/"; + public static final String FILESYSTEM_TEMPLATE_DIR = "./templates/"; + + public static final String TEMPLATE_HTML_ERROR = "error_message.html"; + public static final String TEMPLATE_HTML_PVP_POSTBINDING = "pvp2_post_binding.html"; + public static final String TEMPLATE_HTML_COUNTRYSELECTION = "countrySelection.html"; + + // ************ execution context and generic data ************ + public static final String REQ_PARAM_SELECTED_COUNTRY = "selectedCountry"; + public static final String REQ_PARAM_SELECTED_ENVIRONMENT = "selectedEnvironment"; + public static final String REQ_PARAM_STOP_PROCESS = "stopAuthProcess"; + + public static final String REQ_PARAM_SELECTED_ENVIRONMENT_VALUE_PRODUCTION = "prod"; + public static final String REQ_PARAM_SELECTED_ENVIRONMENT_VALUE_QS = "qs"; + public static final String REQ_PARAM_SELECTED_ENVIRONMENT_VALUE_TESTING = "test"; + public static final String REQ_PARAM_SELECTED_ENVIRONMENT_VALUE_DEVELOPMENT = "dev"; + + 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 List COUNTRY_SELECTION_PARAM_WHITELIST = + Arrays.asList(REQ_PARAM_SELECTED_COUNTRY, REQ_PARAM_SELECTED_ENVIRONMENT); + + + public static final String EID_BINDING_PUBLIC_KEY_NAME = "urn:eidgvat:attributes.binding.pubkey"; + + + // ---- Attribute configuration ------ + public static final String ATTR_EIDAS_PERSONAL_IDENTIFIER = + AbstractAuthenticationDataBuilder.GENERIC_AUTHDATA_IDENTIFIER + PvpAttributeDefinitions.BPK_NAME; + public static final String ATTR_EIDAS_NAT_MANDATOR_PERSONAL_IDENTIFIER = + AbstractAuthenticationDataBuilder.GENERIC_AUTHDATA_IDENTIFIER + PvpAttributeDefinitions.MANDATE_NAT_PER_BPK_NAME; + public static final String ATTR_EIDAS_JUR_MANDATOR_PERSONAL_IDENTIFIER = + AbstractAuthenticationDataBuilder.GENERIC_AUTHDATA_IDENTIFIER + + PvpAttributeDefinitions.MANDATE_LEG_PER_SOURCE_PIN_NAME; + + public static final String AUTH_DATA_SZR_AUTHBLOCK = "authData_AUTHBLOCK"; + public static final String AUTH_DATA_EIDAS_BIND = "authData_EIDAS_BIND"; + + + public static final List> DEFAULT_REQUIRED_MANDATE_NAT_PVP_ATTRIBUTES = + Collections.unmodifiableList(new ArrayList>() { + private static final long serialVersionUID = 1L; + { + add(Triple.newInstance(PvpAttributeDefinitions.MANDATE_NAT_PER_BPK_NAME, + PvpAttributeDefinitions.MANDATE_NAT_PER_BPK_FRIENDLY_NAME, false)); + add(Triple.newInstance(PvpAttributeDefinitions.MANDATE_NAT_PER_GIVEN_NAME_NAME, + PvpAttributeDefinitions.MANDATE_NAT_PER_GIVEN_NAME_FRIENDLY_NAME, false)); + add(Triple.newInstance(PvpAttributeDefinitions.MANDATE_NAT_PER_FAMILY_NAME_NAME, + PvpAttributeDefinitions.MANDATE_NAT_PER_FAMILY_NAME_FRIENDLY_NAME, false)); + add(Triple.newInstance(PvpAttributeDefinitions.MANDATE_NAT_PER_BIRTHDATE_NAME, + PvpAttributeDefinitions.MANDATE_NAT_PER_BIRTHDATE_FRIENDLY_NAME, false)); + + } + }); + + public static final List> DEFAULT_REQUIRED_MANDATE_JUR_PVP_ATTRIBUTES = + Collections.unmodifiableList(new ArrayList>() { + private static final long serialVersionUID = 1L; + { + add(Triple.newInstance(PvpAttributeDefinitions.MANDATE_LEG_PER_FULL_NAME_NAME, + PvpAttributeDefinitions.MANDATE_LEG_PER_FULL_NAME_FRIENDLY_NAME, false)); + add(Triple.newInstance(PvpAttributeDefinitions.MANDATE_LEG_PER_SOURCE_PIN_NAME, + PvpAttributeDefinitions.MANDATE_LEG_PER_SOURCE_PIN_FRIENDLY_NAME, false)); + add(Triple.newInstance(PvpAttributeDefinitions.MANDATE_LEG_PER_SOURCE_PIN_TYPE_NAME, + PvpAttributeDefinitions.MANDATE_LEG_PER_SOURCE_PIN_TYPE_FRIENDLY_NAME, false)); + + } + }); + + + private MsEidasNodeConstants() { + //hidden Constructor for class with static values only. + } + +} diff --git a/modules/core_common_lib/src/main/java/at/asitplus/eidas/specific/core/config/BasicConfigurationProvider.java b/modules/core_common_lib/src/main/java/at/asitplus/eidas/specific/core/config/BasicConfigurationProvider.java new file mode 100644 index 00000000..3a1bdc9c --- /dev/null +++ b/modules/core_common_lib/src/main/java/at/asitplus/eidas/specific/core/config/BasicConfigurationProvider.java @@ -0,0 +1,155 @@ +/* + * Copyright 2018 A-SIT Plus GmbH + * AT-specific eIDAS Connector has been developed in a cooperation between EGIZ, + * A-SIT Plus GmbH, A-SIT, and Graz University of Technology. + * + * Licensed under the EUPL, Version 1.2 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "License"); + * You may not use this work except in compliance with the License. + * You may obtain a copy of the License at: + * https://joinup.ec.europa.eu/news/understanding-eupl-v12 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. +*/ + +package at.asitplus.eidas.specific.core.config; + +import java.net.URL; +import java.util.HashMap; +import java.util.Map; +import java.util.Map.Entry; + +import org.apache.commons.lang3.StringUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.context.annotation.Profile; +import org.springframework.stereotype.Service; + +import at.asitplus.eidas.specific.core.MsEidasNodeConstants; +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.impl.idp.conf.AbstractConfigurationImpl; +import at.gv.egiz.eaaf.core.impl.utils.KeyValueUtils; + +@Service("BasicMSSpecificNodeConfig") +@Profile("deprecatedConfig") +public class BasicConfigurationProvider extends AbstractConfigurationImpl { + private static final Logger log = LoggerFactory.getLogger(BasicConfigurationProvider.class); + + private final Map spConfigCache = new HashMap<>(); + + public BasicConfigurationProvider(String configPath) throws EaafConfigurationException { + super(configPath); + + } + + @Override + public ISpConfiguration getServiceProviderConfiguration(String entityId) throws EaafConfigurationException { + if (!spConfigCache.containsKey(entityId)) { + log.debug("SP: " + entityId + " is NOT cached. Starting load operation ... "); + final Map allSPs = getBasicConfigurationWithPrefix( + MsEidasNodeConstants.PROP_CONFIG_SP_LIST_PREFIX + KeyValueUtils.KEY_DELIMITER); + for (Entry entry : allSPs.entrySet()) { + if (entry.getKey().endsWith(MsEidasNodeConstants.PROP_CONFIG_SP_UNIQUEIDENTIFIER) + && entry.getValue().equals(entityId)) { + final String listId = KeyValueUtils.getParentKey(entry.getKey()); + log.trace("Find SP configuration with list-Id: " + listId + + ". Extracting configuration elements ... "); + final Map spConfig = KeyValueUtils.getSubSetWithPrefix(allSPs, listId + + KeyValueUtils.KEY_DELIMITER); + spConfigCache.put(entityId, + new ServiceProviderConfiguration(spConfig, this)); + break; + } + } + + if (spConfigCache.containsKey(entityId)) { + log.info("SP: " + entityId + " is loaded. Continuing auth. process ... "); + } else { + log.warn("SP: " + entityId + " is NOT found in configuration. Stopping auth. process ... "); + return null; + + } + + } else { + log.trace("SP: " + entityId + " is already cached. Use configuration from there ... "); + } + + return spConfigCache.get(entityId); + } + + @Override + public T getServiceProviderConfiguration(String entityId, Class decorator) + throws EaafConfigurationException { + final ISpConfiguration spConfig = getServiceProviderConfiguration(entityId); + if (spConfig != null && decorator != null) { + if (decorator.isInstance(spConfig)) { + return (T) spConfig; + } else { + log.error("SPConfig: " + spConfig.getClass().getName() + " is NOT instance of: " + decorator + .getName()); + } + + } + + return null; + + } + + @Override + public String validateIdpUrl(URL url) throws EaafException { + log.trace("Validate requested URL: " + url); + String urlPrefixFromConfig = getBasicConfiguration( + MsEidasNodeConstants.PROP_CONFIG_APPLICATION_PUBLIC_URL_PREFIX); + if (StringUtils.isEmpty(urlPrefixFromConfig)) { + log.warn("Application config containts NO URL prefix"); + throw new EaafConfigurationException("config.27", + new Object[] { "Application config containts NO " + + getApplicationSpecificKeyPrefix() + + MsEidasNodeConstants.PROP_CONFIG_APPLICATION_PUBLIC_URL_PREFIX }); + + } + + // remove last slash + if (urlPrefixFromConfig.endsWith("/")) { + urlPrefixFromConfig = urlPrefixFromConfig.substring(0, urlPrefixFromConfig.length() - 1); + } + + if (getBasicConfigurationBoolean( + MsEidasNodeConstants.PROP_CONFIG_APPLICATION_PUBLIC_URL_REQUEST_VALIDATION, false)) { + if (url != null && url.toExternalForm().startsWith(urlPrefixFromConfig)) { + return urlPrefixFromConfig; + } + + log.info("URL: " + url + " does NOT match to allowed application prefix: " + urlPrefixFromConfig); + return null; + + } else { + return urlPrefixFromConfig; + + } + } + + @Override + public String getApplicationSpecificKeyPrefix() { + return MsEidasNodeConstants.PROP_CONFIG_APPLICATION_PREFIX; + + } + + @Override + protected String getBackupConfigPath() { + return null; + + } + +} diff --git a/modules/core_common_lib/src/main/java/at/asitplus/eidas/specific/core/config/ServiceProviderConfiguration.java b/modules/core_common_lib/src/main/java/at/asitplus/eidas/specific/core/config/ServiceProviderConfiguration.java new file mode 100644 index 00000000..5ca1c8c5 --- /dev/null +++ b/modules/core_common_lib/src/main/java/at/asitplus/eidas/specific/core/config/ServiceProviderConfiguration.java @@ -0,0 +1,171 @@ +/* + * Copyright 2018 A-SIT Plus GmbH + * AT-specific eIDAS Connector has been developed in a cooperation between EGIZ, + * A-SIT Plus GmbH, A-SIT, and Graz University of Technology. + * + * Licensed under the EUPL, Version 1.2 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "License"); + * You may not use this work except in compliance with the License. + * You may obtain a copy of the License at: + * https://joinup.ec.europa.eu/news/understanding-eupl-v12 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. +*/ + +package at.asitplus.eidas.specific.core.config; + +import java.util.Arrays; +import java.util.List; +import java.util.Map; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import at.asitplus.eidas.specific.core.MsEidasNodeConstants; +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.IConfiguration; +import at.gv.egiz.eaaf.core.exceptions.EaafException; +import at.gv.egiz.eaaf.core.impl.idp.conf.SpConfigurationImpl; +import lombok.Getter; +import lombok.Setter; + +public class ServiceProviderConfiguration extends SpConfigurationImpl { + private static final long serialVersionUID = 1L; + private static final Logger log = LoggerFactory.getLogger(ServiceProviderConfiguration.class); + + private List minimumLoA = Arrays.asList(EaafConstants.EIDAS_LOA_HIGH); + private String bpkTargetIdentifier; + private String loaMachtingMode = EaafConstants.EIDAS_LOA_MATCHING_MINIMUM; + + @Setter + @Getter + private List mandateProfiles; + + @Getter + @Setter + private SpMandateModes mandateMode = SpMandateModes.NONE; + + public ServiceProviderConfiguration(Map spConfig, IConfiguration authConfig) { + super(spConfig, authConfig); + + } + + @Override + public boolean hasBaseIdInternalProcessingRestriction() { + return false; + + } + + + @Override + public boolean hasBaseIdTransferRestriction() { + final Boolean spConfigPolicy = isConfigurationValue( + MsEidasNodeConstants.PROP_CONFIG_SP_POLICY_BASEIDTRANSFER_RESTRICTION); + if (spConfigPolicy) { + return spConfigPolicy; + + } else { + log.trace("SP configuration defines no baseID transfer restriction. Enforce default policy ..."); + for (final String el : getTargetsWithNoBaseIdTransferRestriction()) { + if (this.bpkTargetIdentifier != null && this.bpkTargetIdentifier.startsWith(el)) { + log.debug("SP-Target: " + this.bpkTargetIdentifier + + " has NO baseID transfer restriction in default policy"); + return false; + + } + } + } + + log.debug("Default-policy defines baseID transfer restriction for SP-Target: " + + this.bpkTargetIdentifier); + return true; + } + + @Override + public List getRequiredLoA() { + return minimumLoA; + + } + + @Override + public String getLoAMatchingMode() { + return loaMachtingMode; + + } + + @Override + public String getAreaSpecificTargetIdentifier() { + return bpkTargetIdentifier; + } + + @Override + public String getFriendlyName() { + return getConfigurationValue( + MsEidasNodeConstants.PROP_CONFIG_SP_FRIENDLYNAME, + "NO FRIENDLYNAME SET"); + + } + + /** + * Set the minimum level of eIDAS authentication for this SP
+ * Default: http://eidas.europa.eu/LoA/high
+ * Info: In case of MINIMUM matching-mode, only one entry is allowed + * + * @param minimumLoA eIDAS LoA URIs + */ + + public void setRequiredLoA(List minimumLoA) { + this.minimumLoA = minimumLoA; + } + + /** + * Set the mode of operation for LoA matching for this SP. Default: + * minimum
+ * Info: Currently only 'minimum' and 'exact' are supported + * + * @param mode LoA matching mode according to SAML2 core specification + */ + public void setLoAMachtingMode(String mode) { + this.loaMachtingMode = mode; + } + + /** + * Set the bPK Target for this service provider. + * + * @param bpkTargetIdentifier Set the bPK sector + * @throws EAAFException If the bPKTargetIdentifier is NOT ALLOWED for this + * service provider + */ + public void setBpkTargetIdentifier(String bpkTargetIdentifier) throws EaafException { + final String allowedTargetIdentifierRegExPattern = getConfigurationValue( + MsEidasNodeConstants.PROP_CONFIG_SP_POLICY_ALLOWED_TARGETS, + MsEidasNodeConstants.POLICY_DEFAULT_ALLOWED_TARGETS); + log.trace("Use bPK-target regex pattern: " + allowedTargetIdentifierRegExPattern); + + final Pattern p = Pattern.compile(allowedTargetIdentifierRegExPattern); + final Matcher m = p.matcher(bpkTargetIdentifier); + if (m.matches()) { + log.debug("Requested bPK-target: " + bpkTargetIdentifier + " matches regex pattern"); + this.bpkTargetIdentifier = bpkTargetIdentifier; + + } else { + log.warn("Requested bPK-target: " + bpkTargetIdentifier + " does NOT match regex pattern."); + throw new EaafException("auth.37", new Object[] { bpkTargetIdentifier, getUniqueIdentifier() }); + + } + + } + +} diff --git a/modules/core_common_lib/src/main/java/at/asitplus/eidas/specific/core/config/SpringBootBasicConfigurationProvider.java b/modules/core_common_lib/src/main/java/at/asitplus/eidas/specific/core/config/SpringBootBasicConfigurationProvider.java new file mode 100644 index 00000000..f5492913 --- /dev/null +++ b/modules/core_common_lib/src/main/java/at/asitplus/eidas/specific/core/config/SpringBootBasicConfigurationProvider.java @@ -0,0 +1,122 @@ +package at.asitplus.eidas.specific.core.config; + +import java.net.URL; +import java.util.HashMap; +import java.util.Map; +import java.util.Map.Entry; + +import org.apache.commons.lang3.StringUtils; + +import at.asitplus.eidas.specific.core.MsEidasNodeConstants; +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.impl.idp.conf.AbstractSpringBootConfigurationImpl; +import at.gv.egiz.eaaf.core.impl.utils.KeyValueUtils; +import lombok.extern.slf4j.Slf4j; + +@Slf4j +public class SpringBootBasicConfigurationProvider extends AbstractSpringBootConfigurationImpl { + + private final Map spConfigCache = new HashMap<>(); + + @Override + public ISpConfiguration getServiceProviderConfiguration(String entityId) throws EaafConfigurationException { + if (!spConfigCache.containsKey(entityId)) { + log.debug("SP: " + entityId + " is NOT cached. Starting load operation ... "); + final Map allSPs = getBasicConfigurationWithPrefix( + MsEidasNodeConstants.PROP_CONFIG_SP_LIST_PREFIX); + for (Entry entry : allSPs.entrySet()) { + if (entry.getKey().endsWith(MsEidasNodeConstants.PROP_CONFIG_SP_UNIQUEIDENTIFIER) + && entry.getValue().equals(entityId)) { + final String listId = KeyValueUtils.getParentKey(entry.getKey()); + log.trace("Find SP configuration with list-Id: " + listId + + ". Extracting configuration elements ... "); + final Map spConfig = KeyValueUtils.getSubSetWithPrefix(allSPs, listId + + KeyValueUtils.KEY_DELIMITER); + spConfigCache.put(entityId, + new ServiceProviderConfiguration(spConfig, this)); + break; + } + } + + if (spConfigCache.containsKey(entityId)) { + log.info("SP: " + entityId + " is loaded. Continuing auth. process ... "); + } else { + log.warn("SP: " + entityId + " is NOT found in configuration. Stopping auth. process ... "); + return null; + + } + + } else { + log.trace("SP: " + entityId + " is already cached. Use configuration from there ... "); + } + + return spConfigCache.get(entityId); + } + + @Override + public T getServiceProviderConfiguration(String entityId, Class decorator) + throws EaafConfigurationException { + final ISpConfiguration spConfig = getServiceProviderConfiguration(entityId); + if (spConfig != null && decorator != null) { + if (decorator.isInstance(spConfig)) { + return (T) spConfig; + } else { + log.error("SPConfig: " + spConfig.getClass().getName() + " is NOT instance of: " + decorator + .getName()); + } + + } + + return null; + + } + + @Override + public String validateIdpUrl(URL url) throws EaafException { + log.trace("Validate requested URL: " + url); + String urlPrefixFromConfig = getBasicConfiguration( + MsEidasNodeConstants.PROP_CONFIG_APPLICATION_PUBLIC_URL_PREFIX); + if (StringUtils.isEmpty(urlPrefixFromConfig)) { + log.warn("Application config containts NO URL prefix"); + throw new EaafConfigurationException("config.27", + new Object[] { "Application config containts NO " + + getApplicationSpecificKeyPrefix() + + MsEidasNodeConstants.PROP_CONFIG_APPLICATION_PUBLIC_URL_PREFIX }); + + } + + // remove last slash + if (urlPrefixFromConfig.endsWith("/")) { + urlPrefixFromConfig = urlPrefixFromConfig.substring(0, urlPrefixFromConfig.length() - 1); + } + + if (getBasicConfigurationBoolean( + MsEidasNodeConstants.PROP_CONFIG_APPLICATION_PUBLIC_URL_REQUEST_VALIDATION, false)) { + if (url != null && url.toExternalForm().startsWith(urlPrefixFromConfig)) { + return urlPrefixFromConfig; + } + + log.info("URL: " + url + " does NOT match to allowed application prefix: " + urlPrefixFromConfig); + return null; + + } else { + return urlPrefixFromConfig; + + } + } + + @Override + public String getApplicationSpecificKeyPrefix() { + return MsEidasNodeConstants.PROP_CONFIG_APPLICATION_PREFIX; + + } + + @Override + protected String getBackupConfigPath() { + return null; + + } + +} diff --git a/modules/core_common_lib/src/main/java/at/asitplus/eidas/specific/core/gui/DefaultVelocityGuiBuilderImpl.java b/modules/core_common_lib/src/main/java/at/asitplus/eidas/specific/core/gui/DefaultVelocityGuiBuilderImpl.java new file mode 100644 index 00000000..96d58def --- /dev/null +++ b/modules/core_common_lib/src/main/java/at/asitplus/eidas/specific/core/gui/DefaultVelocityGuiBuilderImpl.java @@ -0,0 +1,77 @@ +/* + * Copyright 2018 A-SIT Plus GmbH + * AT-specific eIDAS Connector has been developed in a cooperation between EGIZ, + * A-SIT Plus GmbH, A-SIT, and Graz University of Technology. + * + * Licensed under the EUPL, Version 1.2 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "License"); + * You may not use this work except in compliance with the License. + * You may obtain a copy of the License at: + * https://joinup.ec.europa.eu/news/understanding-eupl-v12 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. +*/ + +package at.asitplus.eidas.specific.core.gui; + +import java.io.InputStream; + +import javax.servlet.http.HttpServletRequest; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.http.MediaType; +import org.springframework.stereotype.Service; + +import at.gv.egiz.eaaf.core.api.gui.IGuiBuilderConfiguration; +import at.gv.egiz.eaaf.core.api.gui.IVelocityGuiBuilderConfiguration; +import at.gv.egiz.eaaf.core.exceptions.GuiBuildException; +import at.gv.egiz.eaaf.core.impl.gui.AbstractVelocityGuiFormBuilderImpl; + +@Service("velocityGUIBuilderImpl") +public class DefaultVelocityGuiBuilderImpl extends AbstractVelocityGuiFormBuilderImpl { + private static final Logger log = LoggerFactory.getLogger(DefaultVelocityGuiBuilderImpl.class); + + private static final String CLASSPATH_HTMLTEMPLATES_DIR = "templates/"; + + public DefaultVelocityGuiBuilderImpl() throws GuiBuildException { + super(); + + } + + @Override + protected InputStream getInternalTemplate(IVelocityGuiBuilderConfiguration config) + throws GuiBuildException { + final String viewName = config.getViewName(); + log.debug("GUI template:" + viewName + " is not found in configuration directory. " + + " Load template from project library ... "); + final String pathLocation = getInternalClasspathTemplateDir(config, CLASSPATH_HTMLTEMPLATES_DIR) + + viewName; + try { + final InputStream is = Thread.currentThread().getContextClassLoader().getResourceAsStream(pathLocation); + return is; + + } catch (final Exception e1) { + log.error("GUI template:" + pathLocation + " is NOT loadable from classpath!", e1); + throw new GuiBuildException("GUI template:" + pathLocation + " is NOT loadable from classpath!", e1); + + } + } + + @Override + public String evaluateResponseContentType(HttpServletRequest httpReq, IGuiBuilderConfiguration config, + String loggerName) throws GuiBuildException { + return MediaType.TEXT_HTML_VALUE; + + } + +} diff --git a/modules/core_common_lib/src/main/java/at/asitplus/eidas/specific/core/gui/GuiBuilderConfigurationFactory.java b/modules/core_common_lib/src/main/java/at/asitplus/eidas/specific/core/gui/GuiBuilderConfigurationFactory.java new file mode 100644 index 00000000..62a0005d --- /dev/null +++ b/modules/core_common_lib/src/main/java/at/asitplus/eidas/specific/core/gui/GuiBuilderConfigurationFactory.java @@ -0,0 +1,69 @@ +/* + * Copyright 2018 A-SIT Plus GmbH + * AT-specific eIDAS Connector has been developed in a cooperation between EGIZ, + * A-SIT Plus GmbH, A-SIT, and Graz University of Technology. + * + * Licensed under the EUPL, Version 1.2 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "License"); + * You may not use this work except in compliance with the License. + * You may obtain a copy of the License at: + * https://joinup.ec.europa.eu/news/understanding-eupl-v12 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. +*/ + +package at.asitplus.eidas.specific.core.gui; + +import java.net.MalformedURLException; +import java.net.URI; + +import javax.annotation.Nonnull; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.core.io.ResourceLoader; +import org.springframework.stereotype.Service; + +import at.asitplus.eidas.specific.core.MsEidasNodeConstants; +import at.gv.egiz.eaaf.core.api.IRequest; +import at.gv.egiz.eaaf.core.api.gui.IGuiBuilderConfiguration; +import at.gv.egiz.eaaf.core.api.gui.IGuiBuilderConfigurationFactory; +import at.gv.egiz.eaaf.core.api.gui.IVelocityGuiBuilderConfiguration; +import at.gv.egiz.eaaf.core.api.idp.IConfiguration; + +@Service("GUIBuilderConfigurationFactory") +public class GuiBuilderConfigurationFactory implements IGuiBuilderConfigurationFactory { + @Autowired(required = true) private IConfiguration basicConfig; + @Autowired(required = true) private ResourceLoader resourceLoader; + + @Override + public IGuiBuilderConfiguration getDefaultErrorGui(String authUrl) { + return new StaticGuiBuilderConfiguration(basicConfig, authUrl, MsEidasNodeConstants.TEMPLATE_HTML_ERROR, + null, resourceLoader); + } + + @Override + public IVelocityGuiBuilderConfiguration getSpSpecificSaml2PostConfiguration(IRequest pendingReq, + String viewName, URI configRootContextDir) + throws MalformedURLException { + return new StaticGuiBuilderConfiguration(basicConfig, pendingReq, + MsEidasNodeConstants.TEMPLATE_HTML_PVP_POSTBINDING, null, resourceLoader); + } + + @Override + public IGuiBuilderConfiguration getDefaultIFrameParentHopGui(IRequest pendingReq, + @Nonnull String endpoint, @Nonnull String errorId) { + //TODO: implement if iFrame to parent hop is needed + throw new RuntimeException("Operation not supported yet."); + + } + +} diff --git a/modules/core_common_lib/src/main/java/at/asitplus/eidas/specific/core/gui/StaticGuiBuilderConfiguration.java b/modules/core_common_lib/src/main/java/at/asitplus/eidas/specific/core/gui/StaticGuiBuilderConfiguration.java new file mode 100644 index 00000000..0fd85d3d --- /dev/null +++ b/modules/core_common_lib/src/main/java/at/asitplus/eidas/specific/core/gui/StaticGuiBuilderConfiguration.java @@ -0,0 +1,148 @@ +/* + * Copyright 2018 A-SIT Plus GmbH + * AT-specific eIDAS Connector has been developed in a cooperation between EGIZ, + * A-SIT Plus GmbH, A-SIT, and Graz University of Technology. + * + * Licensed under the EUPL, Version 1.2 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "License"); + * You may not use this work except in compliance with the License. + * You may obtain a copy of the License at: + * https://joinup.ec.europa.eu/news/understanding-eupl-v12 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. +*/ + +package at.asitplus.eidas.specific.core.gui; + +import java.io.IOException; +import java.io.InputStream; + +import org.apache.commons.text.StringEscapeUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.core.io.Resource; +import org.springframework.core.io.ResourceLoader; + +import at.asitplus.eidas.specific.core.MsEidasNodeConstants; +import at.gv.egiz.eaaf.core.api.IRequest; +import at.gv.egiz.eaaf.core.api.gui.GroupDefinition; +import at.gv.egiz.eaaf.core.api.gui.IVelocityGuiBuilderConfiguration; +import at.gv.egiz.eaaf.core.api.gui.ModifyableGuiBuilderConfiguration; +import at.gv.egiz.eaaf.core.api.idp.IConfiguration; +import at.gv.egiz.eaaf.core.impl.gui.AbstractGuiFormBuilderConfiguration; +import at.gv.egiz.eaaf.core.impl.utils.FileUtils; + +public class StaticGuiBuilderConfiguration extends AbstractGuiFormBuilderConfiguration implements + IVelocityGuiBuilderConfiguration, ModifyableGuiBuilderConfiguration { + private static final Logger log = LoggerFactory.getLogger(StaticGuiBuilderConfiguration.class); + + private IRequest pendingReq = null; + private IConfiguration basicConfig = null; + private ResourceLoader resourceLoader; + + /** + * Static resource configuration for GUI Builder implementations. + * + * @param basicConfig basicConfig + * @param authUrl Public URL of the application + * @param viewName Name of the template + * @param formSubmitEndpoint Form Submit end-point, if template contains a form. + * @param resourceLoader Spring ResourceLoader implementation + */ + public StaticGuiBuilderConfiguration(IConfiguration basicConfig, String authUrl, String viewName, + String formSubmitEndpoint, ResourceLoader resourceLoader) { + super(authUrl, viewName, formSubmitEndpoint); + this.basicConfig = basicConfig; + this.resourceLoader = resourceLoader; + + } + + /** + * Static resource configuration for GUI Builder implementations. + * + * @param basicConfig Application configuration + * @param pendingReq Current pending request + * @param viewName Name of the template + * @param formSubmitEndpoint Form Submit end-point, if template contains a form. + * @param resourceLoader Spring ResourceLoader implementation + */ + public StaticGuiBuilderConfiguration(IConfiguration basicConfig, IRequest pendingReq, String viewName, + String formSubmitEndpoint, ResourceLoader resourceLoader) { + super(pendingReq.getAuthUrl(), viewName, formSubmitEndpoint); + this.pendingReq = pendingReq; + this.basicConfig = basicConfig; + this.resourceLoader = resourceLoader; + + } + + @Override + public String getClasspathTemplateDir() { + return MsEidasNodeConstants.CLASSPATH_TEMPLATE_DIR; + + } + + @Override + public String getDefaultContentType() { + return null; + + } + + @Override + public InputStream getTemplate(String viewName) { + final String templateUrl = MsEidasNodeConstants.FILESYSTEM_TEMPLATE_DIR + viewName; + try { + final String absUrl = FileUtils.makeAbsoluteUrl(templateUrl, this.basicConfig + .getConfigurationRootDirectory()); + log.debug("Load template URL for view: " + viewName + " from: " + absUrl); + Resource resource = resourceLoader.getResource(absUrl); + return resource.getInputStream(); + + } catch (IOException e) { + log.info("Can can build filesytem path to template: " + templateUrl + + " Reason: " + e.getMessage()); + + } + + return null; + } + + @Override + public void putCustomParameterWithOutEscaption(GroupDefinition group, String key, Object value) { + setViewParameter(getFromGroup(), key, value); + + } + + @Override + public void putCustomParameter(GroupDefinition group, String key, String value) { + setViewParameter(getFromGroup(), key, StringEscapeUtils.escapeHtml4(value)); + + } + + @Override + protected void putSpecificViewParameters() { + if (pendingReq != null) { + setViewParameter(getFromGroup(), PARAM_PENDINGREQUESTID, StringEscapeUtils.escapeHtml4(pendingReq + .getPendingRequestId())); + setViewParameter(getFromGroup(), PARAM_PENDINGREQUESTID_DEPRECATED, StringEscapeUtils.escapeHtml4( + pendingReq.getPendingRequestId())); + + } + + } + + @Override + protected GroupDefinition getFromGroup() { + return null; + + } + +} diff --git a/modules/core_common_lib/src/main/resources/common_gui.beans.xml b/modules/core_common_lib/src/main/resources/common_gui.beans.xml new file mode 100644 index 00000000..969a40f7 --- /dev/null +++ b/modules/core_common_lib/src/main/resources/common_gui.beans.xml @@ -0,0 +1,60 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/modules/core_common_lib/src/test/java/at/asitplus/eidas/specific/core/test/config/BasicConfigProviderTest.java b/modules/core_common_lib/src/test/java/at/asitplus/eidas/specific/core/test/config/BasicConfigProviderTest.java new file mode 100644 index 00000000..224618b9 --- /dev/null +++ b/modules/core_common_lib/src/test/java/at/asitplus/eidas/specific/core/test/config/BasicConfigProviderTest.java @@ -0,0 +1,156 @@ +package at.asitplus.eidas.specific.core.test.config; + +import java.net.MalformedURLException; +import java.net.URL; +import java.util.Map; + +import org.apache.commons.lang3.RandomStringUtils; +import org.junit.Assert; +import org.junit.BeforeClass; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.test.annotation.DirtiesContext; +import org.springframework.test.annotation.DirtiesContext.ClassMode; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; + +import at.asitplus.eidas.specific.core.MsEidasNodeConstants; +import at.asitplus.eidas.specific.core.config.ServiceProviderConfiguration; +import at.gv.egiz.eaaf.core.api.idp.IConfigurationWithSP; +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; + +@RunWith(SpringJUnit4ClassRunner.class) +@ContextConfiguration(locations = { + "/SpringTest-context_basic_realConfig.xml"}) +@DirtiesContext(classMode = ClassMode.BEFORE_CLASS) +public class BasicConfigProviderTest { + + @Autowired private IConfigurationWithSP basicConfig; + + /** + * jUnit class initializer. + * + */ + @BeforeClass + public static void classInitializer() { + final String current = new java.io.File(".").toURI().toString(); + System.setProperty("eidas.ms.configuration", current + "src/test/resources/config/junit_config_1.properties"); + + } + + @Test + public void configPropInfos() { + Assert.assertEquals("size", 2, MsEidasNodeConstants.COUNTRY_SELECTION_PARAM_WHITELIST.size()); + + } + + @Test + public void loadSpNoExist() throws EaafConfigurationException { + ISpConfiguration spConfig = basicConfig.getServiceProviderConfiguration( + RandomStringUtils.randomAlphabetic(5)); + Assert.assertNull("spConfig", spConfig); + + } + + @Test + public void loadSpConfigBasicMode() throws EaafConfigurationException { + ISpConfiguration spConfig = basicConfig.getServiceProviderConfiguration("jUnitTest1"); + + Assert.assertNotNull("spConfig", spConfig); + Assert.assertEquals("uniqueId", "jUnitTest1", spConfig.getUniqueIdentifier()); + Assert.assertEquals("friendlyName", "NO FRIENDLYNAME SET", spConfig.getFriendlyName()); + Assert.assertEquals("pvp2.truststore", "", spConfig.getConfigurationValue("pvp2.metadata.truststore")); + String test = RandomStringUtils.randomAlphabetic(5); + Assert.assertEquals("pvp2.password", "1234pass", + spConfig.getConfigurationValue("pvp2.metadata.truststore.password", test)); + Assert.assertEquals("eidMode", true, spConfig.isConfigurationValue("newEidMode")); + Assert.assertEquals("notexistflag", false, spConfig.isConfigurationValue("notexist", false)); + Assert.assertNotNull("fullConfig", spConfig.getFullConfiguration()); + Assert.assertEquals("fullConfig", 4, spConfig.getFullConfiguration().size()); + + } + + @Test + public void loadSpConfigAdvancedMode() throws EaafConfigurationException { + ISpConfiguration spConfig = basicConfig.getServiceProviderConfiguration( + "jUnitTest2", ServiceProviderConfiguration.class); + + Assert.assertNotNull("spConfig", spConfig); + Assert.assertEquals("uniqueId", "jUnitTest2", spConfig.getUniqueIdentifier()); + Assert.assertEquals("friendlyName", "jUnit tester 2", spConfig.getFriendlyName()); + Assert.assertEquals("pvp2.truststore", "", spConfig.getConfigurationValue("pvp2.metadata.truststore")); + String test = RandomStringUtils.randomAlphabetic(5); + Assert.assertEquals("pvp2.password", test, + spConfig.getConfigurationValue("pvp2.metadata.truststore.notexist", test)); + Assert.assertEquals("eidMode", false, spConfig.isConfigurationValue("newEidMode")); + Assert.assertEquals("notexistflag", false, spConfig.isConfigurationValue("notexist", false)); + Assert.assertNotNull("fullConfig", spConfig.getFullConfiguration()); + Assert.assertEquals("fullConfig", 5, spConfig.getFullConfiguration().size()); + Assert.assertFalse("baseIdInternal", spConfig.hasBaseIdInternalProcessingRestriction()); + Assert.assertTrue("baseIdTransfer", spConfig.hasBaseIdTransferRestriction()); + + } + + @Test + public void loadSpConfigAdvancedModeWrongDecorator() throws EaafConfigurationException { + ISpConfiguration spConfig1 = basicConfig.getServiceProviderConfiguration( + "jUnitTest2", null); + Assert.assertNull("spConfig", spConfig1); + + String spConfig2 = basicConfig.getServiceProviderConfiguration( + "jUnitTest2", String.class); + Assert.assertNull("spConfig", spConfig2); + + } + + @Test + public void loadConfigValuesString() { + Assert.assertEquals("without default", "ownSpecificConnector", + basicConfig.getBasicConfiguration("auth.eIDAS.node_v2.entityId")); + + Assert.assertEquals("with default", "", + basicConfig.getBasicConfiguration("auth.eIDAS.szrclient.endpoint.prod", + RandomStringUtils.randomAlphabetic(5))); + + String rand1 = RandomStringUtils.randomAlphanumeric(5); + Assert.assertEquals("unknown with default", rand1, + basicConfig.getBasicConfiguration("notexist", rand1)); + + } + + @Test + public void loadConfigValuesBoolean() { + Assert.assertEquals("without default", true, + basicConfig.getBasicConfigurationBoolean("auth.eIDAS.szrclient.useTestService")); + + Assert.assertEquals("with default", false, + basicConfig.getBasicConfigurationBoolean("auth.notexist", + false)); + + Assert.assertEquals("unknown with default", false, + basicConfig.getBasicConfigurationBoolean("auth.eIDAS.szrclient.params.vkz", true)); + + } + + @Test + public void loadConfigMap() { + Map entries = basicConfig.getBasicConfigurationWithPrefix("auth.eIDAS.szrclient"); + Assert.assertEquals("wrong size", 16, entries.size()); + Assert.assertTrue("missing element", entries.containsKey("endpoint.test")); + Assert.assertEquals("wrong entry", "http://localhost:1234/demoszr", entries.get("endpoint.test")); + + } + + @Test + public void validateUrl() throws MalformedURLException, EaafException { + Assert.assertEquals("wrong URL", "http://localhost/test", + basicConfig.validateIdpUrl(new URL("http://localhost/test/" + RandomStringUtils.randomAlphabetic(5)))); + + Assert.assertNull("wrong URL", + basicConfig.validateIdpUrl(new URL("http://localhost/wrong/" + RandomStringUtils.randomAlphabetic(5)))); + + } +} diff --git a/modules/core_common_lib/src/test/java/at/asitplus/eidas/specific/core/test/config/ServiceProviderConfigurationTest.java b/modules/core_common_lib/src/test/java/at/asitplus/eidas/specific/core/test/config/ServiceProviderConfigurationTest.java new file mode 100644 index 00000000..99ea2a47 --- /dev/null +++ b/modules/core_common_lib/src/test/java/at/asitplus/eidas/specific/core/test/config/ServiceProviderConfigurationTest.java @@ -0,0 +1,54 @@ +package at.asitplus.eidas.specific.core.test.config; + +import java.util.Arrays; +import java.util.HashMap; +import java.util.Map; + +import org.apache.commons.lang3.RandomStringUtils; +import org.junit.Assert; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.BlockJUnit4ClassRunner; + +import at.asitplus.eidas.specific.core.config.ServiceProviderConfiguration; +import at.asitplus.eidas.specific.core.test.config.dummy.MsConnectorDummyConfigMap; +import at.gv.egiz.eaaf.core.api.data.EaafConstants; +import at.gv.egiz.eaaf.core.api.idp.IConfiguration; +import at.gv.egiz.eaaf.core.exceptions.EaafException; + +@RunWith(BlockJUnit4ClassRunner.class) +public class ServiceProviderConfigurationTest { + + + + @Test + public void spConfigLoad() throws EaafException { + IConfiguration authConfig = new MsConnectorDummyConfigMap(); + + Map map = new HashMap<>(); + map.put("uniqueID", RandomStringUtils.randomAlphabetic(10)); + map.put("policy.allowed.requested.targets", "urn:publicid:gv.at:cdid\\+.*"); + + ServiceProviderConfiguration spConfig = new ServiceProviderConfiguration(map, authConfig); + + spConfig.setRequiredLoA(Arrays.asList(EaafConstants.EIDAS_LOA_LOW)); + Assert.assertEquals("LoA", 1, spConfig.getRequiredLoA().size()); + Assert.assertEquals("LoA", "http://eidas.europa.eu/LoA/low", spConfig.getRequiredLoA().get(0)); + + spConfig.setLoAMachtingMode("exact"); + Assert.assertEquals("wrong machtingMode", "exact", spConfig.getLoAMatchingMode()); + + String bpkTarget = EaafConstants.URN_PREFIX_CDID + RandomStringUtils.randomAlphabetic(2); + spConfig.setBpkTargetIdentifier(bpkTarget); + Assert.assertEquals("wrong bPK", bpkTarget, spConfig.getAreaSpecificTargetIdentifier()); + + + try { + spConfig.setBpkTargetIdentifier(EaafConstants.URN_PREFIX_WBPK + RandomStringUtils.randomAlphabetic(2)); + + } catch (EaafException e) { + Assert.assertEquals("ErrorId", "auth.37", e.getErrorId()); + } + + } +} diff --git a/modules/core_common_lib/src/test/java/at/asitplus/eidas/specific/core/test/config/SpringBootBasicConfigurationProviderTest.java b/modules/core_common_lib/src/test/java/at/asitplus/eidas/specific/core/test/config/SpringBootBasicConfigurationProviderTest.java new file mode 100644 index 00000000..0dd34494 --- /dev/null +++ b/modules/core_common_lib/src/test/java/at/asitplus/eidas/specific/core/test/config/SpringBootBasicConfigurationProviderTest.java @@ -0,0 +1,148 @@ +package at.asitplus.eidas.specific.core.test.config; + +import java.net.MalformedURLException; +import java.net.URL; +import java.util.Map; + +import org.apache.commons.lang3.RandomStringUtils; +import org.junit.Assert; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.test.annotation.DirtiesContext; +import org.springframework.test.annotation.DirtiesContext.ClassMode; +import org.springframework.test.context.ActiveProfiles; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.TestPropertySource; +import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; + +import at.asitplus.eidas.specific.core.MsEidasNodeConstants; +import at.asitplus.eidas.specific.core.config.ServiceProviderConfiguration; +import at.gv.egiz.eaaf.core.api.idp.IConfigurationWithSP; +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; + +@RunWith(SpringJUnit4ClassRunner.class) +@ContextConfiguration(locations = { + "/SpringTest-context_basic_realConfig.xml"}) +@TestPropertySource(locations = { "/config/junit_config_1.properties" }) +@ActiveProfiles("springBoot") +@DirtiesContext(classMode = ClassMode.BEFORE_CLASS) +public class SpringBootBasicConfigurationProviderTest { + + @Autowired private IConfigurationWithSP basicConfig; + + @Test + public void configPropInfos() { + Assert.assertEquals("size", 2, MsEidasNodeConstants.COUNTRY_SELECTION_PARAM_WHITELIST.size()); + + } + + @Test + public void loadSpNoExist() throws EaafConfigurationException { + ISpConfiguration spConfig = basicConfig.getServiceProviderConfiguration( + RandomStringUtils.randomAlphabetic(5)); + Assert.assertNull("spConfig", spConfig); + + } + + @Test + public void loadSpConfigBasicMode() throws EaafConfigurationException { + ISpConfiguration spConfig = basicConfig.getServiceProviderConfiguration("jUnitTest1"); + + Assert.assertNotNull("spConfig", spConfig); + Assert.assertEquals("uniqueId", "jUnitTest1", spConfig.getUniqueIdentifier()); + Assert.assertEquals("friendlyName", "NO FRIENDLYNAME SET", spConfig.getFriendlyName()); + Assert.assertEquals("pvp2.truststore", "", spConfig.getConfigurationValue("pvp2.metadata.truststore")); + String test = RandomStringUtils.randomAlphabetic(5); + Assert.assertEquals("pvp2.password", "1234pass", + spConfig.getConfigurationValue("pvp2.metadata.truststore.password", test)); + Assert.assertEquals("eidMode", true, spConfig.isConfigurationValue("newEidMode")); + Assert.assertEquals("notexistflag", false, spConfig.isConfigurationValue("notexist", false)); + Assert.assertNotNull("fullConfig", spConfig.getFullConfiguration()); + Assert.assertEquals("fullConfig", 4, spConfig.getFullConfiguration().size()); + + } + + @Test + public void loadSpConfigAdvancedMode() throws EaafConfigurationException { + ISpConfiguration spConfig = basicConfig.getServiceProviderConfiguration( + "jUnitTest2", ServiceProviderConfiguration.class); + + Assert.assertNotNull("spConfig", spConfig); + Assert.assertEquals("uniqueId", "jUnitTest2", spConfig.getUniqueIdentifier()); + Assert.assertEquals("friendlyName", "jUnit tester 2", spConfig.getFriendlyName()); + Assert.assertEquals("pvp2.truststore", "", spConfig.getConfigurationValue("pvp2.metadata.truststore")); + String test = RandomStringUtils.randomAlphabetic(5); + Assert.assertEquals("pvp2.password", test, + spConfig.getConfigurationValue("pvp2.metadata.truststore.notexist", test)); + Assert.assertEquals("eidMode", false, spConfig.isConfigurationValue("newEidMode")); + Assert.assertEquals("notexistflag", false, spConfig.isConfigurationValue("notexist", false)); + Assert.assertNotNull("fullConfig", spConfig.getFullConfiguration()); + Assert.assertEquals("fullConfig", 5, spConfig.getFullConfiguration().size()); + Assert.assertFalse("baseIdInternal", spConfig.hasBaseIdInternalProcessingRestriction()); + Assert.assertTrue("baseIdTransfer", spConfig.hasBaseIdTransferRestriction()); + + } + + @Test + public void loadSpConfigAdvancedModeWrongDecorator() throws EaafConfigurationException { + ISpConfiguration spConfig1 = basicConfig.getServiceProviderConfiguration( + "jUnitTest2", null); + Assert.assertNull("spConfig", spConfig1); + + String spConfig2 = basicConfig.getServiceProviderConfiguration( + "jUnitTest2", String.class); + Assert.assertNull("spConfig", spConfig2); + + } + + @Test + public void loadConfigValuesString() { + Assert.assertEquals("without default", "ownSpecificConnector", + basicConfig.getBasicConfiguration("auth.eIDAS.node_v2.entityId")); + + Assert.assertEquals("with default", "", + basicConfig.getBasicConfiguration("auth.eIDAS.szrclient.endpoint.prod", + RandomStringUtils.randomAlphabetic(5))); + + String rand1 = RandomStringUtils.randomAlphanumeric(5); + Assert.assertEquals("unknown with default", rand1, + basicConfig.getBasicConfiguration("notexist", rand1)); + + } + + @Test + public void loadConfigValuesBoolean() { + Assert.assertEquals("without default", true, + basicConfig.getBasicConfigurationBoolean("auth.eIDAS.szrclient.useTestService")); + + Assert.assertEquals("not exist with default", false, + basicConfig.getBasicConfigurationBoolean("auth.notexist", + false)); + + Assert.assertEquals("exist but empty with default", true, + basicConfig.getBasicConfigurationBoolean("auth.eIDAS.szrclient.params.vkz", true)); + + } + + @Test + public void loadConfigMap() { + Map entries = basicConfig.getBasicConfigurationWithPrefix("auth.eIDAS.szrclient"); + Assert.assertEquals("wrong size", 16, entries.size()); + Assert.assertTrue("missing element", entries.containsKey("endpoint.test")); + Assert.assertEquals("wrong entry", "http://localhost:1234/demoszr", entries.get("endpoint.test")); + + } + + @Test + public void validateUrl() throws MalformedURLException, EaafException { + Assert.assertEquals("wrong URL", "http://localhost/test", + basicConfig.validateIdpUrl(new URL("http://localhost/test/" + RandomStringUtils.randomAlphabetic(5)))); + + Assert.assertNull("wrong URL", + basicConfig.validateIdpUrl(new URL("http://localhost/wrong/" + RandomStringUtils.randomAlphabetic(5)))); + + } +} diff --git a/modules/core_common_lib/src/test/java/at/asitplus/eidas/specific/core/test/config/dummy/MsConnectorDummyConfigMap.java b/modules/core_common_lib/src/test/java/at/asitplus/eidas/specific/core/test/config/dummy/MsConnectorDummyConfigMap.java new file mode 100644 index 00000000..59ae5aff --- /dev/null +++ b/modules/core_common_lib/src/test/java/at/asitplus/eidas/specific/core/test/config/dummy/MsConnectorDummyConfigMap.java @@ -0,0 +1,120 @@ +package at.asitplus.eidas.specific.core.test.config.dummy; + +import java.io.IOException; +import java.io.InputStream; +import java.net.URI; +import java.net.URISyntaxException; +import java.net.URL; +import java.util.Map; + +import org.apache.commons.lang3.StringUtils; + +import at.gv.egiz.eaaf.core.exceptions.EaafException; +import at.gv.egiz.eaaf.core.test.dummy.DummyAuthConfigMap; +import lombok.Setter; + +/** + * MS-Connector specific dummy basic-config implementation. + * + * @author tlenz + * + */ +public class MsConnectorDummyConfigMap extends DummyAuthConfigMap { + + private static final String CONFIG_PREFIX = "eidas.ms."; + + @Setter + private String configRootDirSufix; + + /** + * Creates an emptry configuration. + * + */ + public MsConnectorDummyConfigMap() { + + } + + /** + * Dummy Application-configuration. + * + * @param configIs Property based configuration + * @throws IOException In case of an configuration read error + */ + public MsConnectorDummyConfigMap(final InputStream configIs) throws IOException { + super(configIs); + + } + + /** + * Dummy Application-configuration. + * + * @param path Path to property based configuration + * @throws IOException In case of an configuration read error + */ + public MsConnectorDummyConfigMap(final String path) throws IOException { + super(path); + + } + + + @Override + public String getBasicConfiguration(final String key) { + return super.getBasicConfiguration(addPrefixToKey(key)); + + } + + @Override + public String validateIdpUrl(final URL authReqUrl) throws EaafException { + return authReqUrl.toExternalForm(); + + } + + @Override + public Map getBasicConfigurationWithPrefix(final String prefix) { + return super.getBasicConfigurationWithPrefix(addPrefixToKey(prefix)); + + } + + @Override + public void putConfigValue(final String key, final String value) { + super.putConfigValue(addPrefixToKey(key), value); + } + + @Override + public void removeConfigValue(final String key) { + super.removeConfigValue(addPrefixToKey(key)); + + } + + @Override + public URI getConfigurationRootDirectory() { + URI basePath = super.getConfigurationRootDirectory(); + if (StringUtils.isNotEmpty(configRootDirSufix)) { + try { + return new URI(basePath.toString() + configRootDirSufix); + + } catch (URISyntaxException e) { + throw new RuntimeException("Wrong Dummyconfig", e); + + } + + } else { + return basePath; + + } + + + } + + private String addPrefixToKey(final String key) { + if (key.startsWith(CONFIG_PREFIX)) { + return key; + + } else { + return CONFIG_PREFIX + key; + + } + } + + +} diff --git a/modules/core_common_lib/src/test/java/at/asitplus/eidas/specific/core/test/config/dummy/MsConnectorDummySpConfiguration.java b/modules/core_common_lib/src/test/java/at/asitplus/eidas/specific/core/test/config/dummy/MsConnectorDummySpConfiguration.java new file mode 100644 index 00000000..922a13b7 --- /dev/null +++ b/modules/core_common_lib/src/test/java/at/asitplus/eidas/specific/core/test/config/dummy/MsConnectorDummySpConfiguration.java @@ -0,0 +1,28 @@ +package at.asitplus.eidas.specific.core.test.config.dummy; + +import java.util.List; +import java.util.Map; + +import at.gv.egiz.eaaf.core.api.idp.IConfiguration; +import at.gv.egiz.eaaf.core.impl.idp.module.test.DummySpConfiguration; +import lombok.Setter; + +public class MsConnectorDummySpConfiguration extends DummySpConfiguration { + + private static final long serialVersionUID = -3249018889871026127L; + + @Setter + private List loa; + + public MsConnectorDummySpConfiguration(Map spConfig, IConfiguration authConfig) { + super(spConfig, authConfig); + + } + + @Override + public List getRequiredLoA() { + return loa; + + } + +} diff --git a/modules/core_common_lib/src/test/resources/SpringTest-context_basic_realConfig.xml b/modules/core_common_lib/src/test/resources/SpringTest-context_basic_realConfig.xml new file mode 100644 index 00000000..66abbb39 --- /dev/null +++ b/modules/core_common_lib/src/test/resources/SpringTest-context_basic_realConfig.xml @@ -0,0 +1,25 @@ + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/modules/core_common_lib/src/test/resources/config/junit_config_1.properties b/modules/core_common_lib/src/test/resources/config/junit_config_1.properties new file mode 100644 index 00000000..160725d4 --- /dev/null +++ b/modules/core_common_lib/src/test/resources/config/junit_config_1.properties @@ -0,0 +1,124 @@ +## Basic service configuration +eidas.ms.context.url.prefix=http://localhost/test/ +eidas.ms.context.url.request.validation=true +eidas.ms.core.configRootDir=file:./src/test/resources/config/ + +eidas.ms.context.use.clustermode=true + +##Monitoring +eidas.ms.monitoring.eIDASNode.metadata.url= + + +##Specific logger configuration +eidas.ms.technicallog.write.MDS.into.techlog=true +eidas.ms.revisionlog.write.MDS.into.revisionlog=true +eidas.ms.revisionlog.logIPAddressOfUser=true + +##Directory for static Web content +eidas.ms.webcontent.static.directory=webcontent/ +eidas.ms.webcontent.templates=templates/ +eidas.ms.webcontent.properties=properties/messages + +## extended validation of pending-request Id's +eidas.ms.core.pendingrequestid.maxlifetime=300 +eidas.ms.core.pendingrequestid.digist.algorithm=HmacSHA256 +eidas.ms.core.pendingrequestid.digist.secret=pendingReqIdSecret + +## eIDAS Ref. Implementation connector ### +eidas.ms.auth.eIDAS.node_v2.entityId=ownSpecificConnector +eidas.ms.auth.eIDAS.node_v2.forward.endpoint= +eidas.ms.auth.eIDAS.node_v2.forward.method=POST +eidas.ms.auth.eIDAS.node_v2.countrycode=AT +eidas.ms.auth.eIDAS.node_v2.publicSectorTargets=.* +eidas.ms.auth.eIDAS.node_v2.workarounds.addAlwaysProviderName=true +eidas.ms.auth.eIDAS.node_v2.workarounds.useRequestIdAsTransactionIdentifier=true +eidas.ms.auth.eIDAS.node_v2.workarounds.useStaticProviderNameForPublicSPs=true +eidas.ms.auth.eIDAS.node_v2.staticProviderNameForPublicSPs=myNode + +eidas.ms.auth.eIDAS.node_v2.loa.requested.minimum=http://eidas.europa.eu/LoA/high + +eidas.ms.auth.eIDAS.szrclient.useTestService=true +eidas.ms.auth.eIDAS.szrclient.endpoint.prod= +eidas.ms.auth.eIDAS.szrclient.endpoint.test=http://localhost:1234/demoszr +eidas.ms.auth.eIDAS.szrclient.ssl.keyStore.path=keys/..... +eidas.ms.auth.eIDAS.szrclient.ssl.keyStore.password= +eidas.ms.auth.eIDAS.szrclient.ssl.trustStore.path= +eidas.ms.auth.eIDAS.szrclient.ssl.trustStore.password= +eidas.ms.auth.eIDAS.szrclient.timeout.connection=15 +eidas.ms.auth.eIDAS.szrclient.timeout.response=30 +eidas.ms.auth.eIDAS.szrclient.params.vkz= + +eidas.ms.auth.eIDAS.szrclient.params.useSZRForbPKCalculation=false + + +eidas.ms.auth.eIDAS.authblock.keystore.password=f/+saJBc3a}*/T^s +eidas.ms.auth.eIDAS.authblock.keystore.friendlyName=connectorkeypair +eidas.ms.auth.eIDAS.authblock.keystore.path=./../keystore/teststore.jks +eidas.ms.auth.eIDAS.authblock.keystore.type=jks +eidas.ms.auth.eIDAS.authblock.key.alias=connectorkeypair +eidas.ms.auth.eIDAS.authblock.key.password=f/+saJBc3a}*/T^s + + +#Raw eIDAS Id data storage +eidas.ms.auth.eIDAS.szrclient.workarounds.eidmapping.revisionlog.active=true + +eidas.ms.auth.eIDAS.szrclient.params.setPlaceOfBirthIfAvailable=true +eidas.ms.auth.eIDAS.szrclient.params.setBirthNameIfAvailable=true + +eidas.ms.auth.eIDAS.szrclient.debug.logfullmessages=true +eidas.ms.auth.eIDAS.szrclient.debug.useDummySolution=true + +##without mandates +eidas.ms.auth.eIDAS.node_v2.attributes.requested.onlynatural.0=PersonIdentifier,true +eidas.ms.auth.eIDAS.node_v2.attributes.requested.onlynatural.1=FamilyName,true +eidas.ms.auth.eIDAS.node_v2.attributes.requested.onlynatural.2=FirstName,true +eidas.ms.auth.eIDAS.node_v2.attributes.requested.onlynatural.3=DateOfBirth,true + +eidas.ms.auth.eIDAS.node_v2.attributes.requested.de.onlynatural.4=PlaceOfBirth,false +eidas.ms.auth.eIDAS.node_v2.attributes.requested.de.onlynatural.5=BirthName,false +eidas.ms.auth.eIDAS.node_v2.attributes.requested.de.onlynatural.6=Gender,false +eidas.ms.auth.eIDAS.node_v2.attributes.requested.de.onlynatural.7=CurrentAddress,false +eidas.ms.auth.eIDAS.node_v2.attributes.requested.de.onlynatural.8=testtest,false + +##with mandates ---- NOT FULLY SUPPORTED AT THE MOMENT ----- +eidas.ms.auth.eIDAS.node_v2.attributes.requested.representation.0=PersonIdentifier,true +eidas.ms.auth.eIDAS.node_v2.attributes.requested.representation.1=FamilyName,true +eidas.ms.auth.eIDAS.node_v2.attributes.requested.representation.2=FirstName,true +eidas.ms.auth.eIDAS.node_v2.attributes.requested.representation.3=DateOfBirth,true +eidas.ms.auth.eIDAS.node_v2.attributes.requested.representation.4=LegalPerson,true +eidas.ms.auth.eIDAS.node_v2.attributes.requested.representation.5=LegalName,true + + +## PVP2 S-Profile end-point configuration +eidas.ms.pvp2.keystore.path=keys/..... +eidas.ms.pvp2.keystore.password= +eidas.ms.pvp2.key.metadata.alias= +eidas.ms.pvp2.key.metadata.password= +eidas.ms.pvp2.key.signing.alias= +eidas.ms.pvp2.key.signing.password= +eidas.ms.pvp2.metadata.validity=24 + +## Service Provider configuration +eidas.ms.sp.0.uniqueID=jUnitTest1 +eidas.ms.sp.0.pvp2.metadata.truststore= +eidas.ms.sp.0.pvp2.metadata.truststore.password=1234pass +eidas.ms.sp.0.newEidMode=true + +eidas.ms.sp.1.uniqueID=jUnitTest2 +eidas.ms.sp.1.friendlyName=jUnit tester 2 +eidas.ms.sp.1.pvp2.metadata.truststore= +eidas.ms.sp.1.pvp2.metadata.truststore.password= +eidas.ms.sp.1.newEidMode=false + +#eidas.ms.sp.0.friendlyName= +#eidas.ms.sp.0.pvp2.metadata.url= +#eidas.ms.sp.0.policy.allowed.requested.targets=.* +#eidas.ms.sp.0.policy.hasBaseIdTransferRestriction=false + + +##only for advanced config +eidas.ms.configuration.sp.disableRegistrationRequirement= +eidas.ms.configuration.restrictions.baseID.spTransmission= +eidas.ms.configuration.auth.default.countrycode= +eidas.ms.configuration.pvp.scheme.validation= +eidas.ms.configuration.pvp.enable.entitycategories= \ No newline at end of file diff --git a/modules/core_common_webapp/checks/spotbugs-exclude.xml b/modules/core_common_webapp/checks/spotbugs-exclude.xml new file mode 100644 index 00000000..fbab3b53 --- /dev/null +++ b/modules/core_common_webapp/checks/spotbugs-exclude.xml @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/modules/core_common_webapp/pom.xml b/modules/core_common_webapp/pom.xml new file mode 100644 index 00000000..b36153e6 --- /dev/null +++ b/modules/core_common_webapp/pom.xml @@ -0,0 +1,136 @@ + + 4.0.0 + + at.asitplus.eidas.ms_specific + modules + 1.2.4-SNAPSHOT + + core_common_webapp + WebApplication commons + + + + eIDASNode-local + local + file:${basedir}/../../repository + + + + + + at.asitplus.eidas.ms_specific + core_common_lib + + + + at.gv.egiz.eaaf + eaaf-core + + + + + eu.eidas + eidas-jcache-ignite-specific-communication + + + org.springframework.boot + spring-boot-starter-actuator + + + org.thymeleaf + thymeleaf-spring5 + + + + javax.servlet + javax.servlet-api + provided + + + + + + junit + junit + test + + + org.springframework + spring-test + test + + + org.springframework.boot + spring-boot-starter-test + test + + + at.gv.egiz.eaaf + eaaf_core_utils + test + test-jar + + + at.gv.egiz.eaaf + eaaf-core + test + test-jar + + + at.gv.egiz.eaaf + eaaf_module_pvp2_sp + test + test-jar + + + at.gv.egiz.eaaf + eaaf_module_pvp2_idp + test + + + at.gv.egiz.eaaf + eaaf_module_pvp2_idp + test + test-jar + + + com.squareup.okhttp3 + mockwebserver + test + + + + + + + core_common_webapp + + + + + maven-surefire-plugin + + 1 + + + + org.apache.maven.surefire + surefire-junit47 + ${surefire.version} + + + + + + com.github.spotbugs + spotbugs-maven-plugin + ${spotbugs-maven-plugin.version} + + checks/spotbugs-exclude.xml + + + + + + + diff --git a/modules/core_common_webapp/src/main/java/at/asitplus/eidas/specific/core/SpringContextCloseHandler.java b/modules/core_common_webapp/src/main/java/at/asitplus/eidas/specific/core/SpringContextCloseHandler.java new file mode 100644 index 00000000..81f23841 --- /dev/null +++ b/modules/core_common_webapp/src/main/java/at/asitplus/eidas/specific/core/SpringContextCloseHandler.java @@ -0,0 +1,170 @@ +package at.asitplus.eidas.specific.core; + +import java.util.Iterator; +import java.util.Map; +import java.util.Map.Entry; + +import org.slf4j.Logger; +import org.springframework.beans.BeansException; +import org.springframework.beans.factory.config.BeanPostProcessor; +import org.springframework.context.ApplicationContext; +import org.springframework.context.ApplicationContextAware; +import org.springframework.context.ApplicationListener; +import org.springframework.context.event.ContextClosedEvent; +import org.springframework.context.event.EventListener; +import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor; +import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler; + +import at.gv.egiz.components.spring.api.IDestroyableObject; +import eu.eidas.auth.cache.IgniteInstanceInitializerSpecificCommunication; + +/** + * SpringContext CloseHandler. + * + * @author tlenz + * + */ + +public class SpringContextCloseHandler + implements ApplicationListener, ApplicationContextAware, BeanPostProcessor { + + private static final Logger log = + org.slf4j.LoggerFactory.getLogger(SpringContextCloseHandler.class); + + private ApplicationContext context; + + /* + * (non-Javadoc) + * + * @see org.springframework.context.ApplicationListener#onApplicationEvent(org. + * springframework.context. ApplicationEvent) + */ + @Override + @EventListener + public void onApplicationEvent(final ContextClosedEvent arg0) { + log.info("MS-specific eIDAS-Node shutdown process started ..."); + + try { + log.debug("CleanUp objects with implements the IDestroyable interface ... "); + final Map objectsToDestroy = + context.getBeansOfType(IDestroyableObject.class); + internalIDestroyableObject(objectsToDestroy); + log.info("Object cleanUp complete"); + + log.debug("Stopping Spring Thread-Pools ... "); + // shut-down task schedulers + final Map schedulers = + context.getBeansOfType(ThreadPoolTaskScheduler.class); + internalThreadPoolTaskScheduler(schedulers); + + // shut-down task executors + final Map executers = + context.getBeansOfType(ThreadPoolTaskExecutor.class); + internalThreadPoolTaskExecutor(executers); + log.debug("Spring Thread-Pools stopped"); + + + //clean-up eIDAS node + Map nodeIgnite = + context.getBeansOfType(IgniteInstanceInitializerSpecificCommunication.class); + log.info("Find #{} Apache Ignite instances from eIDAS Ref. impl.", nodeIgnite.size()); + for (Entry el : nodeIgnite.entrySet()) { + if (el.getValue().getInstance() != null) { + el.getValue().getInstance().close(); + el.getValue().destroyInstance(); + log.debug("Shutdown Apache-Ignite: {}", el.getKey()); + + } + } + + log.info("MS-specific eIDAS-Node shutdown process finished"); + + } catch (final Exception e) { + log.warn("MS-specific eIDAS-Node shutdown process has an error.", e); + + } + + } + + /* + * (non-Javadoc) + * + * @see org.springframework.beans.factory.config.BeanPostProcessor# + * postProcessAfterInitialization(java. lang.Object, java.lang.String) + */ + @Override + public Object postProcessAfterInitialization(final Object arg0, final String arg1) + throws BeansException { + if (arg0 instanceof ThreadPoolTaskScheduler) { + ((ThreadPoolTaskScheduler) arg0).setWaitForTasksToCompleteOnShutdown(true); + } + if (arg0 instanceof ThreadPoolTaskExecutor) { + ((ThreadPoolTaskExecutor) arg0).setWaitForTasksToCompleteOnShutdown(true); + } + return arg0; + + } + + /* + * (non-Javadoc) + * + * @see org.springframework.beans.factory.config.BeanPostProcessor# + * postProcessBeforeInitialization(java .lang.Object, java.lang.String) + */ + @Override + public Object postProcessBeforeInitialization(final Object arg0, final String arg1) + throws BeansException { + return arg0; + + } + + /* + * (non-Javadoc) + * + * @see + * org.springframework.context.ApplicationContextAware#setApplicationContext(org + * .springframework. context.ApplicationContext) + */ + @Override + public void setApplicationContext(final ApplicationContext arg0) throws BeansException { + this.context = arg0; + + } + + private void internalThreadPoolTaskExecutor(final Map executers) { + for (final ThreadPoolTaskExecutor executor : executers.values()) { + executor.shutdown(); + log.debug("Executer {} with active {} work has killed", executor.getThreadNamePrefix(), + executor.getActiveCount()); + + } + + } + + // Not required at the moment + private void internalThreadPoolTaskScheduler( + final Map schedulers) { + log.trace("Stopping #{} task-schedulers", schedulers.size()); + + } + + private void internalIDestroyableObject(final Map objectsToDestroy) { + if (objectsToDestroy != null) { + final Iterator> interator = + objectsToDestroy.entrySet().iterator(); + while (interator.hasNext()) { + final Entry object = interator.next(); + try { + object.getValue().fullyDestroy(); + log.debug("Object with ID: {} is destroyed", object.getKey()); + + } catch (final Exception e) { + log.warn("Destroing object with ID: {} FAILED!", object.getKey(), null, e); + + } + } + } + + } + +} diff --git a/modules/core_common_webapp/src/main/java/at/asitplus/eidas/specific/core/auth/AuthenticationManager.java b/modules/core_common_webapp/src/main/java/at/asitplus/eidas/specific/core/auth/AuthenticationManager.java new file mode 100644 index 00000000..6be1f0ba --- /dev/null +++ b/modules/core_common_webapp/src/main/java/at/asitplus/eidas/specific/core/auth/AuthenticationManager.java @@ -0,0 +1,60 @@ +/* + * Copyright 2018 A-SIT Plus GmbH + * AT-specific eIDAS Connector has been developed in a cooperation between EGIZ, + * A-SIT Plus GmbH, A-SIT, and Graz University of Technology. + * + * Licensed under the EUPL, Version 1.2 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "License"); + * You may not use this work except in compliance with the License. + * You may obtain a copy of the License at: + * https://joinup.ec.europa.eu/news/understanding-eupl-v12 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. +*/ + +package at.asitplus.eidas.specific.core.auth; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.stereotype.Service; + +import at.gv.egiz.eaaf.core.api.IRequest; +import at.gv.egiz.eaaf.core.api.idp.process.ExecutionContext; +import at.gv.egiz.eaaf.core.api.idp.slo.ISloInformationContainer; +import at.gv.egiz.eaaf.core.exceptions.EaafException; +import at.gv.egiz.eaaf.core.impl.idp.auth.AbstractAuthenticationManager; +import at.gv.egiz.eaaf.core.impl.idp.controller.protocols.RequestImpl; + +@Service("AuthenticationManager") +public class AuthenticationManager extends AbstractAuthenticationManager { + private static final Logger log = LoggerFactory.getLogger(AuthenticationManager.class); + + @Override + public ISloInformationContainer performSingleLogOut(HttpServletRequest httpReq, + HttpServletResponse httpResp, + IRequest pendingReq, String internalSsoId) throws EaafException { + throw new RuntimeException("Single LogOut is NOT supported by this implementation"); + + } + + @Override + protected void populateExecutionContext(ExecutionContext executionContext, + RequestImpl pendingReq, HttpServletRequest httpReq) + throws EaafException { + log.trace("No implementation-specific population of execution-context required ... "); + + } + +} diff --git a/modules/core_common_webapp/src/main/java/at/asitplus/eidas/specific/core/builder/AuthenticationDataBuilder.java b/modules/core_common_webapp/src/main/java/at/asitplus/eidas/specific/core/builder/AuthenticationDataBuilder.java new file mode 100644 index 00000000..e5937b99 --- /dev/null +++ b/modules/core_common_webapp/src/main/java/at/asitplus/eidas/specific/core/builder/AuthenticationDataBuilder.java @@ -0,0 +1,255 @@ +/* + * Copyright 2018 A-SIT Plus GmbH + * AT-specific eIDAS Connector has been developed in a cooperation between EGIZ, + * A-SIT Plus GmbH, A-SIT, and Graz University of Technology. + * + * Licensed under the EUPL, Version 1.2 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "License"); + * You may not use this work except in compliance with the License. + * You may obtain a copy of the License at: + * https://joinup.ec.europa.eu/news/understanding-eupl-v12 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + */ + +package at.asitplus.eidas.specific.core.builder; + +import java.util.Date; +import java.util.Optional; +import java.util.Set; +import java.util.stream.Collectors; + +import org.springframework.stereotype.Service; + +import com.google.common.collect.Streams; + +import at.asitplus.eidas.specific.core.MsEidasNodeConstants; +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.data.PvpAttributeDefinitions.EidIdentityStatusLevelValues; +import at.gv.egiz.eaaf.core.api.idp.IAuthData; +import at.gv.egiz.eaaf.core.api.idp.ISpConfiguration; +import at.gv.egiz.eaaf.core.api.idp.auth.data.IAuthProcessDataContainer; +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.impl.data.Pair; +import at.gv.egiz.eaaf.core.impl.data.Triple; +import at.gv.egiz.eaaf.core.impl.idp.AuthenticationData; +import at.gv.egiz.eaaf.core.impl.idp.EidAuthenticationData; +import at.gv.egiz.eaaf.core.impl.idp.auth.builder.AbstractAuthenticationDataBuilder; +import at.gv.egiz.eaaf.core.impl.idp.auth.data.EidAuthProcessDataWrapper; +import lombok.extern.slf4j.Slf4j; + +@Service("AuthenticationDataBuilder") +@Slf4j +public class AuthenticationDataBuilder extends AbstractAuthenticationDataBuilder { + + private static final String ERROR_B11 = "builder.11"; + + @Override + protected IAuthData buildDeprecatedAuthData(IRequest pendingReq) throws EaafException { + final EidAuthProcessDataWrapper authProcessData = + pendingReq.getSessionData(EidAuthProcessDataWrapper.class); + final EidAuthenticationData authData = new EidAuthenticationData(); + + // set basis infos + super.generateDeprecatedBasicAuthData(authData, pendingReq, authProcessData); + + // set specific informations + authData.setSsoSessionValidTo( + new Date(new Date().getTime() + MsEidasNodeConstants.DEFAULT_PVP_ASSERTION_VALIDITY * 60 * 1000)); + + authData.setEidStatus(authProcessData.isTestIdentity() + ? EidIdentityStatusLevelValues.TESTIDENTITY + : EidIdentityStatusLevelValues.IDENTITY); + + return authData; + + } + + @Override + protected void buildServiceSpecificAuthenticationData(IAuthData authData, IRequest pendingReq) + throws EaafException { + if (authData instanceof EidAuthenticationData) { + ((EidAuthenticationData) authData).setGenericData( + ExtendedPvpAttributeDefinitions.EID_PII_TRANSACTION_ID_NAME, + pendingReq.getUniquePiiTransactionIdentifier()); + log.trace("Inject piiTransactionId: {} into AuthData", pendingReq.getUniquePiiTransactionIdentifier()); + + // set specific informations + ((EidAuthenticationData) authData).setSsoSessionValidTo( + new Date(new Date().getTime() + MsEidasNodeConstants.DEFAULT_PVP_ASSERTION_VALIDITY * 60 * 1000)); + + // set E-ID status-level + final EidAuthProcessDataWrapper authProcessData = + pendingReq.getSessionData(EidAuthProcessDataWrapper.class); + ((EidAuthenticationData) authData).setEidStatus(authProcessData.isTestIdentity() + ? EidIdentityStatusLevelValues.TESTIDENTITY + : EidIdentityStatusLevelValues.IDENTITY); + + // handle mandate informations + buildMandateInformation((EidAuthenticationData) authData, pendingReq, authProcessData); + + } else { + throw new RuntimeException("Can not inject PiiTransactionId because AuthData is of unknown type: " + + authData.getClass().getName()); + + } + + } + + @Override + protected IAuthData getAuthDataInstance(IRequest arg0) throws EaafException { + return new EidAuthenticationData(); + + } + + @Override + protected Pair buildOAspecificbPK(IRequest pendingReq, AuthenticationData authData) + throws EaafBuilderException { + return super.buildOAspecificbPK(pendingReq, authData); + + } + + @Override + protected Pair getEncryptedBpkFromPvpAttribute(IAuthProcessDataContainer arg0, + AuthenticationData arg1, ISpConfiguration arg2) throws EaafBuilderException { + return null; + + } + + @Override + protected Pair getbaseIdFromSzr(AuthenticationData arg0, String arg1, String arg2) { + return null; + + } + + private void buildMandateInformation(EidAuthenticationData authData, IRequest pendingReq, + EidAuthProcessDataWrapper authProcessData) throws EaafAuthenticationException, EaafBuilderException, + EaafStorageException { + authData.setUseMandate(authProcessData.isMandateUsed()); + if (authProcessData.isMandateUsed()) { + log.debug("Build mandate-releated authentication data ... "); + if (authProcessData.isForeigner()) { + buildMandateInformationForEidasIncoming(); + + } else { + buildMandateInformationForEidasOutgoing(authData, pendingReq, authProcessData); + + } + + // inject mandate information into authdata + final Set mandateAttributes = Streams.concat( + MsEidasNodeConstants.DEFAULT_REQUIRED_MANDATE_NAT_PVP_ATTRIBUTES.stream(), + MsEidasNodeConstants.DEFAULT_REQUIRED_MANDATE_JUR_PVP_ATTRIBUTES.stream()) + .map(el -> el.getFirst()) + .collect(Collectors.toSet()); + + authProcessData.getGenericSessionDataStream() + .filter(el -> mandateAttributes.contains(el.getKey())) + .forEach(el -> { + try { + authData.setGenericData(el.getKey(), el.getValue()); + + } catch (final EaafStorageException e) { + log.error("Can not store attribute: {} into session.", el.getKey(), e); + throw new RuntimeException(e); + + } + }); + } + } + + private void buildMandateInformationForEidasIncoming() { + log.debug("Find eIDAS incoming process. Generated mandate-information for ID-Austria system ... "); + + // TODO: implement IDA specific processing of foreign mandate + + } + + private void buildMandateInformationForEidasOutgoing(EidAuthenticationData authData, IRequest pendingReq, + EidAuthProcessDataWrapper authProcessData) throws EaafAuthenticationException, EaafBuilderException, + EaafStorageException { + log.debug("Find eIDAS outgoing process. Generated mandate-information for other country ... "); + if (authProcessData.getGenericDataFromSession( + PvpAttributeDefinitions.MANDATE_NAT_PER_BPK_NAME) != null) { + final Optional> missingAttribute = + MsEidasNodeConstants.DEFAULT_REQUIRED_MANDATE_NAT_PVP_ATTRIBUTES.stream() + .filter(el -> authProcessData.getGenericDataFromSession(el.getFirst()) == null) + .findFirst(); + if (missingAttribute.isPresent()) { + log.error("ID-Austria response contains not all attributes for nat. person mandator. Missing: {}", + missingAttribute.get().getFirst()); + throw new EaafAuthenticationException(ERROR_B11, new Object[] { "Nat. person mandate" }); + + } else { + log.trace("Find nat. person mandate. Mandate can be used as it is "); + authData.setGenericData(MsEidasNodeConstants.ATTR_EIDAS_NAT_MANDATOR_PERSONAL_IDENTIFIER, + extractBpkFromResponse(authProcessData.getGenericDataFromSession( + PvpAttributeDefinitions.MANDATE_NAT_PER_BPK_NAME, String.class))); + + } + + } else { + final Optional> missingAttribute = + MsEidasNodeConstants.DEFAULT_REQUIRED_MANDATE_JUR_PVP_ATTRIBUTES.stream() + .filter(el -> authProcessData.getGenericDataFromSession(el.getFirst()) == null) + .findFirst(); + if (missingAttribute.isPresent()) { + log.error("ID-Austria response contains not all attributes for legal. person mandator. Missing: {}", + missingAttribute.get().getFirst()); + throw new EaafAuthenticationException(ERROR_B11, new Object[] { "Legal. person mandate" }); + + } else { + log.trace( + "Find jur. person mandate. Generate eIDAS identifier from legal-person sourcePin and type ... "); + final String sourcePin = authProcessData.getGenericDataFromSession( + PvpAttributeDefinitions.MANDATE_LEG_PER_SOURCE_PIN_NAME, String.class); + final String sourcePinType = authProcessData.getGenericDataFromSession( + PvpAttributeDefinitions.MANDATE_LEG_PER_SOURCE_PIN_TYPE_NAME, String.class); + + // build leagl-person identifier for eIDAS out-going + final String[] splittedTarget = + pendingReq.getServiceProviderConfiguration().getAreaSpecificTargetIdentifier().split("\\+"); + StringBuilder sb = new StringBuilder(); + sb.append(splittedTarget[1]) + .append("/") + .append(splittedTarget[2]) + .append("/") + .append(sourcePinType) + .append("+") + .append(sourcePin); + + log.debug("Use legal-person eIDAS identifer: {} from baseId: {} and baseIdType: {}", + sb.toString(), sourcePin, sourcePinType); + authData.setGenericData(MsEidasNodeConstants.ATTR_EIDAS_JUR_MANDATOR_PERSONAL_IDENTIFIER, sb.toString()); + + } + } + } + + 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; + + } + } + +} diff --git a/modules/core_common_webapp/src/main/java/at/asitplus/eidas/specific/core/config/StaticResourceConfiguration.java b/modules/core_common_webapp/src/main/java/at/asitplus/eidas/specific/core/config/StaticResourceConfiguration.java new file mode 100644 index 00000000..06377c3f --- /dev/null +++ b/modules/core_common_webapp/src/main/java/at/asitplus/eidas/specific/core/config/StaticResourceConfiguration.java @@ -0,0 +1,220 @@ +/* + * Copyright 2019 A-SIT Plus GmbH + * AT-specific eIDAS Connector has been developed in a cooperation between EGIZ, + * A-SIT Plus GmbH, A-SIT, and Graz University of Technology. + * + * Licensed under the EUPL, Version 1.2 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "License"); + * You may not use this work except in compliance with the License. + * You may obtain a copy of the License at: + * https://joinup.ec.europa.eu/news/understanding-eupl-v12 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + */ + +package at.asitplus.eidas.specific.core.config; + +import java.net.MalformedURLException; +import java.util.List; + +import org.apache.commons.lang3.StringUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.support.ReloadableResourceBundleMessageSource; +import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry; +import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; +import org.springframework.web.servlet.i18n.CookieLocaleResolver; +import org.thymeleaf.templateresolver.FileTemplateResolver; + +import at.asitplus.eidas.specific.core.MsEidasNodeConstants; +import at.gv.egiz.eaaf.core.api.idp.IConfiguration; +import at.gv.egiz.eaaf.core.api.logging.IMessageSourceLocation; +import at.gv.egiz.eaaf.core.impl.utils.FileUtils; + +/** + * Spring configurator for Web resources. + * + * @author tlenz + * + */ +@Configuration +public class StaticResourceConfiguration implements WebMvcConfigurer { + private static final Logger log = LoggerFactory.getLogger(StaticResourceConfiguration.class); + private static final String[] CLASSPATH_RESOURCE_LOCATIONS = { + "/" + }; + + private static final String DEFAULT_MESSAGE_SOURCE = "classpath:properties/status_messages"; + + @Autowired + private IConfiguration basicConfig; + + @Override + public void addResourceHandlers(ResourceHandlerRegistry registry) { + final String staticResources = basicConfig.getBasicConfiguration( + MsEidasNodeConstants.PROP_CONFIG_WEBCONTENT_STATIC_PATH); + try { + if (StringUtils.isNotEmpty(staticResources)) { + String absPath = FileUtils.makeAbsoluteUrl(staticResources, basicConfig + .getConfigurationRootDirectory()); + if (!absPath.endsWith("/")) { + absPath += "/"; + } + + registry.addResourceHandler("/static/**").addResourceLocations(absPath); + log.info("Add Ressourcefolder: " + absPath + " for static Web content"); + + } else { + log.debug("No Ressourcefolder for static Web content"); + } + + } catch (final MalformedURLException e) { + log.warn("Can NOT initialize ressourcefolder for static Web content", e); + + } + + registry.addResourceHandler("/**").addResourceLocations(CLASSPATH_RESOURCE_LOCATIONS); + + } + + /** + * Get a message source with only internal message properties. + * + * @param ressourceLocations List of source-locations + * @return + */ + @Bean + public ReloadableResourceBundleMessageSource internalMessageSource( + @Autowired(required = false) final List ressourceLocations) { + final ReloadableResourceBundleMessageSource messageSource = + new ReloadableResourceBundleMessageSource(); + + // add default message source + messageSource.setBasename(DEFAULT_MESSAGE_SOURCE); + + if (ressourceLocations != null) { + // load more message sources + for (final IMessageSourceLocation el : ressourceLocations) { + if (el.getMessageSourceLocation() != null) { + for (final String source : el.getMessageSourceLocation()) { + messageSource.addBasenames(source); + log.debug("Add additional messageSources: {}", el.getMessageSourceLocation().toArray()); + + } + } + } + } + + messageSource.setDefaultEncoding("UTF-8"); + return messageSource; + + } + + /** + * Get full message source with internal and external message-properties files. + * + * @param ressourceLocations List of source-locations + * @return + */ + @Bean + public ReloadableResourceBundleMessageSource messageSource( + @Autowired(required = false) final List ressourceLocations) { + final ReloadableResourceBundleMessageSource messageSource = + new ReloadableResourceBundleMessageSource(); + messageSource.setDefaultEncoding("UTF-8"); + messageSource.setParentMessageSource(internalMessageSource(ressourceLocations)); + + final String staticResources = basicConfig + .getBasicConfiguration(MsEidasNodeConstants.PROP_CONFIG_WEBCONTENT_PROPERTIES_PATH); + try { + if (StringUtils.isNotEmpty(staticResources)) { + final String absPath = + FileUtils.makeAbsoluteUrl(staticResources, basicConfig.getConfigurationRootDirectory()); + messageSource.setBasename(absPath); + + } else { + log.debug("No Ressourcefolder for dynamic Web content templates"); + + } + + } catch (final MalformedURLException e) { + log.warn("Can NOT initialize ressourcefolder for dynamic Web content templates", e); + + } + + return messageSource; + + } + + /** + * Get a i18n resolver based on cookies. + * + * @return + */ + @Bean + public CookieLocaleResolver localeResolver() { + final CookieLocaleResolver localeResolver = new CookieLocaleResolver(); + localeResolver.setCookieName("currentLanguage"); + localeResolver.setCookieMaxAge(3600); + return localeResolver; + + } + + /** + * Get a Tyhmeleaf Template-Resolver with external configuration path. + * + * @return + */ + @Bean(name = "templateResolver") + public FileTemplateResolver templateResolver() { + final String staticResources = basicConfig + .getBasicConfiguration(MsEidasNodeConstants.PROP_CONFIG_WEBCONTENT_TEMPLATES_PATH); + try { + if (StringUtils.isNotEmpty(staticResources)) { + String absPath = + FileUtils.makeAbsoluteUrl(staticResources, basicConfig.getConfigurationRootDirectory()); + if (!absPath.endsWith("/")) { + absPath += "/"; + + } + + if (absPath.startsWith("file:")) { + absPath = absPath.substring("file:".length()); + + } + + final FileTemplateResolver viewResolver = new FileTemplateResolver(); + viewResolver.setPrefix(absPath); + viewResolver.setSuffix(".html"); + viewResolver.setTemplateMode("HTML"); + viewResolver.setCacheable(false); + + log.info("Add Ressourcefolder: {} for dynamic Web content templates", absPath); + return viewResolver; + + } else { + log.debug("No Ressourcefolder for dynamic Web content templates"); + + } + + } catch (final MalformedURLException e) { + log.warn("Can NOT initialize ressourcefolder for dynamic Web content templates", e); + + } + + throw new RuntimeException("Can NOT initialize HTML template resolver"); + + } +} diff --git a/modules/core_common_webapp/src/main/java/at/asitplus/eidas/specific/core/health/EidasNodeMetadataHealthIndicator.java b/modules/core_common_webapp/src/main/java/at/asitplus/eidas/specific/core/health/EidasNodeMetadataHealthIndicator.java new file mode 100644 index 00000000..754fe9ab --- /dev/null +++ b/modules/core_common_webapp/src/main/java/at/asitplus/eidas/specific/core/health/EidasNodeMetadataHealthIndicator.java @@ -0,0 +1,69 @@ +package at.asitplus.eidas.specific.core.health; + +import java.io.ByteArrayInputStream; + +import javax.xml.transform.TransformerFactoryConfigurationError; + +import org.apache.commons.lang3.StringUtils; +import org.apache.http.StatusLine; +import org.apache.http.client.methods.HttpGet; +import org.apache.http.client.methods.HttpUriRequest; +import org.apache.http.client.utils.URIBuilder; +import org.apache.http.entity.ContentType; +import org.apache.http.impl.client.CloseableHttpClient; +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.core.MsEidasNodeConstants; +import at.gv.egiz.eaaf.core.api.idp.IConfiguration; +import at.gv.egiz.eaaf.core.impl.data.Triple; +import at.gv.egiz.eaaf.core.impl.http.HttpUtils; +import at.gv.egiz.eaaf.core.impl.http.IHttpClientFactory; +import at.gv.egiz.eaaf.core.impl.utils.DomUtils; +import lombok.extern.slf4j.Slf4j; + +@Slf4j +public class EidasNodeMetadataHealthIndicator implements HealthIndicator { + + @Autowired IConfiguration config; + @Autowired IHttpClientFactory httpClientFactory; + + @Override + public Health health() { + try { + final String urlString = config.getBasicConfiguration( + MsEidasNodeConstants.PROP_CONFIG_MONITORING_EIDASNODE_METADATAURL); + if (StringUtils.isEmpty(urlString)) { + log.trace("No eIDASNode metadata URL. Skipping test ... "); + return Health.unknown().build(); + + } + + // create HTTP client + CloseableHttpClient httpClient = httpClientFactory.getHttpClient(); + URIBuilder uriBuilder = new URIBuilder(urlString); + HttpUriRequest request = new HttpGet(uriBuilder.build()); + + final Triple respCode = httpClient.execute(request, + HttpUtils.bodyStatusCodeResponseHandler()); + if (respCode.getFirst().getStatusCode() != 200) { + log.warn("Monitoring: Get http StatusCode: {} from eIDAS-Node Metadata endpoint", + respCode.getFirst().getStatusCode()); + return Health.down().withDetail("http StatusCode", respCode.getFirst().getStatusCode()).build(); + + } + + // parse metadata + DomUtils.parseXmlNonValidating(respCode.getSecond()); + + return Health.up().build(); + + } catch (Exception | TransformerFactoryConfigurationError e) { + log.warn("Monitoring: Can not read SAML2 metadata from eIDAS-Node", e); + return Health.down().down(e).build(); + + } + } + +} diff --git a/modules/core_common_webapp/src/main/java/at/asitplus/eidas/specific/core/health/IgniteClusterHealthIndicator.java b/modules/core_common_webapp/src/main/java/at/asitplus/eidas/specific/core/health/IgniteClusterHealthIndicator.java new file mode 100644 index 00000000..651f9125 --- /dev/null +++ b/modules/core_common_webapp/src/main/java/at/asitplus/eidas/specific/core/health/IgniteClusterHealthIndicator.java @@ -0,0 +1,52 @@ +package at.asitplus.eidas.specific.core.health; + +import org.apache.ignite.Ignite; +import org.springframework.boot.actuate.health.Health; +import org.springframework.boot.actuate.health.HealthIndicator; + +import eu.eidas.auth.cache.IgniteInstanceInitializerSpecificCommunication; +import lombok.Setter; +import lombok.extern.slf4j.Slf4j; + +/** + * HealthCheck that validate Nodes in Apache-Ignite Cluster. + * + * @author tlenz + * + */ +@Slf4j +public class IgniteClusterHealthIndicator implements HealthIndicator { + + @Setter + protected IgniteInstanceInitializerSpecificCommunication igniteInstanceInitializerSpecificCommunication; + + @Override + public Health health() { + final Ignite instance = igniteInstanceInitializerSpecificCommunication.getInstance(); + + // check if Apache Ignite cluster is active + if (!instance.cluster().active()) { + return Health.outOfService().build(); + + } + + final Health.Builder healthBuilder; + // Status UP requires more than 1 node because MS-Connector and eIDAS-Node operations as + // micro-services + if (instance.cluster().nodes().size() > 1) { + healthBuilder = Health.up(); + + } else { + // Something looks wrong if only a single node was found because MS-Connector and eIDAS-Node + // operations as micro-services + healthBuilder = Health.outOfService(); + + } + + healthBuilder.withDetail("#Nodes", instance.cluster().nodes().size()); + log.trace("Ignite state. #Nodes: {}", instance.cluster().nodes().size()); + return healthBuilder.build(); + + } + +} diff --git a/modules/core_common_webapp/src/main/java/at/asitplus/eidas/specific/core/interceptor/WebFrontEndSecurityInterceptor.java b/modules/core_common_webapp/src/main/java/at/asitplus/eidas/specific/core/interceptor/WebFrontEndSecurityInterceptor.java new file mode 100644 index 00000000..f665be51 --- /dev/null +++ b/modules/core_common_webapp/src/main/java/at/asitplus/eidas/specific/core/interceptor/WebFrontEndSecurityInterceptor.java @@ -0,0 +1,90 @@ +/* + * Copyright 2018 A-SIT Plus GmbH + * AT-specific eIDAS Connector has been developed in a cooperation between EGIZ, + * A-SIT Plus GmbH, A-SIT, and Graz University of Technology. + * + * Licensed under the EUPL, Version 1.2 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "License"); + * You may not use this work except in compliance with the License. + * You may obtain a copy of the License at: + * https://joinup.ec.europa.eu/news/understanding-eupl-v12 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. +*/ + +package at.asitplus.eidas.specific.core.interceptor; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.springframework.web.servlet.HandlerInterceptor; +import org.springframework.web.servlet.ModelAndView; + +/** + * Spring interceptor to inject securtiy headers into http response. + * + * @author tlenz + * + */ +public class WebFrontEndSecurityInterceptor implements HandlerInterceptor { + + /* + * (non-Javadoc) + * + * @see + * org.springframework.web.servlet.HandlerInterceptor#preHandle(javax.servlet. + * http.HttpServletRequest, javax.servlet.http.HttpServletResponse, + * java.lang.Object) + */ + @Override + public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) + throws Exception { + + // set security headers + response.setHeader("Expires", "Sat, 6 May 1995 12:00:00 GMT"); + response.setHeader("Pragma", "no-cache"); + response.setHeader("Cache-control", "no-store, no-cache, must-revalidate"); + + return true; + + } + + /* + * (non-Javadoc) + * + * @see + * org.springframework.web.servlet.HandlerInterceptor#postHandle(javax.servlet. + * http.HttpServletRequest, javax.servlet.http.HttpServletResponse, + * java.lang.Object, org.springframework.web.servlet.ModelAndView) + */ + @Override + public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, + ModelAndView modelAndView) throws Exception { + + } + + /* + * (non-Javadoc) + * + * @see + * org.springframework.web.servlet.HandlerInterceptor#afterCompletion(javax. + * servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse, + * java.lang.Object, java.lang.Exception) + */ + @Override + public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, + Exception ex) + throws Exception { + + } + +} diff --git a/modules/core_common_webapp/src/main/java/at/asitplus/eidas/specific/core/logger/RevisionLogger.java b/modules/core_common_webapp/src/main/java/at/asitplus/eidas/specific/core/logger/RevisionLogger.java new file mode 100644 index 00000000..03a56976 --- /dev/null +++ b/modules/core_common_webapp/src/main/java/at/asitplus/eidas/specific/core/logger/RevisionLogger.java @@ -0,0 +1,110 @@ +/* + * Copyright 2018 A-SIT Plus GmbH + * AT-specific eIDAS Connector has been developed in a cooperation between EGIZ, + * A-SIT Plus GmbH, A-SIT, and Graz University of Technology. + * + * Licensed under the EUPL, Version 1.2 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "License"); + * You may not use this work except in compliance with the License. + * You may obtain a copy of the License at: + * https://joinup.ec.europa.eu/news/understanding-eupl-v12 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. +*/ + +package at.asitplus.eidas.specific.core.logger; + +import java.util.Date; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; + +import at.asitplus.eidas.specific.core.MsEidasNodeConstants; +import at.gv.egiz.components.eventlog.api.Event; +import at.gv.egiz.components.eventlog.api.EventConstants; +import at.gv.egiz.components.eventlog.api.EventLogFactory; +import at.gv.egiz.components.eventlog.api.EventLoggingException; +import at.gv.egiz.eaaf.core.api.IRequest; +import at.gv.egiz.eaaf.core.api.idp.IConfiguration; +import at.gv.egiz.eaaf.core.api.idp.ISpConfiguration; +import at.gv.egiz.eaaf.core.api.logging.IRevisionLogger; + +public class RevisionLogger extends EventLogFactory implements IRevisionLogger { + private static final Logger log = LoggerFactory.getLogger(RevisionLogger.class); + + @Autowired + private IConfiguration basicConfig; + + @Override + public void logEvent(ISpConfiguration oaConfig, int eventCode, String message) { + logEvent(createNewEvent(new Date().getTime(), eventCode, message)); + + } + + @Override + public void logEvent(IRequest pendingRequest, int eventCode) { + logEvent(createNewEvent(new Date().getTime(), eventCode, + pendingRequest.getUniqueSessionIdentifier(), pendingRequest.getUniqueTransactionIdentifier())); + + } + + @Override + public void logEvent(IRequest pendingRequest, int eventCode, String message) { + logEvent(createNewEvent(new Date().getTime(), eventCode, message, + pendingRequest.getUniqueSessionIdentifier(), pendingRequest.getUniqueTransactionIdentifier())); + + } + + @Override + public void logEvent(int eventCode, String message) { + logEvent(createNewEvent(new Date().getTime(), eventCode, message)); + + } + + @Override + public void logEvent(String sessionID, String transactionID, int eventCode, String message) { + logEvent(createNewEvent(new Date().getTime(), eventCode, message, sessionID, transactionID)); + + } + + @Override + public void logEvent(String sessionID, String transactionID, int eventCode) { + logEvent(createNewEvent(new Date().getTime(), eventCode, sessionID, transactionID)); + + } + + private void logEvent(Event event) { + try { + if (event.getEventCode() >= 1100) { + if (event.getEventCode() == EventConstants.TRANSACTION_IP + && !basicConfig.getBasicConfigurationBoolean( + MsEidasNodeConstants.PROP_CONFIG_REVISIONLOG_LOG_IP_ADDRESS_OF_USER, true)) { + log.trace("Ignore Event: " + event.getEventCode() + " because IP adresse logging prohibited"); + return; + + } + + getEventLog().logEvent(event); + + } else { + log.trace("Ignore Event: " + event.getEventCode() + + " because session functionallity is not implemented"); + } + + } catch (final EventLoggingException e) { + log.warn("Event logging FAILED! Reason: " + e.getMessage()); + + } + + } +} diff --git a/modules/core_common_webapp/src/main/java/at/asitplus/eidas/specific/core/logger/StatisticLogger.java b/modules/core_common_webapp/src/main/java/at/asitplus/eidas/specific/core/logger/StatisticLogger.java new file mode 100644 index 00000000..bdaf83f6 --- /dev/null +++ b/modules/core_common_webapp/src/main/java/at/asitplus/eidas/specific/core/logger/StatisticLogger.java @@ -0,0 +1,141 @@ +/* + * Copyright 2018 A-SIT Plus GmbH + * AT-specific eIDAS Connector has been developed in a cooperation between EGIZ, + * A-SIT Plus GmbH, A-SIT, and Graz University of Technology. + * + * Licensed under the EUPL, Version 1.2 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "License"); + * You may not use this work except in compliance with the License. + * You may obtain a copy of the License at: + * https://joinup.ec.europa.eu/news/understanding-eupl-v12 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. +*/ + +package at.asitplus.eidas.specific.core.logger; + +import org.apache.commons.lang3.StringUtils; +import org.joda.time.DateTime; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import at.asitplus.eidas.specific.core.MsEidasNodeConstants; +import at.gv.egiz.eaaf.core.api.IRequest; +import at.gv.egiz.eaaf.core.api.idp.IAuthData; +import at.gv.egiz.eaaf.core.api.logging.IStatisticLogger; +import at.gv.egiz.eaaf.core.exceptions.EaafException; + +public class StatisticLogger implements IStatisticLogger { + + private static final Logger log = LoggerFactory.getLogger(StatisticLogger.class); + + private static final String DATEFORMATER = "yyyy.MM.dd-HH:mm:ss+z"; + private static final String STATUS_SUCCESS = "success"; + private static final String STATUS_ERROR = "error"; + + @Override + public void logSuccessOperation(IRequest protocolRequest, IAuthData authData, boolean isSsoSession) { + log.info(buildLogMessage( + protocolRequest.getUniqueTransactionIdentifier(), + protocolRequest.getSpEntityId(), + protocolRequest.getRawData(MsEidasNodeConstants.DATA_REQUESTERID), + protocolRequest.getServiceProviderConfiguration().getAreaSpecificTargetIdentifier(), + authData.getCiticenCountryCode(), + STATUS_SUCCESS, + StringUtils.EMPTY, + StringUtils.EMPTY)); + + } + + @Override + public void logErrorOperation(Throwable throwable) { + String errorId = "TODO"; + if (throwable instanceof EaafException) { + errorId = ((EaafException) throwable).getErrorId(); + } + + log.info(buildLogMessage( + StringUtils.EMPTY, + StringUtils.EMPTY, + StringUtils.EMPTY, + StringUtils.EMPTY, + StringUtils.EMPTY, + STATUS_ERROR, + errorId, + throwable.getMessage())); + + } + + @Override + public void logErrorOperation(Throwable throwable, IRequest errorRequest) { + String errorId = "TODO"; + if (throwable instanceof EaafException) { + errorId = ((EaafException) throwable).getErrorId(); + } + + if (errorRequest != null) { + log.info(buildLogMessage( + errorRequest.getUniqueTransactionIdentifier(), + errorRequest.getSpEntityId(), + errorRequest.getRawData(MsEidasNodeConstants.DATA_REQUESTERID), + errorRequest.getServiceProviderConfiguration().getAreaSpecificTargetIdentifier(), + StringUtils.EMPTY, + STATUS_ERROR, + errorId, + throwable.getMessage())); + } else { + log.info(buildLogMessage( + StringUtils.EMPTY, + StringUtils.EMPTY, + StringUtils.EMPTY, + StringUtils.EMPTY, + StringUtils.EMPTY, + STATUS_ERROR, + errorId, + throwable.getMessage())); + } + + } + + @Override + public void internalTesting() throws Exception { + log.trace("Not implemented for a File-based logger"); + + } + + private String buildLogMessage(String transId, String entityId, Object requesterId, String target, + String cc, + String status, String errorCode, String errorMsg) { + String logMsg = StringUtils.EMPTY; + + // data,tId,MOAID-Id,SP-Id,bPKTarget,CC,status,error-code,error-msg + + logMsg += DateTime.now().toString(DATEFORMATER) + ","; + logMsg += transId + ","; + logMsg += entityId + ","; + + if (requesterId instanceof String && StringUtils.isNotEmpty((String) requesterId)) { + logMsg += (String) requesterId + ","; + } else { + logMsg += StringUtils.EMPTY + ","; + } + + logMsg += target + ","; + logMsg += cc + ","; + + logMsg += status + ","; + logMsg += errorCode + ","; + logMsg += errorMsg; + + return logMsg; + } +} diff --git a/modules/core_common_webapp/src/main/java/at/asitplus/eidas/specific/core/mapper/LoALevelMapper.java b/modules/core_common_webapp/src/main/java/at/asitplus/eidas/specific/core/mapper/LoALevelMapper.java new file mode 100644 index 00000000..e3ab5d45 --- /dev/null +++ b/modules/core_common_webapp/src/main/java/at/asitplus/eidas/specific/core/mapper/LoALevelMapper.java @@ -0,0 +1,60 @@ +/* + * Copyright 2018 A-SIT Plus GmbH + * AT-specific eIDAS Connector has been developed in a cooperation between EGIZ, + * A-SIT Plus GmbH, A-SIT, and Graz University of Technology. + * + * Licensed under the EUPL, Version 1.2 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "License"); + * You may not use this work except in compliance with the License. + * You may obtain a copy of the License at: + * https://joinup.ec.europa.eu/news/understanding-eupl-v12 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. +*/ + +package at.asitplus.eidas.specific.core.mapper; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.stereotype.Service; + +import at.gv.egiz.eaaf.core.api.data.EaafConstants; +import at.gv.egiz.eaaf.core.api.data.ILoALevelMapper; + +@Service("LoALevelMapper") +public class LoALevelMapper implements ILoALevelMapper { + private static final Logger log = LoggerFactory.getLogger(LoALevelMapper.class); + + @Override + public String mapToSecClass(String loa) { + log.info("Mapping to PVP SecClass is NOT supported"); + return null; + } + + @Override + public String mapToEidasLoa(String loa) { + if (loa.startsWith(EaafConstants.EIDAS_LOA_PREFIX)) { + return loa; + } else { + log.info("Can NOT map '" + loa + "' to eIDAS LoA"); + } + + return null; + + } + + @Override + public String mapEidasQaaToStorkQaa(String eidasqaaLevel) { + return null; + } + +} diff --git a/modules/core_common_webapp/src/main/java/at/asitplus/eidas/specific/core/provider/StatusMessageProvider.java b/modules/core_common_webapp/src/main/java/at/asitplus/eidas/specific/core/provider/StatusMessageProvider.java new file mode 100644 index 00000000..b47c0b63 --- /dev/null +++ b/modules/core_common_webapp/src/main/java/at/asitplus/eidas/specific/core/provider/StatusMessageProvider.java @@ -0,0 +1,182 @@ +/* + * Copyright 2018 A-SIT Plus GmbH + * AT-specific eIDAS Connector has been developed in a cooperation between EGIZ, + * A-SIT Plus GmbH, A-SIT, and Graz University of Technology. + * + * Licensed under the EUPL, Version 1.2 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "License"); + * You may not use this work except in compliance with the License. + * You may obtain a copy of the License at: + * https://joinup.ec.europa.eu/news/understanding-eupl-v12 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. +*/ + +package at.asitplus.eidas.specific.core.provider; + +import java.text.MessageFormat; +import java.util.Locale; +import java.util.MissingResourceException; +import java.util.ResourceBundle; + +import org.apache.commons.lang3.StringUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.context.MessageSource; +import org.springframework.context.MessageSourceAware; +import org.springframework.context.NoSuchMessageException; +import org.springframework.context.i18n.LocaleContextHolder; +import org.springframework.stereotype.Service; + +import at.gv.egiz.eaaf.core.api.IStatusMessenger; +import at.gv.egiz.eaaf.core.exceptions.EaafException; +import at.gv.egiz.eaaf.core.impl.logging.LogMessageProviderFactory; + +@Service("StatusMessageProvider") +public class StatusMessageProvider implements IStatusMessenger, MessageSourceAware { + private static final Logger log = LoggerFactory.getLogger(StatusMessageProvider.class); + + private static final String ERROR_MESSAGES_UNAVAILABLE = + "Error messages can NOT be load from application. Only errorCode: {0} is availabe"; + private static final String ERROR_NO_MESSAGE = "No errormesseage for error with number.={0}"; + + private static final String ERROR_EXTERNALERROR_CODES_UNAVAILABLE = + "External error-codes can NOT be load from application. Only internal errorCode: {0} is availabe"; + private static final String ERROR_NO_EXTERNALERROR_CODE = + "No external error for internal error with number.={0}"; + private static final String MSG_WARN_NO_SOURCE = "MessageCode: {} is NOT SET for locale: {}"; + private static final String MSG_INFO = "Use locale: {} as default"; + + // external error codes + private static final String DEFAULT_EXTERNALERROR_RESOURCES = "properties/external_statuscodes_map"; + private static final Locale DEFAULT_EXTERNALERROR_LOCALES = new Locale("en", "GB"); + private ResourceBundle externalError = null; + + //internal messanges + private MessageSource messageSource; + + @Override + public String getMessageWithoutDefault(final String messageId, final Object[] parameters) { + if (messageSource == null) { + return null; + + } else { + try { + final Locale locale = LocaleContextHolder.getLocale(); + return messageSource.getMessage(messageId, parameters, locale); + + } catch (final NoSuchMessageException e) { + log.info(MSG_WARN_NO_SOURCE, messageId, LocaleContextHolder.getLocale()); + log.debug(MSG_INFO, Locale.ENGLISH); + + try { + return messageSource.getMessage(messageId, parameters, Locale.ENGLISH); + + } catch (final NoSuchMessageException e2) { + log.info(MSG_WARN_NO_SOURCE, messageId, Locale.ENGLISH); + + } + + } catch (final MissingResourceException e2) { + log.warn("No message source", e2); + + } + } + + return null; + + } + + @Override + public String getMessage(final String messageId, final Object[] parameters) { + if (messageSource == null) { + return MessageFormat.format(ERROR_MESSAGES_UNAVAILABLE, new Object[]{messageId}); + + } else { + try { + final Locale locale = LocaleContextHolder.getLocale(); + return messageSource.getMessage(messageId, parameters, locale); + + } catch (final NoSuchMessageException e) { + log.info(MSG_WARN_NO_SOURCE, messageId, LocaleContextHolder.getLocale()); + log.debug(MSG_INFO, Locale.ENGLISH); + + try { + return messageSource.getMessage(messageId, parameters, Locale.ENGLISH); + + } catch (final NoSuchMessageException e2) { + return MessageFormat.format(ERROR_NO_MESSAGE, new Object[]{messageId}); + + } + + } catch (final MissingResourceException e2) { + return MessageFormat.format(ERROR_NO_MESSAGE, new Object[]{messageId}); + + } + } + } + + @Override + public String getResponseErrorCode(Throwable throwable) { + String errorCode = IStatusMessenger.CODES_EXTERNAL_ERROR_GENERIC; + if (throwable instanceof EaafException) { + errorCode = ((EaafException) throwable).getErrorId(); + + } + + return errorCode; + + } + + @Override + public String mapInternalErrorToExternalError(String intErrorCode) { + // initialize messages + if (externalError == null) { + this.externalError = ResourceBundle.getBundle( + DEFAULT_EXTERNALERROR_RESOURCES, + DEFAULT_EXTERNALERROR_LOCALES); + + } + + // create the message + if (externalError == null) { + log.warn(MessageFormat.format(ERROR_EXTERNALERROR_CODES_UNAVAILABLE, new Object[] { intErrorCode })); + return IStatusMessenger.CODES_EXTERNAL_ERROR_GENERIC; + + } else { + try { + if (StringUtils.isNotEmpty(intErrorCode)) { + return externalError.getString(intErrorCode); + + } else { + return IStatusMessenger.CODES_EXTERNAL_ERROR_GENERIC; + + } + + } catch (final MissingResourceException e2) { + log.info(MessageFormat.format(ERROR_NO_EXTERNALERROR_CODE, new Object[] { intErrorCode })); + return IStatusMessenger.CODES_EXTERNAL_ERROR_GENERIC; + + } + } + } + + @Override + public void setMessageSource(MessageSource messageSource) { + this.messageSource = messageSource; + + log.info("Injecting 'StatusMessanger' into 'LogMessageProviderFactory'"); + LogMessageProviderFactory.setStatusMessager(this); + + } + +} diff --git a/modules/core_common_webapp/src/main/java/at/asitplus/eidas/specific/core/storage/CacheWithEidasBackend.java b/modules/core_common_webapp/src/main/java/at/asitplus/eidas/specific/core/storage/CacheWithEidasBackend.java new file mode 100644 index 00000000..0eeb35d9 --- /dev/null +++ b/modules/core_common_webapp/src/main/java/at/asitplus/eidas/specific/core/storage/CacheWithEidasBackend.java @@ -0,0 +1,35 @@ +/* + * Copyright 2018 A-SIT Plus GmbH + * AT-specific eIDAS Connector has been developed in a cooperation between EGIZ, + * A-SIT Plus GmbH, A-SIT, and Graz University of Technology. + * + * Licensed under the EUPL, Version 1.2 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "License"); + * You may not use this work except in compliance with the License. + * You may obtain a copy of the License at: + * https://joinup.ec.europa.eu/news/understanding-eupl-v12 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. +*/ + +package at.asitplus.eidas.specific.core.storage; + +import eu.eidas.auth.commons.cache.ConcurrentCacheService; +import eu.eidas.auth.commons.tx.AbstractCache; + +public class CacheWithEidasBackend extends AbstractCache { + + protected CacheWithEidasBackend(ConcurrentCacheService concurrentMapService) { + super(concurrentMapService); + } + +} diff --git a/modules/core_common_webapp/src/main/java/at/asitplus/eidas/specific/core/storage/EidasCacheTransactionStoreDecorator.java b/modules/core_common_webapp/src/main/java/at/asitplus/eidas/specific/core/storage/EidasCacheTransactionStoreDecorator.java new file mode 100644 index 00000000..5a59a4e0 --- /dev/null +++ b/modules/core_common_webapp/src/main/java/at/asitplus/eidas/specific/core/storage/EidasCacheTransactionStoreDecorator.java @@ -0,0 +1,180 @@ +/* + * Copyright 2018 A-SIT Plus GmbH + * AT-specific eIDAS Connector has been developed in a cooperation between EGIZ, + * A-SIT Plus GmbH, A-SIT, and Graz University of Technology. + * + * Licensed under the EUPL, Version 1.2 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "License"); + * You may not use this work except in compliance with the License. + * You may obtain a copy of the License at: + * https://joinup.ec.europa.eu/news/understanding-eupl-v12 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. +*/ + +package at.asitplus.eidas.specific.core.storage; + +import java.util.Arrays; +import java.util.Date; +import java.util.List; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.actuate.health.Health; +import org.springframework.boot.actuate.health.HealthIndicator; + +import at.gv.egiz.eaaf.core.api.storage.ITransactionStorage; +import at.gv.egiz.eaaf.core.exceptions.EaafException; +import at.gv.egiz.eaaf.core.exceptions.EaafStorageException; +import at.gv.egiz.eaaf.core.impl.utils.Random; + +public class EidasCacheTransactionStoreDecorator implements ITransactionStorage, HealthIndicator { + private static final Logger log = LoggerFactory.getLogger(EidasCacheTransactionStoreDecorator.class); + + @Autowired(required = true) + private CacheWithEidasBackend storage; + + @Override + public Health health() { + try { + final String key = Random.nextHexRandom16(); + final String value = Random.nextHexRandom16(); + + this.put(key, value, -1); + final String result = this.get(key, String.class); + this.remove(key); + + if (result != null && result.equals(value)) { + return Health.up().build(); + + } else { + log.warn("Montioring: TestValue: " + value + " does NOT match in Storage test"); + return Health.down().build(); + + } + + } catch (final EaafException e) { + log.warn("Montioring: Can not read/write to storage.", e); + return Health.down().down(e).build(); + + } + } + + @Override + public void changeKey(String oldKey, String newKey, Object value) throws EaafException { + if (containsKey(oldKey)) { + final TransactionStoreElement el = storage.get(oldKey); + el.setKey(newKey); + el.setData(value); + storage.put(newKey, el); + boolean delResult = storage.remove(oldKey); + log.trace("Object: {} removed from cache: {}", oldKey, delResult); + + } else { + throw new EaafStorageException("No element in TransactionStorage with key: " + oldKey); + } + + } + + @Override + public List clean(Date now, long dataTimeOut) { + log.info("Clean is NOT implemented, because its not needed"); + return Arrays.asList(); + + } + + @Override + public boolean containsKey(String key) { + return storage.containsKey(key); + + } + + @Override + public Object get(String key) throws EaafException { + if (key != null && containsKey(key)) { + final TransactionStoreElement element = storage.get(key); + return element.getData(); + + } else { + return null; + } + } + + @Override + public T get(String key, Class type) throws EaafException { + return get(key, type, -1); + + } + + @Override + public T get(String key, Class type, long dataTimeOut) throws EaafException { + if (key != null && containsKey(key)) { + final TransactionStoreElement value = storage.get(key); + + if (dataTimeOut > -1) { + final long now = new Date().getTime(); + if (now - value.getCreated().getTime() > dataTimeOut) { + log.info("Transaction-Data with key: " + key + " is out of time."); + throw new EaafStorageException("Transaction-Data with key: " + key + " is out of time."); + + } + } + + if (type.isAssignableFrom(value.getData().getClass())) { + return (T) value.getData(); + + } else { + log.warn("Can NOT cast '" + value.getClass() + "' to '" + type + "'"); + } + + } + + return null; + } + + @Override + public Object getRaw(String key) throws EaafException { + return storage.get(key); + + } + + @Override + public void put(String key, Object value, int dataTimeOut) throws EaafException { + final TransactionStoreElement element = new TransactionStoreElement(); + element.setKey(key); + element.setData(value); + storage.put(key, element); + + } + + @Override + public void putRaw(String key, Object value) throws EaafException { + if (value instanceof TransactionStoreElement) { + storage.put(((TransactionStoreElement) value).getKey(), (TransactionStoreElement) value); + } else { + log.info(value.getClass().getName() + " is NOT a RAW element of " + ITransactionStorage.class + .getName()); + } + + } + + @Override + public void remove(String key) { + if (containsKey(key)) { + log.trace("Remove element with key: " + key + " from " + ITransactionStorage.class.getName()); + boolean delResult = storage.remove(key); + log.trace("Object: {} removed from cache: {}", key, delResult); + + } + } +} diff --git a/modules/core_common_webapp/src/main/java/at/asitplus/eidas/specific/core/storage/SimpleInMemoryTransactionStorage.java b/modules/core_common_webapp/src/main/java/at/asitplus/eidas/specific/core/storage/SimpleInMemoryTransactionStorage.java new file mode 100644 index 00000000..a3a8af0f --- /dev/null +++ b/modules/core_common_webapp/src/main/java/at/asitplus/eidas/specific/core/storage/SimpleInMemoryTransactionStorage.java @@ -0,0 +1,169 @@ +/* + * Copyright 2018 A-SIT Plus GmbH + * AT-specific eIDAS Connector has been developed in a cooperation between EGIZ, + * A-SIT Plus GmbH, A-SIT, and Graz University of Technology. + * + * Licensed under the EUPL, Version 1.2 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "License"); + * You may not use this work except in compliance with the License. + * You may obtain a copy of the License at: + * https://joinup.ec.europa.eu/news/understanding-eupl-v12 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. +*/ + +package at.asitplus.eidas.specific.core.storage; + +import java.util.ArrayList; +import java.util.Date; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; +import java.util.concurrent.ConcurrentHashMap; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import at.gv.egiz.eaaf.core.api.storage.ITransactionStorage; +import at.gv.egiz.eaaf.core.exceptions.EaafException; +import at.gv.egiz.eaaf.core.exceptions.EaafStorageException; + +public class SimpleInMemoryTransactionStorage implements ITransactionStorage { + private static final Logger log = LoggerFactory.getLogger(SimpleInMemoryTransactionStorage.class); + + private final Map storage = + new ConcurrentHashMap<>(); + + @Override + public void changeKey(String oldKey, String newKey, Object value) throws EaafException { + if (containsKey(oldKey)) { + final TransactionStoreElement el = storage.get(oldKey); + el.setKey(newKey); + storage.put(newKey, el); + storage.remove(oldKey); + + } else { + throw new EaafStorageException("No element in TransactionStorage with key: " + oldKey); + } + + } + + @Override + public List clean(Date now, long dataTimeOut) { + final List result = new ArrayList<>(); + final Iterator> iterator = storage.entrySet().iterator(); + while (iterator.hasNext()) { + final Entry key = iterator.next(); + synchronized (storage) { + if (storage.containsKey(key.getKey())) { + final TransactionStoreElement element = key.getValue(); + if (now.getTime() - element.getCreated().getTime() > dataTimeOut) { + result.add(key.getKey()); + } + } + } + } + + return result; + + } + + @Override + public boolean containsKey(String key) { + if (key != null) { + return storage.containsKey(key); + } else { + return false; + } + + } + + @Override + public Object get(String key) throws EaafException { + if (key != null && containsKey(key)) { + final TransactionStoreElement element = storage.get(key); + return element.getData(); + + } else { + return null; + } + } + + @Override + public T get(String key, Class type) throws EaafException { + return get(key, type, -1); + + } + + @Override + public T get(String key, Class type, long dataTimeOut) throws EaafException { + if (key != null && containsKey(key)) { + final TransactionStoreElement value = storage.get(key); + + if (dataTimeOut > -1) { + final long now = new Date().getTime(); + if (now - value.getCreated().getTime() > dataTimeOut) { + log.info("Transaction-Data with key: " + key + " is out of time."); + throw new EaafStorageException("Transaction-Data with key: " + key + " is out of time."); + + } + } + + if (type.isAssignableFrom(value.getData().getClass())) { + return (T) value.getData(); + + } else { + log.warn("Can NOT cast '" + value.getClass() + "' to '" + type + "'"); + } + + } + + return null; + } + + @Override + public Object getRaw(String key) throws EaafException { + return storage.get(key); + + } + + @Override + public void put(String key, Object value, int dataTimeOut) throws EaafException { + final TransactionStoreElement element = new TransactionStoreElement(); + element.setKey(key); + element.setData(value); + storage.put(key, element); + + } + + @Override + public void putRaw(String key, Object value) throws EaafException { + if (value instanceof TransactionStoreElement) { + storage.put(((TransactionStoreElement) value).getKey(), (TransactionStoreElement) value); + } else { + log.info(value.getClass().getName() + " is NOT a RAW element of " + ITransactionStorage.class + .getName()); + } + + } + + @Override + public void remove(String key) { + if (containsKey(key)) { + log.debug("Remove element with key: " + key + " from " + ITransactionStorage.class.getName()); + storage.remove(key); + + } + } + +} diff --git a/modules/core_common_webapp/src/main/java/at/asitplus/eidas/specific/core/storage/TransactionStoreElement.java b/modules/core_common_webapp/src/main/java/at/asitplus/eidas/specific/core/storage/TransactionStoreElement.java new file mode 100644 index 00000000..48668d4b --- /dev/null +++ b/modules/core_common_webapp/src/main/java/at/asitplus/eidas/specific/core/storage/TransactionStoreElement.java @@ -0,0 +1,70 @@ +/* + * Copyright 2018 A-SIT Plus GmbH + * AT-specific eIDAS Connector has been developed in a cooperation between EGIZ, + * A-SIT Plus GmbH, A-SIT, and Graz University of Technology. + * + * Licensed under the EUPL, Version 1.2 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "License"); + * You may not use this work except in compliance with the License. + * You may obtain a copy of the License at: + * https://joinup.ec.europa.eu/news/understanding-eupl-v12 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. +*/ + +package at.asitplus.eidas.specific.core.storage; + +import java.io.Serializable; +import java.util.Date; + +public class TransactionStoreElement implements Serializable { + + private static final long serialVersionUID = 1L; + private String key = null; + private Object data = null; + private Date created; + + public String getKey() { + return key; + } + + public void setKey(String key) { + this.key = key; + } + + public Object getData() { + return data; + } + + public void setData(Object data) { + this.data = data; + } + + public Date getCreated() { + return copyOrNull(created); + } + + public void setCreated(Date created) { + this.created = copyOrNull(created); + } + + private Date copyOrNull(Date in) { + if (in != null) { + return new Date(in.getTime()); + + } + + return null; + + } + +} diff --git a/modules/core_common_webapp/src/main/resources/specific_eIDAS_core.beans.xml b/modules/core_common_webapp/src/main/resources/specific_eIDAS_core.beans.xml new file mode 100644 index 00000000..f37dc451 --- /dev/null +++ b/modules/core_common_webapp/src/main/resources/specific_eIDAS_core.beans.xml @@ -0,0 +1,61 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/modules/core_common_webapp/src/main/resources/specific_eIDAS_core_storage.beans.xml b/modules/core_common_webapp/src/main/resources/specific_eIDAS_core_storage.beans.xml new file mode 100644 index 00000000..259f5605 --- /dev/null +++ b/modules/core_common_webapp/src/main/resources/specific_eIDAS_core_storage.beans.xml @@ -0,0 +1,39 @@ + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/modules/core_common_webapp/src/test/java/at/asitplus/eidas/specific/core/test/health/EidasNodeMetadataHealthIndicatorNoEndpointTest.java b/modules/core_common_webapp/src/test/java/at/asitplus/eidas/specific/core/test/health/EidasNodeMetadataHealthIndicatorNoEndpointTest.java new file mode 100644 index 00000000..06ce8abe --- /dev/null +++ b/modules/core_common_webapp/src/test/java/at/asitplus/eidas/specific/core/test/health/EidasNodeMetadataHealthIndicatorNoEndpointTest.java @@ -0,0 +1,70 @@ +package at.asitplus.eidas.specific.core.test.health; + +import java.io.IOException; + +import org.apache.commons.io.IOUtils; +import org.junit.AfterClass; +import org.junit.Assert; +import org.junit.BeforeClass; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.actuate.health.Health; +import org.springframework.http.MediaType; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.TestPropertySource; +import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; +import org.springframework.test.context.web.WebAppConfiguration; + +import at.asitplus.eidas.specific.core.health.EidasNodeMetadataHealthIndicator; +import okhttp3.mockwebserver.MockResponse; +import okhttp3.mockwebserver.MockWebServer; + +@RunWith(SpringJUnit4ClassRunner.class) +@ContextConfiguration({ + "/spring/SpringTest-context_healthcheck.xml" }) +@TestPropertySource(locations = {"classpath:/config/junit_config_2_springboot.properties"}) +@WebAppConfiguration +public class EidasNodeMetadataHealthIndicatorNoEndpointTest { + + @Autowired EidasNodeMetadataHealthIndicator health; + + private static MockWebServer mockWebServer = null; + + /** + * Testclass initializer. + * + * @throws IOException In case of an error + */ + @BeforeClass + public static void classInitializer() throws IOException { + mockWebServer = new MockWebServer(); + mockWebServer.start(40900); + mockWebServer.url("/mockup"); + + } + + @AfterClass + public static void resetTestEnviroment() throws NoSuchFieldException, SecurityException, + IllegalArgumentException, IllegalAccessException, IOException { + mockWebServer.shutdown(); + + } + + @Test + public void noEndpointInConfiguration() throws IOException { + //set-up status + mockWebServer.enqueue(new MockResponse().setResponseCode(200) + .setBody(IOUtils.toString(EidasNodeMetadataHealthIndicatorNoEndpointTest.class + .getResourceAsStream("/config/log4j.properties"), "UTF-8")) + .setHeader("Content-Type", MediaType.APPLICATION_XML)); + + //perform test + Health status = health.health(); + + //validate state + Assert.assertEquals("wrong healthState", Health.unknown().build().getStatus(), status.getStatus()); + + } + +} diff --git a/modules/core_common_webapp/src/test/java/at/asitplus/eidas/specific/core/test/health/EidasNodeMetadataHealthIndicatorTest.java b/modules/core_common_webapp/src/test/java/at/asitplus/eidas/specific/core/test/health/EidasNodeMetadataHealthIndicatorTest.java new file mode 100644 index 00000000..e8bc7817 --- /dev/null +++ b/modules/core_common_webapp/src/test/java/at/asitplus/eidas/specific/core/test/health/EidasNodeMetadataHealthIndicatorTest.java @@ -0,0 +1,102 @@ +package at.asitplus.eidas.specific.core.test.health; + +import java.io.IOException; + +import org.apache.commons.io.IOUtils; +import org.junit.AfterClass; +import org.junit.Assert; +import org.junit.BeforeClass; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.actuate.health.Health; +import org.springframework.http.MediaType; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.TestPropertySource; +import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; +import org.springframework.test.context.web.WebAppConfiguration; + +import at.asitplus.eidas.specific.core.health.EidasNodeMetadataHealthIndicator; +import okhttp3.mockwebserver.MockResponse; +import okhttp3.mockwebserver.MockWebServer; + +@RunWith(SpringJUnit4ClassRunner.class) +@ContextConfiguration({ + "/spring/SpringTest-context_healthcheck.xml" }) +@TestPropertySource(locations = {"classpath:/config/junit_config_1_springboot.properties"}) +@WebAppConfiguration +public class EidasNodeMetadataHealthIndicatorTest { + + @Autowired EidasNodeMetadataHealthIndicator health; + + private static MockWebServer mockWebServer = null; + + /** + * Testclass initializer. + * + * @throws IOException In case of an error + */ + @BeforeClass + public static void classInitializer() throws IOException { + mockWebServer = new MockWebServer(); + mockWebServer.start(40900); + mockWebServer.url("/mockup"); + + } + + @AfterClass + public static void resetTestEnviroment() throws NoSuchFieldException, SecurityException, + IllegalArgumentException, IllegalAccessException, IOException { + mockWebServer.shutdown(); + + } + + @Test + public void httpStatusCode500() throws IOException { + //set-up status + mockWebServer.enqueue(new MockResponse().setResponseCode(500) + .setBody(IOUtils.toString(EidasNodeMetadataHealthIndicatorTest.class + .getResourceAsStream("/data/metadata_valid.xml"), "UTF-8")) + .setHeader("Content-Type", MediaType.APPLICATION_XML)); + + //perform test + Health status = health.health(); + + //validate state + Assert.assertEquals("wrong healthState", Health.down().build().getStatus(), status.getStatus()); + + } + + @Test + public void httpStatusCode200() throws IOException { + //set-up status + mockWebServer.enqueue(new MockResponse().setResponseCode(200) + .setBody(IOUtils.toString(EidasNodeMetadataHealthIndicatorTest.class + .getResourceAsStream("/data/metadata_valid.xml"), "UTF-8")) + .setHeader("Content-Type", MediaType.APPLICATION_XML)); + + //perform test + Health status = health.health(); + + //validate state + Assert.assertEquals("wrong healthState", Health.up().build().getStatus(), status.getStatus()); + + } + + @Test + public void noXmlResponse() throws IOException { + //set-up status + mockWebServer.enqueue(new MockResponse().setResponseCode(200) + .setBody(IOUtils.toString(EidasNodeMetadataHealthIndicatorTest.class + .getResourceAsStream("/config/log4j.properties"), "UTF-8")) + .setHeader("Content-Type", MediaType.APPLICATION_XML)); + + //perform test + Health status = health.health(); + + //validate state + Assert.assertEquals("wrong healthState", Health.down().build().getStatus(), status.getStatus()); + + } + +} diff --git a/modules/core_common_webapp/src/test/java/at/asitplus/eidas/specific/core/test/utils/AuthenticationDataBuilderTest.java b/modules/core_common_webapp/src/test/java/at/asitplus/eidas/specific/core/test/utils/AuthenticationDataBuilderTest.java new file mode 100644 index 00000000..586749cb --- /dev/null +++ b/modules/core_common_webapp/src/test/java/at/asitplus/eidas/specific/core/test/utils/AuthenticationDataBuilderTest.java @@ -0,0 +1,635 @@ +package at.asitplus.eidas.specific.core.test.utils; + +import static at.asitplus.eidas.specific.core.MsEidasNodeConstants.PROP_CONFIG_SP_NEW_EID_MODE; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertThrows; +import static org.junit.Assert.assertTrue; + +import java.io.IOException; +import java.security.PublicKey; +import java.util.Date; +import java.util.HashMap; +import java.util.Map; + +import javax.xml.transform.TransformerException; + +import org.apache.commons.lang3.RandomStringUtils; +import org.apache.commons.lang3.RandomUtils; +import org.junit.Assert; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.opensaml.core.config.InitializationException; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.i18n.LocaleContextHolder; +import org.springframework.mock.web.MockHttpServletRequest; +import org.springframework.mock.web.MockHttpServletResponse; +import org.springframework.test.context.ActiveProfiles; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; +import org.springframework.test.context.web.WebAppConfiguration; +import org.springframework.web.context.request.RequestContextHolder; +import org.springframework.web.context.request.ServletRequestAttributes; +import org.w3c.dom.Element; + +import at.asitplus.eidas.specific.core.MsEidasNodeConstants; +import at.asitplus.eidas.specific.core.builder.AuthenticationDataBuilder; +import at.gv.egiz.eaaf.core.api.data.EaafConfigConstants; +import at.gv.egiz.eaaf.core.api.data.EaafConstants; +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.data.PvpAttributeDefinitions.EidIdentityStatusLevelValues; +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.auth.data.IIdentityLink; +import at.gv.egiz.eaaf.core.exceptions.EaafAuthenticationException; +import at.gv.egiz.eaaf.core.exceptions.EaafBuilderException; +import at.gv.egiz.eaaf.core.exceptions.EaafParserException; +import at.gv.egiz.eaaf.core.exceptions.EaafStorageException; +import at.gv.egiz.eaaf.core.impl.builder.BpkBuilder; +import at.gv.egiz.eaaf.core.impl.idp.EidAuthenticationData; +import at.gv.egiz.eaaf.core.impl.idp.auth.data.AuthProcessDataWrapper; +import at.gv.egiz.eaaf.core.impl.idp.auth.data.EidAuthProcessDataWrapper; +import at.gv.egiz.eaaf.core.impl.idp.auth.data.SimpleIdentityLinkAssertionParser; +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.modules.pvp2.impl.opensaml.initialize.EaafOpenSaml3xInitializer; +import net.shibboleth.utilities.java.support.component.ComponentInitializationException; + +@RunWith(SpringJUnit4ClassRunner.class) +@ContextConfiguration({ "/spring/SpringTest_core_config.beans.xml", "/spring/SpringTest_core.beans.xml", "/eaaf_core.beans.xml", + "/eaaf_pvp.beans.xml", "/spring/SpringTest-context_simple_storage.xml" }) +@ActiveProfiles(profiles = {"deprecatedConfig"}) +@WebAppConfiguration +public class AuthenticationDataBuilderTest { + + @Autowired + private AuthenticationDataBuilder authenticationDataBuilder; + + @Autowired(required = true) + private IConfiguration basicConfig; + + private MockHttpServletRequest httpReq; + private MockHttpServletResponse httpResp; + private TestRequestImpl pendingReq; + + private DummySpConfiguration oaParam; + private Map spConfig; + + private String eidasBind; + private String authBlock; + + @BeforeClass + public static void classInitializer() throws InitializationException, ComponentInitializationException { + final String current = new java.io.File(".").toURI().toString(); + System.setProperty("eidas.ms.configuration", current + + "src/test/resources/config/junit_config_3.properties"); + + EaafOpenSaml3xInitializer.eaafInitialize(); + } + + @Before + public void initialize() throws EaafStorageException { + httpReq = new MockHttpServletRequest("POST", "https://localhost/ms_connector"); + httpResp = new MockHttpServletResponse(); + RequestContextHolder.resetRequestAttributes(); + RequestContextHolder.setRequestAttributes(new ServletRequestAttributes(httpReq, httpResp)); + + spConfig = new HashMap<>(); + spConfig.put(EaafConfigConstants.SERVICE_UNIQUEIDENTIFIER, "testSp"); + spConfig.put("target", "urn:publicid:gv.at:cdid+XX"); + spConfig.put(PROP_CONFIG_SP_NEW_EID_MODE, "true"); + oaParam = new DummySpConfiguration(spConfig, basicConfig); + + pendingReq = new TestRequestImpl(); + pendingReq.setAuthUrl("https://localhost/ms_connector"); + pendingReq.setPendingReqId(RandomStringUtils.randomAlphanumeric(10)); + pendingReq.setPiiTransactionId(RandomStringUtils.randomAlphanumeric(10)); + pendingReq.setSpConfig(oaParam); + authBlock = RandomStringUtils.randomAlphanumeric(20); + eidasBind = RandomStringUtils.randomAlphanumeric(20); + pendingReq.getSessionData(AuthProcessDataWrapper.class) + .setQaaLevel(EaafConstants.EIDAS_LOA_PREFIX + RandomStringUtils.randomAlphabetic(5)); + pendingReq.getSessionData(AuthProcessDataWrapper.class).setGenericDataToSession( + PvpAttributeDefinitions.EID_ISSUING_NATION_NAME, + RandomStringUtils.randomAlphabetic(2).toUpperCase()); + + LocaleContextHolder.resetLocaleContext(); + + } + + @Test + public void eidasProxyMode() throws EaafAuthenticationException, EaafStorageException { + // initialize state + boolean isTestIdentity = RandomUtils.nextBoolean(); + pendingReq.getSessionData(EidAuthProcessDataWrapper.class).setTestIdentity(isTestIdentity); + pendingReq.getSessionData(AuthProcessDataWrapper.class).setEidProcess(true); + + String givenName = RandomStringUtils.randomAlphabetic(10); + String familyName = RandomStringUtils.randomAlphabetic(10); + String dateOfBirth = "1956-12-08"; + String bpk = RandomStringUtils.randomAlphanumeric(10); + String cc = pendingReq.getSessionData(AuthProcessDataWrapper.class) + .getGenericDataFromSession(PvpAttributeDefinitions.EID_ISSUING_NATION_NAME, String.class); + String spC = RandomStringUtils.randomAlphabetic(2).toUpperCase(); + + spConfig.put("target", EaafConstants.URN_PREFIX_EIDAS + cc + "+" + spC); + + pendingReq.getSessionData(AuthProcessDataWrapper.class).setEidProcess(true); + pendingReq.getSessionData(AuthProcessDataWrapper.class).setForeigner(false); + pendingReq.getSessionData(AuthProcessDataWrapper.class) + .setGenericDataToSession(PvpAttributeDefinitions.GIVEN_NAME_NAME, givenName); + pendingReq.getSessionData(AuthProcessDataWrapper.class) + .setGenericDataToSession(PvpAttributeDefinitions.PRINCIPAL_NAME_NAME, familyName); + pendingReq.getSessionData(AuthProcessDataWrapper.class) + .setGenericDataToSession(PvpAttributeDefinitions.BIRTHDATE_NAME, dateOfBirth); + pendingReq.getSessionData(AuthProcessDataWrapper.class) + .setGenericDataToSession(MsEidasNodeConstants.ATTR_EIDAS_PERSONAL_IDENTIFIER, bpk); + + //set LoA level attribute instead of explicit session-data + pendingReq.getSessionData(AuthProcessDataWrapper.class) + .setGenericDataToSession(PvpAttributeDefinitions.EID_CITIZEN_EIDAS_QAA_LEVEL_NAME, + pendingReq.getSessionData(AuthProcessDataWrapper.class).getQaaLevel()); + pendingReq.getSessionData(AuthProcessDataWrapper.class).setQaaLevel(null); + + + + // execute test + IAuthData authData = authenticationDataBuilder.buildAuthenticationData(pendingReq); + + + // validate state + Assert.assertNotNull("AuthData null", authData); + Assert.assertNull("authBlock null", authData.getGenericData(MsEidasNodeConstants.AUTH_DATA_SZR_AUTHBLOCK, String.class)); + Assert.assertNull("eidasBind null", authData.getGenericData(MsEidasNodeConstants.AUTH_DATA_EIDAS_BIND, String.class)); + + Assert.assertEquals("LoA", pendingReq.getSessionData(AuthProcessDataWrapper.class) + .getGenericDataFromSession(PvpAttributeDefinitions.EID_CITIZEN_EIDAS_QAA_LEVEL_NAME, String.class), + authData.getEidasQaaLevel()); + Assert.assertEquals("CitizenCountry", cc, authData.getCiticenCountryCode()); + Assert.assertEquals("familyName", familyName, authData.getFamilyName()); + Assert.assertEquals("givenName", givenName, authData.getGivenName()); + Assert.assertEquals("DateOfBirth", dateOfBirth, authData.getDateOfBirth()); + + Assert.assertEquals("bPK", pendingReq.getSessionData(AuthProcessDataWrapper.class) + .getGenericDataFromSession(MsEidasNodeConstants.ATTR_EIDAS_PERSONAL_IDENTIFIER, String.class), + authData.getGenericData(MsEidasNodeConstants.ATTR_EIDAS_PERSONAL_IDENTIFIER, String.class)); + + Assert.assertEquals("testIdentity flag", + isTestIdentity ? EidIdentityStatusLevelValues.TESTIDENTITY : EidIdentityStatusLevelValues.IDENTITY, + ((EidAuthenticationData)authData).getEidStatus()); + assertFalse("mandate flag", ((EidAuthenticationData)authData).isUseMandate()); + + } + + @Test + public void eidasProxyModeWithJurMandate() throws EaafAuthenticationException, EaafStorageException { + // initialize state + injectRepresentativeInfosIntoSession(); + + String commonMandate = RandomStringUtils.randomAlphabetic(10); + + // set constant country-code and sourcePin to check hashed eIDAS identifier + String sourcePinMandate = "asfdsadfsadfsafsdafsadfasr"; + spConfig.put("target", EaafConstants.URN_PREFIX_EIDAS + "AT+EE"); + + // set nat. person mandate information + pendingReq.getSessionData(AuthProcessDataWrapper.class).setUseMandates(true); + pendingReq.getSessionData(AuthProcessDataWrapper.class) + .setGenericDataToSession(PvpAttributeDefinitions.MANDATE_LEG_PER_FULL_NAME_NAME, commonMandate); + pendingReq.getSessionData(AuthProcessDataWrapper.class) + .setGenericDataToSession(PvpAttributeDefinitions.MANDATE_LEG_PER_SOURCE_PIN_NAME, sourcePinMandate); + pendingReq.getSessionData(AuthProcessDataWrapper.class) + .setGenericDataToSession(PvpAttributeDefinitions.MANDATE_LEG_PER_SOURCE_PIN_TYPE_NAME, + EaafConstants.URN_PREFIX_BASEID + "+XFN"); + + // execute test + IAuthData authData = authenticationDataBuilder.buildAuthenticationData(pendingReq); + + + // validate state + Assert.assertNotNull("AuthData null", authData); + assertTrue("mandate flag", ((EidAuthenticationData)authData).isUseMandate()); + + //check mandate informations + checkGenericAttribute(authData, PvpAttributeDefinitions.MANDATE_LEG_PER_FULL_NAME_NAME, commonMandate); + checkGenericAttribute(authData, MsEidasNodeConstants.ATTR_EIDAS_JUR_MANDATOR_PERSONAL_IDENTIFIER, + "AT/EE/urn:publicid:gv.at:baseid+XFN+asfdsadfsadfsafsdafsadfasr"); + + } + + @Test + public void eidasProxyModeWithJurMandateMissingAttribute() throws EaafAuthenticationException, EaafStorageException { + // initialize state + injectRepresentativeInfosIntoSession(); + + // set constant country-code and sourcePin to check hashed eIDAS identifier + String sourcePinMandate = "asfdsadfsadfsafsdafsadfasr"; + spConfig.put("target", EaafConstants.URN_PREFIX_EIDAS + "AT+EE"); + + // set nat. person mandate information + pendingReq.getSessionData(AuthProcessDataWrapper.class).setUseMandates(true); + pendingReq.getSessionData(AuthProcessDataWrapper.class) + .setGenericDataToSession(PvpAttributeDefinitions.MANDATE_LEG_PER_SOURCE_PIN_NAME, sourcePinMandate); + pendingReq.getSessionData(AuthProcessDataWrapper.class) + .setGenericDataToSession(PvpAttributeDefinitions.MANDATE_LEG_PER_SOURCE_PIN_TYPE_NAME, + EaafConstants.URN_PREFIX_BASEID + "+XFN"); + + // execute test + // execute test + EaafAuthenticationException error = assertThrows(EaafAuthenticationException.class, + () -> authenticationDataBuilder.buildAuthenticationData(pendingReq)); + Assert.assertEquals("wrong errorId", "builder.11", error.getErrorId()); + + } + + @Test + public void eidasProxyModeWithNatMandate() throws EaafAuthenticationException, EaafStorageException { + // initialize state + injectRepresentativeInfosIntoSession(); + + String givenNameMandate = RandomStringUtils.randomAlphabetic(10); + String familyNameMandate = RandomStringUtils.randomAlphabetic(10); + String dateOfBirthMandate = "1957-09-15"; + String bpkMandate = RandomStringUtils.randomAlphanumeric(10); + + // set nat. person mandate information + pendingReq.getSessionData(AuthProcessDataWrapper.class).setUseMandates(true); + pendingReq.getSessionData(AuthProcessDataWrapper.class) + .setGenericDataToSession(PvpAttributeDefinitions.MANDATE_NAT_PER_GIVEN_NAME_NAME, givenNameMandate); + pendingReq.getSessionData(AuthProcessDataWrapper.class) + .setGenericDataToSession(PvpAttributeDefinitions.MANDATE_NAT_PER_FAMILY_NAME_NAME, familyNameMandate); + pendingReq.getSessionData(AuthProcessDataWrapper.class) + .setGenericDataToSession(PvpAttributeDefinitions.MANDATE_NAT_PER_BIRTHDATE_NAME, dateOfBirthMandate); + pendingReq.getSessionData(AuthProcessDataWrapper.class) + .setGenericDataToSession(PvpAttributeDefinitions.MANDATE_NAT_PER_BPK_NAME, "AT+XX:" + bpkMandate); + + // execute test + IAuthData authData = authenticationDataBuilder.buildAuthenticationData(pendingReq); + + + // validate state + Assert.assertNotNull("AuthData null", authData); + assertTrue("mandate flag", ((EidAuthenticationData)authData).isUseMandate()); + + //check mandate informations + checkGenericAttribute(authData, PvpAttributeDefinitions.MANDATE_NAT_PER_GIVEN_NAME_NAME, givenNameMandate); + checkGenericAttribute(authData, PvpAttributeDefinitions.MANDATE_NAT_PER_FAMILY_NAME_NAME, familyNameMandate); + checkGenericAttribute(authData, PvpAttributeDefinitions.MANDATE_NAT_PER_BIRTHDATE_NAME, "1957-09-15"); + checkGenericAttribute(authData, MsEidasNodeConstants.ATTR_EIDAS_NAT_MANDATOR_PERSONAL_IDENTIFIER, bpkMandate); + + } + + @Test + public void eidasProxyModeWithNatMandateWrongBpkFormat() throws EaafAuthenticationException, EaafStorageException { + // initialize state + injectRepresentativeInfosIntoSession(); + + String givenNameMandate = RandomStringUtils.randomAlphabetic(10); + String familyNameMandate = RandomStringUtils.randomAlphabetic(10); + String dateOfBirthMandate = "1957-09-15"; + String bpkMandate = RandomStringUtils.randomAlphanumeric(10); + + // set nat. person mandate information + pendingReq.getSessionData(AuthProcessDataWrapper.class).setUseMandates(true); + pendingReq.getSessionData(AuthProcessDataWrapper.class) + .setGenericDataToSession(PvpAttributeDefinitions.MANDATE_NAT_PER_GIVEN_NAME_NAME, givenNameMandate); + pendingReq.getSessionData(AuthProcessDataWrapper.class) + .setGenericDataToSession(PvpAttributeDefinitions.MANDATE_NAT_PER_FAMILY_NAME_NAME, familyNameMandate); + pendingReq.getSessionData(AuthProcessDataWrapper.class) + .setGenericDataToSession(PvpAttributeDefinitions.MANDATE_NAT_PER_BIRTHDATE_NAME, dateOfBirthMandate); + pendingReq.getSessionData(AuthProcessDataWrapper.class) + .setGenericDataToSession(PvpAttributeDefinitions.MANDATE_NAT_PER_BPK_NAME, bpkMandate); + + // execute test + IAuthData authData = authenticationDataBuilder.buildAuthenticationData(pendingReq); + + + // validate state + Assert.assertNotNull("AuthData null", authData); + assertTrue("mandate flag", ((EidAuthenticationData)authData).isUseMandate()); + + //check mandate informations + checkGenericAttribute(authData, PvpAttributeDefinitions.MANDATE_NAT_PER_GIVEN_NAME_NAME, givenNameMandate); + checkGenericAttribute(authData, PvpAttributeDefinitions.MANDATE_NAT_PER_FAMILY_NAME_NAME, familyNameMandate); + checkGenericAttribute(authData, PvpAttributeDefinitions.MANDATE_NAT_PER_BIRTHDATE_NAME, "1957-09-15"); + checkGenericAttribute(authData, MsEidasNodeConstants.ATTR_EIDAS_NAT_MANDATOR_PERSONAL_IDENTIFIER, bpkMandate); + + } + + @Test + public void eidasProxyModeWithNatMandateMissingAttribute() throws EaafAuthenticationException, EaafStorageException { + // initialize state + injectRepresentativeInfosIntoSession(); + + String familyNameMandate = RandomStringUtils.randomAlphabetic(10); + String dateOfBirthMandate = "1957-09-15"; + String bpkMandate = RandomStringUtils.randomAlphanumeric(10); + + // set nat. person mandate information + pendingReq.getSessionData(AuthProcessDataWrapper.class).setUseMandates(true); + pendingReq.getSessionData(AuthProcessDataWrapper.class) + .setGenericDataToSession(PvpAttributeDefinitions.MANDATE_NAT_PER_FAMILY_NAME_NAME, familyNameMandate); + pendingReq.getSessionData(AuthProcessDataWrapper.class) + .setGenericDataToSession(PvpAttributeDefinitions.MANDATE_NAT_PER_BIRTHDATE_NAME, dateOfBirthMandate); + pendingReq.getSessionData(AuthProcessDataWrapper.class) + .setGenericDataToSession(PvpAttributeDefinitions.MANDATE_NAT_PER_BPK_NAME, bpkMandate); + + // execute test + EaafAuthenticationException error = assertThrows(EaafAuthenticationException.class, + () -> authenticationDataBuilder.buildAuthenticationData(pendingReq)); + Assert.assertEquals("wrong errorId", "builder.11", error.getErrorId()); + + } + + @Test + public void eidMode() throws EaafAuthenticationException, EaafStorageException { + // initialize state + boolean isTestIdentity = RandomUtils.nextBoolean(); + pendingReq.getSessionData(EidAuthProcessDataWrapper.class).setTestIdentity(isTestIdentity); + pendingReq.getSessionData(AuthProcessDataWrapper.class).setEidProcess(true); + pendingReq.getSessionData(AuthProcessDataWrapper.class) + .setGenericDataToSession(MsEidasNodeConstants.AUTH_DATA_SZR_AUTHBLOCK, authBlock); + pendingReq.getSessionData(AuthProcessDataWrapper.class) + .setGenericDataToSession(MsEidasNodeConstants.AUTH_DATA_EIDAS_BIND, eidasBind); + + // execute + IAuthData authData = authenticationDataBuilder.buildAuthenticationData(pendingReq); + + // validate state + Assert.assertNotNull("AuthData null", authData); + Assert.assertNotNull("authBlock null", authData.getGenericData(MsEidasNodeConstants.AUTH_DATA_SZR_AUTHBLOCK, String.class)); + Assert.assertNotNull("eidasBind null", authData.getGenericData(MsEidasNodeConstants.AUTH_DATA_EIDAS_BIND, String.class)); + Assert.assertNotNull("LoA null", authData.getEidasQaaLevel()); + Assert.assertEquals("testIdentity flag", + isTestIdentity ? EidIdentityStatusLevelValues.TESTIDENTITY : EidIdentityStatusLevelValues.IDENTITY, + ((EidAuthenticationData)authData).getEidStatus()); + + String authBlock = authData.getGenericData(MsEidasNodeConstants.AUTH_DATA_SZR_AUTHBLOCK, String.class); + String eidasBind = authData.getGenericData(MsEidasNodeConstants.AUTH_DATA_EIDAS_BIND, String.class); + + Assert.assertEquals("authBlock not equal", this.authBlock, authBlock); + Assert.assertEquals("eidasBind not equal", this.eidasBind, eidasBind); + Assert.assertEquals("piiTransactionId", + authData.getGenericData(ExtendedPvpAttributeDefinitions.EID_PII_TRANSACTION_ID_NAME, String.class), + this.pendingReq.getUniquePiiTransactionIdentifier()); + Assert.assertNotNull("assertion validTo", authData.getSsoSessionValidTo()); + Assert.assertEquals("LoA", pendingReq.getSessionData(AuthProcessDataWrapper.class).getQaaLevel(), + authData.getEidasQaaLevel()); + Assert.assertEquals("EID-ISSUING-NATION", + pendingReq.getSessionData(AuthProcessDataWrapper.class).getGenericDataFromSession( + PvpAttributeDefinitions.EID_ISSUING_NATION_NAME), + authData.getCiticenCountryCode()); + + Assert.assertNull("bPK", authData.getBpk()); + Assert.assertNull("bPKType", authData.getBpkType()); + Assert.assertNull("FamilyName", authData.getFamilyName()); + Assert.assertNull("GivenName", authData.getGivenName()); + Assert.assertNull("DateOfBirth", authData.getDateOfBirth()); + Assert.assertNull("baseId", authData.getIdentificationValue()); + Assert.assertNull("baseIdType", authData.getIdentificationType()); + Assert.assertNull("IDL", authData.getIdentityLink()); + + } + + @Test + public void moaIdMode() throws EaafAuthenticationException, EaafBuilderException { + //initialize state + boolean isTestIdentity = RandomUtils.nextBoolean(); + pendingReq.getSessionData(EidAuthProcessDataWrapper.class).setTestIdentity(isTestIdentity); + pendingReq.getSessionData(AuthProcessDataWrapper.class).setEidProcess(false); + IIdentityLink idl = buildDummyIdl(); + pendingReq.getSessionData(AuthProcessDataWrapper.class).setIdentityLink(idl); + + //execute + IAuthData authData = authenticationDataBuilder.buildAuthenticationData(pendingReq); + + //validate state + Assert.assertNotNull("AuthData null", authData); + Assert.assertNull("authBlock null", authData.getGenericData(MsEidasNodeConstants.AUTH_DATA_SZR_AUTHBLOCK, String.class)); + Assert.assertNull("eidasBind null", authData.getGenericData(MsEidasNodeConstants.AUTH_DATA_EIDAS_BIND, String.class)); + Assert.assertNull("piiTransactionId", + authData.getGenericData(ExtendedPvpAttributeDefinitions.EID_PII_TRANSACTION_ID_NAME, String.class)); + + Assert.assertEquals("testIdentity flag", + isTestIdentity ? EidIdentityStatusLevelValues.TESTIDENTITY : EidIdentityStatusLevelValues.IDENTITY, + ((EidAuthenticationData)authData).getEidStatus()); + + Assert.assertNotNull("assertion validTo", authData.getSsoSessionValidTo()); + Assert.assertNotNull("LoA null", authData.getEidasQaaLevel()); + Assert.assertEquals("LoA", pendingReq.getSessionData(AuthProcessDataWrapper.class).getQaaLevel(), + authData.getEidasQaaLevel()); + Assert.assertEquals("EID-ISSUING-NATION", + pendingReq.getSessionData(AuthProcessDataWrapper.class).getGenericDataFromSession( + PvpAttributeDefinitions.EID_ISSUING_NATION_NAME), + authData.getCiticenCountryCode()); + + Assert.assertEquals("FamilyName", idl.getFamilyName(), authData.getFamilyName()); + Assert.assertEquals("GivenName", idl.getGivenName(), authData.getGivenName()); + Assert.assertEquals("DateOfBirth", idl.getDateOfBirth(), authData.getDateOfBirth()); + Assert.assertEquals("bPK", + BpkBuilder.generateAreaSpecificPersonIdentifier( + idl.getIdentificationValue(), EaafConstants.URN_PREFIX_CDID + "XX").getFirst(), + authData.getBpk()); + Assert.assertEquals("bPKType", EaafConstants.URN_PREFIX_CDID + "XX", authData.getBpkType()); + Assert.assertNotNull("IDL", authData.getIdentityLink()); + + + } + + private void injectRepresentativeInfosIntoSession() throws EaafStorageException { + boolean isTestIdentity = RandomUtils.nextBoolean(); + pendingReq.getSessionData(EidAuthProcessDataWrapper.class).setTestIdentity(isTestIdentity); + pendingReq.getSessionData(AuthProcessDataWrapper.class).setEidProcess(true); + + String givenName = RandomStringUtils.randomAlphabetic(10); + String familyName = RandomStringUtils.randomAlphabetic(10); + String dateOfBirth = "1956-12-08"; + String bpk = RandomStringUtils.randomAlphanumeric(10); + String cc = pendingReq.getSessionData(AuthProcessDataWrapper.class) + .getGenericDataFromSession(PvpAttributeDefinitions.EID_ISSUING_NATION_NAME, String.class); + String spC = RandomStringUtils.randomAlphabetic(2).toUpperCase(); + spConfig.put("target", EaafConstants.URN_PREFIX_EIDAS + cc + "+" + spC); + + pendingReq.getSessionData(AuthProcessDataWrapper.class).setEidProcess(true); + pendingReq.getSessionData(AuthProcessDataWrapper.class).setForeigner(false); + pendingReq.getSessionData(AuthProcessDataWrapper.class) + .setGenericDataToSession(PvpAttributeDefinitions.GIVEN_NAME_NAME, givenName); + pendingReq.getSessionData(AuthProcessDataWrapper.class) + .setGenericDataToSession(PvpAttributeDefinitions.PRINCIPAL_NAME_NAME, familyName); + pendingReq.getSessionData(AuthProcessDataWrapper.class) + .setGenericDataToSession(PvpAttributeDefinitions.BIRTHDATE_NAME, dateOfBirth); + pendingReq.getSessionData(AuthProcessDataWrapper.class) + .setGenericDataToSession(MsEidasNodeConstants.ATTR_EIDAS_PERSONAL_IDENTIFIER, bpk); + + //set LoA level attribute instead of explicit session-data + pendingReq.getSessionData(AuthProcessDataWrapper.class) + .setGenericDataToSession(PvpAttributeDefinitions.EID_CITIZEN_EIDAS_QAA_LEVEL_NAME, + pendingReq.getSessionData(AuthProcessDataWrapper.class).getQaaLevel()); + pendingReq.getSessionData(AuthProcessDataWrapper.class).setQaaLevel(null); + + } + + private void checkGenericAttribute(IAuthData authData, String attrName, String expected) { + assertEquals("Wrong: " + attrName, expected, authData.getGenericData(attrName, String.class)); + + } + + private IIdentityLink buildDummyIdl() { + return new IIdentityLink() { + + String familyName = RandomStringUtils.randomAlphabetic(10); + String givenName = RandomStringUtils.randomAlphabetic(10); + String dateOfBirth = "1955-02-03"; + String baseId = RandomStringUtils.randomAlphanumeric(20); + String saml2Serialized = RandomStringUtils.randomAlphanumeric(150); + + + + @Override + public void setSamlAssertion(Element arg0) throws TransformerException, IOException { + + } + + @Override + public void setPublicKey(PublicKey[] arg0) { + // TODO Auto-generated method stub + + } + + @Override + public void setPrPerson(Element arg0) { + // TODO Auto-generated method stub + + } + + @Override + public void setIssueInstant(String arg0) { + // TODO Auto-generated method stub + + } + + @Override + public void setIdentificationValue(String arg0) { + // TODO Auto-generated method stub + + } + + @Override + public void setIdentificationType(String arg0) { + // TODO Auto-generated method stub + + } + + @Override + public void setGivenName(String arg0) { + // TODO Auto-generated method stub + + } + + @Override + public void setFamilyName(String arg0) { + // TODO Auto-generated method stub + + } + + @Override + public void setDsigReferenceTransforms(Element[] arg0) { + // TODO Auto-generated method stub + + } + + @Override + public void setDateOfBirth(String arg0) { + // TODO Auto-generated method stub + + } + + @Override + public String getSerializedSamlAssertion() { + return this.saml2Serialized; + } + + @Override + public Element getSamlAssertion() { + IIdentityLink fullIdl; + try { + fullIdl = new SimpleIdentityLinkAssertionParser( + AuthenticationDataBuilderTest.class.getResourceAsStream("/data/test_idl_1.xml")).parseIdentityLink(); + return fullIdl.getSamlAssertion(); + + } catch (EaafParserException e) { + e.printStackTrace(); + } + + return null; + + } + + @Override + public PublicKey[] getPublicKey() { + // TODO Auto-generated method stub + return null; + } + + @Override + public Element getPrPerson() { + // TODO Auto-generated method stub + return null; + } + + @Override + public String getName() { + // TODO Auto-generated method stub + return null; + } + + @Override + public Date getIssueInstantDate() { + // TODO Auto-generated method stub + return null; + } + + @Override + public String getIssueInstant() { + // TODO Auto-generated method stub + return null; + } + + @Override + public String getIdentificationValue() { + return this.baseId; + } + + @Override + public String getIdentificationType() { + return EaafConstants.URN_PREFIX_BASEID; + } + + @Override + public String getGivenName() { + return this.givenName; + } + + @Override + public String getFamilyName() { + return this.familyName; + } + + @Override + public Element[] getDsigReferenceTransforms() { + // TODO Auto-generated method stub + return null; + } + + @Override + public String getDateOfBirth() { + return this.dateOfBirth; + + } + }; + } + +} diff --git a/modules/core_common_webapp/src/test/resources/config/junit_config_1_springboot.properties b/modules/core_common_webapp/src/test/resources/config/junit_config_1_springboot.properties new file mode 100644 index 00000000..991036fe --- /dev/null +++ b/modules/core_common_webapp/src/test/resources/config/junit_config_1_springboot.properties @@ -0,0 +1,113 @@ +## embbeded Tomcat +tomcat.workingdir=./target/work +tomcat.ajp.enabled=true +tomcat.ajp.port=8009 +tomcat.ajp.networkAddress=127.0.0.1 +tomcat.ajp.additionalAttributes.secretrequired=true +tomcat.ajp.additionalAttributes.secret=junit + +## Basic service configuration +eidas.ms.context.url.prefix=http://localhost +eidas.ms.core.configRootDir=file:./src/test/resources/config/ + +eidas.ms.context.use.clustermode=true + +##Monitoring +eidas.ms.monitoring.eIDASNode.metadata.url=http://localhost:40900/mockup + +## extended validation of pending-request Id's +eidas.ms.core.pendingrequestid.digist.secret=pendingReqIdSecret + +## eIDAS Ref. Implementation connector ### +eidas.ms.auth.eIDAS.node_v2.forward.endpoint=http://eidas.node/junit + +eidas.ms.auth.eIDAS.szrclient.useTestService=true +eidas.ms.auth.eIDAS.szrclient.endpoint.prod= +eidas.ms.auth.eIDAS.szrclient.endpoint.test=http://localhost:1234/demoszr +eidas.ms.auth.eIDAS.szrclient.ssl.keyStore.path=keys/junit.jks +eidas.ms.auth.eIDAS.szrclient.ssl.keyStore.password=password +eidas.ms.auth.eIDAS.szrclient.ssl.trustStore.path= +eidas.ms.auth.eIDAS.szrclient.ssl.trustStore.password= + +#tech. AuthBlock signing for E-ID process +eidas.ms.auth.eIDAS.authblock.keystore.password=f/+saJBc3a}*/T^s +eidas.ms.auth.eIDAS.authblock.keystore.friendlyName=connectorkeypair +eidas.ms.auth.eIDAS.authblock.keystore.path=keys/teststore.jks +eidas.ms.auth.eIDAS.authblock.keystore.type=jks +eidas.ms.auth.eIDAS.authblock.key.alias=connectorkeypair +eidas.ms.auth.eIDAS.authblock.key.password=f/+saJBc3a}*/T^s + + +#Raw eIDAS Id data storage +eidas.ms.auth.eIDAS.szrclient.debug.logfullmessages=true +eidas.ms.auth.eIDAS.szrclient.debug.useDummySolution=false + + +## PVP2 S-Profile end-point configuration +eidas.ms.pvp2.keystore.type=jks +eidas.ms.pvp2.keystore.path=keys/junit.jks +eidas.ms.pvp2.keystore.password=password +eidas.ms.pvp2.key.metadata.alias=meta +eidas.ms.pvp2.key.metadata.password=password +eidas.ms.pvp2.key.signing.alias=sig +eidas.ms.pvp2.key.signing.password=password +eidas.ms.pvp2.metadata.validity=24 + +eidas.ms.pvp2.metadata.organisation.name=JUnit +eidas.ms.pvp2.metadata.organisation.friendyname=For testing with jUnit +eidas.ms.pvp2.metadata.organisation.url=http://junit.test +eidas.ms.pvp2.metadata.contact.givenname=Max +eidas.ms.pvp2.metadata.contact.surname=Mustermann +eidas.ms.pvp2.metadata.contact.email=max@junit.test + +## Service Provider configuration +eidas.ms.sp.0.uniqueID=https://demo.egiz.gv.at/demoportal_moaid-2.0/sp/eidas/metadata +eidas.ms.sp.0.pvp2.metadata.truststore=keys/junit.jks +eidas.ms.sp.0.pvp2.metadata.truststore.password=password +eidas.ms.sp.0.friendlyName=jUnit test +eidas.ms.sp.0.newEidMode=true + +#eidas.ms.sp.0.pvp2.metadata.url= +#eidas.ms.sp.0.policy.allowed.requested.targets=.* +#eidas.ms.sp.0.policy.hasBaseIdTransferRestriction=false + +## Service Provider configuration +eidas.ms.sp.1.uniqueID=https://demo.egiz.gv.at/junit_test +eidas.ms.sp.1.pvp2.metadata.truststore=keys/junit.jks +eidas.ms.sp.1.pvp2.metadata.truststore.password=password +eidas.ms.sp.1.friendlyName=jUnit test +eidas.ms.sp.1.pvp2.metadata.url=http://junit.test/metadata +eidas.ms.sp.1.policy.allowed.requested.targets=test +eidas.ms.sp.1.policy.hasBaseIdTransferRestriction=true + + + +#### eIDAS ms-specific Proxy-Service configuration +eidas.ms.auth.eIDAS.node_v2.proxy.entityId=ownSpecificProxy +eidas.ms.auth.eIDAS.node_v2.proxy.forward.endpoint=http://eidas.proxy/endpoint + + +## PVP2 S-Profile communication with ID Austria System +# EntityId and optional metadata of ID Austria System +eidas.ms.modules.idaustriaauth.idp.entityId=http://junit.idaustria.at/idp +#eidas.ms.modules.idaustriaauth.idp.metadataUrl=http://junit.idaustria.at/idp/metadata + +# SAML2 client configuration +eidas.ms.modules.idaustriaauth.keystore.type=jks +#eidas.ms.modules.idaustriaauth.keystore.name= +eidas.ms.modules.idaustriaauth.keystore.path=keys/junit_test.jks +eidas.ms.modules.idaustriaauth.keystore.password=password +eidas.ms.modules.idaustriaauth.metadata.sign.alias=meta +eidas.ms.modules.idaustriaauth.metadata.sign.password=password +eidas.ms.modules.idaustriaauth.request.sign.alias=sig +eidas.ms.modules.idaustriaauth.request.sign.password=password +eidas.ms.modules.idaustriaauth.response.encryption.alias=enc +eidas.ms.modules.idaustriaauth.response.encryption.password=password + +# TrustStore to validate SAML2 metadata from ID Austria +eidas.ms.modules.idaustriaauth.truststore.type=jks +eidas.ms.modules.idaustriaauth.truststore.name= +eidas.ms.modules.idaustriaauth.truststore.path=keys/junit_test.jks +eidas.ms.modules.idaustriaauth.truststore.password=password + + diff --git a/modules/core_common_webapp/src/test/resources/config/junit_config_2_springboot.properties b/modules/core_common_webapp/src/test/resources/config/junit_config_2_springboot.properties new file mode 100644 index 00000000..de887fe6 --- /dev/null +++ b/modules/core_common_webapp/src/test/resources/config/junit_config_2_springboot.properties @@ -0,0 +1,113 @@ +## embbeded Tomcat +tomcat.workingdir=./target/work +tomcat.ajp.enabled=true +tomcat.ajp.port=8009 +tomcat.ajp.networkAddress=127.0.0.1 +tomcat.ajp.additionalAttributes.secretrequired=true +tomcat.ajp.additionalAttributes.secret=junit + +## Basic service configuration +eidas.ms.context.url.prefix=http://localhost +eidas.ms.core.configRootDir=file:./src/test/resources/config/ + +eidas.ms.context.use.clustermode=true + +##Monitoring +eidas.ms.monitoring.eIDASNode.metadata.url= + +## extended validation of pending-request Id's +eidas.ms.core.pendingrequestid.digist.secret=pendingReqIdSecret + +## eIDAS Ref. Implementation connector ### +eidas.ms.auth.eIDAS.node_v2.forward.endpoint=http://eidas.node/junit + +eidas.ms.auth.eIDAS.szrclient.useTestService=true +eidas.ms.auth.eIDAS.szrclient.endpoint.prod= +eidas.ms.auth.eIDAS.szrclient.endpoint.test=http://localhost:1234/demoszr +eidas.ms.auth.eIDAS.szrclient.ssl.keyStore.path=keys/junit.jks +eidas.ms.auth.eIDAS.szrclient.ssl.keyStore.password=password +eidas.ms.auth.eIDAS.szrclient.ssl.trustStore.path= +eidas.ms.auth.eIDAS.szrclient.ssl.trustStore.password= + +#tech. AuthBlock signing for E-ID process +eidas.ms.auth.eIDAS.authblock.keystore.password=f/+saJBc3a}*/T^s +eidas.ms.auth.eIDAS.authblock.keystore.friendlyName=connectorkeypair +eidas.ms.auth.eIDAS.authblock.keystore.path=keys/teststore.jks +eidas.ms.auth.eIDAS.authblock.keystore.type=jks +eidas.ms.auth.eIDAS.authblock.key.alias=connectorkeypair +eidas.ms.auth.eIDAS.authblock.key.password=f/+saJBc3a}*/T^s + + +#Raw eIDAS Id data storage +eidas.ms.auth.eIDAS.szrclient.debug.logfullmessages=true +eidas.ms.auth.eIDAS.szrclient.debug.useDummySolution=false + + + +## PVP2 S-Profile end-point configuration +eidas.ms.pvp2.keystore.type=jks +eidas.ms.pvp2.keystore.path=keys/junit.jks +eidas.ms.pvp2.keystore.password=password +eidas.ms.pvp2.key.metadata.alias=meta +eidas.ms.pvp2.key.metadata.password=password +eidas.ms.pvp2.key.signing.alias=sig +eidas.ms.pvp2.key.signing.password=password +eidas.ms.pvp2.metadata.validity=24 + +eidas.ms.pvp2.metadata.organisation.name=JUnit +eidas.ms.pvp2.metadata.organisation.friendyname=For testing with jUnit +eidas.ms.pvp2.metadata.organisation.url=http://junit.test +eidas.ms.pvp2.metadata.contact.givenname=Max +eidas.ms.pvp2.metadata.contact.surname=Mustermann +eidas.ms.pvp2.metadata.contact.email=max@junit.test + +## Service Provider configuration +eidas.ms.sp.0.uniqueID=https://demo.egiz.gv.at/demoportal_moaid-2.0/sp/eidas/metadata +eidas.ms.sp.0.pvp2.metadata.truststore=keys/junit.jks +eidas.ms.sp.0.pvp2.metadata.truststore.password=password +eidas.ms.sp.0.friendlyName=jUnit test +eidas.ms.sp.0.newEidMode=true + +#eidas.ms.sp.0.pvp2.metadata.url= +#eidas.ms.sp.0.policy.allowed.requested.targets=.* +#eidas.ms.sp.0.policy.hasBaseIdTransferRestriction=false + +## Service Provider configuration +eidas.ms.sp.1.uniqueID=https://demo.egiz.gv.at/junit_test +eidas.ms.sp.1.pvp2.metadata.truststore=keys/junit.jks +eidas.ms.sp.1.pvp2.metadata.truststore.password=password +eidas.ms.sp.1.friendlyName=jUnit test +eidas.ms.sp.1.pvp2.metadata.url=http://junit.test/metadata +eidas.ms.sp.1.policy.allowed.requested.targets=test +eidas.ms.sp.1.policy.hasBaseIdTransferRestriction=true + + + +#### eIDAS ms-specific Proxy-Service configuration +eidas.ms.auth.eIDAS.node_v2.proxy.entityId=ownSpecificProxy +eidas.ms.auth.eIDAS.node_v2.proxy.forward.endpoint=http://eidas.proxy/endpoint + + +## PVP2 S-Profile communication with ID Austria System +# EntityId and optional metadata of ID Austria System +eidas.ms.modules.idaustriaauth.idp.entityId=http://junit.idaustria.at/idp +#eidas.ms.modules.idaustriaauth.idp.metadataUrl=http://junit.idaustria.at/idp/metadata + +# SAML2 client configuration +eidas.ms.modules.idaustriaauth.keystore.type=jks +#eidas.ms.modules.idaustriaauth.keystore.name= +eidas.ms.modules.idaustriaauth.keystore.path=keys/junit_test.jks +eidas.ms.modules.idaustriaauth.keystore.password=password +eidas.ms.modules.idaustriaauth.metadata.sign.alias=meta +eidas.ms.modules.idaustriaauth.metadata.sign.password=password +eidas.ms.modules.idaustriaauth.request.sign.alias=sig +eidas.ms.modules.idaustriaauth.request.sign.password=password +eidas.ms.modules.idaustriaauth.response.encryption.alias=enc +eidas.ms.modules.idaustriaauth.response.encryption.password=password + +# TrustStore to validate SAML2 metadata from ID Austria +eidas.ms.modules.idaustriaauth.truststore.type=jks +eidas.ms.modules.idaustriaauth.truststore.name= +eidas.ms.modules.idaustriaauth.truststore.path=keys/junit_test.jks +eidas.ms.modules.idaustriaauth.truststore.password=password + diff --git a/modules/core_common_webapp/src/test/resources/config/junit_config_3.properties b/modules/core_common_webapp/src/test/resources/config/junit_config_3.properties new file mode 100644 index 00000000..b4de5aa9 --- /dev/null +++ b/modules/core_common_webapp/src/test/resources/config/junit_config_3.properties @@ -0,0 +1,148 @@ +## Basic service configuration +eidas.ms.context.url.prefix= +eidas.ms.context.url.request.validation=false +eidas.ms.core.configRootDir=file:./src/test/resources/config/ + +eidas.ms.context.use.clustermode=true + +##Monitoring +eidas.ms.monitoring.eIDASNode.metadata.url= + + +##Specific logger configuration +eidas.ms.technicallog.write.MDS.into.techlog=true +eidas.ms.revisionlog.write.MDS.into.revisionlog=true +eidas.ms.revisionlog.logIPAddressOfUser=true + +##Directory for static Web content +eidas.ms.webcontent.static.directory=webcontent/ +eidas.ms.webcontent.templates=templates/ +eidas.ms.webcontent.properties=properties/messages +eidas.ms.webcontent.templates.countryselection=countrySelection.html + +## extended validation of pending-request Id's +eidas.ms.core.pendingrequestid.maxlifetime=300 +eidas.ms.core.pendingrequestid.digist.algorithm=HmacSHA256 +eidas.ms.core.pendingrequestid.digist.secret=pendingReqIdSecret + +## eIDAS Ref. Implementation connector ### +eidas.ms.auth.eIDAS.node_v2.entityId=ownSpecificConnector +eidas.ms.auth.eIDAS.node_v2.forward.endpoint= +eidas.ms.auth.eIDAS.node_v2.forward.method=POST +eidas.ms.auth.eIDAS.node_v2.countrycode=AT +eidas.ms.auth.eIDAS.node_v2.publicSectorTargets=.* +eidas.ms.auth.eIDAS.node_v2.workarounds.addAlwaysProviderName=true +eidas.ms.auth.eIDAS.node_v2.workarounds.useRequestIdAsTransactionIdentifier=true +eidas.ms.auth.eIDAS.node_v2.workarounds.useStaticProviderNameForPublicSPs=true + +eidas.ms.auth.eIDAS.node_v2.loa.requested.minimum=http://eidas.europa.eu/LoA/substantial + +eidas.ms.auth.eIDAS.szrclient.useTestService=true +eidas.ms.auth.eIDAS.szrclient.endpoint.prod= +eidas.ms.auth.eIDAS.szrclient.endpoint.test=http://localhost:1234/demoszr +eidas.ms.auth.eIDAS.szrclient.ssl.keyStore.path=keys/junit.jks +eidas.ms.auth.eIDAS.szrclient.ssl.keyStore.password=password +eidas.ms.auth.eIDAS.szrclient.ssl.trustStore.path= +eidas.ms.auth.eIDAS.szrclient.ssl.trustStore.password= +eidas.ms.auth.eIDAS.szrclient.timeout.connection=15 +eidas.ms.auth.eIDAS.szrclient.timeout.response=30 +eidas.ms.auth.eIDAS.szrclient.params.vkz= + +eidas.ms.auth.eIDAS.szrclient.params.useSZRForbPKCalculation=false + + +#Raw eIDAS Id data storage +eidas.ms.auth.eIDAS.szrclient.workarounds.eidmapping.revisionlog.active=true + +eidas.ms.auth.eIDAS.szrclient.params.setPlaceOfBirthIfAvailable=true +eidas.ms.auth.eIDAS.szrclient.params.setBirthNameIfAvailable=true + +eidas.ms.auth.eIDAS.szrclient.debug.logfullmessages=true +eidas.ms.auth.eIDAS.szrclient.debug.useDummySolution=true + +##without mandates +eidas.ms.auth.eIDAS.node_v2.attributes.requested.onlynatural.0=PersonIdentifier,true +eidas.ms.auth.eIDAS.node_v2.attributes.requested.onlynatural.1=FamilyName,true +eidas.ms.auth.eIDAS.node_v2.attributes.requested.onlynatural.2=FirstName,true +eidas.ms.auth.eIDAS.node_v2.attributes.requested.onlynatural.3=DateOfBirth,true + +eidas.ms.auth.eIDAS.node_v2.attributes.requested.de.onlynatural.4=PlaceOfBirth,false +eidas.ms.auth.eIDAS.node_v2.attributes.requested.de.onlynatural.5=BirthName,false +eidas.ms.auth.eIDAS.node_v2.attributes.requested.de.onlynatural.6=Gender,false +eidas.ms.auth.eIDAS.node_v2.attributes.requested.de.onlynatural.7=CurrentAddress,false + +##with mandates ---- NOT FULLY SUPPORTED AT THE MOMENT ----- +eidas.ms.auth.eIDAS.node_v2.attributes.requested.representation.0=PersonIdentifier,true +eidas.ms.auth.eIDAS.node_v2.attributes.requested.representation.1=FamilyName,true +eidas.ms.auth.eIDAS.node_v2.attributes.requested.representation.2=FirstName,true +eidas.ms.auth.eIDAS.node_v2.attributes.requested.representation.3=DateOfBirth,true +eidas.ms.auth.eIDAS.node_v2.attributes.requested.representation.4=LegalPerson,true +eidas.ms.auth.eIDAS.node_v2.attributes.requested.representation.5=LegalName,true + + +## PVP2 S-Profile end-point configuration +eidas.ms.pvp2.keystore.type=jks +eidas.ms.pvp2.keystore.path=keys/junit.jks +eidas.ms.pvp2.keystore.password=password +eidas.ms.pvp2.key.metadata.alias= +eidas.ms.pvp2.key.metadata.password= +eidas.ms.pvp2.key.signing.alias= +eidas.ms.pvp2.key.signing.password= +eidas.ms.pvp2.metadata.validity=24 + +eidas.ms.pvp2.metadata.organisation.name=JUnit +eidas.ms.pvp2.metadata.organisation.friendyname=For testing with jUnit +eidas.ms.pvp2.metadata.organisation.url=http://junit.test +eidas.ms.pvp2.metadata.contact.givenname=Max +eidas.ms.pvp2.metadata.contact.surname=Mustermann +eidas.ms.pvp2.metadata.contact.email=max@junit.test + +## Service Provider configuration +eidas.ms.sp.0.uniqueID= +eidas.ms.sp.0.pvp2.metadata.truststore=keys/junit.jks +eidas.ms.sp.0.pvp2.metadata.truststore.password=password +eidas.ms.sp.0.newEidMode=true + +#eidas.ms.sp.0.friendlyName= +#eidas.ms.sp.0.pvp2.metadata.url= +#eidas.ms.sp.0.policy.allowed.requested.targets=.* +#eidas.ms.sp.0.policy.hasBaseIdTransferRestriction=false + + + +#### eIDAS ms-specific Proxy-Service configuration +eidas.ms.auth.eIDAS.node_v2.proxy.entityId=ownSpecificProxy +eidas.ms.auth.eIDAS.node_v2.proxy.forward.endpoint=http://eidas.proxy/endpoint + + +## PVP2 S-Profile communication with ID Austria System +# EntityId and optional metadata of ID Austria System +eidas.ms.modules.idaustriaauth.idp.entityId=http://junit.idaustria.at/idp +#eidas.ms.modules.idaustriaauth.idp.metadataUrl=http://junit.idaustria.at/idp/metadata + +# SAML2 client configuration +eidas.ms.modules.idaustriaauth.keystore.type=jks +#eidas.ms.modules.idaustriaauth.keystore.name= +eidas.ms.modules.idaustriaauth.keystore.path=keys/junit_test.jks +eidas.ms.modules.idaustriaauth.keystore.password=password +eidas.ms.modules.idaustriaauth.metadata.sign.alias=meta +eidas.ms.modules.idaustriaauth.metadata.sign.password=password +eidas.ms.modules.idaustriaauth.request.sign.alias=sig +eidas.ms.modules.idaustriaauth.request.sign.password=password +eidas.ms.modules.idaustriaauth.response.encryption.alias=enc +eidas.ms.modules.idaustriaauth.response.encryption.password=password + +# TrustStore to validate SAML2 metadata from ID Austria +eidas.ms.modules.idaustriaauth.truststore.type=jks +eidas.ms.modules.idaustriaauth.truststore.name= +eidas.ms.modules.idaustriaauth.truststore.path=keys/junit_test.jks +eidas.ms.modules.idaustriaauth.truststore.password=password + + + +##only for advanced config +eidas.ms.configuration.sp.disableRegistrationRequirement= +eidas.ms.configuration.restrictions.baseID.spTransmission= +eidas.ms.configuration.auth.default.countrycode= +eidas.ms.configuration.pvp.scheme.validation= +eidas.ms.configuration.pvp.enable.entitycategories= \ No newline at end of file diff --git a/modules/core_common_webapp/src/test/resources/config/log4j.properties b/modules/core_common_webapp/src/test/resources/config/log4j.properties new file mode 100644 index 00000000..4426ea7e --- /dev/null +++ b/modules/core_common_webapp/src/test/resources/config/log4j.properties @@ -0,0 +1,54 @@ +# commons-logging setup +org.apache.commons.logging.LogFactory=org.apache.commons.logging.impl.Log4jFactory + +# define log4j root loggers +log4j.rootLogger=warn,stdout, console + +log4j.logger.at.gv.egiz.eidas.specific=info, msnode +log4j.logger.at.gv.egiz.eidas.specific.connector.logger.RevisionLogger=info, reversion +log4j.logger.at.gv.egiz.eidas.specific.connector.logger.StatisticLogger=info, statistic +log4j.logger.eu.eidas=info, EIDASNODE + +log4j.additivity.at.gv.egiz.eidas.specific=false +log4j.additivity.at.gv.egiz.eidas.specific.connector.logger.RevisionLogger=false +log4j.additivity.at.gv.egiz.eidas.specific.connector.logger.StatisticLogger=false +log4j.additivity.eu.eidas=false + +log4j.appender.console=org.apache.log4j.ConsoleAppender +log4j.appender.console.layout=org.apache.log4j.PatternLayout +log4j.appender.console.layout.ConversionPattern=%5p | %d{dd HH:mm:ss,SSS} | %20c | %10t | %m%n + +log4j.appender.stdout=org.apache.log4j.RollingFileAppender +log4j.appender.stdout.File=${catalina.base}/logs/console.log +log4j.appender.stdout.MaxFileSize=10000KB +log4j.appender.stdout.MaxBackupIndex=9999 +log4j.appender.stdout.layout=org.apache.log4j.PatternLayout +log4j.appender.stdout.layout.ConversionPattern=%5p | %d{dd HH:mm:ss,SSS} | %t | %m%n + +log4j.appender.msnode=org.apache.log4j.RollingFileAppender +log4j.appender.msnode.File=${catalina.base}/logs/eidas-ms-reversion.log +log4j.appender.msnode.MaxFileSize=10000KB +log4j.appender.msnode.MaxBackupIndex=9999 +log4j.appender.msnode.layout=org.apache.log4j.PatternLayout +log4j.appender.msnode.layout.ConversionPattern=%5p | %d{dd HH:mm:ss,SSS} | %t | %m%n + +log4j.appender.reversion=org.apache.log4j.RollingFileAppender +log4j.appender.reversion.File=${catalina.base}/logs/eidas-ms-reversion.log +log4j.appender.reversion.MaxFileSize=10000KB +log4j.appender.reversion.MaxBackupIndex=9999 +log4j.appender.reversion.layout=org.apache.log4j.PatternLayout +log4j.appender.reversion.layout.ConversionPattern=%5p | %d{dd HH:mm:ss,SSS} | %t | %m%n + +log4j.appender.statistic=org.apache.log4j.RollingFileAppender +log4j.appender.statistic.File=${catalina.base}/logs/eidas-ms-statistic.log +log4j.appender.statistic.MaxFileSize=10000KB +log4j.appender.statistic.MaxBackupIndex=9999 +log4j.appender.statistic.layout=org.apache.log4j.PatternLayout +log4j.appender.statistic.layout.ConversionPattern=%m%n + +log4j.appender.EIDASNODE=org.apache.log4j.RollingFileAppender +log4j.appender.EIDASNODE.File=${catalina.base}/logs/eIDAS_node.log +log4j.appender.EIDASNODE.MaxFileSize=10000KB +log4j.appender.EIDASNODE.MaxBackupIndex=9999 +log4j.appender.EIDASNODE.layout=org.apache.log4j.PatternLayout +log4j.appender.EIDASNODE.layout.ConversionPattern=%5p | %d{dd HH:mm:ss,SSS} | %t | %m%n \ No newline at end of file diff --git a/modules/core_common_webapp/src/test/resources/data/metadata_valid.xml b/modules/core_common_webapp/src/test/resources/data/metadata_valid.xml new file mode 100644 index 00000000..06e1e785 --- /dev/null +++ b/modules/core_common_webapp/src/test/resources/data/metadata_valid.xml @@ -0,0 +1,106 @@ + + + + + + + + + + + + + 00SaL0XjeknOb/DttutP50lTyAux1jaRPJIVdSupWvU= + + + PfEBmLMX/ZgL6ViXghyWtal5MaMoW8k3zjw+54+WK1OAtVsVgOsIDRJE0M/a/VXBbMSifgY6J1gN23xhr61jkrjRQEkbDzLpWZLzWAJ65YqqUQo8wsKI2Gz0j12yY5D8/GOamKOH9KDi5ba1veXR/fnxRINoy7nZo4tcUWZChdl8BWkMN5ugr6dORNIQg/Ym3GabQ/hR5z+9FmveAKphdH63MC6qW3EgM9EMvOVkrLBTP92sNMAAJeaawui9tlxi9anVQ0OqwZsgKLvI7fyV4CM/0sd/ELjeReIlWlHk07Nz4eltMq3eOx3q1YurYvhE8XapHiQMehOtCS+Fzh10sw== + + + MIIDKzCCAhMCBFrxKO4wDQYJKoZIhvcNAQELBQAwWjELMAkGA1UEBhMCQVQxDTALBgNVBAoMBEVH +SVoxGDAWBgNVBAsMD2RlbW8uZWdpei5ndi5hdDEiMCAGA1UEAwwZTU9BLUlEIElEUCAoVGVzdC1W +ZXJzaW9uKTAeFw0xODA1MDgwNDM0NTRaFw0yMTAxMzEwNDM0NTRaMFoxCzAJBgNVBAYTAkFUMQ0w +CwYDVQQKDARFR0laMRgwFgYDVQQLDA9kZW1vLmVnaXouZ3YuYXQxIjAgBgNVBAMMGU1PQS1JRCBJ +RFAgKFRlc3QtVmVyc2lvbikwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCaFnqoaYoq +UptenemC6FiVDg5F2hEjpjix8+ow6/6QhUl2cPOS0uwZHaIvwT/RVbJ9CPdil6+11qaCPfZ+FoY+ +M+ke7TRd2RS1DqFbe1KC0imEnwemyLQrYe5Pm7DNcaY/kHTTq+k0eeGbYH0U/Iopyi0VuN5OWl4F +Vg45pf7knhXkaimItdjnCXnKcYM91mmltCf6TDgUrz7US7PmgvinnhfBgdITAT4GRr4ehliT+/jt +1OzHEyWRHanBGIpXNeZNqxgnpnGtaDh4JZuYR8qfH+GRK6dtW2ziej6rGIiUElGVCkXsohgxMNzq +nWeD9JT8+yyp1XZlyQf+IxhhESQLAgMBAAEwDQYJKoZIhvcNAQELBQADggEBAIFejAFQepaEl/kC +VLvidMR+MXq5LCGHthUiI6eDTQZ+H7lZdHlj547XwEdX15b6Md3h7eSJ4hwlfV4go/0FaoLPzvVq +itwtYY5htywB3B6ZV34Eyi6C59Gl34XrV8CWxH4KKwLsVAjAy+/p/Xh0q2pzSBkeOChzBMBkjmyc +2Ue4MEKdL9guzp6+Yc/HL/phHAKYapkVyFwvsdqWOgyRzxAHINko8ExImMMB3xB5a52kfqLcui5O +fzEhjwLFJaGBMmFCmFGGOUwtIvl/6ZQ2LLzOE9+giVK9WsIgH11Pu+ejPFAbXf8cf4oWhbAfTkiy +4jpXrp77JXFRSDWddb0yePc= + + + + + + + + MIIBbTCCARKgAwIBAgIEXjF+qTAKBggqhkjOPQQDAjA+MQswCQYDVQQGEwJBVDEN +MAsGA1UEBwwERUdJWjEOMAwGA1UECgwFalVuaXQxEDAOBgNVBAMMB3NpZ25pbmcw +HhcNMjAwMTI5MTI0NjMzWhcNMjcwMTI4MTI0NjMzWjA+MQswCQYDVQQGEwJBVDEN +MAsGA1UEBwwERUdJWjEOMAwGA1UECgwFalVuaXQxEDAOBgNVBAMMB3NpZ25pbmcw +WTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAASRt7gZRrr4rSEE7Q922oKQJF+mlkwC +LZnv8ZzHtH54s4VdyQFIBjQF1PPf9PTn+5tid8QJehZPndcoeD7J8fPJMAoGCCqG +SM49BAMCA0kAMEYCIQDFUO0owvqMVRO2FmD+vb8mqJBpWCE6Cl5pEHaygTa5LwIh +ANsmjI2azWiTSFjb7Ou5fnCfbeiJUP0s66m8qS4rYl9L + + + + + + + MIIDKzCCAhMCBFrxKO4wDQYJKoZIhvcNAQELBQAwWjELMAkGA1UEBhMCQVQxDTALBgNVBAoMBEVH +SVoxGDAWBgNVBAsMD2RlbW8uZWdpei5ndi5hdDEiMCAGA1UEAwwZTU9BLUlEIElEUCAoVGVzdC1W +ZXJzaW9uKTAeFw0xODA1MDgwNDM0NTRaFw0yMTAxMzEwNDM0NTRaMFoxCzAJBgNVBAYTAkFUMQ0w +CwYDVQQKDARFR0laMRgwFgYDVQQLDA9kZW1vLmVnaXouZ3YuYXQxIjAgBgNVBAMMGU1PQS1JRCBJ +RFAgKFRlc3QtVmVyc2lvbikwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCaFnqoaYoq +UptenemC6FiVDg5F2hEjpjix8+ow6/6QhUl2cPOS0uwZHaIvwT/RVbJ9CPdil6+11qaCPfZ+FoY+ +M+ke7TRd2RS1DqFbe1KC0imEnwemyLQrYe5Pm7DNcaY/kHTTq+k0eeGbYH0U/Iopyi0VuN5OWl4F +Vg45pf7knhXkaimItdjnCXnKcYM91mmltCf6TDgUrz7US7PmgvinnhfBgdITAT4GRr4ehliT+/jt +1OzHEyWRHanBGIpXNeZNqxgnpnGtaDh4JZuYR8qfH+GRK6dtW2ziej6rGIiUElGVCkXsohgxMNzq +nWeD9JT8+yyp1XZlyQf+IxhhESQLAgMBAAEwDQYJKoZIhvcNAQELBQADggEBAIFejAFQepaEl/kC +VLvidMR+MXq5LCGHthUiI6eDTQZ+H7lZdHlj547XwEdX15b6Md3h7eSJ4hwlfV4go/0FaoLPzvVq +itwtYY5htywB3B6ZV34Eyi6C59Gl34XrV8CWxH4KKwLsVAjAy+/p/Xh0q2pzSBkeOChzBMBkjmyc +2Ue4MEKdL9guzp6+Yc/HL/phHAKYapkVyFwvsdqWOgyRzxAHINko8ExImMMB3xB5a52kfqLcui5O +fzEhjwLFJaGBMmFCmFGGOUwtIvl/6ZQ2LLzOE9+giVK9WsIgH11Pu+ejPFAbXf8cf4oWhbAfTkiy +4jpXrp77JXFRSDWddb0yePc= + + + + urn:oasis:names:tc:SAML:2.0:nameid-format:persistent + + + + Default Service + + + + + + + + + + + + + + + + + + EGIZ + E-Government Innovationszentrum + http://www.egiz.gv.at + + + E-Government Innovationszentrum + Lenz + Thomas + thomas.lenz@egiz.gv.at + +43 316 873 5525 + + diff --git a/modules/core_common_webapp/src/test/resources/data/test_idl_1.xml b/modules/core_common_webapp/src/test/resources/data/test_idl_1.xml new file mode 100644 index 00000000..8151468b --- /dev/null +++ b/modules/core_common_webapp/src/test/resources/data/test_idl_1.xml @@ -0,0 +1,46 @@ + + + + + urn:oasis:names:tc:SAML:1.0:cm:sender-vouches + + AT/CZ/xWE0vFWarzpzSL4LYlpst9b6vg0=urn:publicid:gv.at:eidasid+AT+CZXXXMaria-Theresia KunigundaXXXHabsburg-Lothringen1980-02-29 + + + + 1BFOitiQUc1lAHDGksneXWZGKGaFBcu03HEiIFsjHjNt/IfRZ4IzqHotUKItxnCdNtsFc1MkMJg+ +g0AXHsuU6MNgcbcXPaPfmHp+8+BJh+amDF3FnAN4ceG8oFAGVEZteOgfdWk1r5RQ2SK+0PuXPuLp +Tee7IzXtksReZkVEadUCxn/hiRXZa0dABgkFe3kSXbDr5tKXOF0FCtLKhZBI9z+NbX+aTSKOmAOq +4jyymoo5EP3L+iPecrUwHijD0Bm89h1JjxP521fkYe3Si+0J40okrmCCQHBr+IzB1uX98pKhvs7X +6rPjOJ6lBwP7XjK7D128P/cg4eH6v58cCfbLcQ==AQAB + +E+BXH0C2F6EYHjdJrOUKr+DsKT8=Hvj40m9ridp2HOz81MTAqzf0q+sZC5YeKpJP43eK5G1HNH1/DNGU/r/6IVPibU9Y +YGYJoXpznxRFibEQ6dFCHAaNPyADmdGHyJSWryI5ypAap4Y8MJnaUGSWY49IZbht +PjfKWB2jUNzj1T2u6ebIifAThAK8ZqIE+e5uaR+qrrLicxIhXcSZoyScbKxMuT1Q +p6zNsNBOHujbVAfKFUE8WmGInyvuoDgerUrA0XstWWg2M9ghytcDJwZpTYwXvmmo +GV47ue0ITrtM+QqWVbt+dHO8369JFnGQ9h/6h/4j9iyNuxfG7u/EyHQiSuy0+FP8 +1lkLsg1YX+2pN0HElyXVqw==MIIEqzCCBBSgAwIBAgIHANux81oNezANBgkqhkiG9w0BAQUFADBAMSIwIAYDVQQD +ExlJQUlLIFRlc3QgSW50ZXJtZWRpYXRlIENBMQ0wCwYDVQQKEwRJQUlLMQswCQYD +VQQGEwJBVDAeFw0xMzA5MjcwNTMzMzdaFw0yMzA5MjcwNTMzMzdaMIHkMQswCQYD +VQQGEwJBVDENMAsGA1UEBxMER3JhejEmMCQGA1UEChMdR3JheiBVbml2ZXJzaXR5 +IG9mIFRlY2hub2xvZ3kxSDBGBgNVBAsTP0luc3RpdHV0ZSBmb3IgQXBwbGllZCBJ +bmZvcm1hdGlvbiBQcm9jZXNzaW5nIGFuZCBDb21tdW5pY2F0aW9uczEUMBIGA1UE +BBMLTU9BLVNTIFRlc3QxGDAWBgNVBCoTD0VHSVogVGVzdHBvcnRhbDEkMCIGA1UE +AxMbRUdJWiBUZXN0cG9ydGFsIE1PQS1TUyBUZXN0MIIBIjANBgkqhkiG9w0BAQEF +AAOCAQ8AMIIBCgKCAQEAuDjOyf+mY+oQL2FQzzuaiC8C23vVKbq/n2Zi7BqSibZH +mtqMJfmj4pT+hWSNHvVvWsaxFcx4KeNqdCMzwnw1r4P3Sf+2o5uFku5KHEMLMokR +yYQG9VqY/KkB94ye7Pv6zT8gvKqxGFg96UamECep4swPaSZrA8AOER5WAtyGDzKI +Tz+a5zfFaTXDoba7f98PCWR96yKiFjVOhzp38WVz4VJgz+b8ZSY7Xsv5Kn7DXjOL +STX4MevFLki3rFPup3+4vGToaMBW3PEj67HXBdqR855Le6+E6rVxORqsXqlVwhsI +6nuS0CO2LWYmBNR1IB0mXteeYH/HfxvuZc+7yDjdPQIDAQABo4IBhDCCAYAwDgYD +VR0PAQH/BAQDAgbAMAwGA1UdEwEB/wQCMAAwHQYDVR0OBBYEFEmcH6VY4BG1EAGB +TLoNR9vH/g6yMFAGA1UdHwRJMEcwRaBDoEGGP2h0dHA6Ly9jYS5pYWlrLnR1Z3Jh +ei5hdC9jYXBzby9jcmxzL0lBSUtUZXN0X0ludGVybWVkaWF0ZUNBLmNybDCBqgYI +KwYBBQUHAQEEgZ0wgZowSgYIKwYBBQUHMAGGPmh0dHA6Ly9jYS5pYWlrLnR1Z3Jh +ei5hdC9jYXBzby9PQ1NQP2NhPUlBSUtUZXN0X0ludGVybWVkaWF0ZUNBMEwGCCsG +AQUFBzAChkBodHRwOi8vY2EuaWFpay50dWdyYXouYXQvY2Fwc28vY2VydHMvSUFJ +S1Rlc3RfSW50ZXJtZWRpYXRlQ0EuY2VyMCEGA1UdEQQaMBiBFnRob21hcy5sZW56 +QGVnaXouZ3YuYXQwHwYDVR0jBBgwFoAUaKJeEdreL4BrRES/jfplNoEkp28wDQYJ +KoZIhvcNAQEFBQADgYEAlFGjUxXLs7SAT8NtXSrv2WrjlklaRnHTFHLQwyVo8JWb +gvRkHHDUv2o8ofXUY2R2WJ38dxeDoccgbXrJb/Qhi8IY7YhCwv/TuIZDisyAqo8W +ORKSip/6HWlGCSR/Vgoet1GtCmF0FoUxFUIGSAuQ2yyt4fIzt5GJrU1X5ujjI1w= \ No newline at end of file diff --git a/modules/core_common_webapp/src/test/resources/spring/SpringTest-context_basic_test.xml b/modules/core_common_webapp/src/test/resources/spring/SpringTest-context_basic_test.xml new file mode 100644 index 00000000..bf2c78ac --- /dev/null +++ b/modules/core_common_webapp/src/test/resources/spring/SpringTest-context_basic_test.xml @@ -0,0 +1,22 @@ + + + + + + + + + + + + \ No newline at end of file diff --git a/modules/core_common_webapp/src/test/resources/spring/SpringTest-context_healthcheck.xml b/modules/core_common_webapp/src/test/resources/spring/SpringTest-context_healthcheck.xml new file mode 100644 index 00000000..5a37b98f --- /dev/null +++ b/modules/core_common_webapp/src/test/resources/spring/SpringTest-context_healthcheck.xml @@ -0,0 +1,22 @@ + + + + + + + + + + + + \ No newline at end of file diff --git a/modules/core_common_webapp/src/test/resources/spring/SpringTest-context_simple_storage.xml b/modules/core_common_webapp/src/test/resources/spring/SpringTest-context_simple_storage.xml new file mode 100644 index 00000000..966d317a --- /dev/null +++ b/modules/core_common_webapp/src/test/resources/spring/SpringTest-context_simple_storage.xml @@ -0,0 +1,15 @@ + + + + + + \ No newline at end of file diff --git a/modules/core_common_webapp/src/test/resources/spring/SpringTest_core.beans.xml b/modules/core_common_webapp/src/test/resources/spring/SpringTest_core.beans.xml new file mode 100644 index 00000000..e66ac987 --- /dev/null +++ b/modules/core_common_webapp/src/test/resources/spring/SpringTest_core.beans.xml @@ -0,0 +1,70 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/modules/core_common_webapp/src/test/resources/spring/SpringTest_core_config.beans.xml b/modules/core_common_webapp/src/test/resources/spring/SpringTest_core_config.beans.xml new file mode 100644 index 00000000..2da610f0 --- /dev/null +++ b/modules/core_common_webapp/src/test/resources/spring/SpringTest_core_config.beans.xml @@ -0,0 +1,25 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/modules/eidas_proxy-sevice/checks/spotbugs-exclude.xml b/modules/eidas_proxy-sevice/checks/spotbugs-exclude.xml new file mode 100644 index 00000000..cdc9fa95 --- /dev/null +++ b/modules/eidas_proxy-sevice/checks/spotbugs-exclude.xml @@ -0,0 +1,20 @@ + + + + + + + + + + + + + + + + + + + + diff --git a/modules/eidas_proxy-sevice/pom.xml b/modules/eidas_proxy-sevice/pom.xml new file mode 100644 index 00000000..55a6974c --- /dev/null +++ b/modules/eidas_proxy-sevice/pom.xml @@ -0,0 +1,184 @@ + + 4.0.0 + + at.asitplus.eidas.ms_specific + modules + 1.2.4-SNAPSHOT + + at.asitplus.eidas.ms_specific.modules + eidas_proxy-sevice + eIDAS specific proxy-service + Austrian specific eIDAS Proxy-Service to handle eIDAS Proxy-Service requests from other member states + + + + eIDASNode-local + local + file:${basedir}/../../repository + + + + + + at.gv.egiz.components + egiz-spring-api + + + at.asitplus.eidas.ms_specific + core_common_lib + + + at.asitplus.eidas.ms_specific.modules + authmodule-eIDAS-v2 + + + at.gv.egiz.eaaf + eaaf-core + + + at.gv.egiz.eaaf + eaaf_module_pvp2_sp + + + + eu.eidas + eidas-light-commons + + + eu.eidas + eidas-specific-communication-definition + + + eu.eidas + eidas-jcache-ignite-specific-communication + + + + org.apache.commons + commons-lang3 + + + com.google.guava + guava + + + org.apache.commons + commons-text + + + + javax.servlet + javax.servlet-api + provided + + + + + junit + junit + test + + + org.springframework + spring-test + test + + + org.powermock + powermock-module-junit4 + 2.0.7 + test + + + org.powermock + powermock-api-mockito2 + 2.0.7 + test + + + + at.asitplus.eidas.ms_specific + core_common_lib + test + test-jar + + + at.asitplus.eidas.ms_specific.modules + authmodule-eIDAS-v2 + test + test-jar + + + + at.gv.egiz.eaaf + eaaf_core_utils + test + test-jar + + + at.gv.egiz.eaaf + eaaf-core + test + test-jar + + + + + + + + src/main/resources + + + + + + org.apache.maven.plugins + maven-compiler-plugin + + + + com.github.spotbugs + spotbugs-maven-plugin + ${spotbugs-maven-plugin.version} + + checks/spotbugs-exclude.xml + + + + + org.jacoco + jacoco-maven-plugin + + + post-unit-check + test + + check + report + + + true + + + + + + + + maven-surefire-plugin + + 1 + + + + org.apache.maven.surefire + surefire-junit47 + ${surefire.version} + + + + + + + \ No newline at end of file diff --git a/modules/eidas_proxy-sevice/src/main/java/at/asitplus/eidas/specific/modules/msproxyservice/EidasProxyMessageSource.java b/modules/eidas_proxy-sevice/src/main/java/at/asitplus/eidas/specific/modules/msproxyservice/EidasProxyMessageSource.java new file mode 100644 index 00000000..23390da8 --- /dev/null +++ b/modules/eidas_proxy-sevice/src/main/java/at/asitplus/eidas/specific/modules/msproxyservice/EidasProxyMessageSource.java @@ -0,0 +1,22 @@ +package at.asitplus.eidas.specific.modules.msproxyservice; + +import java.util.Arrays; +import java.util.List; + +import at.gv.egiz.eaaf.core.api.logging.IMessageSourceLocation; + +/** + * i18n Message-Source for eIDAS Proxy-Service messages. + * + * @author tlenz + * + */ +public class EidasProxyMessageSource implements IMessageSourceLocation { + + @Override + public List getMessageSourceLocation() { + return Arrays.asList("classpath:messages/eidasproxy_messages"); + + } + +} 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 new file mode 100644 index 00000000..f6a88aa3 --- /dev/null +++ b/modules/eidas_proxy-sevice/src/main/java/at/asitplus/eidas/specific/modules/msproxyservice/MsProxyServiceConstants.java @@ -0,0 +1,54 @@ +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.EaafConfigConstants; + +/** + * Constants for MS-specific eIDAS Proxy-Service. + * + * @author tlenz + * + */ +public class MsProxyServiceConstants { + + // general constants + public static final String TEMPLATE_SP_UNIQUE_ID = "eidasProxyAuth_from_{0}_type_{1}"; + + // 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"; + + // mandate configuration + public static final String CONIG_PROPS_EIDAS_PROXY_MANDATES_ENABLED = + Constants.CONIG_PROPS_EIDAS_PREFIX + ".proxy.mandates.enabled"; + public static final String CONIG_PROPS_EIDAS_PROXY_MANDATES_PROFILE_DEFAULT_NATURAL = + Constants.CONIG_PROPS_EIDAS_PREFIX + ".proxy.mandates.profiles.natural.default"; + public static final String CONIG_PROPS_EIDAS_PROXY_MANDATES_PROFILE_DEFAULT_LEGAL = + Constants.CONIG_PROPS_EIDAS_PREFIX + ".proxy.mandates.profiles.legal.default"; + + + public static final String CONIG_PROPS_EIDAS_PROXY_WORKAROUND_MANDATES_LEGAL_PERSON = + Constants.CONIG_PROPS_EIDAS_PREFIX + ".proxy.workaround.mandates.legalperson"; + + // specific eIDAS-Connector configuration + public static final String CONIG_PROPS_CONNECTOR_PREFIX = "connector"; + public static final String CONIG_PROPS_CONNECTOR_UNIQUEID = EaafConfigConstants.SERVICE_UNIQUEIDENTIFIER; + public static final String CONIG_PROPS_CONNECTOR_COUNTRYCODE = "countryCode"; + public static final String CONIG_PROPS_CONNECTOR_MANDATES_ENABLED = "mandates.enabled"; + public static final String CONIG_PROPS_CONNECTOR_MANDATES_PROFILE_NATURAL = "mandates.natural"; + public static final String CONIG_PROPS_CONNECTOR_MANDATES_PROFILE_LEGAL = "mandates.legal"; + public static final String CONIG_PROPS_CONNECTOR_VALIDATION_ATTR_MDS = "validation.attributes.mds"; + + + //http end-points + public static final String EIDAS_HTTP_ENDPOINT_IDP_POST = "/eidas/light/idp/post"; + public static final String EIDAS_HTTP_ENDPOINT_IDP_REDIRECT = "/eidas/light/idp/redirect"; + + private MsProxyServiceConstants() { + //private constructor for class with only constant values + + } + +} diff --git a/modules/eidas_proxy-sevice/src/main/java/at/asitplus/eidas/specific/modules/msproxyservice/MsProxyServiceSpringResourceProvider.java b/modules/eidas_proxy-sevice/src/main/java/at/asitplus/eidas/specific/modules/msproxyservice/MsProxyServiceSpringResourceProvider.java new file mode 100644 index 00000000..d36e4712 --- /dev/null +++ b/modules/eidas_proxy-sevice/src/main/java/at/asitplus/eidas/specific/modules/msproxyservice/MsProxyServiceSpringResourceProvider.java @@ -0,0 +1,52 @@ +/* + * Copyright 2018 A-SIT Plus GmbH + * AT-specific eIDAS Connector has been developed in a cooperation between EGIZ, + * A-SIT Plus GmbH, A-SIT, and Graz University of Technology. + * + * Licensed under the EUPL, Version 1.2 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "License"); + * You may not use this work except in compliance with the License. + * You may obtain a copy of the License at: + * https://joinup.ec.europa.eu/news/understanding-eupl-v12 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. +*/ + +package at.asitplus.eidas.specific.modules.msproxyservice; + +import org.springframework.core.io.ClassPathResource; +import org.springframework.core.io.Resource; + +import at.gv.egiz.components.spring.api.SpringResourceProvider; + +public class MsProxyServiceSpringResourceProvider implements SpringResourceProvider { + + @Override + public String getName() { + return "MS-specific eIDAS Proxy-Service module"; + } + + @Override + public String[] getPackagesToScan() { + return null; + + } + + @Override + public Resource[] getResourcesToLoad() { + final ClassPathResource eidasProxyServiceConfig = + new ClassPathResource("/spring/eidas_proxy-service.beans.xml", MsProxyServiceSpringResourceProvider.class); + + return new Resource[] { eidasProxyServiceConfig }; + } + +} diff --git a/modules/eidas_proxy-sevice/src/main/java/at/asitplus/eidas/specific/modules/msproxyservice/exception/EidasProxyServiceException.java b/modules/eidas_proxy-sevice/src/main/java/at/asitplus/eidas/specific/modules/msproxyservice/exception/EidasProxyServiceException.java new file mode 100644 index 00000000..43592a28 --- /dev/null +++ b/modules/eidas_proxy-sevice/src/main/java/at/asitplus/eidas/specific/modules/msproxyservice/exception/EidasProxyServiceException.java @@ -0,0 +1,19 @@ +package at.asitplus.eidas.specific.modules.msproxyservice.exception; + +import at.gv.egiz.eaaf.core.exceptions.EaafException; + +public class EidasProxyServiceException extends EaafException { + + private static final long serialVersionUID = 1L; + + public EidasProxyServiceException(String errorId, Object[] params) { + super(errorId, params); + + } + + public EidasProxyServiceException(String errorId, Object[] params, Throwable e) { + super(errorId, params, e); + + } + +} 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 new file mode 100644 index 00000000..e24c753e --- /dev/null +++ b/modules/eidas_proxy-sevice/src/main/java/at/asitplus/eidas/specific/modules/msproxyservice/protocol/EidasProxyServiceController.java @@ -0,0 +1,443 @@ +package at.asitplus.eidas.specific.modules.msproxyservice.protocol; + +import java.io.IOException; +import java.text.MessageFormat; +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; +import java.util.UUID; +import java.util.stream.Collectors; + +import javax.servlet.ServletException; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.apache.commons.lang.StringEscapeUtils; +import org.apache.commons.lang3.StringUtils; +import org.opensaml.saml.saml2.core.NameIDType; +import org.opensaml.saml.saml2.core.StatusCode; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Controller; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; + +import com.google.common.collect.ImmutableSortedSet; + +import at.asitplus.eidas.specific.core.MsEidasNodeConstants; +import at.asitplus.eidas.specific.core.config.ServiceProviderConfiguration; +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.asitplus.eidas.specific.modules.msproxyservice.utils.EidasProxyServiceUtils; +import at.gv.egiz.components.eventlog.api.EventConstants; +import at.gv.egiz.eaaf.core.api.IRequest; +import at.gv.egiz.eaaf.core.api.data.EaafConfigConstants; +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.EaafException; +import at.gv.egiz.eaaf.core.exceptions.GuiBuildException; +import at.gv.egiz.eaaf.core.impl.idp.controller.AbstractController; +import at.gv.egiz.eaaf.core.impl.utils.KeyValueUtils; +import eu.eidas.auth.commons.EIDASSubStatusCode; +import eu.eidas.auth.commons.EidasParameterKeys; +import eu.eidas.auth.commons.light.ILightRequest; +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.specificcommunication.SpecificCommunicationDefinitionBeanNames; +import eu.eidas.specificcommunication.exception.SpecificCommunicationException; +import eu.eidas.specificcommunication.protocol.SpecificCommunicationService; +import lombok.extern.slf4j.Slf4j; + +/** + * End-point implementation for authentication requests from eIDAS Proxy-Service + * to MS-specific eIDAS Proxy-Service. + * + * @author tlenz + * + */ +@Slf4j +@Controller +public class EidasProxyServiceController extends AbstractController implements IModulInfo { + + private static final String ERROR_01 = "eidas.proxyservice.01"; + private static final String ERROR_02 = "eidas.proxyservice.02"; + private static final String ERROR_03 = "eidas.proxyservice.03"; + private static final String ERROR_04 = "eidas.proxyservice.04"; + private static final String ERROR_05 = "eidas.proxyservice.05"; + private static final String ERROR_07 = "eidas.proxyservice.07"; + private static final String ERROR_08 = "eidas.proxyservice.08"; + private static final String ERROR_09 = "eidas.proxyservice.09"; + private static final String ERROR_10 = "eidas.proxyservice.10"; + private static final String ERROR_11 = "eidas.proxyservice.11"; + + public static final String PROTOCOL_ID = "eidasProxy"; + + @Autowired EidasAttributeRegistry attrRegistry; + @Autowired ProxyServiceAuthenticationAction responseAction; + + /** + * End-point that receives authentication requests from eIDAS Node. + * + * @param httpReq Http request + * @param httpResp Http response + * @throws IOException In case of general error + * @throws EaafException In case of a validation or processing error + */ + @RequestMapping(value = { + MsProxyServiceConstants.EIDAS_HTTP_ENDPOINT_IDP_POST, + MsProxyServiceConstants.EIDAS_HTTP_ENDPOINT_IDP_REDIRECT + }, + method = { RequestMethod.POST, RequestMethod.GET }) + public void receiveEidasAuthnRequest(HttpServletRequest httpReq, HttpServletResponse httpResp) + throws IOException, + EaafException { + log.trace("Receive request on eidas proxy-service end-points"); + ProxyServicePendingRequest pendingReq = null; + try { + // get token from Request + final String tokenBase64 = httpReq.getParameter(EidasParameterKeys.TOKEN.toString()); + if (StringUtils.isEmpty(tokenBase64)) { + log.warn("NO eIDAS message token found."); + throw new EidasProxyServiceException(ERROR_02, null); + + } + log.trace("Receive eIDAS-node token: {}. Searching authentication request from eIDAS Proxy-Service ...", + tokenBase64); + + // read authentication request from shared cache + final SpecificCommunicationService specificProxyCommunicationService = + (SpecificCommunicationService) applicationContext.getBean( + SpecificCommunicationDefinitionBeanNames.SPECIFIC_PROXYSERVICE_COMMUNICATION_SERVICE + .toString()); + final ILightRequest eidasRequest = specificProxyCommunicationService.getAndRemoveRequest( + tokenBase64, + ImmutableSortedSet.copyOf(attrRegistry.getCoreAttributeRegistry().getAttributes())); + if (eidasRequest == null) { + log.info("Find no eIDAS Authn. Request with stated token."); + throw new EidasProxyServiceException(ERROR_11, null); + + } + + log.debug("Received eIDAS auth. request from: {}, Initializing authentication environment ... ", + eidasRequest.getSpCountryCode() != null ? eidasRequest.getSpCountryCode() : "'missing SP-country'"); + log.trace("Received eIDAS requst: {}", eidasRequest); + + // create pendingRequest object + pendingReq = applicationContext.getBean(ProxyServicePendingRequest.class); + pendingReq.initialize(httpReq, authConfig); + pendingReq.setModule(getName()); + + // log 'transaction created' event + revisionsLogger.logEvent(EventConstants.TRANSACTION_CREATED, + pendingReq.getUniqueTransactionIdentifier()); + revisionsLogger.logEvent(pendingReq.getUniqueSessionIdentifier(), + pendingReq.getUniqueTransactionIdentifier(), EventConstants.TRANSACTION_IP, + httpReq.getRemoteAddr()); + + // validate eIDAS Authn. request and set into pending-request + validateEidasAuthnRequest(eidasRequest); + pendingReq.setEidasRequest(eidasRequest); + + // generate Service-Provider configuration from eIDAS request + final ISpConfiguration spConfig = generateSpConfigurationFromEidasRequest(eidasRequest); + + // validate eIDAS Authn. request by using eIDAS Connector specifc parameters + validateEidasAuthnRequest(spConfig, eidasRequest); + + // populate pendingRequest with parameters + pendingReq.setOnlineApplicationConfiguration(spConfig); + pendingReq.setSpEntityId(spConfig.getUniqueIdentifier()); + pendingReq.setPassiv(false); + pendingReq.setForce(true); + + // AuthnRequest needs authentication + pendingReq.setNeedAuthentication(true); + + // set protocol action, which should be executed after authentication + pendingReq.setAction(ProxyServiceAuthenticationAction.class.getName()); + + // switch to session authentication + protAuthService.performAuthentication(httpReq, httpResp, pendingReq); + + } catch (final EidasProxyServiceException e) { + throw e; + + } catch (final SpecificCommunicationException e) { + log.error("Can not read eIDAS Authn request from shared cache. Reason: {}", e.getMessage()); + throw new EidasProxyServiceException(ERROR_03, new Object[] { e.getMessage() }, e); + + } catch (final Throwable e) { + // write revision log entries + if (pendingReq != null) { + revisionsLogger.logEvent(pendingReq, EventConstants.TRANSACTION_ERROR, + pendingReq.getUniqueTransactionIdentifier()); + } + + throw new EidasProxyServiceException(ERROR_01, new Object[] { e.getMessage() }, e); + } + + } + + @Override + public boolean generateErrorMessage(Throwable e, HttpServletRequest httpReq, HttpServletResponse httpResp, + IRequest pendingReq) throws Throwable { + 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.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; + + } + + @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; + + } + + /** + * Generic validation of incoming eIDAS request. + * + * @param eidasRequest Incoming eIDAS authentication request + * @throws EidasProxyServiceException In case of a validation error + */ + private void validateEidasAuthnRequest(ILightRequest eidasRequest) throws EidasProxyServiceException { + if (StringUtils.isEmpty(eidasRequest.getIssuer())) { + throw new EidasProxyServiceException(ERROR_05, null); + + } + + // TODO: validate some other stuff + + } + + /** + * eIDAS Connector specific validation of incoming eIDAS request. + * + * @param eidasRequest Incoming eIDAS authentication request + * @param spConfig eIDAS Connector configuration + * @throws EidasProxyServiceException In case of a validation error + */ + private void validateEidasAuthnRequest(ISpConfiguration spConfig, ILightRequest eidasRequest) + throws EidasProxyServiceException { + // check if natural-person and legal-person attributes requested in parallel + if (spConfig.isConfigurationValue(MsProxyServiceConstants.CONIG_PROPS_CONNECTOR_VALIDATION_ATTR_MDS, true) + && EidasProxyServiceUtils.isLegalPersonRequested(eidasRequest) + && EidasProxyServiceUtils.isNaturalPersonRequested(eidasRequest)) { + throw new EidasProxyServiceException(ERROR_08, null); + + } + + // TODO: validate some other stuff + + } + + /** + * Generate a dummy Service-Provider configuration for processing. + * + * @param eidasRequest Incoming eIDAS authentication request + * @return Service-Provider configuration that can be used for authentication + * @throws EidasProxyServiceException In case of a configuration error + */ + private ISpConfiguration generateSpConfigurationFromEidasRequest(ILightRequest eidasRequest) + throws EidasProxyServiceException { + try { + + Map connectorConfigMap = extractRawConnectorConfiguration(eidasRequest); + + // check if country-code is available + String spCountry = connectorConfigMap.get(MsProxyServiceConstants.CONIG_PROPS_CONNECTOR_COUNTRYCODE); + if (StringUtils.isEmpty(spCountry)) { + throw new EidasProxyServiceException(ERROR_07, null); + + } + + // build FriendyName from CountryCode and SPType + connectorConfigMap.put(MsEidasNodeConstants.PROP_CONFIG_SP_FRIENDLYNAME, + MessageFormat.format(MsProxyServiceConstants.TEMPLATE_SP_UNIQUE_ID, + spCountry, eidasRequest.getSpType())); + + // build Service-Provider configuration object + final ServiceProviderConfiguration spConfig = new ServiceProviderConfiguration(connectorConfigMap, authConfig); + + // build bPK target from Country-Code + final String ccCountry = authConfig.getBasicConfiguration(Constants.CONIG_PROPS_EIDAS_NODE_COUNTRYCODE, + Constants.DEFAULT_MS_NODE_COUNTRY_CODE); + spConfig.setBpkTargetIdentifier( + EaafConstants.URN_PREFIX_EIDAS + ccCountry + "+" + spCountry); + + // set required LoA from eIDAS request + spConfig.setRequiredLoA( + eidasRequest.getLevelsOfAssurance().stream().map(el -> el.getValue()).collect(Collectors.toList())); + + //build mandate profiles for this specific request + buildMandateProfileConfiguration(spConfig, eidasRequest); + + return spConfig; + + } catch (EidasProxyServiceException e) { + throw e; + + } catch (final EaafException e) { + throw new EidasProxyServiceException(ERROR_04, new Object[] { e.getMessage() }, e); + + } + } + + + private Map extractRawConnectorConfiguration(ILightRequest eidasRequest) { + Map allConnectorConfigs = authConfig.getBasicConfigurationWithPrefix( + MsProxyServiceConstants.CONIG_PROPS_CONNECTOR_PREFIX); + if (log.isTraceEnabled()) { + log.trace("Full-connector configuration:"); + allConnectorConfigs.entrySet().stream().forEach( + el -> log.trace("Key: {} -> Value: {}", el.getKey(), el.getValue())); + + } + + + Map connectorConfig = allConnectorConfigs.entrySet().stream() + .filter(el -> el.getKey().endsWith(MsEidasNodeConstants.PROP_CONFIG_SP_UNIQUEIDENTIFIER) + && el.getValue().equals(eidasRequest.getIssuer())) + .findFirst() + .map(el -> KeyValueUtils.getSubSetWithPrefix(allConnectorConfigs, + KeyValueUtils.getParentKey(el.getKey()) + KeyValueUtils.KEY_DELIMITER)) + .orElse(new HashMap<>()); + + + if (connectorConfig.isEmpty()) { + log.debug("No specific configuration for eIDAS Connector: {} Using default configuration ... ", + eidasRequest.getIssuer()); + + // set EntityId of the requesting eIDAS Connector + connectorConfig.put(EaafConfigConstants.SERVICE_UNIQUEIDENTIFIER, eidasRequest.getIssuer()); + + // set country-code from eIDAS request + connectorConfig.put(MsProxyServiceConstants.CONIG_PROPS_CONNECTOR_COUNTRYCODE, + eidasRequest.getSpCountryCode()); + + // set default mandate configuration + connectorConfig.put(MsProxyServiceConstants.CONIG_PROPS_CONNECTOR_MANDATES_ENABLED, + String.valueOf(authConfig.getBasicConfigurationBoolean( + MsProxyServiceConstants.CONIG_PROPS_EIDAS_PROXY_MANDATES_ENABLED, false))); + connectorConfig.put(MsProxyServiceConstants.CONIG_PROPS_CONNECTOR_MANDATES_PROFILE_NATURAL, + authConfig.getBasicConfiguration( + MsProxyServiceConstants.CONIG_PROPS_EIDAS_PROXY_MANDATES_PROFILE_DEFAULT_NATURAL)); + connectorConfig.put(MsProxyServiceConstants.CONIG_PROPS_CONNECTOR_MANDATES_PROFILE_LEGAL, + authConfig.getBasicConfiguration( + MsProxyServiceConstants.CONIG_PROPS_EIDAS_PROXY_MANDATES_PROFILE_DEFAULT_LEGAL)); + + } else { + log.debug("Find specific configuration for eIDAS Connector: {}", eidasRequest.getIssuer()); + + } + + return connectorConfig; + + } + + + private void buildMandateProfileConfiguration(ServiceProviderConfiguration spConfig, ILightRequest eidasRequest) + throws EidasProxyServiceException { + // check if mandates are enabled + if (spConfig.isConfigurationValue(MsProxyServiceConstants.CONIG_PROPS_CONNECTOR_MANDATES_ENABLED, false)) { + injectMandateInfosIntoSpConfig(spConfig, eidasRequest); + + } else { + if (EidasProxyServiceUtils.isLegalPersonRequested(eidasRequest)) { + throw new EidasProxyServiceException(ERROR_09, null); + + } + + spConfig.setMandateProfiles(Collections.emptyList()); + spConfig.setMandateMode(SpMandateModes.NONE); + + } + + } + + private void injectMandateInfosIntoSpConfig(ServiceProviderConfiguration spConfig, + ILightRequest eidasRequest) throws EidasProxyServiceException { + log.trace("eIDAS Proxy-Service allows mandates for Connector: {}. Selecting profiles ... ", + spConfig.getUniqueIdentifier()); + + //check if legal person is requested + if (EidasProxyServiceUtils.isLegalPersonRequested(eidasRequest)) { + spConfig.setMandateProfiles(KeyValueUtils.getListOfCsvValues( + spConfig.getConfigurationValue(MsProxyServiceConstants.CONIG_PROPS_CONNECTOR_MANDATES_PROFILE_LEGAL))); + spConfig.setMandateMode(SpMandateModes.LEGAL_FORCE); + + if (spConfig.getMandateProfiles().isEmpty()) { + throw new EidasProxyServiceException(ERROR_10, null); + + } + + } else if (EidasProxyServiceUtils.isNaturalPersonRequested(eidasRequest)) { + spConfig.setMandateProfiles(KeyValueUtils.getListOfCsvValues( + spConfig.getConfigurationValue(MsProxyServiceConstants.CONIG_PROPS_CONNECTOR_MANDATES_PROFILE_NATURAL))); + + spConfig.setMandateMode(SpMandateModes.NATURAL); + + } + + + if (spConfig.getMandateProfiles().isEmpty()) { + log.debug("No mandate-profiles for issure: {}. Set mandate-mode to 'none'", + spConfig.getUniqueIdentifier()); + spConfig.setMandateMode(SpMandateModes.NONE); + + } else { + log.debug("Set mandate-profiles: {} to request from issuer: {}", + spConfig.getMandateProfiles(), spConfig.getUniqueIdentifier()); + + } + + } +} diff --git a/modules/eidas_proxy-sevice/src/main/java/at/asitplus/eidas/specific/modules/msproxyservice/protocol/ProxyServiceAuthenticationAction.java b/modules/eidas_proxy-sevice/src/main/java/at/asitplus/eidas/specific/modules/msproxyservice/protocol/ProxyServiceAuthenticationAction.java new file mode 100644 index 00000000..15524005 --- /dev/null +++ b/modules/eidas_proxy-sevice/src/main/java/at/asitplus/eidas/specific/modules/msproxyservice/protocol/ProxyServiceAuthenticationAction.java @@ -0,0 +1,374 @@ +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.core.MsEidasNodeConstants; +import at.asitplus.eidas.specific.core.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.asitplus.eidas.specific.modules.msproxyservice.utils.EidasProxyServiceUtils; +import at.gv.egiz.eaaf.core.api.IRequest; +import at.gv.egiz.eaaf.core.api.data.PvpAttributeDefinitions; +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.IEidAuthData; +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 + * + */ +@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, eidasReq)); + + // 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, lightRespBuilder.build()); + + return sloInformation; + + } catch (ServletException | IOException | GuiBuildException e) { + throw new EidasProxyServiceException("eidas.proxyservice.06", null, e); + + } + + } 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) { + return true; + + } + + @Override + public String getDefaultActionName() { + return PROXYSERVICE_AUTH_ACTION_NAME; + + } + + + /** + * Forward eIDAS Light response to eIDAS node. + * + * @param pendingReq Current pending request. + * @param httpReq Current HTTP request + * @param httpResp Current HTTP response + * @param lightResponse eIDAS LightResponse + * @throws EaafConfigurationException In case of a configuration error + * @throws IOException In case of a general error + * @throws GuiBuildException In case of a GUI rendering error, if http POST binding is used + * @throws ServletException In case of a general error + */ + public void forwardToEidasProxy(IRequest pendingReq, HttpServletRequest httpReq, + HttpServletResponse httpResp, LightResponse lightResponse) throws EaafConfigurationException, IOException, + GuiBuildException, ServletException { + + // put request into shared cache + final BinaryLightToken token = putResponseInCommunicationCache(lightResponse); + final String tokenBase64 = BinaryLightTokenHelper.encodeBinaryLightTokenBase64(token); + + // 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"); + + } + } + + @PostConstruct + private void checkConfiguration() { + //TODO: validate configuration on start-up + + } + + + private ImmutableAttributeMap buildAttributesFromAuthData(IAuthData authData, + ILightRequest eidasReq) { + IEidAuthData eidAuthData = (IEidAuthData) authData; + if (eidAuthData.isUseMandate()) { + log.debug("Building eIDAS Proxy-Service response with mandate ... "); + final ImmutableAttributeMap.Builder attributeMap = ImmutableAttributeMap.builder(); + injectRepesentativeInformation(attributeMap, eidAuthData); + injectMandatorInformation(attributeMap, eidAuthData); + + // work-around that injects nat. person subject to bypass validation on eIDAS Node + injectJurPersonWorkaroundIfRequired(attributeMap, eidasReq, authData); + + return attributeMap.build(); + + } else { + log.debug("Building eIDAS Proxy-Service response without mandates ... "); + return buildAttributesWithoutMandate(eidAuthData); + + } + } + + private void injectMandatorInformation( + ImmutableAttributeMap.Builder attributeMap, IEidAuthData eidAuthData) { + String natMandatorId = eidAuthData.getGenericData( + MsEidasNodeConstants.ATTR_EIDAS_NAT_MANDATOR_PERSONAL_IDENTIFIER, String.class); + + if (StringUtils.isNotEmpty(natMandatorId)) { + log.debug("Injecting natural mandator informations ... "); + 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(); + + attributeMap.put(attrDefPersonalId, natMandatorId); + attributeMap.put(attrDefFamilyName, eidAuthData.getGenericData( + PvpAttributeDefinitions.MANDATE_NAT_PER_FAMILY_NAME_NAME, String.class)); + attributeMap.put(attrDefGivenName, eidAuthData.getGenericData( + PvpAttributeDefinitions.MANDATE_NAT_PER_GIVEN_NAME_NAME, String.class)); + attributeMap.put(attrDefDateOfBirth, eidAuthData.getGenericData( + PvpAttributeDefinitions.MANDATE_NAT_PER_BIRTHDATE_NAME, String.class)); + + } else { + log.debug("Injecting legal mandator informations ... "); + final AttributeDefinition commonName = attrRegistry.getCoreAttributeRegistry().getByFriendlyName( + Constants.eIDAS_ATTR_LEGALNAME).first(); + final AttributeDefinition legalPersonId = attrRegistry.getCoreAttributeRegistry().getByFriendlyName( + Constants.eIDAS_ATTR_LEGALPERSONIDENTIFIER).first(); + + attributeMap.put(commonName, eidAuthData.getGenericData( + PvpAttributeDefinitions.MANDATE_LEG_PER_FULL_NAME_NAME, String.class)); + attributeMap.put(legalPersonId, eidAuthData.getGenericData( + MsEidasNodeConstants.ATTR_EIDAS_JUR_MANDATOR_PERSONAL_IDENTIFIER, String.class)); + + } + } + + private void injectRepesentativeInformation( + ImmutableAttributeMap.Builder attributeMap, IEidAuthData eidAuthData) { + final AttributeDefinition attrDefPersonalId = attrRegistry.getCoreAttributeRegistry().getByFriendlyName( + Constants.eIDAS_ATTR_REPRESENTATIVE_PERSONALIDENTIFIER).first(); + final AttributeDefinition attrDefFamilyName = attrRegistry.getCoreAttributeRegistry().getByFriendlyName( + Constants.eIDAS_ATTR_REPRESENTATIVE_CURRENTFAMILYNAME).first(); + final AttributeDefinition attrDefGivenName = attrRegistry.getCoreAttributeRegistry().getByFriendlyName( + Constants.eIDAS_ATTR_REPRESENTATIVE_CURRENTGIVENNAME).first(); + final AttributeDefinition attrDefDateOfBirth = attrRegistry.getCoreAttributeRegistry().getByFriendlyName( + Constants.eIDAS_ATTR_REPRESENTATIVE_DATEOFBIRTH).first(); + + attributeMap.put(attrDefPersonalId, + eidAuthData.getGenericData(MsEidasNodeConstants.ATTR_EIDAS_PERSONAL_IDENTIFIER, String.class)); + attributeMap.put(attrDefFamilyName, eidAuthData.getFamilyName()); + attributeMap.put(attrDefGivenName, eidAuthData.getGivenName()); + + //TODO: throw an error in case of SZR Date with month or day = "00" + attributeMap.put(attrDefDateOfBirth, eidAuthData.getDateOfBirth()); + + } + + /** + * Work-around to inject representative information as nat. person subject to bypass eIDAS Node validation. + * + *

Injection will only be done if this work-around is enabled by configuration, + * the mandator is a legal person, and both legal and natural person subject's is requested.

+ * + * @param attributeMap Attribute set for eIDAS response + * @param eidasReq Incoming eIDAS request + * @param authData Authentication data + */ + private void injectJurPersonWorkaroundIfRequired( + ImmutableAttributeMap.Builder attributeMap, ILightRequest eidasReq, IAuthData authData) { + if (isLegalPersonWorkaroundActive() && isLegalPersonMandateAvailable(authData) + && EidasProxyServiceUtils.isNaturalPersonRequested(eidasReq) + && EidasProxyServiceUtils.isLegalPersonRequested(eidasReq)) { + log.debug("Injecting representative information as nat. person subject to bypass eIDAS Node validation"); + attributeMap.putAll(buildAttributesWithoutMandate(authData)); + + } + } + + private ImmutableAttributeMap buildAttributesWithoutMandate(IAuthData eidAuthData) { + //TODO: throw an error in case of SZR Date with month or day = "00" + return buildAttributesWithoutMandate( + eidAuthData.getGenericData(MsEidasNodeConstants.ATTR_EIDAS_PERSONAL_IDENTIFIER, String.class), + eidAuthData.getFamilyName(), + eidAuthData.getGivenName(), + eidAuthData.getDateOfBirth()); + + } + + private ImmutableAttributeMap buildAttributesWithoutMandate(String personalIdentifier, String familyName, + String givenName, String dateOfBirth) { + 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, personalIdentifier) + .put(attrDefFamilyName, familyName) + .put(attrDefGivenName, givenName) + .put(attrDefDateOfBirth, dateOfBirth); + + 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 boolean isLegalPersonWorkaroundActive() { + return basicConfig.getBasicConfigurationBoolean( + MsProxyServiceConstants.CONIG_PROPS_EIDAS_PROXY_WORKAROUND_MANDATES_LEGAL_PERSON, + false); + + } + + private boolean isLegalPersonMandateAvailable(IAuthData authData) { + return StringUtils.isNoneEmpty(authData.getGenericData( + MsEidasNodeConstants.ATTR_EIDAS_JUR_MANDATOR_PERSONAL_IDENTIFIER, String.class)); + + } + +} diff --git a/modules/eidas_proxy-sevice/src/main/java/at/asitplus/eidas/specific/modules/msproxyservice/protocol/ProxyServicePendingRequest.java b/modules/eidas_proxy-sevice/src/main/java/at/asitplus/eidas/specific/modules/msproxyservice/protocol/ProxyServicePendingRequest.java new file mode 100644 index 00000000..a3b5007a --- /dev/null +++ b/modules/eidas_proxy-sevice/src/main/java/at/asitplus/eidas/specific/modules/msproxyservice/protocol/ProxyServicePendingRequest.java @@ -0,0 +1,28 @@ +package at.asitplus.eidas.specific.modules.msproxyservice.protocol; + +import org.springframework.beans.factory.config.BeanDefinition; +import org.springframework.context.annotation.Scope; +import org.springframework.stereotype.Component; + +import at.gv.egiz.eaaf.core.impl.idp.controller.protocols.RequestImpl; +import eu.eidas.auth.commons.light.ILightRequest; +import lombok.Getter; +import lombok.Setter; + +/** + * Pending-request of an authentication process from eIDAS Proxy-Service. + * + * @author tlenz + * + */ +@Component("ProxyServicePendingRequest") +@Scope(value = BeanDefinition.SCOPE_PROTOTYPE) +public class ProxyServicePendingRequest extends RequestImpl { + + private static final long serialVersionUID = 4227378344716277935L; + + @Getter + @Setter + ILightRequest eidasRequest; + +} diff --git a/modules/eidas_proxy-sevice/src/main/java/at/asitplus/eidas/specific/modules/msproxyservice/utils/EidasProxyServiceUtils.java b/modules/eidas_proxy-sevice/src/main/java/at/asitplus/eidas/specific/modules/msproxyservice/utils/EidasProxyServiceUtils.java new file mode 100644 index 00000000..4cd7ba6c --- /dev/null +++ b/modules/eidas_proxy-sevice/src/main/java/at/asitplus/eidas/specific/modules/msproxyservice/utils/EidasProxyServiceUtils.java @@ -0,0 +1,45 @@ +package at.asitplus.eidas.specific.modules.msproxyservice.utils; + +import at.asitplus.eidas.specific.modules.auth.eidas.v2.Constants; +import eu.eidas.auth.commons.light.ILightRequest; + +/** + * Common utils for eIDAS Proxy-Service implementation. + * + * @author tlenz + * + */ +public class EidasProxyServiceUtils { + + /** + * Check if legal person subject is requested by eIDAS Connector. + * + * @param eidasRequest Authentication request from eIDAS Connector. + * @return true if LegalPersonIdentifier is requested, otherwise falselse + */ + public static boolean isLegalPersonRequested(ILightRequest eidasRequest) { + return eidasRequest.getRequestedAttributes().entrySet().stream() + .filter(el -> el.getKey().getFriendlyName().equals(Constants.eIDAS_ATTR_LEGALPERSONIDENTIFIER)) + .findFirst() + .isPresent(); + + } + + /** + * Check if natural person subject is requested by eIDAS Connector. + * + * @param eidasRequest Authentication request from eIDAS Connector. + * @return true if PersonIdentifier is requested, otherwise falselse + */ + public static boolean isNaturalPersonRequested(ILightRequest eidasRequest) { + return eidasRequest.getRequestedAttributes().entrySet().stream() + .filter(el -> el.getKey().getFriendlyName().equals(Constants.eIDAS_ATTR_PERSONALIDENTIFIER)) + .findFirst() + .isPresent(); + + } + + private EidasProxyServiceUtils() { + //hide constructor for class with static methods only + } +} diff --git a/modules/eidas_proxy-sevice/src/main/resources/META-INF/services/at.gv.egiz.components.spring.api.SpringResourceProvider b/modules/eidas_proxy-sevice/src/main/resources/META-INF/services/at.gv.egiz.components.spring.api.SpringResourceProvider new file mode 100644 index 00000000..9158d2e6 --- /dev/null +++ b/modules/eidas_proxy-sevice/src/main/resources/META-INF/services/at.gv.egiz.components.spring.api.SpringResourceProvider @@ -0,0 +1 @@ +at.asitplus.eidas.specific.modules.msproxyservice.MsProxyServiceSpringResourceProvider \ No newline at end of file diff --git a/modules/eidas_proxy-sevice/src/main/resources/messages/eidasproxy_messages.properties b/modules/eidas_proxy-sevice/src/main/resources/messages/eidasproxy_messages.properties new file mode 100644 index 00000000..3f92d58a --- /dev/null +++ b/modules/eidas_proxy-sevice/src/main/resources/messages/eidasproxy_messages.properties @@ -0,0 +1,14 @@ +eidas.proxyservice.01=General error on request-validation from national eIDAS Proxy-Service +eidas.proxyservice.02=Authentication request contains not communication token. +eidas.proxyservice.03=General error during eIDAS-Node communication. Reason: {} +eidas.proxyservice.04=Validation of eIDAS Authn request failed. Reason: {} +eidas.proxyservice.05=No eIDAS-Connector Issuer in Authn. request. Authentication not possible +eidas.proxyservice.06=Can not build eIDAS Proxy-Service response. Authentication FAILED. +eidas.proxyservice.07=Can not determine eIDAS-Connector CountryCode. Authentication not possible +eidas.proxyservice.08=Validation of eIDAS Authn request failed. Reason: Legal person and natural person can not be requested at once. +eidas.proxyservice.09=eIDAS authentication not possible, because legal person is requested but mandates are disabled in general +eidas.proxyservice.10=eIDAS authentication not possible, because legal person is requested but not mandate profiles are defined +eidas.proxyservice.11=No Authentication request with stated communication token. + + +eidas.proxyservice.99=Internal error during eIDAS Proxy-Service authentication \ No newline at end of file diff --git a/modules/eidas_proxy-sevice/src/main/resources/spring/eidas_proxy-service.beans.xml b/modules/eidas_proxy-sevice/src/main/resources/spring/eidas_proxy-service.beans.xml new file mode 100644 index 00000000..2055b5a9 --- /dev/null +++ b/modules/eidas_proxy-sevice/src/main/resources/spring/eidas_proxy-service.beans.xml @@ -0,0 +1,28 @@ + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/modules/eidas_proxy-sevice/src/test/java/at/asitplus/eidas/specific/modules/auth/idaustria/test/EidasProxyMessageSourceTest.java b/modules/eidas_proxy-sevice/src/test/java/at/asitplus/eidas/specific/modules/auth/idaustria/test/EidasProxyMessageSourceTest.java new file mode 100644 index 00000000..efe572b5 --- /dev/null +++ b/modules/eidas_proxy-sevice/src/test/java/at/asitplus/eidas/specific/modules/auth/idaustria/test/EidasProxyMessageSourceTest.java @@ -0,0 +1,50 @@ +package at.asitplus.eidas.specific.modules.auth.idaustria.test; + +import java.util.List; + +import org.junit.Assert; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.core.io.Resource; +import org.springframework.core.io.ResourceLoader; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; + +import at.asitplus.eidas.specific.modules.msproxyservice.EidasProxyMessageSource; +import at.gv.egiz.eaaf.core.api.logging.IMessageSourceLocation; + +@RunWith(SpringJUnit4ClassRunner.class) +@ContextConfiguration(locations = { + "/spring/SpringTest-context_basic_test.xml", + "/spring/SpringTest-context_basic_mapConfig.xml", + }) +public class EidasProxyMessageSourceTest { + + @Autowired + private ResourceLoader loader; + @Autowired(required = false) + private List messageSources; + + @Test + public void checkMessageSources() { + Assert.assertNotNull("No messageSource", messageSources); + Assert.assertFalse("No message source", messageSources.isEmpty()); + + boolean found = false; + + for (final IMessageSourceLocation messageSource : messageSources) { + found = found ? found : messageSource instanceof EidasProxyMessageSource; + + Assert.assertNotNull("No sourcePath", messageSource.getMessageSourceLocation()); + for (final String el : messageSource.getMessageSourceLocation()) { + final Resource messages = loader.getResource(el + ".properties"); + Assert.assertTrue("Source not exist", messages.exists()); + + } + } + + Assert.assertTrue("Internal messagesource not found", found); + + } +} diff --git a/modules/eidas_proxy-sevice/src/test/java/at/asitplus/eidas/specific/modules/auth/idaustria/test/MsProxyServiceSpringResourceProviderTest.java b/modules/eidas_proxy-sevice/src/test/java/at/asitplus/eidas/specific/modules/auth/idaustria/test/MsProxyServiceSpringResourceProviderTest.java new file mode 100644 index 00000000..8c6da366 --- /dev/null +++ b/modules/eidas_proxy-sevice/src/test/java/at/asitplus/eidas/specific/modules/auth/idaustria/test/MsProxyServiceSpringResourceProviderTest.java @@ -0,0 +1,56 @@ +package at.asitplus.eidas.specific.modules.auth.idaustria.test; + +import java.io.IOException; +import java.io.InputStream; + +import org.apache.commons.io.IOUtils; +import org.junit.Assert; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.BlockJUnit4ClassRunner; +import org.springframework.core.io.Resource; + +import at.asitplus.eidas.specific.modules.msproxyservice.MsProxyServiceSpringResourceProvider; +import at.gv.egiz.eaaf.core.test.TestConstants; + + + +@RunWith(BlockJUnit4ClassRunner.class) +public class MsProxyServiceSpringResourceProviderTest { + + @Test + public void testSpringConfig() { + final MsProxyServiceSpringResourceProvider test = + new MsProxyServiceSpringResourceProvider(); + for (final Resource el : test.getResourcesToLoad()) { + try { + IOUtils.toByteArray(el.getInputStream()); + + } catch (final IOException e) { + Assert.fail("Ressouce: " + el.getFilename() + " not found"); + } + + } + + Assert.assertNotNull("no Name", test.getName()); + Assert.assertNull("Find package definitions", test.getPackagesToScan()); + + } + + @Test + public void testSpILoaderConfig() { + final InputStream el = this.getClass().getResourceAsStream(TestConstants.TEST_SPI_LOADER_PATH); + try { + final String spiFile = IOUtils.toString(el, "UTF-8"); + + Assert.assertEquals("Wrong classpath in SPI file", + MsProxyServiceSpringResourceProvider.class.getName(), spiFile); + + + } catch (final IOException e) { + Assert.fail("Ressouce: " + TestConstants.TEST_SPI_LOADER_PATH + " not found"); + + } + } + +} diff --git a/modules/eidas_proxy-sevice/src/test/java/at/asitplus/eidas/specific/modules/auth/idaustria/test/protocol/EidasProxyServiceControllerTest.java b/modules/eidas_proxy-sevice/src/test/java/at/asitplus/eidas/specific/modules/auth/idaustria/test/protocol/EidasProxyServiceControllerTest.java new file mode 100644 index 00000000..55958d9e --- /dev/null +++ b/modules/eidas_proxy-sevice/src/test/java/at/asitplus/eidas/specific/modules/auth/idaustria/test/protocol/EidasProxyServiceControllerTest.java @@ -0,0 +1,666 @@ +package at.asitplus.eidas.specific.modules.auth.idaustria.test.protocol; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertThrows; +import static org.junit.Assert.assertTrue; + +import java.io.IOException; +import java.net.URISyntaxException; +import java.net.URLDecoder; +import java.text.MessageFormat; +import java.util.Arrays; +import java.util.List; +import java.util.UUID; + +import org.apache.commons.lang3.RandomStringUtils; +import org.apache.commons.lang3.StringUtils; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.opensaml.saml.saml2.core.NameIDType; +import org.opensaml.saml.saml2.core.StatusCode; +import org.powermock.core.classloader.annotations.PrepareForTest; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.ApplicationContext; +import org.springframework.mock.web.MockHttpServletRequest; +import org.springframework.mock.web.MockHttpServletResponse; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; +import org.springframework.web.context.request.RequestContextHolder; +import org.springframework.web.context.request.ServletRequestAttributes; +import org.springframework.web.servlet.config.annotation.EnableWebMvc; + +import com.google.common.collect.ImmutableSortedSet; + +import at.asitplus.eidas.specific.core.config.ServiceProviderConfiguration; +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.service.EidasAttributeRegistry; +import at.asitplus.eidas.specific.modules.auth.eidas.v2.tasks.CreateIdentityLinkTask; +import at.asitplus.eidas.specific.modules.auth.eidas.v2.test.dummy.DummySpecificCommunicationService; +import at.asitplus.eidas.specific.modules.msproxyservice.MsProxyServiceConstants; +import at.asitplus.eidas.specific.modules.msproxyservice.exception.EidasProxyServiceException; +import at.asitplus.eidas.specific.modules.msproxyservice.protocol.EidasProxyServiceController; +import at.asitplus.eidas.specific.modules.msproxyservice.protocol.ProxyServicePendingRequest; +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.exceptions.EaafException; +import at.gv.egiz.eaaf.core.exceptions.EaafStorageException; +import at.gv.egiz.eaaf.core.impl.idp.module.test.DummyProtocolAuthService; +import eu.eidas.auth.commons.EidasParameterKeys; +import eu.eidas.auth.commons.attribute.ImmutableAttributeMap; +import eu.eidas.auth.commons.light.ILightResponse; +import eu.eidas.auth.commons.light.impl.LightRequest; +import eu.eidas.specificcommunication.SpecificCommunicationDefinitionBeanNames; +import eu.eidas.specificcommunication.exception.SpecificCommunicationException; +import eu.eidas.specificcommunication.protocol.SpecificCommunicationService; + +@RunWith(SpringJUnit4ClassRunner.class) +@PrepareForTest(CreateIdentityLinkTask.class) +@ContextConfiguration(locations = { + "/spring/SpringTest-context_basic_test.xml", + "/spring/SpringTest-context_basic_mapConfig.xml", + }) +@EnableWebMvc +public class EidasProxyServiceControllerTest { + + @Autowired private EidasProxyServiceController controller; + + @Autowired private DummySpecificCommunicationService proxyService; + @Autowired private DummyProtocolAuthService authService; + @Autowired private EidasAttributeRegistry attrRegistry; + @Autowired private ApplicationContext context; + + @Autowired MsConnectorDummyConfigMap config; + + private MockHttpServletRequest httpReq; + private MockHttpServletResponse httpResp; + + private SpecificCommunicationService springManagedSpecificConnectorCommunicationService; + + /** + * jUnit test set-up. + */ + @Before + public void setUp() throws EaafStorageException, URISyntaxException { + httpReq = new MockHttpServletRequest("POST", "http://localhost/ms_connector/eidas/light/idp/redirect"); + httpResp = new MockHttpServletResponse(); + RequestContextHolder.resetRequestAttributes(); + RequestContextHolder.setRequestAttributes(new ServletRequestAttributes(httpReq, httpResp)); + + proxyService.setiLightRequest(null); + proxyService.setError(null); + + config.putConfigValue("eidas.ms.auth.eIDAS.node_v2.proxy.forward.endpoint", + "http://eidas.proxy/endpoint"); + + springManagedSpecificConnectorCommunicationService = + (SpecificCommunicationService) context.getBean( + SpecificCommunicationDefinitionBeanNames.SPECIFIC_PROXYSERVICE_COMMUNICATION_SERVICE + .toString()); + + } + + @Test + public void generateErrorResponseWrongPendingReq() throws Throwable { + Assert.assertFalse("wrong statusCode", controller.generateErrorMessage( + new EaafException("1000"), + httpReq, httpResp, null)); + + } + + @Test + public void generateErrorResponse() throws Throwable { + 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.assertTrue("wrong statusCode", controller.generateErrorMessage( + new EaafException("1000"), + httpReq, httpResp, + pendingReq)); + + // validate state + assertNotNull("not redirct Header", httpResp.getHeader("Location")); + assertTrue("wrong redirect URL", httpResp.getHeader("Location").startsWith("http://eidas.proxy/endpoint?token=")); + String token = httpResp.getHeader("Location").substring("http://eidas.proxy/endpoint?token=".length()); + + ILightResponse resp = springManagedSpecificConnectorCommunicationService.getAndRemoveResponse(URLDecoder.decode(token, "UTF-8"), + ImmutableSortedSet.copyOf(attrRegistry.getCoreAttributeRegistry().getAttributes())); + + assertNotNull("responseId", resp.getId()); + assertEquals("inResponseTo", pendingReq.getEidasRequest().getId(), resp.getInResponseToId()); + assertEquals("relayState", pendingReq.getEidasRequest().getRelayState(), resp.getRelayState()); + + assertNotNull("subjectNameId", resp.getSubject()); + assertEquals("subjectNameIdFormat", NameIDType.TRANSIENT, resp.getSubjectNameIdFormat()); + assertTrue("not attributes", resp.getAttributes().isEmpty()); + + assertEquals("StatusCode", StatusCode.RESPONDER, resp.getStatus().getStatusCode()); + //assertEquals("SubStatusCode", "", resp.getStatus().getSubStatusCode()); + //assertEquals("StatusMsg", "", resp.getStatus().getStatusMessage()); + + } + + @Test + public void missingEidasToken() { + EidasProxyServiceException exception = assertThrows(EidasProxyServiceException.class, + () -> controller.receiveEidasAuthnRequest(httpReq, httpResp)); + Assert.assertEquals("wrong errorCode", "eidas.proxyservice.02", exception.getErrorId()); + + } + + @Test + public void wrongEidasTokenWithNullpointerException() { + //initialize state + httpReq.addParameter(EidasParameterKeys.TOKEN.toString(), RandomStringUtils.randomAlphanumeric(10)); + + //validate state + EidasProxyServiceException exception = assertThrows(EidasProxyServiceException.class, + () -> controller.receiveEidasAuthnRequest(httpReq, httpResp)); + Assert.assertEquals("wrong errorCode", "eidas.proxyservice.11", exception.getErrorId()); + + } + + @Test + public void wrongEidasTokenCacheCommunicationError() { + //initialize state + httpReq.addParameter(EidasParameterKeys.TOKEN.toString(), RandomStringUtils.randomAlphanumeric(10)); + proxyService.setError(new SpecificCommunicationException(RandomStringUtils.randomAlphanumeric(10))); + + //validate state + EidasProxyServiceException exception = assertThrows(EidasProxyServiceException.class, + () -> controller.receiveEidasAuthnRequest(httpReq, httpResp)); + Assert.assertEquals("wrong errorCode", "eidas.proxyservice.03", exception.getErrorId()); + Assert.assertTrue("Wrong exception", (exception.getCause() instanceof SpecificCommunicationException)); + + } + + @Test + public void missingServiceProviderCountry() { + //initialize state + httpReq.addParameter(EidasParameterKeys.TOKEN.toString(), RandomStringUtils.randomAlphanumeric(10)); + LightRequest.Builder authnReqBuilder = LightRequest.builder() + .id(UUID.randomUUID().toString()) + .issuer(RandomStringUtils.randomAlphabetic(10)) + .citizenCountryCode(RandomStringUtils.randomAlphabetic(2).toUpperCase()) + .levelOfAssurance(EaafConstants.EIDAS_LOA_HIGH); + + proxyService.setiLightRequest(authnReqBuilder.build()); + + //validate state + EidasProxyServiceException exception = assertThrows(EidasProxyServiceException.class, + () -> controller.receiveEidasAuthnRequest(httpReq, httpResp)); + Assert.assertEquals("wrong errorCode", "eidas.proxyservice.07", exception.getErrorId()); + + } + + @Test + public void requestingLegalAndNaturalPerson() { + //initialize state + httpReq.addParameter(EidasParameterKeys.TOKEN.toString(), RandomStringUtils.randomAlphanumeric(10)); + LightRequest.Builder authnReqBuilder = LightRequest.builder() + .id(UUID.randomUUID().toString()) + .issuer(RandomStringUtils.randomAlphabetic(10)) + .citizenCountryCode(RandomStringUtils.randomAlphabetic(2).toUpperCase()) + .spCountryCode(RandomStringUtils.randomAlphabetic(2).toUpperCase()) + .levelOfAssurance(EaafConstants.EIDAS_LOA_HIGH) + .requestedAttributes(ImmutableAttributeMap.builder() + .put(attrRegistry.getCoreAttributeRegistry().getByFriendlyName( + Constants.eIDAS_ATTR_PERSONALIDENTIFIER).first()) + .put(attrRegistry.getCoreAttributeRegistry().getByFriendlyName( + Constants.eIDAS_ATTR_LEGALPERSONIDENTIFIER).first()) + .build()); + + proxyService.setiLightRequest(authnReqBuilder.build()); + + //validate state + EidasProxyServiceException exception = assertThrows(EidasProxyServiceException.class, + () -> controller.receiveEidasAuthnRequest(httpReq, httpResp)); + Assert.assertEquals("wrong errorCode", "eidas.proxyservice.08", exception.getErrorId()); + + } + + @Test + public void requestLegalPersonButNoMandates() throws IOException, EaafException { + //initialize state + httpReq.addParameter(EidasParameterKeys.TOKEN.toString(), RandomStringUtils.randomAlphanumeric(10)); + String spCountryCode = RandomStringUtils.randomAlphabetic(2).toUpperCase(); + LightRequest.Builder authnReqBuilder = LightRequest.builder() + .id(UUID.randomUUID().toString()) + .issuer(RandomStringUtils.randomAlphabetic(10)) + .citizenCountryCode(RandomStringUtils.randomAlphabetic(2).toUpperCase()) + .levelOfAssurance(EaafConstants.EIDAS_LOA_HIGH) + .spCountryCode(spCountryCode) + .spType("public") + .requestedAttributes(ImmutableAttributeMap.builder() + .put(attrRegistry.getCoreAttributeRegistry().getByFriendlyName( + Constants.eIDAS_ATTR_LEGALPERSONIDENTIFIER).first()).build()); + + proxyService.setiLightRequest(authnReqBuilder.build()); + + config.putConfigValue(MsProxyServiceConstants.CONIG_PROPS_EIDAS_PROXY_MANDATES_ENABLED, "false"); + config.putConfigValue(MsProxyServiceConstants.CONIG_PROPS_EIDAS_PROXY_MANDATES_PROFILE_DEFAULT_NATURAL, + StringUtils.join(Arrays.asList( + RandomStringUtils.randomAlphabetic(5), RandomStringUtils.randomAlphabetic(5)), ",")); + + //validate state + EidasProxyServiceException exception = assertThrows(EidasProxyServiceException.class, + () -> controller.receiveEidasAuthnRequest(httpReq, httpResp)); + Assert.assertEquals("wrong errorCode", "eidas.proxyservice.09", exception.getErrorId()); + + } + + @Test + public void validAuthnRequest() throws IOException, EaafException { + //initialize state + httpReq.addParameter(EidasParameterKeys.TOKEN.toString(), RandomStringUtils.randomAlphanumeric(10)); + String spCountryCode = RandomStringUtils.randomAlphabetic(2).toUpperCase(); + LightRequest.Builder authnReqBuilder = LightRequest.builder() + .id(UUID.randomUUID().toString()) + .issuer(RandomStringUtils.randomAlphabetic(10)) + .citizenCountryCode(RandomStringUtils.randomAlphabetic(2).toUpperCase()) + .levelOfAssurance(EaafConstants.EIDAS_LOA_HIGH) + .spCountryCode(spCountryCode) + .spType("public") + .requestedAttributes(ImmutableAttributeMap.builder() + .put(attrRegistry.getCoreAttributeRegistry().getByFriendlyName( + Constants.eIDAS_ATTR_PERSONALIDENTIFIER).first()).build()); + + proxyService.setiLightRequest(authnReqBuilder.build()); + + + config.putConfigValue(MsProxyServiceConstants.CONIG_PROPS_EIDAS_PROXY_MANDATES_ENABLED, "false"); + config.putConfigValue(MsProxyServiceConstants.CONIG_PROPS_EIDAS_PROXY_MANDATES_PROFILE_DEFAULT_NATURAL, + StringUtils.join(Arrays.asList( + RandomStringUtils.randomAlphabetic(5), RandomStringUtils.randomAlphabetic(5)), ",")); + + + //execute + controller.receiveEidasAuthnRequest(httpReq, httpResp); + + //validate state + Assert.assertNotNull("pendingRequest", authService.getPendingReq()); + Assert.assertTrue("wrong pendingRequest", authService.getPendingReq() instanceof ProxyServicePendingRequest); + ProxyServicePendingRequest pendingReq = (ProxyServicePendingRequest) authService.getPendingReq(); + Assert.assertNotNull("missing uniqueSpId", pendingReq.getSpEntityId()); + Assert.assertNotNull("missing eidasReq", pendingReq.getEidasRequest()); + + Assert.assertFalse("isPassive", pendingReq.isPassiv()); + Assert.assertTrue("isPassive", pendingReq.forceAuth()); + Assert.assertFalse("isPassive", pendingReq.isAuthenticated()); + Assert.assertFalse("isPassive", pendingReq.isAbortedByUser()); + Assert.assertTrue("isPassive", pendingReq.isNeedAuthentication()); + + Assert.assertNotNull("missing spConfig", pendingReq.getServiceProviderConfiguration()); + ServiceProviderConfiguration spConfig = + pendingReq.getServiceProviderConfiguration(ServiceProviderConfiguration.class); + Assert.assertNotNull("uniqueId", spConfig.getUniqueIdentifier()); + Assert.assertEquals("uniqueId wrong pattern", + authnReqBuilder.build().getIssuer(), + spConfig.getUniqueIdentifier()); + Assert.assertEquals("friendlyName wrong pattern", + MessageFormat.format(MsProxyServiceConstants.TEMPLATE_SP_UNIQUE_ID, spCountryCode, "public"), + spConfig.getFriendlyName()); + + Assert.assertEquals("uniqueId not match to pendingReq", + pendingReq.getSpEntityId(), spConfig.getUniqueIdentifier()); + Assert.assertNotNull("bpkTarget", spConfig.getAreaSpecificTargetIdentifier()); + Assert.assertEquals("wrong bPK Target", + EaafConstants.URN_PREFIX_EIDAS + "AT+" + spCountryCode, + spConfig.getAreaSpecificTargetIdentifier()); + + assertNotNull("mandateprofiles", spConfig.getMandateProfiles()); + assertTrue("mandateprofiles not empty", spConfig.getMandateProfiles().isEmpty()); + assertEquals("MandateMode", SpMandateModes.NONE, spConfig.getMandateMode()); + + } + + @Test + public void validAuthnRequestWithMandatesDefaultProfilesNat() throws IOException, EaafException { + //initialize state + httpReq.addParameter(EidasParameterKeys.TOKEN.toString(), RandomStringUtils.randomAlphanumeric(10)); + String spCountryCode = RandomStringUtils.randomAlphabetic(2).toUpperCase(); + LightRequest.Builder authnReqBuilder = LightRequest.builder() + .id(UUID.randomUUID().toString()) + .issuer(RandomStringUtils.randomAlphabetic(10)) + .citizenCountryCode(RandomStringUtils.randomAlphabetic(2).toUpperCase()) + .levelOfAssurance(EaafConstants.EIDAS_LOA_HIGH) + .spCountryCode(spCountryCode) + .spType("public") + .requestedAttributes(ImmutableAttributeMap.builder() + .put(attrRegistry.getCoreAttributeRegistry().getByFriendlyName( + Constants.eIDAS_ATTR_PERSONALIDENTIFIER).first()).build()); + + + proxyService.setiLightRequest(authnReqBuilder.build()); + + List mandateProfilesNat = + Arrays.asList(RandomStringUtils.randomAlphabetic(5), RandomStringUtils.randomAlphabetic(5)); + List mandateProfilesJur = + Arrays.asList(RandomStringUtils.randomAlphabetic(5), RandomStringUtils.randomAlphabetic(5)); + config.putConfigValue(MsProxyServiceConstants.CONIG_PROPS_EIDAS_PROXY_MANDATES_ENABLED, "true"); + config.putConfigValue(MsProxyServiceConstants.CONIG_PROPS_EIDAS_PROXY_MANDATES_PROFILE_DEFAULT_NATURAL, + StringUtils.join(mandateProfilesNat, ",")); + config.putConfigValue(MsProxyServiceConstants.CONIG_PROPS_EIDAS_PROXY_MANDATES_PROFILE_DEFAULT_LEGAL, + StringUtils.join(mandateProfilesJur, ",")); + + //execute + controller.receiveEidasAuthnRequest(httpReq, httpResp); + + //validate state + ServiceProviderConfiguration spConfig = + authService.getPendingReq().getServiceProviderConfiguration(ServiceProviderConfiguration.class); + assertNotNull("mandateprofiles", spConfig.getMandateProfiles()); + assertFalse("mandateprofiles not empty", spConfig.getMandateProfiles().isEmpty()); + assertEquals("mandateprofile size", mandateProfilesNat.size(), spConfig.getMandateProfiles().size()); + spConfig.getMandateProfiles().stream() + .forEach(el -> assertTrue("missing mandateProfile: " + el, mandateProfilesNat.contains(el))); + assertEquals("MandateMode", SpMandateModes.NATURAL, spConfig.getMandateMode()); + + } + + @Test + public void validAuthnRequestWithMandatesDefaultProfilesJur() throws IOException, EaafException { + //initialize state + httpReq.addParameter(EidasParameterKeys.TOKEN.toString(), RandomStringUtils.randomAlphanumeric(10)); + String spCountryCode = RandomStringUtils.randomAlphabetic(2).toUpperCase(); + LightRequest.Builder authnReqBuilder = LightRequest.builder() + .id(UUID.randomUUID().toString()) + .issuer(RandomStringUtils.randomAlphabetic(10)) + .citizenCountryCode(RandomStringUtils.randomAlphabetic(2).toUpperCase()) + .levelOfAssurance(EaafConstants.EIDAS_LOA_HIGH) + .spCountryCode(spCountryCode) + .spType("public") + .requestedAttributes(ImmutableAttributeMap.builder() + .put(attrRegistry.getCoreAttributeRegistry().getByFriendlyName( + Constants.eIDAS_ATTR_LEGALPERSONIDENTIFIER).first()).build()); + + + proxyService.setiLightRequest(authnReqBuilder.build()); + + List mandateProfilesNat = + Arrays.asList(RandomStringUtils.randomAlphabetic(5), RandomStringUtils.randomAlphabetic(5)); + List mandateProfilesJur = + Arrays.asList(RandomStringUtils.randomAlphabetic(5), RandomStringUtils.randomAlphabetic(5)); + config.putConfigValue(MsProxyServiceConstants.CONIG_PROPS_EIDAS_PROXY_MANDATES_ENABLED, "true"); + config.putConfigValue(MsProxyServiceConstants.CONIG_PROPS_EIDAS_PROXY_MANDATES_PROFILE_DEFAULT_NATURAL, + StringUtils.join(mandateProfilesNat, ",")); + config.putConfigValue(MsProxyServiceConstants.CONIG_PROPS_EIDAS_PROXY_MANDATES_PROFILE_DEFAULT_LEGAL, + StringUtils.join(mandateProfilesJur, ",")); + + //execute + controller.receiveEidasAuthnRequest(httpReq, httpResp); + + //validate state + ServiceProviderConfiguration spConfig = + authService.getPendingReq().getServiceProviderConfiguration(ServiceProviderConfiguration.class); + assertNotNull("mandateprofiles", spConfig.getMandateProfiles()); + assertFalse("mandateprofiles not empty", spConfig.getMandateProfiles().isEmpty()); + assertEquals("mandateprofile size", mandateProfilesJur.size(), spConfig.getMandateProfiles().size()); + spConfig.getMandateProfiles().stream() + .forEach(el -> assertTrue("missing mandateProfile: " + el, mandateProfilesJur.contains(el))); + assertEquals("MandateMode", SpMandateModes.LEGAL_FORCE, spConfig.getMandateMode()); + + } + + @Test + public void validAuthnRequestWithMandatesDefaultNoJurProfiles() throws IOException, EaafException { + //initialize state + httpReq.addParameter(EidasParameterKeys.TOKEN.toString(), RandomStringUtils.randomAlphanumeric(10)); + String spCountryCode = RandomStringUtils.randomAlphabetic(2).toUpperCase(); + LightRequest.Builder authnReqBuilder = LightRequest.builder() + .id(UUID.randomUUID().toString()) + .issuer(RandomStringUtils.randomAlphabetic(10)) + .citizenCountryCode(RandomStringUtils.randomAlphabetic(2).toUpperCase()) + .levelOfAssurance(EaafConstants.EIDAS_LOA_HIGH) + .spCountryCode(spCountryCode) + .spType("public") + .requestedAttributes(ImmutableAttributeMap.builder() + .put(attrRegistry.getCoreAttributeRegistry().getByFriendlyName( + Constants.eIDAS_ATTR_LEGALPERSONIDENTIFIER).first()).build()); + + + proxyService.setiLightRequest(authnReqBuilder.build()); + + List mandateProfilesNat = + Arrays.asList(RandomStringUtils.randomAlphabetic(5), RandomStringUtils.randomAlphabetic(5)); + config.putConfigValue(MsProxyServiceConstants.CONIG_PROPS_EIDAS_PROXY_MANDATES_ENABLED, "true"); + config.putConfigValue(MsProxyServiceConstants.CONIG_PROPS_EIDAS_PROXY_MANDATES_PROFILE_DEFAULT_NATURAL, + StringUtils.join(mandateProfilesNat, ",")); + config.putConfigValue(MsProxyServiceConstants.CONIG_PROPS_EIDAS_PROXY_MANDATES_PROFILE_DEFAULT_LEGAL, ""); + + //validate state + EidasProxyServiceException exception = assertThrows(EidasProxyServiceException.class, + () -> controller.receiveEidasAuthnRequest(httpReq, httpResp)); + Assert.assertEquals("wrong errorCode", "eidas.proxyservice.10", exception.getErrorId()); + + } + + @Test + public void validAuthnRequestWithMandatesDefaultNoNatProfiles() throws IOException, EaafException { + //initialize state + httpReq.addParameter(EidasParameterKeys.TOKEN.toString(), RandomStringUtils.randomAlphanumeric(10)); + String spCountryCode = RandomStringUtils.randomAlphabetic(2).toUpperCase(); + LightRequest.Builder authnReqBuilder = LightRequest.builder() + .id(UUID.randomUUID().toString()) + .issuer(RandomStringUtils.randomAlphabetic(10)) + .citizenCountryCode(RandomStringUtils.randomAlphabetic(2).toUpperCase()) + .levelOfAssurance(EaafConstants.EIDAS_LOA_HIGH) + .spCountryCode(spCountryCode) + .spType("public") + .requestedAttributes(ImmutableAttributeMap.builder() + .put(attrRegistry.getCoreAttributeRegistry().getByFriendlyName( + Constants.eIDAS_ATTR_PERSONALIDENTIFIER).first()).build()); + + + proxyService.setiLightRequest(authnReqBuilder.build()); + + config.putConfigValue(MsProxyServiceConstants.CONIG_PROPS_EIDAS_PROXY_MANDATES_ENABLED, "true"); + config.putConfigValue(MsProxyServiceConstants.CONIG_PROPS_EIDAS_PROXY_MANDATES_PROFILE_DEFAULT_NATURAL, ""); + config.putConfigValue(MsProxyServiceConstants.CONIG_PROPS_EIDAS_PROXY_MANDATES_PROFILE_DEFAULT_LEGAL, ""); + + //execute + controller.receiveEidasAuthnRequest(httpReq, httpResp); + + //validate state + ServiceProviderConfiguration spConfig = + authService.getPendingReq().getServiceProviderConfiguration(ServiceProviderConfiguration.class); + assertNotNull("mandateprofiles", spConfig.getMandateProfiles()); + assertTrue("mandateprofiles not empty", spConfig.getMandateProfiles().isEmpty()); + assertEquals("MandateMode", SpMandateModes.NONE, spConfig.getMandateMode()); + + } + + @Test + public void validAuthnRequestIssueSpecificNoMandates() throws IOException, EaafException { + //initialize state + httpReq.addParameter(EidasParameterKeys.TOKEN.toString(), RandomStringUtils.randomAlphanumeric(10)); + + String issuer = RandomStringUtils.randomAlphabetic(10); + LightRequest.Builder authnReqBuilder = LightRequest.builder() + .id(UUID.randomUUID().toString()) + .issuer(issuer) + .citizenCountryCode(RandomStringUtils.randomAlphabetic(2).toUpperCase()) + .levelOfAssurance(EaafConstants.EIDAS_LOA_HIGH) + .spCountryCode(RandomStringUtils.randomAlphabetic(2).toUpperCase()) + .spType("public") + .requestedAttributes(ImmutableAttributeMap.builder() + .put(attrRegistry.getCoreAttributeRegistry().getByFriendlyName( + Constants.eIDAS_ATTR_PERSONALIDENTIFIER).first()).build()); + + proxyService.setiLightRequest(authnReqBuilder.build()); + + + // set default mandate configuration + config.putConfigValue(MsProxyServiceConstants.CONIG_PROPS_EIDAS_PROXY_MANDATES_ENABLED, "true"); + config.putConfigValue(MsProxyServiceConstants.CONIG_PROPS_EIDAS_PROXY_MANDATES_PROFILE_DEFAULT_NATURAL, + StringUtils.join(Arrays.asList( + RandomStringUtils.randomAlphabetic(5), RandomStringUtils.randomAlphabetic(5)), ",")); + config.putConfigValue(MsProxyServiceConstants.CONIG_PROPS_EIDAS_PROXY_MANDATES_PROFILE_DEFAULT_LEGAL, + StringUtils.join(Arrays.asList( + RandomStringUtils.randomAlphabetic(5), RandomStringUtils.randomAlphabetic(5)), ",")); + + // set specific mandate configuration + String spCountryCode = RandomStringUtils.randomAlphabetic(2).toUpperCase(); + addConnectorConfig(0, MsProxyServiceConstants.CONIG_PROPS_CONNECTOR_UNIQUEID, issuer); + addConnectorConfig(0, MsProxyServiceConstants.CONIG_PROPS_CONNECTOR_COUNTRYCODE, spCountryCode); + addConnectorConfig(0, MsProxyServiceConstants.CONIG_PROPS_CONNECTOR_MANDATES_ENABLED, "false"); + + List mandateProfiles = + Arrays.asList(RandomStringUtils.randomAlphabetic(5), RandomStringUtils.randomAlphabetic(5)); + addConnectorConfig(0, MsProxyServiceConstants.CONIG_PROPS_CONNECTOR_MANDATES_PROFILE_NATURAL, + StringUtils.join(mandateProfiles, ",")); + addConnectorConfig(0, MsProxyServiceConstants.CONIG_PROPS_CONNECTOR_MANDATES_PROFILE_LEGAL, + StringUtils.join(Arrays.asList(RandomStringUtils.randomAlphabetic(5), RandomStringUtils.randomAlphabetic(5)), ",")); + + //execute + controller.receiveEidasAuthnRequest(httpReq, httpResp); + + //validate state + ServiceProviderConfiguration spConfig = + authService.getPendingReq().getServiceProviderConfiguration(ServiceProviderConfiguration.class); + assertNotNull("mandateprofiles", spConfig.getMandateProfiles()); + assertTrue("mandateprofiles not empty", spConfig.getMandateProfiles().isEmpty()); + assertEquals("MandateMode", SpMandateModes.NONE, spConfig.getMandateMode()); + + } + + @Test + public void validAuthnRequestIssueSpecificMandatesNat() throws IOException, EaafException { + //initialize state + httpReq.addParameter(EidasParameterKeys.TOKEN.toString(), RandomStringUtils.randomAlphanumeric(10)); + + String issuer = "https://apps.egiz.gv.at/EidasNode//ConnectorMetadata"; + LightRequest.Builder authnReqBuilder = LightRequest.builder() + .id(UUID.randomUUID().toString()) + .issuer(issuer) + .citizenCountryCode(RandomStringUtils.randomAlphabetic(2).toUpperCase()) + .levelOfAssurance(EaafConstants.EIDAS_LOA_HIGH) + .spCountryCode(RandomStringUtils.randomAlphabetic(2).toUpperCase()) + .spType("public") + .requestedAttributes(ImmutableAttributeMap.builder() + .put(attrRegistry.getCoreAttributeRegistry().getByFriendlyName( + Constants.eIDAS_ATTR_PERSONALIDENTIFIER).first()).build()); + + proxyService.setiLightRequest(authnReqBuilder.build()); + + + // set default mandate configuration + config.putConfigValue(MsProxyServiceConstants.CONIG_PROPS_EIDAS_PROXY_MANDATES_ENABLED, "false"); + config.putConfigValue(MsProxyServiceConstants.CONIG_PROPS_EIDAS_PROXY_MANDATES_PROFILE_DEFAULT_NATURAL, + StringUtils.join(Arrays.asList( + RandomStringUtils.randomAlphabetic(5), RandomStringUtils.randomAlphabetic(5)), ",")); + config.putConfigValue(MsProxyServiceConstants.CONIG_PROPS_EIDAS_PROXY_MANDATES_PROFILE_DEFAULT_LEGAL, + StringUtils.join(Arrays.asList( + RandomStringUtils.randomAlphabetic(5), RandomStringUtils.randomAlphabetic(5)), ",")); + + // set specific mandate configuration + String spCountryCode = RandomStringUtils.randomAlphabetic(2).toUpperCase(); + addConnectorConfig(0, MsProxyServiceConstants.CONIG_PROPS_CONNECTOR_UNIQUEID, issuer); + addConnectorConfig(0, MsProxyServiceConstants.CONIG_PROPS_CONNECTOR_COUNTRYCODE, spCountryCode); + addConnectorConfig(0, MsProxyServiceConstants.CONIG_PROPS_CONNECTOR_MANDATES_ENABLED, "true"); + + List mandateProfiles = + Arrays.asList(RandomStringUtils.randomAlphabetic(5), RandomStringUtils.randomAlphabetic(5)); + addConnectorConfig(0, MsProxyServiceConstants.CONIG_PROPS_CONNECTOR_MANDATES_PROFILE_NATURAL, + StringUtils.join(mandateProfiles, ",")); + addConnectorConfig(0, MsProxyServiceConstants.CONIG_PROPS_CONNECTOR_MANDATES_PROFILE_LEGAL, + StringUtils.join(Arrays.asList(RandomStringUtils.randomAlphabetic(5), RandomStringUtils.randomAlphabetic(5)), ",")); + + //execute + controller.receiveEidasAuthnRequest(httpReq, httpResp); + + //validate state + ServiceProviderConfiguration spConfig = + authService.getPendingReq().getServiceProviderConfiguration(ServiceProviderConfiguration.class); + assertNotNull("mandateprofiles", spConfig.getMandateProfiles()); + assertFalse("mandateprofiles not empty", spConfig.getMandateProfiles().isEmpty()); + assertEquals("mandateprofile size", mandateProfiles.size(), spConfig.getMandateProfiles().size()); + spConfig.getMandateProfiles().stream() + .forEach(el -> assertTrue("missing mandateProfile: " + el, mandateProfiles.contains(el))); + assertEquals("MandateMode", SpMandateModes.NATURAL, spConfig.getMandateMode()); + + } + + @Test + public void validAuthnRequestIssueSpecificMandatesJur() throws IOException, EaafException { + //initialize state + httpReq.addParameter(EidasParameterKeys.TOKEN.toString(), RandomStringUtils.randomAlphanumeric(10)); + + String issuer = RandomStringUtils.randomAlphabetic(10); + LightRequest.Builder authnReqBuilder = LightRequest.builder() + .id(UUID.randomUUID().toString()) + .issuer(issuer) + .citizenCountryCode(RandomStringUtils.randomAlphabetic(2).toUpperCase()) + .levelOfAssurance(EaafConstants.EIDAS_LOA_HIGH) + .spCountryCode(RandomStringUtils.randomAlphabetic(2).toUpperCase()) + .spType("public") + .requestedAttributes(ImmutableAttributeMap.builder() + .put(attrRegistry.getCoreAttributeRegistry().getByFriendlyName( + Constants.eIDAS_ATTR_LEGALPERSONIDENTIFIER).first()).build()); + + proxyService.setiLightRequest(authnReqBuilder.build()); + + + // set default mandate configuration + config.putConfigValue(MsProxyServiceConstants.CONIG_PROPS_EIDAS_PROXY_MANDATES_ENABLED, "true"); + config.putConfigValue(MsProxyServiceConstants.CONIG_PROPS_EIDAS_PROXY_MANDATES_PROFILE_DEFAULT_NATURAL, + StringUtils.join(Arrays.asList( + RandomStringUtils.randomAlphabetic(5), RandomStringUtils.randomAlphabetic(5)), ",")); + config.putConfigValue(MsProxyServiceConstants.CONIG_PROPS_EIDAS_PROXY_MANDATES_PROFILE_DEFAULT_LEGAL, + StringUtils.join(Arrays.asList( + RandomStringUtils.randomAlphabetic(5), RandomStringUtils.randomAlphabetic(5)), ",")); + + // set specific mandate configuration + String spCountryCode = RandomStringUtils.randomAlphabetic(2).toUpperCase(); + addConnectorConfig(0, MsProxyServiceConstants.CONIG_PROPS_CONNECTOR_UNIQUEID, issuer); + addConnectorConfig(0, MsProxyServiceConstants.CONIG_PROPS_CONNECTOR_COUNTRYCODE, spCountryCode); + addConnectorConfig(0, MsProxyServiceConstants.CONIG_PROPS_CONNECTOR_MANDATES_ENABLED, "true"); + + List mandateProfiles = + Arrays.asList(RandomStringUtils.randomAlphabetic(5), RandomStringUtils.randomAlphabetic(5)); + addConnectorConfig(0, MsProxyServiceConstants.CONIG_PROPS_CONNECTOR_MANDATES_PROFILE_LEGAL, + StringUtils.join(mandateProfiles, ",")); + addConnectorConfig(0, MsProxyServiceConstants.CONIG_PROPS_CONNECTOR_MANDATES_PROFILE_NATURAL, + StringUtils.join(Arrays.asList(RandomStringUtils.randomAlphabetic(5), RandomStringUtils.randomAlphabetic(5)), ",")); + + //execute + controller.receiveEidasAuthnRequest(httpReq, httpResp); + + //validate state + ServiceProviderConfiguration spConfig = + authService.getPendingReq().getServiceProviderConfiguration(ServiceProviderConfiguration.class); + assertNotNull("mandateprofiles", spConfig.getMandateProfiles()); + assertFalse("mandateprofiles not empty", spConfig.getMandateProfiles().isEmpty()); + assertEquals("mandateprofile size", mandateProfiles.size(), spConfig.getMandateProfiles().size()); + spConfig.getMandateProfiles().stream() + .forEach(el -> assertTrue("missing mandateProfile: " + el, mandateProfiles.contains(el))); + assertEquals("MandateMode", SpMandateModes.LEGAL_FORCE, spConfig.getMandateMode()); + + } + + private void addConnectorConfig(int i, String key, String value) { + config.putConfigValue(MsProxyServiceConstants.CONIG_PROPS_CONNECTOR_PREFIX + String.valueOf(i) + "." + key, + value); + + } + +} + + diff --git a/modules/eidas_proxy-sevice/src/test/java/at/asitplus/eidas/specific/modules/auth/idaustria/test/protocol/ProxyServiceAuthenticationActionTest.java b/modules/eidas_proxy-sevice/src/test/java/at/asitplus/eidas/specific/modules/auth/idaustria/test/protocol/ProxyServiceAuthenticationActionTest.java new file mode 100644 index 00000000..52cc01d4 --- /dev/null +++ b/modules/eidas_proxy-sevice/src/test/java/at/asitplus/eidas/specific/modules/auth/idaustria/test/protocol/ProxyServiceAuthenticationActionTest.java @@ -0,0 +1,637 @@ +package at.asitplus.eidas.specific.modules.auth.idaustria.test.protocol; + +import static at.asitplus.eidas.specific.core.MsEidasNodeConstants.PROP_CONFIG_SP_NEW_EID_MODE; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertThrows; +import static org.junit.Assert.assertTrue; + +import java.net.URISyntaxException; +import java.net.URLDecoder; +import java.util.Arrays; +import java.util.Collections; +import java.util.Date; +import java.util.HashMap; +import java.util.Map; +import java.util.UUID; + +import org.apache.commons.lang3.RandomStringUtils; +import org.joda.time.DateTime; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.opensaml.saml.saml2.core.NameIDType; +import org.powermock.core.classloader.annotations.PrepareForTest; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.ApplicationContext; +import org.springframework.mock.web.MockHttpServletRequest; +import org.springframework.mock.web.MockHttpServletResponse; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; +import org.springframework.web.context.request.RequestContextHolder; +import org.springframework.web.context.request.ServletRequestAttributes; + +import com.google.common.collect.ImmutableSortedSet; + +import at.asitplus.eidas.specific.core.MsEidasNodeConstants; +import at.asitplus.eidas.specific.core.test.config.dummy.MsConnectorDummyConfigMap; +import at.asitplus.eidas.specific.core.test.config.dummy.MsConnectorDummySpConfiguration; +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.auth.eidas.v2.tasks.CreateIdentityLinkTask; +import at.asitplus.eidas.specific.modules.msproxyservice.protocol.ProxyServiceAuthenticationAction; +import at.asitplus.eidas.specific.modules.msproxyservice.protocol.ProxyServicePendingRequest; +import at.gv.egiz.eaaf.core.api.data.EaafConfigConstants; +import at.gv.egiz.eaaf.core.api.data.EaafConstants; +import at.gv.egiz.eaaf.core.api.data.PvpAttributeDefinitions; +import at.gv.egiz.eaaf.core.api.data.PvpAttributeDefinitions.EidIdentityStatusLevelValues; +import at.gv.egiz.eaaf.core.api.idp.IAuthData; +import at.gv.egiz.eaaf.core.api.idp.IEidAuthData; +import at.gv.egiz.eaaf.core.api.idp.auth.data.IIdentityLink; +import at.gv.egiz.eaaf.core.api.idp.slo.SloInformationInterface; +import at.gv.egiz.eaaf.core.exceptions.EaafException; +import at.gv.egiz.eaaf.core.impl.idp.module.test.TestRequestImpl; +import eu.eidas.auth.commons.attribute.AttributeDefinition; +import eu.eidas.auth.commons.attribute.ImmutableAttributeMap; +import eu.eidas.auth.commons.light.ILightResponse; +import eu.eidas.auth.commons.light.impl.LightRequest; +import eu.eidas.auth.commons.light.impl.LightRequest.Builder; +import eu.eidas.specificcommunication.SpecificCommunicationDefinitionBeanNames; +import eu.eidas.specificcommunication.exception.SpecificCommunicationException; +import eu.eidas.specificcommunication.protocol.SpecificCommunicationService; + +@RunWith(SpringJUnit4ClassRunner.class) +@PrepareForTest(CreateIdentityLinkTask.class) +@ContextConfiguration(locations = { + "/spring/SpringTest-context_basic_test.xml", + "/spring/SpringTest-context_basic_mapConfig.xml", + }) +public class ProxyServiceAuthenticationActionTest { + + @Autowired private MsConnectorDummyConfigMap basicConfig; + @Autowired private ProxyServiceAuthenticationAction action; + @Autowired private ApplicationContext context; + @Autowired EidasAttributeRegistry attrRegistry; + + private MockHttpServletRequest httpReq; + private MockHttpServletResponse httpResp; + private ProxyServicePendingRequest pendingReq; + private MsConnectorDummySpConfiguration oaParam; + private SpecificCommunicationService springManagedSpecificConnectorCommunicationService; + + + /** + * jUnit test set-up. + * @throws EaafException In case of an error + */ + @Before + public void setUp() throws URISyntaxException, EaafException { + httpReq = new MockHttpServletRequest("POST", "https://localhost/authhandler"); + httpResp = new MockHttpServletResponse(); + RequestContextHolder.resetRequestAttributes(); + RequestContextHolder.setRequestAttributes(new ServletRequestAttributes(httpReq, httpResp)); + + basicConfig.putConfigValue("eidas.ms.auth.eIDAS.node_v2.proxy.forward.endpoint", + "http://eidas.proxy/endpoint"); + basicConfig.putConfigValue("auth.eIDAS.proxy.workaround.mandates.legalperson", + "false"); + + final Map spConfig = new HashMap<>(); + spConfig.put(EaafConfigConstants.SERVICE_UNIQUEIDENTIFIER, "testSp"); + spConfig.put("target", "urn:publicid:gv.at:cdid+XX"); + spConfig.put(PROP_CONFIG_SP_NEW_EID_MODE, "true"); + oaParam = new MsConnectorDummySpConfiguration(spConfig, basicConfig); + oaParam.setLoa(Arrays.asList(EaafConstants.EIDAS_LOA_HIGH)); + + pendingReq = new ProxyServicePendingRequest(); + pendingReq.initialize(httpReq, basicConfig); + pendingReq.setOnlineApplicationConfiguration(oaParam); + + LightRequest.Builder eidasRequestBuilder = generateBasicLightRequest(); + pendingReq.setEidasRequest(eidasRequestBuilder.build()); + + + springManagedSpecificConnectorCommunicationService = + (SpecificCommunicationService) context.getBean( + SpecificCommunicationDefinitionBeanNames.SPECIFIC_PROXYSERVICE_COMMUNICATION_SERVICE + .toString()); + + } + + @Test + public void wrongPendingRequestType() { + IAuthData authData = generateDummyAuthData(); + TestRequestImpl internalPendingReq = new TestRequestImpl(); + + EaafException exception = assertThrows(EaafException.class, + () -> action.processRequest(internalPendingReq, httpReq, httpResp, authData)); + Assert.assertEquals("wrong errorCode", "eidas.proxyservice.99", exception.getErrorId()); + + } + + @Test + public void missingForwardUrl() { + Map attr = new HashMap<>(); + attr.put(MsEidasNodeConstants.ATTR_EIDAS_PERSONAL_IDENTIFIER, + "AT+XX:" + RandomStringUtils.randomAlphanumeric(10)); + IAuthData authData = generateDummyAuthData(attr , EaafConstants.EIDAS_LOA_HIGH, + RandomStringUtils.randomAlphanumeric(10), RandomStringUtils.randomAlphanumeric(10), "1945-04-18", false); + basicConfig.removeConfigValue("eidas.ms.auth.eIDAS.node_v2.proxy.forward.endpoint"); + + EaafException exception = assertThrows(EaafException.class, + () -> action.processRequest(pendingReq, httpReq, httpResp, authData)); + Assert.assertEquals("wrong errorCode", "config.08", exception.getErrorId()); + + } + + @Test + public void responseWithoutMandate() throws EaafException, SpecificCommunicationException { + Map attr = new HashMap<>(); + attr.put(MsEidasNodeConstants.ATTR_EIDAS_PERSONAL_IDENTIFIER, + "AT+XX:" + RandomStringUtils.randomAlphanumeric(10)); + IAuthData authData = generateDummyAuthData(attr , EaafConstants.EIDAS_LOA_HIGH, + RandomStringUtils.randomAlphanumeric(10), RandomStringUtils.randomAlphanumeric(10), "1945-04-18", false); + + //perform test + SloInformationInterface result = action.processRequest(pendingReq, httpReq, httpResp, authData); + + //validate state + Assert.assertNotNull("Result should be not null", result); + + ImmutableAttributeMap respAttr = validateBasicEidasResponse(authData); + assertEquals("wrong attr. size", 4, respAttr.size()); + checkAttrValue(respAttr, Constants.eIDAS_ATTR_PERSONALIDENTIFIER, + (String) attr.get(MsEidasNodeConstants.ATTR_EIDAS_PERSONAL_IDENTIFIER)); + checkAttrValue(respAttr, Constants.eIDAS_ATTR_CURRENTFAMILYNAME, authData.getFamilyName()); + checkAttrValue(respAttr, Constants.eIDAS_ATTR_CURRENTGIVENNAME, authData.getGivenName()); + checkAttrValue(respAttr, Constants.eIDAS_ATTR_DATEOFBIRTH, + authData.getDateOfBirth()); + + } + + @Test + public void responseWithNatMandate() throws EaafException, SpecificCommunicationException { + Map attr = new HashMap<>(); + attr.put(MsEidasNodeConstants.ATTR_EIDAS_PERSONAL_IDENTIFIER, + "AT+XX:" + RandomStringUtils.randomAlphanumeric(10)); + + attr.put(MsEidasNodeConstants.ATTR_EIDAS_NAT_MANDATOR_PERSONAL_IDENTIFIER, + RandomStringUtils.randomAlphabetic(10)); + attr.put(PvpAttributeDefinitions.MANDATE_NAT_PER_GIVEN_NAME_NAME, + RandomStringUtils.randomAlphabetic(10)); + attr.put(PvpAttributeDefinitions.MANDATE_NAT_PER_FAMILY_NAME_NAME, + RandomStringUtils.randomAlphabetic(10)); + attr.put(PvpAttributeDefinitions.MANDATE_NAT_PER_BIRTHDATE_NAME, + "1985-11-15"); + + + IAuthData authData = generateDummyAuthData(attr , EaafConstants.EIDAS_LOA_HIGH, + RandomStringUtils.randomAlphanumeric(10), RandomStringUtils.randomAlphanumeric(10), "1945-04-18", true); + + //perform test + SloInformationInterface result = action.processRequest(pendingReq, httpReq, httpResp, authData); + + //validate state + Assert.assertNotNull("Result should be not null", result); + + ImmutableAttributeMap respAttr = validateBasicEidasResponse(authData); + assertEquals("wrong attr. size", 8, respAttr.size()); + checkAttrValue(respAttr, Constants.eIDAS_ATTR_REPRESENTATIVE_PERSONALIDENTIFIER, + (String) attr.get(MsEidasNodeConstants.ATTR_EIDAS_PERSONAL_IDENTIFIER)); + checkAttrValue(respAttr, Constants.eIDAS_ATTR_REPRESENTATIVE_CURRENTFAMILYNAME, authData.getFamilyName()); + checkAttrValue(respAttr, Constants.eIDAS_ATTR_REPRESENTATIVE_CURRENTGIVENNAME, authData.getGivenName()); + checkAttrValue(respAttr, Constants.eIDAS_ATTR_REPRESENTATIVE_DATEOFBIRTH, authData.getDateOfBirth()); + + checkAttrValue(respAttr, Constants.eIDAS_ATTR_PERSONALIDENTIFIER, + (String) attr.get(MsEidasNodeConstants.ATTR_EIDAS_NAT_MANDATOR_PERSONAL_IDENTIFIER)); + checkAttrValue(respAttr, Constants.eIDAS_ATTR_CURRENTFAMILYNAME, + (String) attr.get(PvpAttributeDefinitions.MANDATE_NAT_PER_FAMILY_NAME_NAME)); + checkAttrValue(respAttr, Constants.eIDAS_ATTR_CURRENTGIVENNAME, + (String) attr.get(PvpAttributeDefinitions.MANDATE_NAT_PER_GIVEN_NAME_NAME)); + checkAttrValue(respAttr, Constants.eIDAS_ATTR_DATEOFBIRTH, + (String) attr.get(PvpAttributeDefinitions.MANDATE_NAT_PER_BIRTHDATE_NAME)); + + } + + @Test + public void responseWithJurMandate() throws EaafException, SpecificCommunicationException { + Map attr = new HashMap<>(); + attr.put(MsEidasNodeConstants.ATTR_EIDAS_PERSONAL_IDENTIFIER, + "AT+XX:" + RandomStringUtils.randomAlphanumeric(10)); + IAuthData authData = generateDummyAuthData(attr , EaafConstants.EIDAS_LOA_HIGH, + RandomStringUtils.randomAlphanumeric(10), RandomStringUtils.randomAlphanumeric(10), "1945-04-18", true); + + attr.put(MsEidasNodeConstants.ATTR_EIDAS_JUR_MANDATOR_PERSONAL_IDENTIFIER, + RandomStringUtils.randomAlphabetic(10)); + attr.put(PvpAttributeDefinitions.MANDATE_LEG_PER_FULL_NAME_NAME, + RandomStringUtils.randomAlphabetic(10)); + + //perform test + SloInformationInterface result = action.processRequest(pendingReq, httpReq, httpResp, authData); + + //validate state + Assert.assertNotNull("Result should be not null", result); + + ImmutableAttributeMap respAttr = validateBasicEidasResponse(authData); + assertEquals("wrong attr. size", 6, respAttr.size()); + checkAttrValue(respAttr, Constants.eIDAS_ATTR_REPRESENTATIVE_PERSONALIDENTIFIER, + (String) attr.get(MsEidasNodeConstants.ATTR_EIDAS_PERSONAL_IDENTIFIER)); + checkAttrValue(respAttr, Constants.eIDAS_ATTR_REPRESENTATIVE_CURRENTFAMILYNAME, authData.getFamilyName()); + checkAttrValue(respAttr, Constants.eIDAS_ATTR_REPRESENTATIVE_CURRENTGIVENNAME, authData.getGivenName()); + checkAttrValue(respAttr, Constants.eIDAS_ATTR_REPRESENTATIVE_DATEOFBIRTH, authData.getDateOfBirth()); + + checkAttrValue(respAttr, Constants.eIDAS_ATTR_LEGALPERSONIDENTIFIER, + (String) attr.get(MsEidasNodeConstants.ATTR_EIDAS_JUR_MANDATOR_PERSONAL_IDENTIFIER)); + checkAttrValue(respAttr, Constants.eIDAS_ATTR_LEGALNAME, + (String) attr.get(PvpAttributeDefinitions.MANDATE_LEG_PER_FULL_NAME_NAME)); + + assertNull("find nat. person subject: personalId", + getAttrValue(respAttr, Constants.eIDAS_ATTR_PERSONALIDENTIFIER)); + assertNull("find nat. person subject: familyName", + getAttrValue(respAttr, Constants.eIDAS_ATTR_CURRENTFAMILYNAME)); + assertNull("find nat. person subject: givenName", + getAttrValue(respAttr, Constants.eIDAS_ATTR_CURRENTGIVENNAME)); + assertNull("find nat. person subject: dateOfBirth", + getAttrValue(respAttr, Constants.eIDAS_ATTR_DATEOFBIRTH)); + + } + + @Test + public void responseWithNatMandateWithWorkAround() throws EaafException, SpecificCommunicationException { + basicConfig.putConfigValue("auth.eIDAS.proxy.workaround.mandates.legalperson", + "true"); + + //request natural person subject only + LightRequest.Builder eidasRequestBuilder = generateBasicLightRequest(); + eidasRequestBuilder.requestedAttributes(ImmutableAttributeMap.builder().put( + attrRegistry.getCoreAttributeRegistry().getByFriendlyName(Constants.eIDAS_ATTR_PERSONALIDENTIFIER).first()).build()); + pendingReq.setEidasRequest(eidasRequestBuilder.build()); + + + Map attr = new HashMap<>(); + attr.put(MsEidasNodeConstants.ATTR_EIDAS_PERSONAL_IDENTIFIER, + "AT+XX:" + RandomStringUtils.randomAlphanumeric(10)); + + attr.put(MsEidasNodeConstants.ATTR_EIDAS_NAT_MANDATOR_PERSONAL_IDENTIFIER, + RandomStringUtils.randomAlphabetic(10)); + attr.put(PvpAttributeDefinitions.MANDATE_NAT_PER_GIVEN_NAME_NAME, + RandomStringUtils.randomAlphabetic(10)); + attr.put(PvpAttributeDefinitions.MANDATE_NAT_PER_FAMILY_NAME_NAME, + RandomStringUtils.randomAlphabetic(10)); + attr.put(PvpAttributeDefinitions.MANDATE_NAT_PER_BIRTHDATE_NAME, + "1985-11-15"); + + + IAuthData authData = generateDummyAuthData(attr , EaafConstants.EIDAS_LOA_HIGH, + RandomStringUtils.randomAlphanumeric(10), RandomStringUtils.randomAlphanumeric(10), "1945-04-18", true); + + //perform test + SloInformationInterface result = action.processRequest(pendingReq, httpReq, httpResp, authData); + + //validate state + Assert.assertNotNull("Result should be not null", result); + + ImmutableAttributeMap respAttr = validateBasicEidasResponse(authData); + assertEquals("wrong attr. size", 8, respAttr.size()); + + } + + @Test + public void responseWithJurMandateWithWorkAround() throws EaafException, SpecificCommunicationException { + basicConfig.putConfigValue("auth.eIDAS.proxy.workaround.mandates.legalperson", + "true"); + + //request natural person subject only + LightRequest.Builder eidasRequestBuilder = generateBasicLightRequest(); + eidasRequestBuilder.requestedAttributes(ImmutableAttributeMap.builder() + .put(attrRegistry.getCoreAttributeRegistry().getByFriendlyName(Constants.eIDAS_ATTR_PERSONALIDENTIFIER).first()) + .put(attrRegistry.getCoreAttributeRegistry().getByFriendlyName(Constants.eIDAS_ATTR_LEGALPERSONIDENTIFIER).first()) + .build()); + pendingReq.setEidasRequest(eidasRequestBuilder.build()); + + Map attr = new HashMap<>(); + attr.put(MsEidasNodeConstants.ATTR_EIDAS_PERSONAL_IDENTIFIER, + "AT+XX:" + RandomStringUtils.randomAlphanumeric(10)); + IAuthData authData = generateDummyAuthData(attr , EaafConstants.EIDAS_LOA_HIGH, + RandomStringUtils.randomAlphanumeric(10), RandomStringUtils.randomAlphanumeric(10), "1945-04-18", true); + + attr.put(MsEidasNodeConstants.ATTR_EIDAS_JUR_MANDATOR_PERSONAL_IDENTIFIER, + RandomStringUtils.randomAlphabetic(10)); + attr.put(PvpAttributeDefinitions.MANDATE_LEG_PER_FULL_NAME_NAME, + RandomStringUtils.randomAlphabetic(10)); + + //perform test + SloInformationInterface result = action.processRequest(pendingReq, httpReq, httpResp, authData); + + //validate state + Assert.assertNotNull("Result should be not null", result); + + ImmutableAttributeMap respAttr = validateBasicEidasResponse(authData); + assertEquals("wrong attr. size", 10, respAttr.size()); + checkAttrValue(respAttr, Constants.eIDAS_ATTR_PERSONALIDENTIFIER, + (String) attr.get(MsEidasNodeConstants.ATTR_EIDAS_PERSONAL_IDENTIFIER)); + checkAttrValue(respAttr, Constants.eIDAS_ATTR_CURRENTFAMILYNAME, authData.getFamilyName()); + checkAttrValue(respAttr, Constants.eIDAS_ATTR_CURRENTGIVENNAME, authData.getGivenName()); + checkAttrValue(respAttr, Constants.eIDAS_ATTR_DATEOFBIRTH, authData.getDateOfBirth()); + + } + + @Test + public void responseWithJurMandateWithWorkAroundNoNatSubject() throws EaafException, SpecificCommunicationException { + basicConfig.putConfigValue("auth.eIDAS.proxy.workaround.mandates.legalperson", + "true"); + + //request natural person subject only + LightRequest.Builder eidasRequestBuilder = generateBasicLightRequest(); + eidasRequestBuilder.requestedAttributes(ImmutableAttributeMap.builder() + .put(attrRegistry.getCoreAttributeRegistry().getByFriendlyName(Constants.eIDAS_ATTR_LEGALPERSONIDENTIFIER).first()) + .build()); + pendingReq.setEidasRequest(eidasRequestBuilder.build()); + + Map attr = new HashMap<>(); + attr.put(MsEidasNodeConstants.ATTR_EIDAS_PERSONAL_IDENTIFIER, + "AT+XX:" + RandomStringUtils.randomAlphanumeric(10)); + IAuthData authData = generateDummyAuthData(attr , EaafConstants.EIDAS_LOA_HIGH, + RandomStringUtils.randomAlphanumeric(10), RandomStringUtils.randomAlphanumeric(10), "1945-04-18", true); + + attr.put(MsEidasNodeConstants.ATTR_EIDAS_JUR_MANDATOR_PERSONAL_IDENTIFIER, + RandomStringUtils.randomAlphabetic(10)); + attr.put(PvpAttributeDefinitions.MANDATE_LEG_PER_FULL_NAME_NAME, + RandomStringUtils.randomAlphabetic(10)); + + //perform test + SloInformationInterface result = action.processRequest(pendingReq, httpReq, httpResp, authData); + + //validate state + Assert.assertNotNull("Result should be not null", result); + + ImmutableAttributeMap respAttr = validateBasicEidasResponse(authData); + assertEquals("wrong attr. size", 6, respAttr.size()); + assertNull("find nat. person subject: personalId", + getAttrValue(respAttr, Constants.eIDAS_ATTR_PERSONALIDENTIFIER)); + assertNull("find nat. person subject: familyName", + getAttrValue(respAttr, Constants.eIDAS_ATTR_CURRENTFAMILYNAME)); + assertNull("find nat. person subject: givenName", + getAttrValue(respAttr, Constants.eIDAS_ATTR_CURRENTGIVENNAME)); + assertNull("find nat. person subject: dateOfBirth", + getAttrValue(respAttr, Constants.eIDAS_ATTR_DATEOFBIRTH)); + + } + + @Test + public void checkBasicConstrainsInAction() { + + Assert.assertTrue("Wrong NeedAuthentication", action.needAuthentication(pendingReq, httpReq, httpResp)); + Assert.assertNotNull("Missing ActionName", action.getDefaultActionName()); + + Assert.assertNotNull("missing ActionBean", context.getBean(ProxyServiceAuthenticationAction.class)); + + } + + private IAuthData generateDummyAuthData() { + return generateDummyAuthData(Collections.emptyMap(), EaafConstants.EIDAS_LOA_LOW, + RandomStringUtils.randomAlphanumeric(10), RandomStringUtils.randomAlphanumeric(10), "1940-01-01", false); + + } + + private Object getAttrValue(ImmutableAttributeMap respAttr, String attrName) { + final AttributeDefinition attrDef = + attrRegistry.getCoreAttributeRegistry().getByFriendlyName(attrName).first(); + return respAttr.getFirstValue(attrDef); + + } + + private void checkAttrValue(ImmutableAttributeMap respAttr, String attrName, String expected) { + Object value = getAttrValue(respAttr, attrName); + assertNotNull("not attr value: " + attrName, value); + + if (value instanceof String) { + assertEquals("wrong attr. value: " + attrName, expected, value); + + } else if ( value instanceof DateTime) { + assertEquals("wrong attr. value: " + attrName, expected, ((DateTime)value).toString("yyyy-MM-dd")); + + } + } + + private ImmutableAttributeMap validateBasicEidasResponse(IAuthData authData) throws SpecificCommunicationException { + assertNotNull("not redirct Header", httpResp.getHeader("Location")); + assertTrue("wrong redirect URL", httpResp.getHeader("Location").startsWith("http://eidas.proxy/endpoint?token=")); + String token = httpResp.getHeader("Location").substring("http://eidas.proxy/endpoint?token=".length()); + + ILightResponse resp = springManagedSpecificConnectorCommunicationService.getAndRemoveResponse(URLDecoder.decode(token), + ImmutableSortedSet.copyOf(attrRegistry.getCoreAttributeRegistry().getAttributes())); + + assertNotNull("responseId", resp.getId()); + assertEquals("inResponseTo", pendingReq.getEidasRequest().getId(), resp.getInResponseToId()); + assertEquals("relayState", pendingReq.getEidasRequest().getRelayState(), resp.getRelayState()); + assertEquals("LoA", authData.getEidasQaaLevel(), resp.getLevelOfAssurance()); + + assertNotNull("subjectNameId", resp.getSubject()); + assertEquals("subjectNameIdFormat", NameIDType.TRANSIENT, resp.getSubjectNameIdFormat()); + + assertFalse("not attributes", resp.getAttributes().isEmpty()); + return resp.getAttributes(); + + } + + private Builder generateBasicLightRequest() { + return 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)); + + } + + private IAuthData generateDummyAuthData(Map attrs, String loa, String familyName, String givenName, String dateOfBirth, + boolean useMandates) { + return new IEidAuthData() { + + @Override + public boolean isSsoSession() { + // TODO Auto-generated method stub + return false; + } + + @Override + public boolean isForeigner() { + // TODO Auto-generated method stub + return false; + } + + @Override + public boolean isBaseIdTransferRestrication() { + // TODO Auto-generated method stub + return false; + } + + @Override + public Date getSsoSessionValidTo() { + // TODO Auto-generated method stub + return null; + } + + @Override + public String getSessionIndex() { + // TODO Auto-generated method stub + return null; + } + + @Override + public String getNameIdFormat() { + // TODO Auto-generated method stub + return null; + } + + @Override + public String getNameID() { + // TODO Auto-generated method stub + return null; + } + + @Override + public IIdentityLink getIdentityLink() { + // TODO Auto-generated method stub + return null; + } + + @Override + public String getIdentificationValue() { + // TODO Auto-generated method stub + return null; + } + + @Override + public String getIdentificationType() { + // TODO Auto-generated method stub + return null; + } + + @Override + public String getGivenName() { + return givenName; + } + + @Override + public T getGenericData(String key, Class clazz) { + if (attrs.containsKey(key)) { + return (T) attrs.get(key); + + } else { + return null; + } + + } + + @Override + public String getDateOfBirth() { + return dateOfBirth; + } + + @Override + public String getFamilyName() { + return familyName; + } + + @Override + public String getEncryptedSourceIdType() { + // TODO Auto-generated method stub + return null; + } + + @Override + public String getEncryptedSourceId() { + // TODO Auto-generated method stub + return null; + } + + @Override + public String getEidasQaaLevel() { + return loa; + + } + + + @Override + public String getCiticenCountryCode() { + // TODO Auto-generated method stub + return null; + } + + @Override + public String getBpkType() { + // TODO Auto-generated method stub + return null; + } + + @Override + public String getBpk() { + // TODO Auto-generated method stub + return null; + } + + @Override + public String getAuthenticationIssuer() { + // TODO Auto-generated method stub + return null; + } + + @Override + public String getAuthenticationIssueInstantString() { + // TODO Auto-generated method stub + return null; + } + + @Override + public Date getAuthenticationIssueInstant() { + // TODO Auto-generated method stub + return null; + } + + @Override + public byte[] getSignerCertificate() { + // TODO Auto-generated method stub + return null; + } + + @Override + public byte[] getEidToken() { + // TODO Auto-generated method stub + return null; + } + + @Override + public EidIdentityStatusLevelValues getEidStatus() { + // TODO Auto-generated method stub + return null; + } + + @Override + public String getVdaEndPointUrl() { + // TODO Auto-generated method stub + return null; + } + + @Override + public boolean isUseMandate() { + return useMandates; + + } + + @Override + public String getDateOfBirthFormated(String pattern) { + // TODO Auto-generated method stub + return null; + } + }; + + } +} diff --git a/modules/eidas_proxy-sevice/src/test/resources/config/additional-attributes.xml b/modules/eidas_proxy-sevice/src/test/resources/config/additional-attributes.xml new file mode 100644 index 00000000..6510546e --- /dev/null +++ b/modules/eidas_proxy-sevice/src/test/resources/config/additional-attributes.xml @@ -0,0 +1,39 @@ + + + + + + Dynamic attributes + + http://eidas.europa.eu/attributes/naturalperson/AdditionalAttribute + AdditionalAttribute + NaturalPerson + false + http://www.w3.org/2001/XMLSchema + string + xs + eu.eidas.auth.commons.attribute.impl.LiteralStringAttributeValueMarshaller + + http://eidas.europa.eu/attributes/legalperson/LegalAdditionalAttribute + LegalAdditionalAttribute + LegalPerson + false + http://www.w3.org/2001/XMLSchema + string + xs + eu.eidas.auth.commons.attribute.impl.LiteralStringAttributeValueMarshaller + + diff --git a/modules/eidas_proxy-sevice/src/test/resources/config/eidas-attributes.xml b/modules/eidas_proxy-sevice/src/test/resources/config/eidas-attributes.xml new file mode 100644 index 00000000..cbae35db --- /dev/null +++ b/modules/eidas_proxy-sevice/src/test/resources/config/eidas-attributes.xml @@ -0,0 +1,376 @@ + + + + + + eIDAS attributes + + http://eidas.europa.eu/attributes/naturalperson/PersonIdentifier + PersonIdentifier + NaturalPerson + true + true + http://eidas.europa.eu/attributes/naturalperson + PersonIdentifierType + eidas-natural + eu.eidas.auth.commons.attribute.impl.LiteralStringAttributeValueMarshaller + + http://eidas.europa.eu/attributes/naturalperson/CurrentFamilyName + FamilyName + NaturalPerson + true + true + http://eidas.europa.eu/attributes/naturalperson + CurrentFamilyNameType + eidas-natural + eu.eidas.auth.commons.attribute.impl.LiteralStringAttributeValueMarshaller + + http://eidas.europa.eu/attributes/naturalperson/CurrentGivenName + FirstName + NaturalPerson + true + true + http://eidas.europa.eu/attributes/naturalperson + CurrentGivenNameType + eidas-natural + eu.eidas.auth.commons.attribute.impl.LiteralStringAttributeValueMarshaller + + http://eidas.europa.eu/attributes/naturalperson/DateOfBirth + DateOfBirth + NaturalPerson + true + http://eidas.europa.eu/attributes/naturalperson + DateOfBirthType + eidas-natural + eu.eidas.auth.commons.attribute.impl.DateTimeAttributeValueMarshaller + + http://eidas.europa.eu/attributes/naturalperson/BirthName + BirthName + NaturalPerson + false + true + http://eidas.europa.eu/attributes/naturalperson + BirthNameType + eidas-natural + eu.eidas.auth.commons.attribute.impl.LiteralStringAttributeValueMarshaller + + http://eidas.europa.eu/attributes/naturalperson/PlaceOfBirth + PlaceOfBirth + NaturalPerson + false + http://eidas.europa.eu/attributes/naturalperson + PlaceOfBirthType + eidas-natural + eu.eidas.auth.commons.attribute.impl.LiteralStringAttributeValueMarshaller + + http://eidas.europa.eu/attributes/naturalperson/CurrentAddress + CurrentAddress + NaturalPerson + false + http://eidas.europa.eu/attributes/naturalperson + CurrentAddressType + eidas-natural + eu.eidas.auth.commons.protocol.eidas.impl.CurrentAddressAttributeValueMarshaller + + http://eidas.europa.eu/attributes/naturalperson/Gender + Gender + NaturalPerson + false + http://eidas.europa.eu/attributes/naturalperson + GenderType + eidas-natural + eu.eidas.auth.commons.protocol.eidas.impl.GenderAttributeValueMarshaller + + http://eidas.europa.eu/attributes/legalperson/LegalPersonIdentifier + LegalPersonIdentifier + LegalPerson + true + true + http://eidas.europa.eu/attributes/legalperson + LegalPersonIdentifierType + eidas-legal + eu.eidas.auth.commons.attribute.impl.LiteralStringAttributeValueMarshaller + + http://eidas.europa.eu/attributes/legalperson/LegalName + LegalName + LegalPerson + true + true + http://eidas.europa.eu/attributes/legalperson + LegalNameType + eidas-legal + eu.eidas.auth.commons.attribute.impl.LiteralStringAttributeValueMarshaller + + http://eidas.europa.eu/attributes/legalperson/LegalPersonAddress + LegalAddress + LegalPerson + false + http://eidas.europa.eu/attributes/legalperson + LegalPersonAddressType + eidas-legal + eu.eidas.auth.commons.protocol.eidas.impl.LegalAddressAttributeValueMarshaller + + http://eidas.europa.eu/attributes/legalperson/VATRegistrationNumber + VATRegistration + LegalPerson + false + http://eidas.europa.eu/attributes/legalperson + VATRegistrationNumberType + eidas-legal + eu.eidas.auth.commons.attribute.impl.LiteralStringAttributeValueMarshaller + + http://eidas.europa.eu/attributes/legalperson/TaxReference + TaxReference + LegalPerson + false + http://eidas.europa.eu/attributes/legalperson + TaxReferenceType + eidas-legal + eu.eidas.auth.commons.attribute.impl.LiteralStringAttributeValueMarshaller + + http://eidas.europa.eu/attributes/legalperson/D-2012-17-EUIdentifier + D-2012-17-EUIdentifier + LegalPerson + false + http://eidas.europa.eu/attributes/legalperson + D-2012-17-EUIdentifierType + eidas-legal + eu.eidas.auth.commons.attribute.impl.LiteralStringAttributeValueMarshaller + + http://eidas.europa.eu/attributes/legalperson/LEI + LEI + LegalPerson + false + http://eidas.europa.eu/attributes/legalperson + LEIType + eidas-legal + eu.eidas.auth.commons.attribute.impl.LiteralStringAttributeValueMarshaller + + http://eidas.europa.eu/attributes/legalperson/EORI + EORI + LegalPerson + false + http://eidas.europa.eu/attributes/legalperson + EORIType + eidas-legal + eu.eidas.auth.commons.attribute.impl.LiteralStringAttributeValueMarshaller + + http://eidas.europa.eu/attributes/legalperson/SEED + SEED + LegalPerson + false + http://eidas.europa.eu/attributes/legalperson + SEEDType + eidas-legal + eu.eidas.auth.commons.attribute.impl.LiteralStringAttributeValueMarshaller + + http://eidas.europa.eu/attributes/legalperson/SIC + SIC + LegalPerson + false + http://eidas.europa.eu/attributes/legalperson + SICType + eidas-legal + eu.eidas.auth.commons.attribute.impl.LiteralStringAttributeValueMarshaller + + http://eidas.europa.eu/attributes/naturalperson/representative/PersonIdentifier + RepresentativePersonIdentifier + RepresentativeNaturalPerson + false + true + http://eidas.europa.eu/attributes/naturalperson/representative + PersonIdentifierType + eidas-natural + eu.eidas.auth.commons.attribute.impl.LiteralStringAttributeValueMarshaller + + http://eidas.europa.eu/attributes/naturalperson/representative/CurrentFamilyName + RepresentativeFamilyName + RepresentativeNaturalPerson + false + true + http://eidas.europa.eu/attributes/naturalperson/representative + CurrentFamilyNameType + eidas-reprentative-natural + eu.eidas.auth.commons.attribute.impl.LiteralStringAttributeValueMarshaller + + http://eidas.europa.eu/attributes/naturalperson/representative/CurrentGivenName + RepresentativeFirstName + RepresentativeNaturalPerson + false + true + http://eidas.europa.eu/attributes/naturalperson/representative + CurrentGivenNameType + eidas-reprentative-natural + eu.eidas.auth.commons.attribute.impl.LiteralStringAttributeValueMarshaller + + http://eidas.europa.eu/attributes/naturalperson/representative/DateOfBirth + RepresentativeDateOfBirth + RepresentativeNaturalPerson + false + http://eidas.europa.eu/attributes/naturalperson/representative + DateOfBirthType + eidas-reprentative-natural + eu.eidas.auth.commons.attribute.impl.DateTimeAttributeValueMarshaller + + http://eidas.europa.eu/attributes/naturalperson/representative/BirthName + RepresentativeBirthName + RepresentativeNaturalPerson + false + true + http://eidas.europa.eu/attributes/naturalperson/representative + BirthNameType + eidas-reprentative-natural + eu.eidas.auth.commons.attribute.impl.LiteralStringAttributeValueMarshaller + + http://eidas.europa.eu/attributes/naturalperson/representative/PlaceOfBirth + RepresentativePlaceOfBirth + RepresentativeNaturalPerson + false + http://eidas.europa.eu/attributes/naturalperson/representative + PlaceOfBirthType + eidas-reprentative-natural + eu.eidas.auth.commons.attribute.impl.LiteralStringAttributeValueMarshaller + + http://eidas.europa.eu/attributes/naturalperson/representative/CurrentAddress + RepresentativeCurrentAddress + RepresentativeNaturalPerson + false + http://eidas.europa.eu/attributes/naturalperson/representative + CurrentAddressType + eidas-reprentative-natural + eu.eidas.auth.commons.protocol.eidas.impl.RepvCurrentAddressAttributeValueMarshaller + + http://eidas.europa.eu/attributes/naturalperson/representative/Gender + RepresentativeGender + RepresentativeNaturalPerson + false + http://eidas.europa.eu/attributes/naturalperson/representative + GenderType + eidas-reprentative-natural + eu.eidas.auth.commons.protocol.eidas.impl.GenderAttributeValueMarshaller + + http://eidas.europa.eu/attributes/legalperson/representative/LegalPersonIdentifier + RepresentativeLegalPersonIdentifier + RepresentativeLegalPerson + false + true + http://eidas.europa.eu/attributes/legalperson/representative + LegalPersonIdentifierType + eidas-reprentative-legal + eu.eidas.auth.commons.attribute.impl.LiteralStringAttributeValueMarshaller + + http://eidas.europa.eu/attributes/legalperson/representative/LegalName + RepresentativeLegalName + RepresentativeLegalPerson + false + true + http://eidas.europa.eu/attributes/legalperson/representative + LegalNameType + eidas-reprentative-legal + eu.eidas.auth.commons.attribute.impl.LiteralStringAttributeValueMarshaller + + http://eidas.europa.eu/attributes/legalperson/representative/LegalPersonAddress + RepresentativeLegalAddress + RepresentativeLegalPerson + false + http://eidas.europa.eu/attributes/legalperson/representative + LegalPersonAddressType + eidas-reprentative-legal + eu.eidas.auth.commons.protocol.eidas.impl.RepvLegalAddressAttributeValueMarshaller + + http://eidas.europa.eu/attributes/legalperson/representative/VATRegistrationNumber + RepresentativeVATRegistration + RepresentativeLegalPerson + false + http://eidas.europa.eu/attributes/legalperson/representative + VATRegistrationNumberType + eidas-reprentative-legal + eu.eidas.auth.commons.attribute.impl.LiteralStringAttributeValueMarshaller + + http://eidas.europa.eu/attributes/legalperson/representative/TaxReference + RepresentativeTaxReference + RepresentativeLegalPerson + false + http://eidas.europa.eu/attributes/legalperson/representative + TaxReferenceType + eidas-reprentative-legal + eu.eidas.auth.commons.attribute.impl.LiteralStringAttributeValueMarshaller + + http://eidas.europa.eu/attributes/legalperson/representative/D-2012-17-EUIdentifier + RepresentativeD-2012-17-EUIdentifier + RepresentativeLegalPerson + false + http://eidas.europa.eu/attributes/legalperson/representative + D-2012-17-EUIdentifierType + eidas-reprentative-legal + eu.eidas.auth.commons.attribute.impl.LiteralStringAttributeValueMarshaller + + http://eidas.europa.eu/attributes/legalperson/representative/LEI + RepresentativeLEI + RepresentativeLegalPerson + false + http://eidas.europa.eu/attributes/legalperson/representative + LEIType + eidas-reprentative-legal + eu.eidas.auth.commons.attribute.impl.LiteralStringAttributeValueMarshaller + + http://eidas.europa.eu/attributes/legalperson/representative/EORI + RepresentativeEORI + RepresentativeLegalPerson + false + http://eidas.europa.eu/attributes/legalperson/representative + EORIType + eidas-reprentative-legal + eu.eidas.auth.commons.attribute.impl.LiteralStringAttributeValueMarshaller + + http://eidas.europa.eu/attributes/legalperson/representative/SEED + RepresentativeSEED + RepresentativeLegalPerson + false + http://eidas.europa.eu/attributes/legalperson/representative + SEEDType + eidas-reprentative-legal + eu.eidas.auth.commons.attribute.impl.LiteralStringAttributeValueMarshaller + + http://eidas.europa.eu/attributes/legalperson/representative/SIC + RepresentativeSIC + RepresentativeLegalPerson + false + http://eidas.europa.eu/attributes/legalperson/representative + SICType + eidas-reprentative-legal + eu.eidas.auth.commons.attribute.impl.LiteralStringAttributeValueMarshaller + + http://eidas.europa.eu/attributes/legalperson/representative/LegalPersonAddress + RepresentativeLegalAddress + RepresentativeLegalPerson + false + http://eidas.europa.eu/attributes/legalperson/representative + LegalPersonAddressType + eidas-reprentative-legal + eu.eidas.auth.commons.protocol.eidas.impl.RepvLegalAddressAttributeValueMarshaller + + http://eidas.europa.eu/attributes/legalperson/representative/VATRegistrationNumber + RepresentativeVATRegistration + RepresentativeLegalPerson + false + http://eidas.europa.eu/attributes/legalperson/representative + VATRegistrationNumberType + eidas-reprentative-legal + eu.eidas.auth.commons.attribute.impl.LiteralStringAttributeValueMarshaller + + + diff --git a/modules/eidas_proxy-sevice/src/test/resources/config/junit_config_1.properties b/modules/eidas_proxy-sevice/src/test/resources/config/junit_config_1.properties new file mode 100644 index 00000000..4f3b82b5 --- /dev/null +++ b/modules/eidas_proxy-sevice/src/test/resources/config/junit_config_1.properties @@ -0,0 +1,6 @@ +## Basic service configuration +eidas.ms.context.url.prefix=http://localhost +eidas.ms.context.url.request.validation=false + +eidas.ms.auth.eIDAS.node_v2.proxy.entityId=ownSpecificProxy +eidas.ms.auth.eIDAS.node_v2.proxy.forward.endpoint=http://eidas.proxy/endpoint \ No newline at end of file diff --git a/modules/eidas_proxy-sevice/src/test/resources/spring/SpringTest-context_basic_mapConfig.xml b/modules/eidas_proxy-sevice/src/test/resources/spring/SpringTest-context_basic_mapConfig.xml new file mode 100644 index 00000000..fe9ff441 --- /dev/null +++ b/modules/eidas_proxy-sevice/src/test/resources/spring/SpringTest-context_basic_mapConfig.xml @@ -0,0 +1,20 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/modules/eidas_proxy-sevice/src/test/resources/spring/SpringTest-context_basic_test.xml b/modules/eidas_proxy-sevice/src/test/resources/spring/SpringTest-context_basic_test.xml new file mode 100644 index 00000000..9870d22a --- /dev/null +++ b/modules/eidas_proxy-sevice/src/test/resources/spring/SpringTest-context_basic_test.xml @@ -0,0 +1,42 @@ + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/modules/pom.xml b/modules/pom.xml new file mode 100644 index 00000000..e0b87b3e --- /dev/null +++ b/modules/pom.xml @@ -0,0 +1,23 @@ + + + 4.0.0 + + at.asitplus.eidas + ms_specific + 1.2.4-SNAPSHOT + + at.asitplus.eidas.ms_specific + modules + pom + + Modules for MS specific eIDAS Node + + + core_common_lib + core_common_webapp + authmodule-eIDAS-v2 + authmodule_id-austria + eidas_proxy-sevice + + + -- cgit v1.2.3