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' --- .../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 + 33 files changed, 3652 insertions(+) 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 (limited to 'modules/core_common_webapp') 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 -- cgit v1.2.3 From a35373663d66666d6af5bbe819c7e6bab6cf9989 Mon Sep 17 00:00:00 2001 From: Thomas <> Date: Thu, 31 Mar 2022 13:00:02 +0200 Subject: feature(core): add deny-list for Spring DataBinder This mitigates possible RCE attacked called "Spring4Shell" --- .../src/main/resources/applicationContext.xml | 2 ++ .../controller/DataBinderControllerAdvice.java | 33 ++++++++++++++++++++++ 2 files changed, 35 insertions(+) create mode 100644 modules/core_common_webapp/src/main/java/at/asitplus/eidas/specific/core/controller/DataBinderControllerAdvice.java (limited to 'modules/core_common_webapp') diff --git a/connector/src/main/resources/applicationContext.xml b/connector/src/main/resources/applicationContext.xml index ec8e79f4..5c5e245c 100644 --- a/connector/src/main/resources/applicationContext.xml +++ b/connector/src/main/resources/applicationContext.xml @@ -28,6 +28,8 @@ + + diff --git a/modules/core_common_webapp/src/main/java/at/asitplus/eidas/specific/core/controller/DataBinderControllerAdvice.java b/modules/core_common_webapp/src/main/java/at/asitplus/eidas/specific/core/controller/DataBinderControllerAdvice.java new file mode 100644 index 00000000..0d983c16 --- /dev/null +++ b/modules/core_common_webapp/src/main/java/at/asitplus/eidas/specific/core/controller/DataBinderControllerAdvice.java @@ -0,0 +1,33 @@ +package at.asitplus.eidas.specific.core.controller; + +import org.apache.commons.lang3.StringUtils; +import org.springframework.core.annotation.Order; +import org.springframework.validation.DataBinder; +import org.springframework.web.bind.WebDataBinder; +import org.springframework.web.bind.annotation.ControllerAdvice; +import org.springframework.web.bind.annotation.InitBinder; + +import lombok.extern.slf4j.Slf4j; + +@ControllerAdvice +@Order(10000) +@Slf4j +public class DataBinderControllerAdvice { + + private static String[] DENYLIST = new String[] { "class.*", "Class.*", "*.class.*", "*.Class.*" }; + + /** + * Set list of form parameters that are disallowed by default. + * + * @param dataBinder Spring {@link DataBinder} implementation + */ + @InitBinder + public void setDisallowedFields(WebDataBinder dataBinder) { + // This code protects Spring Core from a "Remote Code Execution" attack (dubbed "Spring4Shell"). + // By applying this mitigation, you prevent the "Class Loader Manipulation attack vector from firing. + // For more details, see this post: https://www.lunasec.io/docs/blog/spring-rce-vulnerabilities/ + dataBinder.setDisallowedFields(DENYLIST); + log.info("Set denyList for Spring DataBinder: {}", StringUtils.join(DENYLIST, ",")); + + } +} -- cgit v1.2.3 From ce7e30f92356f602b65a0608b8224dd93b271f5e Mon Sep 17 00:00:00 2001 From: Thomas <> Date: Fri, 13 May 2022 09:00:52 +0200 Subject: refact(core): switch to eaaf-components 1.3.x and replace 'java.util.Date' by 'java.time.Instant' --- .../eidas/specific/core/builder/AuthenticationDataBuilder.java | 7 +++---- .../test/protocol/ProxyServiceAuthenticationActionTest.java | 6 +++--- pom.xml | 2 +- 3 files changed, 7 insertions(+), 8 deletions(-) (limited to 'modules/core_common_webapp') 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 index 9580a62f..e719735c 100644 --- 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 @@ -23,7 +23,7 @@ package at.asitplus.eidas.specific.core.builder; -import java.util.Date; +import java.time.Instant; import org.springframework.stereotype.Service; @@ -58,8 +58,7 @@ public class AuthenticationDataBuilder extends AbstractAuthenticationDataBuilder // set specific informations authData.setSsoSessionValidTo( - new Date(new Date().getTime() + MsEidasNodeConstants.DEFAULT_PVP_ASSERTION_VALIDITY * 60 * 1000)); - + Instant.now().plusSeconds(MsEidasNodeConstants.DEFAULT_PVP_ASSERTION_VALIDITY * 60)); authData.setEidStatus(authProcessData.isTestIdentity() ? EidIdentityStatusLevelValues.TESTIDENTITY : EidIdentityStatusLevelValues.IDENTITY); @@ -78,7 +77,7 @@ public class AuthenticationDataBuilder extends AbstractAuthenticationDataBuilder // set specific informations ((EidAuthenticationData)authData).setSsoSessionValidTo( - new Date(new Date().getTime() + MsEidasNodeConstants.DEFAULT_PVP_ASSERTION_VALIDITY * 60 * 1000)); + Instant.now().plusSeconds(MsEidasNodeConstants.DEFAULT_PVP_ASSERTION_VALIDITY * 60)); //set E-ID status-level final EidAuthProcessDataWrapper authProcessData = 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 index 52cc01d4..21d2f3b7 100644 --- 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 @@ -10,9 +10,9 @@ import static org.junit.Assert.assertTrue; import java.net.URISyntaxException; import java.net.URLDecoder; +import java.time.Instant; import java.util.Arrays; import java.util.Collections; -import java.util.Date; import java.util.HashMap; import java.util.Map; import java.util.UUID; @@ -474,7 +474,7 @@ public class ProxyServiceAuthenticationActionTest { } @Override - public Date getSsoSessionValidTo() { + public Instant getSsoSessionValidTo() { // TODO Auto-generated method stub return null; } @@ -591,7 +591,7 @@ public class ProxyServiceAuthenticationActionTest { } @Override - public Date getAuthenticationIssueInstant() { + public Instant getAuthenticationIssueInstant() { // TODO Auto-generated method stub return null; } diff --git a/pom.xml b/pom.xml index 0f04a7d7..628e8a1f 100644 --- a/pom.xml +++ b/pom.xml @@ -22,7 +22,7 @@ 0.3 0.4 - 1.2.1-SNAPSHOT + 1.3.2 2.5.13 2.5.6 -- cgit v1.2.3 From 3d9d419a40b17de1f94d46cbc2f5b345a93bff00 Mon Sep 17 00:00:00 2001 From: Thomas <> Date: Wed, 8 Jun 2022 12:32:16 +0200 Subject: feat(eidas): perform mapping between IDA and eIDAS attributes based on external configuration --- .../ms-proxyservice/misc/idaAttributeMapping.json | 170 +++++++++ .../SpRequiredAttributersAttributeBuilder.java | 63 ++++ .../tasks/ReceiveFromIdAustriaSystemTask.java | 30 +- .../tasks/RequestIdAustriaSystemTask.java | 6 + .../at.gv.egiz.eaaf.core.api.idp.IAttributeBuilder | 1 + .../SpRequiredAttributersAttributeBuilderTest.java | 72 ++++ .../test/task/ReceiveAuthnResponseTaskTest.java | 24 +- .../test/task/RequestIdAustriaSystemTaskTest.java | 72 ++-- .../eidas/specific/core/MsEidasNodeConstants.java | 13 +- .../core/builder/AuthenticationDataBuilder.java | 185 ++++++++-- .../main/resources/specific_eIDAS_core.beans.xml | 3 - .../test/utils/AuthenticationDataBuilderTest.java | 311 +++++++++++++++- .../msproxyservice/dto/attributes/Type.java | 7 + .../protocol/ProxyServiceAuthenticationAction.java | 297 +++++++--------- .../service/ProxyEidasAttributeRegistry.java | 34 +- .../ProxyServiceAuthenticationActionTest.java | 217 +++++++++-- .../services/ProxyEidasAttributeRegistryTest.java | 35 ++ .../test/resources/config/idaAttributeMapping.json | 56 ++- .../resources/specific_eIDAS_connector.beans.xml | 3 + .../builder/ProxyAuthenticationDataBuilder.java | 38 ++ .../main/resources/specific_eIDAS_proxy.beans.xml | 3 + .../ProxyAuthenticationDataBuilderTest.java | 395 +++++++++++++++++++++ .../config/junit_config_1_springboot.properties | 2 +- pom.xml | 2 +- 24 files changed, 1713 insertions(+), 326 deletions(-) create mode 100644 basicConfig/ms-proxyservice/misc/idaAttributeMapping.json create mode 100644 modules/authmodule_id-austria/src/main/java/at/asitplus/eidas/specific/modules/auth/idaustria/builder/attributes/SpRequiredAttributersAttributeBuilder.java create mode 100644 modules/authmodule_id-austria/src/test/java/at/asitplus/eidas/specific/modules/auth/idaustria/test/builder/attributes/SpRequiredAttributersAttributeBuilderTest.java create mode 100644 ms_specific_proxyservice/src/main/java/at/asitplus/eidas/specific/proxy/builder/ProxyAuthenticationDataBuilder.java create mode 100644 ms_specific_proxyservice/src/test/java/at/asitplus/eidas/specific/proxy/test/builder/ProxyAuthenticationDataBuilderTest.java (limited to 'modules/core_common_webapp') diff --git a/basicConfig/ms-proxyservice/misc/idaAttributeMapping.json b/basicConfig/ms-proxyservice/misc/idaAttributeMapping.json new file mode 100644 index 00000000..7c44b48a --- /dev/null +++ b/basicConfig/ms-proxyservice/misc/idaAttributeMapping.json @@ -0,0 +1,170 @@ +[ + { + "eidasAttribute": "http://eidas.europa.eu/attributes/naturalperson/PersonIdentifier", + "idaAttribute": { + "basic": "urn:oid:1.2.40.0.10.2.1.1.149", + "withMandates": "urn:oid:1.2.40.0.10.2.1.1.261.98" + }, + "type": { + "mds": true, + "autoIncludeWithMandates": false + } + }, + { + "eidasAttribute": "http://eidas.europa.eu/attributes/naturalperson/CurrentGivenName", + "idaAttribute": { + "basic": "urn:oid:2.5.4.42", + "withMandates": "urn:oid:1.2.40.0.10.2.1.1.261.78" + }, + "type": { + "mds": true, + "autoIncludeWithMandates": false + } + }, + { + "eidasAttribute": "http://eidas.europa.eu/attributes/naturalperson/CurrentFamilyName", + "idaAttribute": { + "basic": "urn:oid:1.2.40.0.10.2.1.1.261.20", + "withMandates": "urn:oid:1.2.40.0.10.2.1.1.261.80" + }, + "type": { + "mds": true, + "autoIncludeWithMandates": false + } + }, + { + "eidasAttribute": "http://eidas.europa.eu/attributes/naturalperson/DateOfBirth", + "idaAttribute": { + "basic": "urn:oid:1.2.40.0.10.2.1.1.55", + "withMandates": "urn:oid:1.2.40.0.10.2.1.1.261.82" + }, + "type": { + "mds": true, + "autoIncludeWithMandates": false + } + }, + { + "eidasAttribute": "http://eidas.europa.eu/attributes/naturalperson/PlaceOfBirth", + "idaAttribute": {}, + "type": { + "mds": false, + "autoIncludeWithMandates": false + } + }, + { + "eidasAttribute": "http://eidas.europa.eu/attributes/naturalperson/BirthName", + "idaAttribute": {}, + "type": { + "mds": false, + "autoIncludeWithMandates": false + } + }, + { + "eidasAttribute": "http://eidas.europa.eu/attributes/legalperson/LegalPersonIdentifier", + "idaAttribute": { + "withMandates": "urn:oid:1.2.40.0.10.2.1.1.261.100" + }, + "addionalRequiredAttributes" : [ + "urn:oid:1.2.40.0.10.2.1.1.149", + "urn:oid:2.5.4.42", + "urn:oid:1.2.40.0.10.2.1.1.261.20", + "urn:oid:1.2.40.0.10.2.1.1.55" + ], + "type": { + "mds": true, + "autoIncludeWithMandates": false + } + }, + { + "eidasAttribute": "http://eidas.europa.eu/attributes/legalperson/LegalName", + "idaAttribute": { + "withMandates": "urn:oid:1.2.40.0.10.2.1.1.261.84" + }, + "type": { + "mds": true, + "autoIncludeWithMandates": false + } + }, + { + "eidasAttribute": "http://eidas.europa.eu/attributes/naturalperson/representative/PersonIdentifier", + "idaAttribute": { + "withMandates": "urn:oid:1.2.40.0.10.2.1.1.149" + }, + "type": { + "mds": true, + "autoIncludeWithMandates": true + } + }, + { + "eidasAttribute": "http://eidas.europa.eu/attributes/naturalperson/representative/CurrentFamilyName", + "idaAttribute": { + "withMandates": "urn:oid:1.2.40.0.10.2.1.1.261.20" + }, + "type": { + "mds": true, + "autoIncludeWithMandates": true + } + }, + { + "eidasAttribute": "http://eidas.europa.eu/attributes/naturalperson/representative/CurrentGivenName", + "idaAttribute": { + "withMandates": "urn:oid:2.5.4.42" + }, + "type": { + "mds": true, + "autoIncludeWithMandates": true + } + }, + { + "eidasAttribute": "http://eidas.europa.eu/attributes/naturalperson/representative/DateOfBirth", + "idaAttribute": { + "withMandates": "urn:oid:1.2.40.0.10.2.1.1.55" + }, + "type": { + "mds": true, + "autoIncludeWithMandates": true + } + }, + { + "eidasAttribute": "*", + "idaAttribute": { + "basic": "urn:oid:1.2.40.0.10.2.1.1.261.32", + "withMandates": "urn:oid:1.2.40.0.10.2.1.1.261.32" + }, + "type": { + "mds": false, + "autoIncludeWithMandates": false + } + }, + { + "eidasAttribute": "*", + "idaAttribute": { + "basic": "urn:oid:1.2.40.0.10.2.1.1.261.108", + "withMandates": "urn:oid:1.2.40.0.10.2.1.1.261.108" + }, + "type": { + "mds": false, + "autoIncludeWithMandates": false + } + }, + { + "eidasAttribute": "*", + "idaAttribute": { + "withMandates": "urn:oid:1.2.40.0.10.2.1.1.261.68" + }, + "type": { + "mds": false, + "autoIncludeWithMandates": false + } + }, + { + "eidasAttribute": "*", + "idaAttribute": { + "withMandates": "urn:oid:1.2.40.0.10.2.1.1.261.106" + }, + "type": { + "mds": false, + "autoIncludeWithMandates": false + } + } +] diff --git a/modules/authmodule_id-austria/src/main/java/at/asitplus/eidas/specific/modules/auth/idaustria/builder/attributes/SpRequiredAttributersAttributeBuilder.java b/modules/authmodule_id-austria/src/main/java/at/asitplus/eidas/specific/modules/auth/idaustria/builder/attributes/SpRequiredAttributersAttributeBuilder.java new file mode 100644 index 00000000..61687088 --- /dev/null +++ b/modules/authmodule_id-austria/src/main/java/at/asitplus/eidas/specific/modules/auth/idaustria/builder/attributes/SpRequiredAttributersAttributeBuilder.java @@ -0,0 +1,63 @@ +/* + * 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 org.apache.commons.lang3.StringUtils; + +import at.asitplus.eidas.specific.core.config.ServiceProviderConfiguration; +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; +import lombok.extern.slf4j.Slf4j; + +@Slf4j +public class SpRequiredAttributersAttributeBuilder + implements IAttributeBuilder, ExtendedPvpAttributeDefinitions { + + @Override + public String getName() { + return SP_REQUIRED_ATTRIBUTES_NAME; + } + + @Override + public ATT build(final ISpConfiguration oaParam, final IAuthData authData, + final IAttributeGenerator g) + throws AttributeBuilderException { + if (oaParam instanceof ServiceProviderConfiguration) { + return g.buildStringAttribute(SP_REQUIRED_ATTRIBUTES_FRIENDLY_NAME, SP_REQUIRED_ATTRIBUTES_NAME, + StringUtils.join(((ServiceProviderConfiguration)oaParam).getRequestedAttributes(), ",")); + + } else { + log.warn("Can not build attribute for required IDA attributes, because SP config-implementation does not match."); + return null; + + } + } + + @Override + public ATT buildEmpty(final IAttributeGenerator g) { + return g.buildEmptyAttribute(SP_REQUIRED_ATTRIBUTES_FRIENDLY_NAME, SP_REQUIRED_ATTRIBUTES_NAME); + + } + +} 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 index e486b851..17e0e0d5 100644 --- 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 @@ -16,7 +16,6 @@ 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; @@ -234,8 +233,7 @@ public class ReceiveFromIdAustriaSystemTask extends AbstractAuthServletTask { // inject all attributes into session final Set includedAttrNames = extractor.getAllIncludeAttributeNames(); for (final String attrName : includedAttrNames) { - injectAuthInfosIntoSession(session, attrName, - extractor.getSingleAttributeValue(attrName)); + injectAuthInfosIntoSession(session, attrName, extractor.getSingleAttributeValue(attrName)); } @@ -306,31 +304,11 @@ public class ReceiveFromIdAustriaSystemTask extends AbstractAuthServletTask { 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); - - } - + log.debug("Inject attribute: {} into AuthSession", attrName); + 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 { 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 index 66aadde6..bbe9b45f 100644 --- 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 @@ -160,6 +160,12 @@ public class RequestIdAustriaSystemTask extends AbstractAuthServletTask { injectAttribute(attributs, PvpAttributeDefinitions.EID_CITIZEN_EIDAS_QAA_LEVEL_NAME, selectHighestLoa(pendingReq.getServiceProviderConfiguration().getRequiredLoA())); + // set list of IDA attributes as attribute + injectAttribute(attributs, ExtendedPvpAttributeDefinitions.SP_REQUIRED_ATTRIBUTES_NAME, + StringUtils.join( + pendingReq.getServiceProviderConfiguration(ServiceProviderConfiguration.class).getRequestedAttributes(), + ",")); + //set ProviderName if available String providerName = ((ProxyServicePendingRequest)pendingReq).getEidasRequest().getProviderName(); if (StringUtils.isNotEmpty(providerName)) { 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 index 65e9482c..3b20d687 100644 --- 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 @@ -1 +1,2 @@ at.asitplus.eidas.specific.modules.auth.idaustria.builder.attributes.EidasConnecorUniqueIdAttributeBuilder +at.asitplus.eidas.specific.modules.auth.idaustria.builder.attributes.SpRequiredAttributersAttributeBuilder diff --git a/modules/authmodule_id-austria/src/test/java/at/asitplus/eidas/specific/modules/auth/idaustria/test/builder/attributes/SpRequiredAttributersAttributeBuilderTest.java b/modules/authmodule_id-austria/src/test/java/at/asitplus/eidas/specific/modules/auth/idaustria/test/builder/attributes/SpRequiredAttributersAttributeBuilderTest.java new file mode 100644 index 00000000..2fe420df --- /dev/null +++ b/modules/authmodule_id-austria/src/test/java/at/asitplus/eidas/specific/modules/auth/idaustria/test/builder/attributes/SpRequiredAttributersAttributeBuilderTest.java @@ -0,0 +1,72 @@ +package at.asitplus.eidas.specific.modules.auth.idaustria.test.builder.attributes; + +import static org.junit.Assert.assertEquals; + +import java.util.List; + +import org.apache.commons.lang3.RandomStringUtils; +import org.junit.Assert; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.internal.util.collections.Sets; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; + +import at.asitplus.eidas.specific.core.config.ServiceProviderConfiguration; +import at.asitplus.eidas.specific.modules.auth.idaustria.builder.attributes.SpRequiredAttributersAttributeBuilder; +import at.gv.egiz.eaaf.core.api.data.PvpAttributeDefinitions; +import at.gv.egiz.eaaf.core.api.idp.IAttributeBuilder; +import at.gv.egiz.eaaf.core.exceptions.AttributeBuilderException; +import at.gv.egiz.eaaf.core.impl.idp.auth.attributes.AbstractAttributeBuilderTest; +import at.gv.egiz.eaaf.core.impl.idp.module.test.DummyConfiguration; +import at.gv.egiz.eaaf.core.impl.utils.KeyValueUtils; + +@RunWith(SpringJUnit4ClassRunner.class) +@ContextConfiguration(locations = { + "/spring/SpringTest-context_basic_mapConfig.xml", + "/spring/SpringTest-context_basic_test.xml", +}) +public class SpRequiredAttributersAttributeBuilderTest extends AbstractAttributeBuilderTest { + +private final IAttributeBuilder attrBuilder = new SpRequiredAttributersAttributeBuilder(); + + @Test + public void attributeName() { + Assert.assertEquals("Wrong attribute name", + "urn:eidgvat:attributes.RequiredAttributes", attrBuilder.getName()); + + } + + @Test + public void checkEmptyAttribute() { + String value = attrBuilder.buildEmpty(gen); + Assert.assertNull("Attr. not null", value); + + } + + @Test + public void withWrongSpConfig() throws AttributeBuilderException, Exception { + String value = attrBuilder.build(spConfig, buildAuthData(), gen); + Assert.assertNull("Attr. not null", value); + + } + + @Test + public void withAttributeValue() throws AttributeBuilderException, Exception { + ServiceProviderConfiguration sp = new ServiceProviderConfiguration(spConfigMap, new DummyConfiguration()); + sp.setRequestedAttributes(Sets.newSet( + "aabbccdd", + RandomStringUtils.randomAlphanumeric(10), + PvpAttributeDefinitions.BIRTHDATE_NAME)); + + + String value = attrBuilder.build(sp, buildAuthData(), gen); + + List elements = KeyValueUtils.getListOfCsvValues(value); + assertEquals("wrong number of attributes", sp.getRequestedAttributes().size(), elements.size()); + sp.getRequestedAttributes().forEach( + el -> elements.contains(el)); + + } + +} 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 index c452fe22..c3be6dad 100644 --- 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 @@ -36,7 +36,6 @@ 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; @@ -542,14 +541,14 @@ public class ReceiveAuthnResponseTaskTest { 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"); + 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="); + checkAttributeInSession(session, PvpAttributeDefinitions.BPK_NAME, "AT+XX:QVGm48cqcM4UcyhDTNGYmVdrIoY="); } @@ -587,7 +586,7 @@ public class ReceiveAuthnResponseTaskTest { checkAttributeInSession(session,PvpAttributeDefinitions.BIRTHDATE_NAME, "1940-01-01"); checkAttributeInSession(session,PvpAttributeDefinitions.EID_ISSUING_NATION_NAME, "AT"); - checkAttributeInSession(session,MsEidasNodeConstants.ATTR_EIDAS_PERSONAL_IDENTIFIER, "QVGm48cqcM4UcyhDTNGYmVdrIoY="); + checkAttributeInSession(session,PvpAttributeDefinitions.BPK_NAME, "AT+CC:QVGm48cqcM4UcyhDTNGYmVdrIoY="); } @@ -625,7 +624,7 @@ public class ReceiveAuthnResponseTaskTest { checkAttributeInSession(session,PvpAttributeDefinitions.EID_ISSUING_NATION_NAME, "AT"); //pre-generated eIDAS identifer - checkAttributeInSession(session,MsEidasNodeConstants.ATTR_EIDAS_PERSONAL_IDENTIFIER, "QVGm48cqcasfasfsafsafdM4UcyhDTNGYmVdrIoY="); + checkAttributeInSession(session,PvpAttributeDefinitions.BPK_NAME, "QVGm48cqcasfasfsafsafdM4UcyhDTNGYmVdrIoY="); } @@ -663,7 +662,7 @@ public class ReceiveAuthnResponseTaskTest { checkAttributeInSession(session,PvpAttributeDefinitions.EID_ISSUING_NATION_NAME, "AT"); //pre-generated eIDAS identifer - checkAttributeInSession(session,MsEidasNodeConstants.ATTR_EIDAS_PERSONAL_IDENTIFIER, "QVGm48cqcasfasfsafsafdM4UcyhDTNGYmVdrIoY="); + checkAttributeInSession(session,PvpAttributeDefinitions.BPK_NAME, "AT+AB:QVGm48cqcasfasfsafsafdM4UcyhDTNGYmVdrIoY="); } @@ -708,7 +707,7 @@ public class ReceiveAuthnResponseTaskTest { 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="); + checkAttributeInSession(session, PvpAttributeDefinitions.BPK_NAME, "AT+XX:QVGm48cqcM4UcyhDTNGYmVdrIoY="); assertNull("find nat. person bpk for mandator", session.getGenericDataFromSession( PvpAttributeDefinitions.MANDATE_NAT_PER_BPK_NAME, String.class)); @@ -758,8 +757,7 @@ public class ReceiveAuthnResponseTaskTest { //pre-generated eIDAS identifer - checkAttributeInSession(session, MsEidasNodeConstants.ATTR_EIDAS_PERSONAL_IDENTIFIER, - "QVGm48cqcM4UcyhDTNGYmVdrIoY="); + checkAttributeInSession(session, PvpAttributeDefinitions.BPK_NAME, "AT+XX:QVGm48cqcM4UcyhDTNGYmVdrIoY="); } 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 index f6ffc729..1feb684d 100644 --- 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 @@ -18,6 +18,7 @@ import org.junit.Before; import org.junit.BeforeClass; import org.junit.Test; import org.junit.runner.RunWith; +import org.mockito.internal.util.collections.Sets; import org.opensaml.core.xml.config.XMLObjectProviderRegistrySupport; import org.opensaml.core.xml.schema.XSString; import org.opensaml.core.xml.util.XMLObjectSupport; @@ -41,6 +42,7 @@ import at.asitplus.eidas.specific.modules.msproxyservice.protocol.ProxyServicePe 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.data.PvpAttributeDefinitions; 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; @@ -213,7 +215,7 @@ public class RequestIdAustriaSystemTaskTest { //validate state final EaafRequestedAttributes reqAttr = validate(); - Assert.assertEquals("#Req Attribute", 4, reqAttr.getAttributes().size()); + Assert.assertEquals("#Req Attribute", 5, reqAttr.getAttributes().size()); Assert.assertEquals("Wrong req attr.", "urn:eidgvat:attributes.eidas.uniqueId", reqAttr.getAttributes().get(0).getName()); @@ -246,15 +248,15 @@ public class RequestIdAustriaSystemTaskTest { ((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()); + reqAttr.getAttributes().get(4).getName()); + Assert.assertNotNull("Req. Attr value element", reqAttr.getAttributes().get(4).getAttributeValues()); Assert.assertEquals("#Req. Attr value", 1, - reqAttr.getAttributes().get(3).getAttributeValues().size()); + reqAttr.getAttributes().get(4).getAttributeValues().size()); org.springframework.util.Assert.isInstanceOf(XSString.class, - reqAttr.getAttributes().get(3).getAttributeValues().get(0), "Wrong requested Attributes Value type"); + reqAttr.getAttributes().get(4).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()); + ((XSString)reqAttr.getAttributes().get(4).getAttributeValues().get(0)).getValue()); } @@ -275,33 +277,55 @@ public class RequestIdAustriaSystemTaskTest { LightRequest eidasReq = eidasRequestBuilder.build(); pendingReq.setEidasRequest(eidasReq); + oaParam.setRequestedAttributes(Sets.newSet( + "aabbccdd", + RandomStringUtils.randomAlphanumeric(10), + PvpAttributeDefinitions.BIRTHDATE_NAME)); + //execute test task.execute(pendingReq, executionContext); //validate state final EaafRequestedAttributes reqAttr = validate(); - Assert.assertEquals("#Req Attribute", 6, reqAttr.getAttributes().size()); + Assert.assertEquals("#Req Attribute", 7, reqAttr.getAttributes().size()); - Assert.assertEquals("Wrong req attr.", "urn:eidgvat:attributes.ServiceProviderFriendlyName", + + Assert.assertEquals("Wrong req attr.", "urn:eidgvat:attributes.RequiredAttributes", reqAttr.getAttributes().get(3).getName()); - Assert.assertNotNull("Req. Attr value element", reqAttr.getAttributes().get(1).getAttributeValues()); + 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", eidasReq.getProviderName(), + + List reqProfiles = KeyValueUtils.getListOfCsvValues( ((XSString)reqAttr.getAttributes().get(3).getAttributeValues().get(0)).getValue()); + reqProfiles.stream().forEach( + el -> assertTrue("missing IDA attribute: " + el, oaParam.getRequestedAttributes().contains(el))); - Assert.assertEquals("Wrong req attr.", "urn:eidgvat:attributes.ServiceProviderUniqueId", + + Assert.assertEquals("Wrong req attr.", "urn:eidgvat:attributes.ServiceProviderFriendlyName", reqAttr.getAttributes().get(4).getName()); - Assert.assertNotNull("Req. Attr value element", reqAttr.getAttributes().get(1).getAttributeValues()); + Assert.assertNotNull("Req. Attr value element", reqAttr.getAttributes().get(4).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(), + Assert.assertEquals("Req. Attr. Value", eidasReq.getProviderName(), ((XSString)reqAttr.getAttributes().get(4).getAttributeValues().get(0)).getValue()); + Assert.assertEquals("Wrong req attr.", "urn:eidgvat:attributes.ServiceProviderUniqueId", + reqAttr.getAttributes().get(5).getName()); + Assert.assertNotNull("Req. Attr value element", reqAttr.getAttributes().get(5).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"); + Assert.assertEquals("Req. Attr. Value", eidasReq.getRequesterId(), + ((XSString)reqAttr.getAttributes().get(5).getAttributeValues().get(0)).getValue()); + + + } @Test @@ -330,31 +354,31 @@ public class RequestIdAustriaSystemTaskTest { //validate state final EaafRequestedAttributes reqAttr = validate(); - Assert.assertEquals("#Req Attribute", 7, reqAttr.getAttributes().size()); + Assert.assertEquals("#Req Attribute", 8, 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()); + 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(5).getAttributeValues().size()); + reqAttr.getAttributes().get(6).getAttributeValues().size()); org.springframework.util.Assert.isInstanceOf(XSString.class, - reqAttr.getAttributes().get(5).getAttributeValues().get(0), "Wrong requested Attributes Value type"); + reqAttr.getAttributes().get(6).getAttributeValues().get(0), "Wrong requested Attributes Value type"); List reqProfiles = KeyValueUtils.getListOfCsvValues( - ((XSString)reqAttr.getAttributes().get(5).getAttributeValues().get(0)).getValue()); + ((XSString)reqAttr.getAttributes().get(6).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()); + reqAttr.getAttributes().get(7).getName()); + Assert.assertNotNull("Req. Attr value element", reqAttr.getAttributes().get(7).getAttributeValues()); Assert.assertEquals("#Req. Attr value", 1, - reqAttr.getAttributes().get(6).getAttributeValues().size()); + reqAttr.getAttributes().get(7).getAttributeValues().size()); org.springframework.util.Assert.isInstanceOf(XSString.class, - reqAttr.getAttributes().get(6).getAttributeValues().get(0), "Wrong requested Attributes Value type"); + reqAttr.getAttributes().get(7).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()); + ((XSString)reqAttr.getAttributes().get(7).getAttributeValues().get(0)).getValue()); } 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 index be5d7c7d..8da7ddd0 100644 --- 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 @@ -31,7 +31,6 @@ 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 ************ @@ -189,17 +188,7 @@ public class MsEidasNodeConstants { 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"; 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 index e719735c..673b8ef5 100644 --- 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 @@ -24,73 +24,92 @@ package at.asitplus.eidas.specific.core.builder; import java.time.Instant; - -import org.springframework.stereotype.Service; +import java.util.Optional; +import java.util.Set; import at.asitplus.eidas.specific.core.MsEidasNodeConstants; +import at.asitplus.eidas.specific.core.config.ServiceProviderConfiguration; 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 { + protected IAuthData buildDeprecatedAuthData(IRequest pendingReq) throws EaafException { final EidAuthProcessDataWrapper authProcessData = - pendingReq.getSessionData(EidAuthProcessDataWrapper.class); - EidAuthenticationData authData = new EidAuthenticationData(); - - //set basis infos + pendingReq.getSessionData(EidAuthProcessDataWrapper.class); + final EidAuthenticationData authData = new EidAuthenticationData(); + + // set basis infos super.generateDeprecatedBasicAuthData(authData, pendingReq, authProcessData); - + // set specific informations authData.setSsoSessionValidTo( Instant.now().plusSeconds(MsEidasNodeConstants.DEFAULT_PVP_ASSERTION_VALIDITY * 60)); - authData.setEidStatus(authProcessData.isTestIdentity() - ? EidIdentityStatusLevelValues.TESTIDENTITY : EidIdentityStatusLevelValues.IDENTITY); - + authData.setEidStatus(authProcessData.isTestIdentity() + ? EidIdentityStatusLevelValues.TESTIDENTITY + : EidIdentityStatusLevelValues.IDENTITY); + return authData; } @Override - protected void buildServiceSpecificAuthenticationData(IAuthData authData, IRequest pendingReq) + protected void buildServiceSpecificAuthenticationData(IAuthData authData, IRequest pendingReq) throws EaafException { if (authData instanceof EidAuthenticationData) { - ((EidAuthenticationData)authData).setGenericData( - ExtendedPvpAttributeDefinitions.EID_PII_TRANSACTION_ID_NAME, + ((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( + ((EidAuthenticationData) authData).setSsoSessionValidTo( Instant.now().plusSeconds(MsEidasNodeConstants.DEFAULT_PVP_ASSERTION_VALIDITY * 60)); - //set E-ID status-level + // set E-ID status-level final EidAuthProcessDataWrapper authProcessData = - pendingReq.getSessionData(EidAuthProcessDataWrapper.class); - ((EidAuthenticationData)authData).setEidStatus(authProcessData.isTestIdentity() - ? EidIdentityStatusLevelValues.TESTIDENTITY : EidIdentityStatusLevelValues.IDENTITY); - + pendingReq.getSessionData(EidAuthProcessDataWrapper.class); + ((EidAuthenticationData) authData).setEidStatus(authProcessData.isTestIdentity() + ? EidIdentityStatusLevelValues.TESTIDENTITY + : EidIdentityStatusLevelValues.IDENTITY); + + // forward all requested IDA attributes into authData + forwardAllRequestedIdaAttributes(authProcessData, (EidAuthenticationData) authData, + pendingReq.getServiceProviderConfiguration(ServiceProviderConfiguration.class) + .getRequestedAttributes()); + + // build specific bPK attribute + buildNatPersonInfos((EidAuthenticationData) authData, authProcessData); + + // handle mandate informations + buildMandateInformation((EidAuthenticationData) authData, pendingReq, authProcessData); + } else { - throw new RuntimeException("Can not inject PiiTransactionId because AuthData is of unknown type: " + throw new RuntimeException("Can not inject PiiTransactionId because AuthData is of unknown type: " + authData.getClass().getName()); - + } - + } @Override @@ -119,4 +138,120 @@ public class AuthenticationDataBuilder extends AbstractAuthenticationDataBuilder } + protected String customizeLegalPersonSourcePin(String sourcePin, String sourcePinType) { + log.trace("Use legal-person sourcePin as it is"); + return sourcePin; + + } + + protected String customizeBpkAttribute(String pvpBpkAttrValue) { + log.trace("Use natural-person bPK as it is"); + return pvpBpkAttrValue; + + } + + private void forwardAllRequestedIdaAttributes(EidAuthProcessDataWrapper authProcessData, + EidAuthenticationData authData, Set requestedIdaAttributes) { + if (requestedIdaAttributes != null && !requestedIdaAttributes.isEmpty()) { + log.trace("Forwarding IDA requested attributes ... "); + authProcessData.getGenericSessionDataStream() + .filter(el -> requestedIdaAttributes.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); + + } + }); + } else { + log.trace("No IDA requested attributes to forwarding. Nothing todo"); + + } + } + + 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); + + } + } + } + + 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 buildNatPersonInfos(EidAuthenticationData authData, + EidAuthProcessDataWrapper authProcessData) throws EaafStorageException { + // clean-up BPK attribute and forward it as new property + authData.setGenericData(PvpAttributeDefinitions.BPK_NAME, + customizeBpkAttribute(authProcessData.getGenericDataFromSession( + PvpAttributeDefinitions.BPK_NAME, String.class))); + + } + + 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(PvpAttributeDefinitions.MANDATE_NAT_PER_BPK_NAME, + customizeBpkAttribute(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); + + // customize attribute-value for source-pin + final String sourcePinToUse = customizeLegalPersonSourcePin(sourcePin, sourcePinType); + log.debug("Use legal-person eIDAS identifer: {} from baseId: {} and baseIdType: {}", + sourcePinToUse, sourcePin, sourcePinType); + authData.setGenericData(PvpAttributeDefinitions.MANDATE_LEG_PER_SOURCE_PIN_NAME, sourcePinToUse); + + } + } + } } 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 index ee67d712..af3594a5 100644 --- 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 @@ -23,9 +23,6 @@ - - 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 index 12936a59..8b2eebd4 100644 --- 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 @@ -1,6 +1,9 @@ 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.assertThrows; +import static org.junit.Assert.assertTrue; import java.io.IOException; import java.security.PublicKey; @@ -30,8 +33,11 @@ import org.springframework.web.context.request.RequestContextHolder; import org.springframework.web.context.request.ServletRequestAttributes; import org.w3c.dom.Element; +import com.google.common.collect.Sets; + import at.asitplus.eidas.specific.core.MsEidasNodeConstants; import at.asitplus.eidas.specific.core.builder.AuthenticationDataBuilder; +import at.asitplus.eidas.specific.core.config.ServiceProviderConfiguration; 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; @@ -49,9 +55,9 @@ 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 lombok.SneakyThrows; import net.shibboleth.utilities.java.support.component.ComponentInitializationException; @RunWith(SpringJUnit4ClassRunner.class) @@ -71,7 +77,8 @@ public class AuthenticationDataBuilderTest { private MockHttpServletResponse httpResp; private TestRequestImpl pendingReq; - private DummySpConfiguration oaParam; + private Map spConfig; + private ServiceProviderConfiguration oaParam; private String eidasBind; private String authBlock; @@ -86,18 +93,20 @@ public class AuthenticationDataBuilderTest { } @Before + @SneakyThrows public void initialize() throws EaafStorageException { httpReq = new MockHttpServletRequest("POST", "https://localhost/ms_connector"); httpResp = new MockHttpServletResponse(); RequestContextHolder.resetRequestAttributes(); RequestContextHolder.setRequestAttributes(new ServletRequestAttributes(httpReq, httpResp)); - final Map spConfig = new HashMap<>(); + 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); - + oaParam = new ServiceProviderConfiguration(spConfig, basicConfig); + oaParam.setBpkTargetIdentifier("urn:publicid:gv.at:cdid+XX"); + pendingReq = new TestRequestImpl(); pendingReq.setAuthUrl("https://localhost/ms_connector"); pendingReq.setPendingReqId(RandomStringUtils.randomAlphanumeric(10)); @@ -119,6 +128,260 @@ public class AuthenticationDataBuilderTest { } + @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"); + + oaParam.setRequestedAttributes(Sets.newHashSet( + PvpAttributeDefinitions.MANDATE_LEG_PER_FULL_NAME_NAME, + PvpAttributeDefinitions.MANDATE_LEG_PER_SOURCE_PIN_NAME, + PvpAttributeDefinitions.MANDATE_LEG_PER_SOURCE_PIN_TYPE_NAME)); + + // 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, PvpAttributeDefinitions.MANDATE_LEG_PER_SOURCE_PIN_NAME, sourcePinMandate); + + } + + @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); + + oaParam.setRequestedAttributes(Sets.newHashSet( + PvpAttributeDefinitions.MANDATE_NAT_PER_GIVEN_NAME_NAME, + PvpAttributeDefinitions.MANDATE_NAT_PER_FAMILY_NAME_NAME, + PvpAttributeDefinitions.MANDATE_NAT_PER_BIRTHDATE_NAME, + PvpAttributeDefinitions.MANDATE_NAT_PER_BPK_NAME)); + + // 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, PvpAttributeDefinitions.MANDATE_NAT_PER_BPK_NAME, "AT+XX:" + 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); + + oaParam.setRequestedAttributes(Sets.newHashSet( + PvpAttributeDefinitions.MANDATE_NAT_PER_GIVEN_NAME_NAME, + PvpAttributeDefinitions.MANDATE_NAT_PER_FAMILY_NAME_NAME, + PvpAttributeDefinitions.MANDATE_NAT_PER_BIRTHDATE_NAME, + PvpAttributeDefinitions.MANDATE_NAT_PER_BPK_NAME)); + + // 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, PvpAttributeDefinitions.MANDATE_NAT_PER_BPK_NAME, 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 + @SneakyThrows + public void eidasProxyMode() throws EaafAuthenticationException { + // initialize state + pendingReq = new TestRequestImpl(); + pendingReq.setAuthUrl("https://localhost/ms_connector"); + pendingReq.setPendingReqId(RandomStringUtils.randomAlphanumeric(10)); + pendingReq.setPiiTransactionId(RandomStringUtils.randomAlphanumeric(10)); + pendingReq.setSpConfig(oaParam); + boolean isTestIdentity = RandomUtils.nextBoolean(); + + pendingReq.getSessionData(AuthProcessDataWrapper.class).setEidProcess(true); + pendingReq.getSessionData(AuthProcessDataWrapper.class).setForeigner(false); + + String bpk = RandomStringUtils.randomAlphanumeric(10); + pendingReq.getSessionData(AuthProcessDataWrapper.class).setGenericDataToSession( + PvpAttributeDefinitions.BPK_NAME, "eidas+AT+XX:" + bpk); + pendingReq.getSessionData(AuthProcessDataWrapper.class).setGenericDataToSession( + PvpAttributeDefinitions.GIVEN_NAME_NAME, "Max"); + pendingReq.getSessionData(AuthProcessDataWrapper.class).setGenericDataToSession( + PvpAttributeDefinitions.PRINCIPAL_NAME_NAME, "Mustermann"); + pendingReq.getSessionData(AuthProcessDataWrapper.class).setGenericDataToSession( + PvpAttributeDefinitions.BIRTHDATE_NAME, "1940-01-01"); + pendingReq.getSessionData(AuthProcessDataWrapper.class).setGenericDataToSession( + PvpAttributeDefinitions.EID_CITIZEN_EIDAS_QAA_LEVEL_NAME, + "http://eidas.europa.eu/LoA/high"); + pendingReq.getSessionData(AuthProcessDataWrapper.class).setGenericDataToSession( + PvpAttributeDefinitions.EID_ISSUING_NATION_NAME, + RandomStringUtils.randomAlphabetic(2)); + + String randAttr = RandomStringUtils.randomAlphabetic(10); + pendingReq.getSessionData(AuthProcessDataWrapper.class).setGenericDataToSession( + randAttr, RandomStringUtils.randomAlphabetic(10)); + + oaParam.setRequestedAttributes(Sets.newHashSet(randAttr, + PvpAttributeDefinitions.BPK_NAME, + PvpAttributeDefinitions.GIVEN_NAME_NAME, + PvpAttributeDefinitions.PRINCIPAL_NAME_NAME, + PvpAttributeDefinitions.BIRTHDATE_NAME, + PvpAttributeDefinitions.EID_CITIZEN_EIDAS_QAA_LEVEL_NAME, + PvpAttributeDefinitions.EID_ISSUING_NATION_NAME)); + + + // 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.assertNotNull("LoA null", authData.getEidasQaaLevel()); + + Assert.assertEquals("FamilyName", "Mustermann", authData.getFamilyName()); + Assert.assertEquals("GivenName", "Max", authData.getGivenName()); + Assert.assertEquals("DateOfBirth", "1940-01-01", authData.getDateOfBirth()); + + Assert.assertEquals("LoA", "http://eidas.europa.eu/LoA/high", authData.getEidasQaaLevel()); + Assert.assertEquals("EID-ISSUING-NATION", + pendingReq.getSessionData(AuthProcessDataWrapper.class).getGenericDataFromSession( + PvpAttributeDefinitions.EID_ISSUING_NATION_NAME), + authData.getCiticenCountryCode()); + + checkGenericAttribute(authData, PvpAttributeDefinitions.BPK_NAME, "eidas+AT+XX:" + bpk); + checkGenericAttribute(authData, PvpAttributeDefinitions.GIVEN_NAME_NAME, "Max"); + checkGenericAttribute(authData, PvpAttributeDefinitions.PRINCIPAL_NAME_NAME, "Mustermann"); + checkGenericAttribute(authData, PvpAttributeDefinitions.BIRTHDATE_NAME, "1940-01-01"); + + Assert.assertEquals("random optional attr.", + pendingReq.getSessionData(AuthProcessDataWrapper.class).getGenericDataFromSession( + randAttr), + authData.getGenericData(randAttr, String.class)); + + } + + + @Test public void eidMode() throws EaafAuthenticationException { // initialize state @@ -207,10 +470,48 @@ public class AuthenticationDataBuilderTest { 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(PvpAttributeDefinitions.BPK_NAME, 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() { diff --git a/modules/eidas_proxy-sevice/src/main/java/at/asitplus/eidas/specific/modules/msproxyservice/dto/attributes/Type.java b/modules/eidas_proxy-sevice/src/main/java/at/asitplus/eidas/specific/modules/msproxyservice/dto/attributes/Type.java index 86ca49fa..f66bb799 100644 --- a/modules/eidas_proxy-sevice/src/main/java/at/asitplus/eidas/specific/modules/msproxyservice/dto/attributes/Type.java +++ b/modules/eidas_proxy-sevice/src/main/java/at/asitplus/eidas/specific/modules/msproxyservice/dto/attributes/Type.java @@ -15,6 +15,7 @@ import lombok.Data; @JsonInclude(JsonInclude.Include.NON_NULL) @JsonPropertyOrder({ "mds", + "autoIncludeWithMandates", "mandator" }) @Data @@ -27,6 +28,12 @@ public class Type { @JsonProperty("mds") private Boolean mds; + /** + * true if that attribute has to be included into eIDAS response in case of mandates. + */ + @JsonProperty("autoIncludeWithMandates") + private Boolean autoIncludeWithMandates; + /** * Classifie that attribute to specific mandate modes. */ 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 index 92165412..bf1c5e5f 100644 --- 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 @@ -1,6 +1,7 @@ package at.asitplus.eidas.specific.modules.msproxyservice.protocol; import java.io.IOException; +import java.util.Optional; import java.util.UUID; import javax.annotation.PostConstruct; @@ -15,12 +16,11 @@ 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.core.eidas.EidasConstants; -import at.asitplus.eidas.specific.modules.core.eidas.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.service.ProxyEidasAttributeRegistry; 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; @@ -69,35 +69,35 @@ public class ProxyServiceAuthenticationAction implements IAction { @Autowired ISpringMvcGuiFormBuilder guiBuilder; @Autowired - EidasAttributeRegistry attrRegistry; + ProxyEidasAttributeRegistry 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(); + try { + final ILightRequest eidasReq = ((ProxyServicePendingRequest) pendingReq).getEidasRequest(); + + // build eIDAS response + final Builder lightRespBuilder = LightResponse.builder(); lightRespBuilder.id(UUID.randomUUID().toString()); lightRespBuilder.inResponseToId(eidasReq.getId()); lightRespBuilder.relayState(eidasReq.getRelayState()); - + lightRespBuilder.status(ResponseStatus.builder() .statusCode(EidasConstants.SUCCESS_URI) .build()); - - //TODO: check if we can use transient subjectNameIds + + // TODO: check if we can use transient subjectNameIds lightRespBuilder.subject(UUID.randomUUID().toString()); lightRespBuilder.subjectNameIdFormat(NameIDType.TRANSIENT); - - //TODO: + + // TODO: lightRespBuilder.issuer(basicConfig.getBasicConfiguration( MsProxyServiceConstants.CONIG_PROPS_EIDAS_PROXY_NODE_ENTITYID)); - lightRespBuilder.levelOfAssurance(authData.getEidasQaaLevel()); + 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()); @@ -121,7 +121,7 @@ public class ProxyServiceAuthenticationAction implements IAction { } } - + @Override public boolean needAuthentication(IRequest req, HttpServletRequest httpReq, HttpServletResponse httpResp) { return true; @@ -133,28 +133,29 @@ public class ProxyServiceAuthenticationAction implements IAction { 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 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 + * @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, + 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); @@ -196,148 +197,80 @@ public class ProxyServiceAuthenticationAction implements IAction { } } - - @PostConstruct + + @PostConstruct private void checkConfiguration() { - //TODO: validate configuration on start-up - + // TODO: validate configuration on start-up + } - - - private ImmutableAttributeMap buildAttributesFromAuthData(IAuthData authData, + + private ImmutableAttributeMap buildAttributesFromAuthData(IAuthData authData, ILightRequest eidasReq) { - IEidAuthData eidAuthData = (IEidAuthData) authData; + final IEidAuthData eidAuthData = (IEidAuthData) authData; + final ImmutableAttributeMap.Builder attributeMap = ImmutableAttributeMap.builder(); + + // inject all requested attributres + injectRequestedAttributes(attributeMap, eidasReq, eidAuthData); + 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 + injectMdsRepesentativeInformation(attributeMap, eidAuthData, eidasReq.getRequestedAttributes()); + + // 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( - EidasConstants.eIDAS_ATTR_PERSONALIDENTIFIER).first(); - final AttributeDefinition attrDefFamilyName = attrRegistry.getCoreAttributeRegistry().getByFriendlyName( - EidasConstants.eIDAS_ATTR_CURRENTFAMILYNAME).first(); - final AttributeDefinition attrDefGivenName = attrRegistry.getCoreAttributeRegistry().getByFriendlyName( - EidasConstants.eIDAS_ATTR_CURRENTGIVENNAME).first(); - final AttributeDefinition attrDefDateOfBirth = attrRegistry.getCoreAttributeRegistry().getByFriendlyName( - EidasConstants.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( - EidasConstants.eIDAS_ATTR_LEGALNAME).first(); - final AttributeDefinition legalPersonId = attrRegistry.getCoreAttributeRegistry().getByFriendlyName( - EidasConstants.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( - EidasConstants.eIDAS_ATTR_REPRESENTATIVE_PERSONALIDENTIFIER).first(); - final AttributeDefinition attrDefFamilyName = attrRegistry.getCoreAttributeRegistry().getByFriendlyName( - EidasConstants.eIDAS_ATTR_REPRESENTATIVE_CURRENTFAMILYNAME).first(); - final AttributeDefinition attrDefGivenName = attrRegistry.getCoreAttributeRegistry().getByFriendlyName( - EidasConstants.eIDAS_ATTR_REPRESENTATIVE_CURRENTGIVENNAME).first(); - final AttributeDefinition attrDefDateOfBirth = attrRegistry.getCoreAttributeRegistry().getByFriendlyName( - EidasConstants.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()); - + } + + return attributeMap.build(); + } - /** - * 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 void injectRequestedAttributes(ImmutableAttributeMap.Builder attributeMap, ILightRequest eidasReq, + IEidAuthData eidAuthData) { + eidasReq.getRequestedAttributes().getAttributeMap().keySet().stream() + .forEach(el -> injectEidasAttribute(attributeMap, eidAuthData, + el.getNameUri().toString(), eidAuthData.isUseMandate())); + } - - 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 void injectMdsRepesentativeInformation( + ImmutableAttributeMap.Builder attributeMap, IEidAuthData eidAuthData, + ImmutableAttributeMap requestedAttributes) { + attrRegistry.getRepresentativeAttributesToAddByDefault() + .filter(el -> requestedAttributes.getAttributeValuesByNameUri(el) == null) + .forEach(el -> injectEidasAttribute(attributeMap, eidAuthData, el, true)); + } - private ImmutableAttributeMap buildAttributesWithoutMandate(String personalIdentifier, String familyName, - String givenName, String dateOfBirth) { - final AttributeDefinition attrDefPersonalId = attrRegistry.getCoreAttributeRegistry().getByFriendlyName( - EidasConstants.eIDAS_ATTR_PERSONALIDENTIFIER).first(); - final AttributeDefinition attrDefFamilyName = attrRegistry.getCoreAttributeRegistry().getByFriendlyName( - EidasConstants.eIDAS_ATTR_CURRENTFAMILYNAME).first(); - final AttributeDefinition attrDefGivenName = attrRegistry.getCoreAttributeRegistry().getByFriendlyName( - EidasConstants.eIDAS_ATTR_CURRENTGIVENNAME).first(); - final AttributeDefinition attrDefDateOfBirth = attrRegistry.getCoreAttributeRegistry().getByFriendlyName( - EidasConstants.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 void injectEidasAttribute(ImmutableAttributeMap.Builder attributeMap, IEidAuthData eidAuthData, + String eidasAttrName, boolean mandatesUsed) { + final Optional releatedIdaAttribute = + attrRegistry.mapEidasAttributeToSpecificIdaAttribute(eidasAttrName, mandatesUsed); + if (releatedIdaAttribute.isPresent()) { + log.trace("Mapping IDA attribute: {} to eIDAS attribute: {}", releatedIdaAttribute.get(), + eidasAttrName); + final String idaAttrValue = eidAuthData.getGenericData(releatedIdaAttribute.get(), String.class); + if (StringUtils.isNotEmpty(idaAttrValue)) { + log.debug("Build eIDAS attribute: {} from IDA attribute: {}", eidasAttrName, releatedIdaAttribute + .get()); + attributeMap.put( + attrRegistry.getCoreRegistry().getCoreAttributeRegistry().getByName(eidasAttrName), + idaAttrValue); + + } else { + log.info("No IDA attribute: {}, eIDAS attribute: {} will be ignored", releatedIdaAttribute.get(), + eidasAttrName); + + } + + } else { + log.warn("Can not build eIDAS attribute: {}, because there is not corresponding IDA attribute defined", + eidasAttrName); + + } } - + private BinaryLightToken putResponseInCommunicationCache(ILightResponse lightResponse) throws ServletException { final BinaryLightToken binaryLightToken; @@ -358,17 +291,61 @@ public class ProxyServiceAuthenticationAction implements IAction { return binaryLightToken; } + /** + * 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"); + + final AttributeDefinition attrDefPersonalId = + attrRegistry.getCoreRegistry().getCoreAttributeRegistry().getByFriendlyName( + EidasConstants.eIDAS_ATTR_PERSONALIDENTIFIER).first(); + final AttributeDefinition attrDefFamilyName = + attrRegistry.getCoreRegistry().getCoreAttributeRegistry().getByFriendlyName( + EidasConstants.eIDAS_ATTR_CURRENTFAMILYNAME).first(); + final AttributeDefinition attrDefGivenName = + attrRegistry.getCoreRegistry().getCoreAttributeRegistry().getByFriendlyName( + EidasConstants.eIDAS_ATTR_CURRENTGIVENNAME).first(); + final AttributeDefinition attrDefDateOfBirth = + attrRegistry.getCoreRegistry().getCoreAttributeRegistry().getByFriendlyName( + EidasConstants.eIDAS_ATTR_DATEOFBIRTH).first(); + + attributeMap.put(attrDefPersonalId, authData.getGenericData(PvpAttributeDefinitions.BPK_NAME, + String.class)); + attributeMap.put(attrDefFamilyName, authData.getFamilyName()); + attributeMap.put(attrDefGivenName, authData.getGivenName()); + attributeMap.put(attrDefDateOfBirth, authData.getDateOfBirth()); + + } + } + private boolean isLegalPersonWorkaroundActive() { return basicConfig.getBasicConfigurationBoolean( - MsProxyServiceConstants.CONIG_PROPS_EIDAS_PROXY_WORKAROUND_MANDATES_LEGAL_PERSON, + 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)); - + PvpAttributeDefinitions.MANDATE_LEG_PER_SOURCE_PIN_NAME, String.class)); + } } diff --git a/modules/eidas_proxy-sevice/src/main/java/at/asitplus/eidas/specific/modules/msproxyservice/service/ProxyEidasAttributeRegistry.java b/modules/eidas_proxy-sevice/src/main/java/at/asitplus/eidas/specific/modules/msproxyservice/service/ProxyEidasAttributeRegistry.java index b9e0c488..a6a50100 100644 --- a/modules/eidas_proxy-sevice/src/main/java/at/asitplus/eidas/specific/modules/msproxyservice/service/ProxyEidasAttributeRegistry.java +++ b/modules/eidas_proxy-sevice/src/main/java/at/asitplus/eidas/specific/modules/msproxyservice/service/ProxyEidasAttributeRegistry.java @@ -7,6 +7,7 @@ import java.util.Collection; import java.util.Collections; import java.util.List; import java.util.Objects; +import java.util.Optional; import java.util.Set; import java.util.stream.Collectors; import java.util.stream.Stream; @@ -76,6 +77,19 @@ public class ProxyEidasAttributeRegistry { } + /** + * Get all eIDAS attributes that are added by default in case of mandates. + * + * @return {@link Stream} of eIDAS attributes + */ + @NonNull + public Stream getRepresentativeAttributesToAddByDefault() { + return attributeConfiguration.stream() + .filter(el -> el.getType() != null && el.getType().getAutoIncludeWithMandates()) + .map(el -> el.getEidasAttributeName()); + + } + /** * Get IDA attributes for a specific eIDAS attribute. * @@ -95,8 +109,24 @@ public class ProxyEidasAttributeRegistry { .collect(Collectors.toSet()); } - - + + /** + * Get eIDAS related IDA attribute. + * + * @param eidasAttributeName Name of the eIDAS attribute. + * @param withMandates true if mandates are supported, otherwise false + * @return Name of the related IDA attribute if available + */ + public Optional mapEidasAttributeToSpecificIdaAttribute( + String eidasAttributeName, boolean withMandates) { + return attributeConfiguration.stream() + .filter(el -> el.getEidasAttributeName().equals(eidasAttributeName)) + .findFirst() + .map(el -> withMandates ? el.getIdaAttribute().getWithMandates() : el.getIdaAttribute().getBasic()) + .filter(el -> StringUtils.isNotEmpty(el)); + + } + @PostConstruct private void initialize() throws EaafConfigurationException { final String attrConfPath = basicConfig.getBasicConfiguration( diff --git a/modules/eidas_proxy-sevice/src/test/java/at/asitplus/eidas/specific/modules/msproxyservice/test/protocol/ProxyServiceAuthenticationActionTest.java b/modules/eidas_proxy-sevice/src/test/java/at/asitplus/eidas/specific/modules/msproxyservice/test/protocol/ProxyServiceAuthenticationActionTest.java index c41d6c99..d44ffc2d 100644 --- a/modules/eidas_proxy-sevice/src/test/java/at/asitplus/eidas/specific/modules/msproxyservice/test/protocol/ProxyServiceAuthenticationActionTest.java +++ b/modules/eidas_proxy-sevice/src/test/java/at/asitplus/eidas/specific/modules/msproxyservice/test/protocol/ProxyServiceAuthenticationActionTest.java @@ -12,7 +12,6 @@ import java.net.URISyntaxException; import java.net.URLDecoder; import java.time.Instant; import java.util.Arrays; -import java.util.Collections; import java.util.HashMap; import java.util.Map; import java.util.UUID; @@ -35,7 +34,6 @@ 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.core.eidas.EidasConstants; @@ -132,7 +130,7 @@ public class ProxyServiceAuthenticationActionTest { @Test public void missingForwardUrl() { Map attr = new HashMap<>(); - attr.put(MsEidasNodeConstants.ATTR_EIDAS_PERSONAL_IDENTIFIER, + attr.put(PvpAttributeDefinitions.BPK_NAME, "AT+XX:" + RandomStringUtils.randomAlphanumeric(10)); IAuthData authData = generateDummyAuthData(attr , EaafConstants.EIDAS_LOA_HIGH, RandomStringUtils.randomAlphanumeric(10), RandomStringUtils.randomAlphanumeric(10), "1945-04-18", false); @@ -147,8 +145,7 @@ public class ProxyServiceAuthenticationActionTest { @Test public void responseWithoutMandate() throws EaafException, SpecificCommunicationException { Map attr = new HashMap<>(); - attr.put(MsEidasNodeConstants.ATTR_EIDAS_PERSONAL_IDENTIFIER, - "AT+XX:" + RandomStringUtils.randomAlphanumeric(10)); + attr.put(PvpAttributeDefinitions.BPK_NAME, RandomStringUtils.randomAlphanumeric(10)); IAuthData authData = generateDummyAuthData(attr , EaafConstants.EIDAS_LOA_HIGH, RandomStringUtils.randomAlphanumeric(10), RandomStringUtils.randomAlphanumeric(10), "1945-04-18", false); @@ -161,7 +158,7 @@ public class ProxyServiceAuthenticationActionTest { ImmutableAttributeMap respAttr = validateBasicEidasResponse(authData); assertEquals("wrong attr. size", 4, respAttr.size()); checkAttrValue(respAttr, EidasConstants.eIDAS_ATTR_PERSONALIDENTIFIER, - (String) attr.get(MsEidasNodeConstants.ATTR_EIDAS_PERSONAL_IDENTIFIER)); + (String) attr.get(PvpAttributeDefinitions.BPK_NAME)); checkAttrValue(respAttr, EidasConstants.eIDAS_ATTR_CURRENTFAMILYNAME, authData.getFamilyName()); checkAttrValue(respAttr, EidasConstants.eIDAS_ATTR_CURRENTGIVENNAME, authData.getGivenName()); checkAttrValue(respAttr, EidasConstants.eIDAS_ATTR_DATEOFBIRTH, @@ -170,12 +167,89 @@ public class ProxyServiceAuthenticationActionTest { } @Test - public void responseWithNatMandate() throws EaafException, SpecificCommunicationException { + public void responseWithoutMandateAndOptionalAttributesExist() throws EaafException, SpecificCommunicationException { + LightRequest.Builder eidasRequestBuilder = generateBasicLightRequest(); + eidasRequestBuilder.requestedAttributes(ImmutableAttributeMap.builder() + .put(attrRegistry.getCoreAttributeRegistry().getByFriendlyName(EidasConstants.eIDAS_ATTR_PERSONALIDENTIFIER).first()) + .put(attrRegistry.getCoreAttributeRegistry().getByFriendlyName(EidasConstants.eIDAS_ATTR_CURRENTGIVENNAME).first()) + .put(attrRegistry.getCoreAttributeRegistry().getByFriendlyName(EidasConstants.eIDAS_ATTR_CURRENTFAMILYNAME).first()) + .put(attrRegistry.getCoreAttributeRegistry().getByFriendlyName(EidasConstants.eIDAS_ATTR_DATEOFBIRTH).first()) + .put(attrRegistry.getCoreAttributeRegistry().getByName("http://eidas.europa.eu/attributes/naturalperson/BirthName")) + .build()); + pendingReq.setEidasRequest(eidasRequestBuilder.build()); + + Map attr = new HashMap<>(); - attr.put(MsEidasNodeConstants.ATTR_EIDAS_PERSONAL_IDENTIFIER, - "AT+XX:" + RandomStringUtils.randomAlphanumeric(10)); + attr.put(PvpAttributeDefinitions.BPK_NAME, + "AT+XX:" + RandomStringUtils.randomAlphanumeric(10)); + attr.put("ida_birthname", 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", 5, respAttr.size()); + checkAttrValue(respAttr, EidasConstants.eIDAS_ATTR_PERSONALIDENTIFIER, + (String) attr.get(PvpAttributeDefinitions.BPK_NAME)); + checkAttrValue(respAttr, EidasConstants.eIDAS_ATTR_CURRENTFAMILYNAME, authData.getFamilyName()); + checkAttrValue(respAttr, EidasConstants.eIDAS_ATTR_CURRENTGIVENNAME, authData.getGivenName()); + checkAttrValue(respAttr, EidasConstants.eIDAS_ATTR_DATEOFBIRTH, + authData.getDateOfBirth()); + checkAttrValue(respAttr, EidasConstants.eIDAS_ATTR_BIRTHNAME, + (String) attr.get("ida_birthname")); + + } + + @Test + public void responseWithoutMandateAndOptionalAttributesNotExist() throws EaafException, SpecificCommunicationException { + LightRequest.Builder eidasRequestBuilder = generateBasicLightRequest(); + eidasRequestBuilder.requestedAttributes(ImmutableAttributeMap.builder() + .put(attrRegistry.getCoreAttributeRegistry().getByFriendlyName(EidasConstants.eIDAS_ATTR_PERSONALIDENTIFIER).first()) + .put(attrRegistry.getCoreAttributeRegistry().getByFriendlyName(EidasConstants.eIDAS_ATTR_CURRENTGIVENNAME).first()) + .put(attrRegistry.getCoreAttributeRegistry().getByFriendlyName(EidasConstants.eIDAS_ATTR_CURRENTFAMILYNAME).first()) + .put(attrRegistry.getCoreAttributeRegistry().getByFriendlyName(EidasConstants.eIDAS_ATTR_DATEOFBIRTH).first()) + .put(attrRegistry.getCoreAttributeRegistry().getByName("http://eidas.europa.eu/attributes/naturalperson/BirthName")) + .build()); + pendingReq.setEidasRequest(eidasRequestBuilder.build()); + + + Map attr = new HashMap<>(); + attr.put(PvpAttributeDefinitions.BPK_NAME, + "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); - attr.put(MsEidasNodeConstants.ATTR_EIDAS_NAT_MANDATOR_PERSONAL_IDENTIFIER, + ImmutableAttributeMap respAttr = validateBasicEidasResponse(authData); + assertEquals("wrong attr. size", 4, respAttr.size()); + checkAttrValue(respAttr, EidasConstants.eIDAS_ATTR_PERSONALIDENTIFIER, + (String) attr.get(PvpAttributeDefinitions.BPK_NAME)); + checkAttrValue(respAttr, EidasConstants.eIDAS_ATTR_CURRENTFAMILYNAME, authData.getFamilyName()); + checkAttrValue(respAttr, EidasConstants.eIDAS_ATTR_CURRENTGIVENNAME, authData.getGivenName()); + checkAttrValue(respAttr, EidasConstants.eIDAS_ATTR_DATEOFBIRTH, + authData.getDateOfBirth()); + + } + + + @Test + public void responseWithNatMandate() throws EaafException, SpecificCommunicationException { + Map attr = new HashMap<>(); + attr.put(PvpAttributeDefinitions.BPK_NAME, + "AT+XX:" + RandomStringUtils.randomAlphanumeric(10)); + attr.put(PvpAttributeDefinitions.MANDATE_NAT_PER_BPK_NAME, RandomStringUtils.randomAlphabetic(10)); attr.put(PvpAttributeDefinitions.MANDATE_NAT_PER_GIVEN_NAME_NAME, RandomStringUtils.randomAlphabetic(10)); @@ -197,13 +271,13 @@ public class ProxyServiceAuthenticationActionTest { ImmutableAttributeMap respAttr = validateBasicEidasResponse(authData); assertEquals("wrong attr. size", 8, respAttr.size()); checkAttrValue(respAttr, EidasConstants.eIDAS_ATTR_REPRESENTATIVE_PERSONALIDENTIFIER, - (String) attr.get(MsEidasNodeConstants.ATTR_EIDAS_PERSONAL_IDENTIFIER)); + (String) attr.get(PvpAttributeDefinitions.BPK_NAME)); checkAttrValue(respAttr, EidasConstants.eIDAS_ATTR_REPRESENTATIVE_CURRENTFAMILYNAME, authData.getFamilyName()); checkAttrValue(respAttr, EidasConstants.eIDAS_ATTR_REPRESENTATIVE_CURRENTGIVENNAME, authData.getGivenName()); checkAttrValue(respAttr, EidasConstants.eIDAS_ATTR_REPRESENTATIVE_DATEOFBIRTH, authData.getDateOfBirth()); checkAttrValue(respAttr, EidasConstants.eIDAS_ATTR_PERSONALIDENTIFIER, - (String) attr.get(MsEidasNodeConstants.ATTR_EIDAS_NAT_MANDATOR_PERSONAL_IDENTIFIER)); + (String) attr.get(PvpAttributeDefinitions.MANDATE_NAT_PER_BPK_NAME)); checkAttrValue(respAttr, EidasConstants.eIDAS_ATTR_CURRENTFAMILYNAME, (String) attr.get(PvpAttributeDefinitions.MANDATE_NAT_PER_FAMILY_NAME_NAME)); checkAttrValue(respAttr, EidasConstants.eIDAS_ATTR_CURRENTGIVENNAME, @@ -213,19 +287,86 @@ public class ProxyServiceAuthenticationActionTest { } + @Test + public void responseWithNatMandateOptionalAttribute() throws EaafException, SpecificCommunicationException { + LightRequest.Builder eidasRequestBuilder = generateBasicLightRequest(); + eidasRequestBuilder.requestedAttributes(ImmutableAttributeMap.builder() + .put(attrRegistry.getCoreAttributeRegistry().getByFriendlyName(EidasConstants.eIDAS_ATTR_PERSONALIDENTIFIER).first()) + .put(attrRegistry.getCoreAttributeRegistry().getByFriendlyName(EidasConstants.eIDAS_ATTR_CURRENTGIVENNAME).first()) + .put(attrRegistry.getCoreAttributeRegistry().getByFriendlyName(EidasConstants.eIDAS_ATTR_CURRENTFAMILYNAME).first()) + .put(attrRegistry.getCoreAttributeRegistry().getByFriendlyName(EidasConstants.eIDAS_ATTR_DATEOFBIRTH).first()) + .put(attrRegistry.getCoreAttributeRegistry().getByName("http://eidas.europa.eu/attributes/naturalperson/BirthName")) + .build()); + pendingReq.setEidasRequest(eidasRequestBuilder.build()); + + Map attr = new HashMap<>(); + attr.put(PvpAttributeDefinitions.BPK_NAME, + "AT+XX:" + RandomStringUtils.randomAlphanumeric(10)); + attr.put("ida_birthName_mandator", RandomStringUtils.randomAlphanumeric(10)); + attr.put("ida_birthName", RandomStringUtils.randomAlphanumeric(10)); + + attr.put(PvpAttributeDefinitions.MANDATE_NAT_PER_BPK_NAME, + 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", 9, respAttr.size()); + checkAttrValue(respAttr, EidasConstants.eIDAS_ATTR_REPRESENTATIVE_PERSONALIDENTIFIER, + (String) attr.get(PvpAttributeDefinitions.BPK_NAME)); + checkAttrValue(respAttr, EidasConstants.eIDAS_ATTR_REPRESENTATIVE_CURRENTFAMILYNAME, authData.getFamilyName()); + checkAttrValue(respAttr, EidasConstants.eIDAS_ATTR_REPRESENTATIVE_CURRENTGIVENNAME, authData.getGivenName()); + checkAttrValue(respAttr, EidasConstants.eIDAS_ATTR_REPRESENTATIVE_DATEOFBIRTH, authData.getDateOfBirth()); + + checkAttrValue(respAttr, EidasConstants.eIDAS_ATTR_PERSONALIDENTIFIER, + (String) attr.get(PvpAttributeDefinitions.MANDATE_NAT_PER_BPK_NAME)); + checkAttrValue(respAttr, EidasConstants.eIDAS_ATTR_CURRENTFAMILYNAME, + (String) attr.get(PvpAttributeDefinitions.MANDATE_NAT_PER_FAMILY_NAME_NAME)); + checkAttrValue(respAttr, EidasConstants.eIDAS_ATTR_CURRENTGIVENNAME, + (String) attr.get(PvpAttributeDefinitions.MANDATE_NAT_PER_GIVEN_NAME_NAME)); + checkAttrValue(respAttr, EidasConstants.eIDAS_ATTR_DATEOFBIRTH, + (String) attr.get(PvpAttributeDefinitions.MANDATE_NAT_PER_BIRTHDATE_NAME)); + + checkAttrValue(respAttr, EidasConstants.eIDAS_ATTR_BIRTHNAME, + (String) attr.get("ida_birthName_mandator")); + + } + @Test public void responseWithJurMandate() throws EaafException, SpecificCommunicationException { Map attr = new HashMap<>(); - attr.put(MsEidasNodeConstants.ATTR_EIDAS_PERSONAL_IDENTIFIER, + attr.put(PvpAttributeDefinitions.BPK_NAME, "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, + attr.put(PvpAttributeDefinitions.MANDATE_LEG_PER_SOURCE_PIN_NAME, RandomStringUtils.randomAlphabetic(10)); attr.put(PvpAttributeDefinitions.MANDATE_LEG_PER_FULL_NAME_NAME, RandomStringUtils.randomAlphabetic(10)); + LightRequest.Builder eidasRequestBuilder = generateBasicLightRequest(); + eidasRequestBuilder.requestedAttributes(ImmutableAttributeMap.builder() + .put(attrRegistry.getCoreAttributeRegistry().getByFriendlyName(EidasConstants.eIDAS_ATTR_LEGALPERSONIDENTIFIER).first()) + .put(attrRegistry.getCoreAttributeRegistry().getByFriendlyName(EidasConstants.eIDAS_ATTR_LEGALNAME).first()) + .build()); + pendingReq.setEidasRequest(eidasRequestBuilder.build()); + + //perform test SloInformationInterface result = action.processRequest(pendingReq, httpReq, httpResp, authData); @@ -235,13 +376,13 @@ public class ProxyServiceAuthenticationActionTest { ImmutableAttributeMap respAttr = validateBasicEidasResponse(authData); assertEquals("wrong attr. size", 6, respAttr.size()); checkAttrValue(respAttr, EidasConstants.eIDAS_ATTR_REPRESENTATIVE_PERSONALIDENTIFIER, - (String) attr.get(MsEidasNodeConstants.ATTR_EIDAS_PERSONAL_IDENTIFIER)); + (String) attr.get(PvpAttributeDefinitions.BPK_NAME)); checkAttrValue(respAttr, EidasConstants.eIDAS_ATTR_REPRESENTATIVE_CURRENTFAMILYNAME, authData.getFamilyName()); checkAttrValue(respAttr, EidasConstants.eIDAS_ATTR_REPRESENTATIVE_CURRENTGIVENNAME, authData.getGivenName()); checkAttrValue(respAttr, EidasConstants.eIDAS_ATTR_REPRESENTATIVE_DATEOFBIRTH, authData.getDateOfBirth()); checkAttrValue(respAttr, EidasConstants.eIDAS_ATTR_LEGALPERSONIDENTIFIER, - (String) attr.get(MsEidasNodeConstants.ATTR_EIDAS_JUR_MANDATOR_PERSONAL_IDENTIFIER)); + (String) attr.get(PvpAttributeDefinitions.MANDATE_LEG_PER_SOURCE_PIN_NAME)); checkAttrValue(respAttr, EidasConstants.eIDAS_ATTR_LEGALNAME, (String) attr.get(PvpAttributeDefinitions.MANDATE_LEG_PER_FULL_NAME_NAME)); @@ -260,19 +401,12 @@ public class ProxyServiceAuthenticationActionTest { 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(EidasConstants.eIDAS_ATTR_PERSONALIDENTIFIER).first()).build()); - pendingReq.setEidasRequest(eidasRequestBuilder.build()); - - + Map attr = new HashMap<>(); - attr.put(MsEidasNodeConstants.ATTR_EIDAS_PERSONAL_IDENTIFIER, + attr.put(PvpAttributeDefinitions.BPK_NAME, "AT+XX:" + RandomStringUtils.randomAlphanumeric(10)); - attr.put(MsEidasNodeConstants.ATTR_EIDAS_NAT_MANDATOR_PERSONAL_IDENTIFIER, + attr.put(PvpAttributeDefinitions.MANDATE_NAT_PER_BPK_NAME, RandomStringUtils.randomAlphabetic(10)); attr.put(PvpAttributeDefinitions.MANDATE_NAT_PER_GIVEN_NAME_NAME, RandomStringUtils.randomAlphabetic(10)); @@ -306,16 +440,17 @@ public class ProxyServiceAuthenticationActionTest { eidasRequestBuilder.requestedAttributes(ImmutableAttributeMap.builder() .put(attrRegistry.getCoreAttributeRegistry().getByFriendlyName(EidasConstants.eIDAS_ATTR_PERSONALIDENTIFIER).first()) .put(attrRegistry.getCoreAttributeRegistry().getByFriendlyName(EidasConstants.eIDAS_ATTR_LEGALPERSONIDENTIFIER).first()) + .put(attrRegistry.getCoreAttributeRegistry().getByFriendlyName(EidasConstants.eIDAS_ATTR_LEGALNAME).first()) .build()); pendingReq.setEidasRequest(eidasRequestBuilder.build()); Map attr = new HashMap<>(); - attr.put(MsEidasNodeConstants.ATTR_EIDAS_PERSONAL_IDENTIFIER, + attr.put(PvpAttributeDefinitions.BPK_NAME, "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, + attr.put(PvpAttributeDefinitions.MANDATE_LEG_PER_SOURCE_PIN_NAME, RandomStringUtils.randomAlphabetic(10)); attr.put(PvpAttributeDefinitions.MANDATE_LEG_PER_FULL_NAME_NAME, RandomStringUtils.randomAlphabetic(10)); @@ -329,7 +464,7 @@ public class ProxyServiceAuthenticationActionTest { ImmutableAttributeMap respAttr = validateBasicEidasResponse(authData); assertEquals("wrong attr. size", 10, respAttr.size()); checkAttrValue(respAttr, EidasConstants.eIDAS_ATTR_PERSONALIDENTIFIER, - (String) attr.get(MsEidasNodeConstants.ATTR_EIDAS_PERSONAL_IDENTIFIER)); + (String) attr.get(PvpAttributeDefinitions.BPK_NAME)); checkAttrValue(respAttr, EidasConstants.eIDAS_ATTR_CURRENTFAMILYNAME, authData.getFamilyName()); checkAttrValue(respAttr, EidasConstants.eIDAS_ATTR_CURRENTGIVENNAME, authData.getGivenName()); checkAttrValue(respAttr, EidasConstants.eIDAS_ATTR_DATEOFBIRTH, authData.getDateOfBirth()); @@ -344,18 +479,18 @@ public class ProxyServiceAuthenticationActionTest { //request natural person subject only LightRequest.Builder eidasRequestBuilder = generateBasicLightRequest(); eidasRequestBuilder.requestedAttributes(ImmutableAttributeMap.builder() - .put(attrRegistry.getCoreAttributeRegistry().getByFriendlyName( - EidasConstants.eIDAS_ATTR_LEGALPERSONIDENTIFIER).first()) + .put(attrRegistry.getCoreAttributeRegistry().getByFriendlyName(EidasConstants.eIDAS_ATTR_LEGALPERSONIDENTIFIER).first()) + .put(attrRegistry.getCoreAttributeRegistry().getByFriendlyName(EidasConstants.eIDAS_ATTR_LEGALNAME).first()) .build()); pendingReq.setEidasRequest(eidasRequestBuilder.build()); Map attr = new HashMap<>(); - attr.put(MsEidasNodeConstants.ATTR_EIDAS_PERSONAL_IDENTIFIER, + attr.put(PvpAttributeDefinitions.BPK_NAME, "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, + attr.put(PvpAttributeDefinitions.MANDATE_LEG_PER_SOURCE_PIN_NAME, RandomStringUtils.randomAlphabetic(10)); attr.put(PvpAttributeDefinitions.MANDATE_LEG_PER_FULL_NAME_NAME, RandomStringUtils.randomAlphabetic(10)); @@ -390,7 +525,7 @@ public class ProxyServiceAuthenticationActionTest { } private IAuthData generateDummyAuthData() { - return generateDummyAuthData(Collections.emptyMap(), EaafConstants.EIDAS_LOA_LOW, + return generateDummyAuthData(new HashMap<>(), EaafConstants.EIDAS_LOA_LOW, RandomStringUtils.randomAlphanumeric(10), RandomStringUtils.randomAlphanumeric(10), "1940-01-01", false); } @@ -445,12 +580,22 @@ public class ProxyServiceAuthenticationActionTest { .spCountryCode(RandomStringUtils.randomAlphabetic(2).toUpperCase()) .spType("public") .requesterId(RandomStringUtils.randomAlphanumeric(10)) - .providerName(RandomStringUtils.randomAlphanumeric(10)); - + .providerName(RandomStringUtils.randomAlphanumeric(10)) + .requestedAttributes(ImmutableAttributeMap.builder() + .put(attrRegistry.getCoreAttributeRegistry().getByFriendlyName(EidasConstants.eIDAS_ATTR_PERSONALIDENTIFIER).first()) + .put(attrRegistry.getCoreAttributeRegistry().getByFriendlyName(EidasConstants.eIDAS_ATTR_CURRENTGIVENNAME).first()) + .put(attrRegistry.getCoreAttributeRegistry().getByFriendlyName(EidasConstants.eIDAS_ATTR_CURRENTFAMILYNAME).first()) + .put(attrRegistry.getCoreAttributeRegistry().getByFriendlyName(EidasConstants.eIDAS_ATTR_DATEOFBIRTH).first()) + .build() + ); } private IAuthData generateDummyAuthData(Map attrs, String loa, String familyName, String givenName, String dateOfBirth, boolean useMandates) { + attrs.put(PvpAttributeDefinitions.BIRTHDATE_NAME, dateOfBirth); + attrs.put(PvpAttributeDefinitions.GIVEN_NAME_NAME, givenName); + attrs.put(PvpAttributeDefinitions.PRINCIPAL_NAME_NAME, familyName); + return new IEidAuthData() { @Override diff --git a/modules/eidas_proxy-sevice/src/test/java/at/asitplus/eidas/specific/modules/msproxyservice/test/services/ProxyEidasAttributeRegistryTest.java b/modules/eidas_proxy-sevice/src/test/java/at/asitplus/eidas/specific/modules/msproxyservice/test/services/ProxyEidasAttributeRegistryTest.java index d3e787bb..8d417c1a 100644 --- a/modules/eidas_proxy-sevice/src/test/java/at/asitplus/eidas/specific/modules/msproxyservice/test/services/ProxyEidasAttributeRegistryTest.java +++ b/modules/eidas_proxy-sevice/src/test/java/at/asitplus/eidas/specific/modules/msproxyservice/test/services/ProxyEidasAttributeRegistryTest.java @@ -1,11 +1,13 @@ package at.asitplus.eidas.specific.modules.msproxyservice.test.services; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; import java.util.Arrays; import java.util.Collections; import java.util.List; +import java.util.Optional; import java.util.Set; import org.apache.commons.lang3.RandomStringUtils; @@ -92,6 +94,39 @@ public class ProxyEidasAttributeRegistryTest { } + @Test + public void attributeResponseMapping() { + assertFalse("find wrong IDA mapping", attrRegistry.mapEidasAttributeToSpecificIdaAttribute( + "http://eidas.europa.eu/attributes/naturalperson/PlaceOfBirth", false).isPresent()); + assertFalse("find wrong IDA mapping", attrRegistry.mapEidasAttributeToSpecificIdaAttribute( + "http://eidas.europa.eu/attributes/naturalperson/PlaceOfBirth", true).isPresent()); + + + Optional attr1 = attrRegistry.mapEidasAttributeToSpecificIdaAttribute( + "http://eidas.europa.eu/attributes/naturalperson/BirthName", false); + assertTrue("find wrong IDA mapping", attr1.isPresent()); + assertEquals("find wrong IDA mapping value", "ida_birthname", attr1.get()); + + Optional attr2 = attrRegistry.mapEidasAttributeToSpecificIdaAttribute( + "http://eidas.europa.eu/attributes/naturalperson/BirthName", true); + assertTrue("find wrong IDA mapping", attr2.isPresent()); + assertEquals("find wrong IDA mapping value", "ida_birthName_mandator", attr2.get()); + + + assertTrue("find wrong IDA mapping", attrRegistry.mapEidasAttributeToSpecificIdaAttribute( + "http://eidas.europa.eu/attributes/naturalperson/PersonIdentifier", false).isPresent()); + assertTrue("find wrong IDA mapping", attrRegistry.mapEidasAttributeToSpecificIdaAttribute( + "http://eidas.europa.eu/attributes/naturalperson/PersonIdentifier", true).isPresent()); + + } + + @Test + public void defaultRepresentativeAttributes() { + assertEquals("wrong number of rep. attributes", 4, + attrRegistry.getRepresentativeAttributesToAddByDefault().count()); + + } + private void checkAttributeMapping(String eidasAttr, boolean withMandates, List idaAttributes) { @NonNull Set idaAttrResult = attrRegistry.getIdaAttributesForEidasAttribute(eidasAttr, withMandates); diff --git a/modules/eidas_proxy-sevice/src/test/resources/config/idaAttributeMapping.json b/modules/eidas_proxy-sevice/src/test/resources/config/idaAttributeMapping.json index 2d375acb..7e41d8f6 100644 --- a/modules/eidas_proxy-sevice/src/test/resources/config/idaAttributeMapping.json +++ b/modules/eidas_proxy-sevice/src/test/resources/config/idaAttributeMapping.json @@ -6,7 +6,8 @@ "withMandates": "urn:oid:1.2.40.0.10.2.1.1.261.98" }, "type": { - "mds": true + "mds": true, + "autoIncludeWithMandates": false } }, { @@ -16,7 +17,8 @@ "withMandates": "urn:oid:1.2.40.0.10.2.1.1.261.78" }, "type": { - "mds": true + "mds": true, + "autoIncludeWithMandates": false } }, { @@ -26,7 +28,8 @@ "withMandates": "urn:oid:1.2.40.0.10.2.1.1.261.80" }, "type": { - "mds": true + "mds": true, + "autoIncludeWithMandates": false } }, { @@ -36,21 +39,27 @@ "withMandates": "urn:oid:1.2.40.0.10.2.1.1.261.82" }, "type": { - "mds": true + "mds": true, + "autoIncludeWithMandates": false } }, { "eidasAttribute": "http://eidas.europa.eu/attributes/naturalperson/PlaceOfBirth", "idaAttribute": {}, "type": { - "mds": false + "mds": false, + "autoIncludeWithMandates": false } }, { "eidasAttribute": "http://eidas.europa.eu/attributes/naturalperson/BirthName", - "idaAttribute": {}, + "idaAttribute": { + "basic": "ida_birthname", + "withMandates": "ida_birthName_mandator" + }, "type": { - "mds": false + "mds": false, + "autoIncludeWithMandates": false } }, { @@ -65,7 +74,8 @@ "urn:oid:1.2.40.0.10.2.1.1.55" ], "type": { - "mds": true + "mds": true, + "autoIncludeWithMandates": false } }, { @@ -74,7 +84,8 @@ "withMandates": "urn:oid:1.2.40.0.10.2.1.1.261.84" }, "type": { - "mds": true + "mds": true, + "autoIncludeWithMandates": false } }, { @@ -83,7 +94,8 @@ "withMandates": "urn:oid:1.2.40.0.10.2.1.1.149" }, "type": { - "mds": true + "mds": true, + "autoIncludeWithMandates": true } }, { @@ -92,7 +104,8 @@ "withMandates": "urn:oid:1.2.40.0.10.2.1.1.261.20" }, "type": { - "mds": true + "mds": true, + "autoIncludeWithMandates": true } }, { @@ -101,7 +114,8 @@ "withMandates": "urn:oid:2.5.4.42" }, "type": { - "mds": true + "mds": true, + "autoIncludeWithMandates": true } }, { @@ -110,7 +124,8 @@ "withMandates": "urn:oid:1.2.40.0.10.2.1.1.55" }, "type": { - "mds": true + "mds": true, + "autoIncludeWithMandates": true } }, { @@ -120,7 +135,8 @@ "withMandates": "urn:oid:1.2.40.0.10.2.1.1.261.32" }, "type": { - "mds": false + "mds": false, + "autoIncludeWithMandates": false } }, { @@ -130,7 +146,8 @@ "withMandates": "urn:oid:1.2.40.0.10.2.1.1.261.108" }, "type": { - "mds": false + "mds": false, + "autoIncludeWithMandates": false } }, { @@ -139,7 +156,8 @@ "withMandates": "urn:oid:1.2.40.0.10.2.1.1.261.68" }, "type": { - "mds": false + "mds": false, + "autoIncludeWithMandates": false } }, { @@ -148,7 +166,8 @@ "withMandates": "urn:oid:1.2.40.0.10.2.1.1.261.106" }, "type": { - "mds": false + "mds": false, + "autoIncludeWithMandates": false } }, { @@ -157,7 +176,8 @@ "withMandates": "urn:oid:1.2.40.0.10.2.1.1.261.106" }, "type": { - "mds": false + "mds": false, + "autoIncludeWithMandates": false } } ] \ No newline at end of file diff --git a/ms_specific_connector/src/main/resources/specific_eIDAS_connector.beans.xml b/ms_specific_connector/src/main/resources/specific_eIDAS_connector.beans.xml index 9861a7c6..0757327a 100644 --- a/ms_specific_connector/src/main/resources/specific_eIDAS_connector.beans.xml +++ b/ms_specific_connector/src/main/resources/specific_eIDAS_connector.beans.xml @@ -14,6 +14,9 @@ + + diff --git a/ms_specific_proxyservice/src/main/java/at/asitplus/eidas/specific/proxy/builder/ProxyAuthenticationDataBuilder.java b/ms_specific_proxyservice/src/main/java/at/asitplus/eidas/specific/proxy/builder/ProxyAuthenticationDataBuilder.java new file mode 100644 index 00000000..bc7f88d4 --- /dev/null +++ b/ms_specific_proxyservice/src/main/java/at/asitplus/eidas/specific/proxy/builder/ProxyAuthenticationDataBuilder.java @@ -0,0 +1,38 @@ +package at.asitplus.eidas.specific.proxy.builder; + +import at.asitplus.eidas.specific.core.builder.AuthenticationDataBuilder; +import at.gv.egiz.eaaf.core.api.data.EaafConstants; +import lombok.extern.slf4j.Slf4j; + +/** + * eIDAS Proxy-Service specific authentication-data builder. + * + * @author tlenz + * + */ +@Slf4j +public class ProxyAuthenticationDataBuilder extends AuthenticationDataBuilder { + + private static final String PLUS = "+"; + + @Override + protected String customizeLegalPersonSourcePin(String sourcePin, String sourcePinType) { + String sectorType = sourcePinType.substring((EaafConstants.URN_PREFIX_BASEID + PLUS).length()); + return sectorType + PLUS + sourcePin; + + } + + @Override + protected String customizeBpkAttribute(String pvpBpkAttrValue) { + final String[] split = pvpBpkAttrValue.split(":", 2); + if (split.length == 2) { + log.debug("Remove prefix from bPK attribute to transform it into eIDAS-Node format"); + return split[1]; + + } else { + log.warn("PVP bPK attribute: {} has wrong format. Use it as it is.", pvpBpkAttrValue); + return pvpBpkAttrValue; + + } + } +} diff --git a/ms_specific_proxyservice/src/main/resources/specific_eIDAS_proxy.beans.xml b/ms_specific_proxyservice/src/main/resources/specific_eIDAS_proxy.beans.xml index 5633cb0e..cc4c904e 100644 --- a/ms_specific_proxyservice/src/main/resources/specific_eIDAS_proxy.beans.xml +++ b/ms_specific_proxyservice/src/main/resources/specific_eIDAS_proxy.beans.xml @@ -13,6 +13,9 @@ + + diff --git a/ms_specific_proxyservice/src/test/java/at/asitplus/eidas/specific/proxy/test/builder/ProxyAuthenticationDataBuilderTest.java b/ms_specific_proxyservice/src/test/java/at/asitplus/eidas/specific/proxy/test/builder/ProxyAuthenticationDataBuilderTest.java new file mode 100644 index 00000000..ee2c8d8c --- /dev/null +++ b/ms_specific_proxyservice/src/test/java/at/asitplus/eidas/specific/proxy/test/builder/ProxyAuthenticationDataBuilderTest.java @@ -0,0 +1,395 @@ +package at.asitplus.eidas.specific.proxy.test.builder; + +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.assertTrue; + +import java.lang.reflect.Field; +import java.util.HashMap; +import java.util.Map; + +import org.apache.commons.lang3.RandomStringUtils; +import org.apache.commons.lang3.RandomUtils; +import org.apache.ignite.Ignition; +import org.junit.AfterClass; +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.boot.test.context.SpringBootTest; +import org.springframework.context.i18n.LocaleContextHolder; +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.ActiveProfiles; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.TestPropertySource; +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.Sets; + +import at.asitplus.eidas.specific.core.MsEidasNodeConstants; +import at.asitplus.eidas.specific.core.builder.AuthenticationDataBuilder; +import at.asitplus.eidas.specific.core.config.ServiceProviderConfiguration; +import at.gv.egiz.components.spring.api.SpringBootApplicationContextInitializer; +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.IAuthData; +import at.gv.egiz.eaaf.core.api.idp.IConfiguration; +import at.gv.egiz.eaaf.core.exceptions.EaafAuthenticationException; +import at.gv.egiz.eaaf.core.exceptions.EaafStorageException; +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.module.test.TestRequestImpl; +import at.gv.egiz.eaaf.modules.pvp2.impl.opensaml.initialize.EaafOpenSaml3xInitializer; +import eu.eidas.auth.cache.IgniteInstanceInitializerSpecificCommunication; +import lombok.SneakyThrows; +import net.shibboleth.utilities.java.support.component.ComponentInitializationException; + +@RunWith(SpringJUnit4ClassRunner.class) +@SpringBootTest +@ContextConfiguration(initializers = { + org.springframework.boot.context.config.DelegatingApplicationContextInitializer.class, + SpringBootApplicationContextInitializer.class + }) +@TestPropertySource(locations = { "file:src/test/resources/config/junit_config_1_springboot.properties" }) +@DirtiesContext(classMode = ClassMode.AFTER_CLASS) +@ActiveProfiles(profiles = {"JUNIT", "jUnitTestMode"}) +public class ProxyAuthenticationDataBuilderTest { + + + @Autowired + private AuthenticationDataBuilder authenticationDataBuilder; + + @Autowired(required = true) + private IConfiguration basicConfig; + + private MockHttpServletRequest httpReq; + private MockHttpServletResponse httpResp; + private TestRequestImpl pendingReq; + + private Map spConfig; + private ServiceProviderConfiguration oaParam; + + 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"); + + //eIDAS Ref. Impl. properties + System.setProperty("EIDAS_CONFIG_REPOSITORY", current.substring("file:".length()) + + "../basicConfig/eIDAS/"); + System.setProperty("SPECIFIC_CONNECTOR_CONFIG_REPOSITORY", current.substring("file:".length()) + + "../basicConfig/eIDAS/"); + System.setProperty("SPECIFIC_PROXY_SERVICE_CONFIG_REPOSITORY", current.substring("file:".length()) + + "../basicConfig/eIDAS/"); + + EaafOpenSaml3xInitializer.eaafInitialize(); + } + + /** + * Test shut-down. + * + * @throws Exception In case of an error + */ + @AfterClass + @SneakyThrows + public static void closeIgniteNode() { + System.out.println("Closiong Ignite Node ... "); + Ignition.stopAll(true); + + //set Ignite-node holder to 'null' because static holders are shared between different tests + final Field field = IgniteInstanceInitializerSpecificCommunication.class.getDeclaredField("instance"); + field.setAccessible(true); + field.set(null, null); + + } + + @Before + @SneakyThrows + 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 ServiceProviderConfiguration(spConfig, basicConfig); + oaParam.setBpkTargetIdentifier("urn:publicid:gv.at:cdid+XX"); + + 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) + .setGenericDataToSession(MsEidasNodeConstants.AUTH_DATA_SZR_AUTHBLOCK, authBlock); + pendingReq.getSessionData(AuthProcessDataWrapper.class) + .setGenericDataToSession(MsEidasNodeConstants.AUTH_DATA_EIDAS_BIND, eidasBind); + 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)); + + LocaleContextHolder.resetLocaleContext(); + + } + + @Test + @SneakyThrows + public void eidasProxyModeSimple() throws EaafAuthenticationException { + // initialize state + pendingReq = new TestRequestImpl(); + pendingReq.setAuthUrl("https://localhost/ms_connector"); + pendingReq.setPendingReqId(RandomStringUtils.randomAlphanumeric(10)); + pendingReq.setPiiTransactionId(RandomStringUtils.randomAlphanumeric(10)); + pendingReq.setSpConfig(oaParam); + boolean isTestIdentity = RandomUtils.nextBoolean(); + + pendingReq.getSessionData(AuthProcessDataWrapper.class).setEidProcess(true); + pendingReq.getSessionData(AuthProcessDataWrapper.class).setForeigner(false); + + String bpk = RandomStringUtils.randomAlphanumeric(10); + pendingReq.getSessionData(AuthProcessDataWrapper.class).setGenericDataToSession( + PvpAttributeDefinitions.BPK_NAME, "eidas+AT+XX:" + bpk); + pendingReq.getSessionData(AuthProcessDataWrapper.class).setGenericDataToSession( + PvpAttributeDefinitions.GIVEN_NAME_NAME, "Max"); + pendingReq.getSessionData(AuthProcessDataWrapper.class).setGenericDataToSession( + PvpAttributeDefinitions.PRINCIPAL_NAME_NAME, "Mustermann"); + pendingReq.getSessionData(AuthProcessDataWrapper.class).setGenericDataToSession( + PvpAttributeDefinitions.BIRTHDATE_NAME, "1940-01-01"); + pendingReq.getSessionData(AuthProcessDataWrapper.class).setGenericDataToSession( + PvpAttributeDefinitions.EID_CITIZEN_EIDAS_QAA_LEVEL_NAME, + "http://eidas.europa.eu/LoA/high"); + pendingReq.getSessionData(AuthProcessDataWrapper.class).setGenericDataToSession( + PvpAttributeDefinitions.EID_ISSUING_NATION_NAME, + RandomStringUtils.randomAlphabetic(2)); + + String randAttr = RandomStringUtils.randomAlphabetic(10); + pendingReq.getSessionData(AuthProcessDataWrapper.class).setGenericDataToSession( + randAttr, RandomStringUtils.randomAlphabetic(10)); + + oaParam.setRequestedAttributes(Sets.newHashSet(randAttr, + PvpAttributeDefinitions.BPK_NAME, + PvpAttributeDefinitions.GIVEN_NAME_NAME, + PvpAttributeDefinitions.PRINCIPAL_NAME_NAME, + PvpAttributeDefinitions.BIRTHDATE_NAME, + PvpAttributeDefinitions.EID_CITIZEN_EIDAS_QAA_LEVEL_NAME, + PvpAttributeDefinitions.EID_ISSUING_NATION_NAME)); + + + // 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.assertNotNull("LoA null", authData.getEidasQaaLevel()); + + Assert.assertEquals("FamilyName", "Mustermann", authData.getFamilyName()); + Assert.assertEquals("GivenName", "Max", authData.getGivenName()); + Assert.assertEquals("DateOfBirth", "1940-01-01", authData.getDateOfBirth()); + + Assert.assertEquals("LoA", "http://eidas.europa.eu/LoA/high", authData.getEidasQaaLevel()); + Assert.assertEquals("EID-ISSUING-NATION", + pendingReq.getSessionData(AuthProcessDataWrapper.class).getGenericDataFromSession( + PvpAttributeDefinitions.EID_ISSUING_NATION_NAME), + authData.getCiticenCountryCode()); + + checkGenericAttribute(authData, PvpAttributeDefinitions.BPK_NAME, bpk); + checkGenericAttribute(authData, PvpAttributeDefinitions.GIVEN_NAME_NAME, "Max"); + checkGenericAttribute(authData, PvpAttributeDefinitions.PRINCIPAL_NAME_NAME, "Mustermann"); + checkGenericAttribute(authData, PvpAttributeDefinitions.BIRTHDATE_NAME, "1940-01-01"); + + Assert.assertEquals("random optional attr.", + pendingReq.getSessionData(AuthProcessDataWrapper.class).getGenericDataFromSession( + randAttr), + authData.getGenericData(randAttr, String.class)); + + } + + + @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); + + oaParam.setRequestedAttributes(Sets.newHashSet( + PvpAttributeDefinitions.MANDATE_NAT_PER_GIVEN_NAME_NAME, + PvpAttributeDefinitions.MANDATE_NAT_PER_FAMILY_NAME_NAME, + PvpAttributeDefinitions.MANDATE_NAT_PER_BIRTHDATE_NAME, + PvpAttributeDefinitions.MANDATE_NAT_PER_BPK_NAME)); + + // 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, PvpAttributeDefinitions.MANDATE_NAT_PER_BPK_NAME, 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); + + oaParam.setRequestedAttributes(Sets.newHashSet( + PvpAttributeDefinitions.MANDATE_NAT_PER_GIVEN_NAME_NAME, + PvpAttributeDefinitions.MANDATE_NAT_PER_FAMILY_NAME_NAME, + PvpAttributeDefinitions.MANDATE_NAT_PER_BIRTHDATE_NAME, + PvpAttributeDefinitions.MANDATE_NAT_PER_BPK_NAME)); + + // 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, PvpAttributeDefinitions.MANDATE_NAT_PER_BPK_NAME, bpkMandate); + + } + + @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"); + + oaParam.setRequestedAttributes(Sets.newHashSet( + PvpAttributeDefinitions.MANDATE_LEG_PER_FULL_NAME_NAME, + PvpAttributeDefinitions.MANDATE_LEG_PER_SOURCE_PIN_NAME, + PvpAttributeDefinitions.MANDATE_LEG_PER_SOURCE_PIN_TYPE_NAME)); + + // 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, PvpAttributeDefinitions.MANDATE_LEG_PER_SOURCE_PIN_NAME, "XFN+" + sourcePinMandate); + + } + + 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(PvpAttributeDefinitions.BPK_NAME, 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)); + + } + +} diff --git a/ms_specific_proxyservice/src/test/resources/config/junit_config_1_springboot.properties b/ms_specific_proxyservice/src/test/resources/config/junit_config_1_springboot.properties index 8cd77046..47d50191 100644 --- a/ms_specific_proxyservice/src/test/resources/config/junit_config_1_springboot.properties +++ b/ms_specific_proxyservice/src/test/resources/config/junit_config_1_springboot.properties @@ -69,7 +69,7 @@ eidas.ms.configuration.pvp.enable.entitycategories=false ############################################################################# ## MS-speccific eIDAS-Proxy-Service configuration - +eidas.ms.auth.eIDAS.proxy.attribute.mapping.config=./../../../../../basicConfig/ms-proxyservice/misc/idaAttributeMapping.json #### eIDAS ms-specific Proxy-Service configuration eidas.ms.auth.eIDAS.node_v2.proxy.entityId=ownSpecificProxy diff --git a/pom.xml b/pom.xml index 309fab68..e469f680 100644 --- a/pom.xml +++ b/pom.xml @@ -22,7 +22,7 @@ 0.3 0.4 - 1.3.2 + 1.3.3-SNAPSHOT 2.5.13 2.5.6 -- cgit v1.2.3 From 2d3c6f1003a2c8cb6f5fc5f7573f7d041e88a453 Mon Sep 17 00:00:00 2001 From: Thomas <> Date: Wed, 8 Jun 2022 14:42:40 +0200 Subject: build(core): optimize package naming and dependency inclusion --- modules/core_common_webapp/pom.xml | 4 ---- ms_specific_connector/pom.xml | 2 +- 2 files changed, 1 insertion(+), 5 deletions(-) (limited to 'modules/core_common_webapp') diff --git a/modules/core_common_webapp/pom.xml b/modules/core_common_webapp/pom.xml index b69585fb..c780a367 100644 --- a/modules/core_common_webapp/pom.xml +++ b/modules/core_common_webapp/pom.xml @@ -21,10 +21,6 @@ at.asitplus.eidas.ms_specific core_common_lib - - at.asitplus.eidas.ms_specific.modules - eidas_proxy-sevice - at.gv.egiz.eaaf diff --git a/ms_specific_connector/pom.xml b/ms_specific_connector/pom.xml index 17a54b5f..9aca807b 100644 --- a/ms_specific_connector/pom.xml +++ b/ms_specific_connector/pom.xml @@ -12,7 +12,7 @@ at.asitplus.eidas.ms_specific ms_specific_connector war - MS-specific eIDAS Service + MS-specific Connector http://maven.apache.org -- cgit v1.2.3 From cab2ab4ddb85b305d77798073b868cf42a7e0111 Mon Sep 17 00:00:00 2001 From: Thomas <> Date: Wed, 8 Jun 2022 14:56:42 +0200 Subject: chore(core): minory style, test and validation fixes --- .../specific/core/config/ServiceProviderConfiguration.java | 2 +- .../specific/core/builder/AuthenticationDataBuilder.java | 8 ++++---- modules/eidas_proxy-sevice/checks/spotbugs-exclude.xml | 11 +++++++++++ .../specific/modules/msproxyservice/dto/attributes/Type.java | 11 ++++++++--- .../test/protocol/EidasProxyServiceControllerTest.java | 2 +- .../eidas/specific/proxy/test/FullStartUpAndProcessTest.java | 2 +- 6 files changed, 26 insertions(+), 10 deletions(-) (limited to 'modules/core_common_webapp') 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 index 2ecbf7d0..d2177323 100644 --- 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 @@ -55,7 +55,7 @@ public class ServiceProviderConfiguration extends SpConfigurationImpl { private List mandateProfiles; /** - * IDA specific requested attributes + * IDA specific requested attributes. */ @Getter @Setter 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 index 673b8ef5..5a8992b5 100644 --- 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 @@ -102,7 +102,7 @@ public class AuthenticationDataBuilder extends AbstractAuthenticationDataBuilder buildNatPersonInfos((EidAuthenticationData) authData, authProcessData); // handle mandate informations - buildMandateInformation((EidAuthenticationData) authData, pendingReq, authProcessData); + buildMandateInformation((EidAuthenticationData) authData, authProcessData); } else { throw new RuntimeException("Can not inject PiiTransactionId because AuthData is of unknown type: " @@ -172,7 +172,7 @@ public class AuthenticationDataBuilder extends AbstractAuthenticationDataBuilder } } - private void buildMandateInformation(EidAuthenticationData authData, IRequest pendingReq, + private void buildMandateInformation(EidAuthenticationData authData, EidAuthProcessDataWrapper authProcessData) throws EaafAuthenticationException, EaafBuilderException, EaafStorageException { authData.setUseMandate(authProcessData.isMandateUsed()); @@ -182,7 +182,7 @@ public class AuthenticationDataBuilder extends AbstractAuthenticationDataBuilder buildMandateInformationForEidasIncoming(); } else { - buildMandateInformationForEidasOutgoing(authData, pendingReq, authProcessData); + buildMandateInformationForEidasOutgoing(authData, authProcessData); } } @@ -204,7 +204,7 @@ public class AuthenticationDataBuilder extends AbstractAuthenticationDataBuilder } - private void buildMandateInformationForEidasOutgoing(EidAuthenticationData authData, IRequest pendingReq, + private void buildMandateInformationForEidasOutgoing(EidAuthenticationData authData, EidAuthProcessDataWrapper authProcessData) throws EaafAuthenticationException, EaafBuilderException, EaafStorageException { log.debug("Find eIDAS outgoing process. Generated mandate-information for other country ... "); diff --git a/modules/eidas_proxy-sevice/checks/spotbugs-exclude.xml b/modules/eidas_proxy-sevice/checks/spotbugs-exclude.xml index cdc9fa95..22dbaa13 100644 --- a/modules/eidas_proxy-sevice/checks/spotbugs-exclude.xml +++ b/modules/eidas_proxy-sevice/checks/spotbugs-exclude.xml @@ -16,5 +16,16 @@ + + + + + + + + + + + diff --git a/modules/eidas_proxy-sevice/src/main/java/at/asitplus/eidas/specific/modules/msproxyservice/dto/attributes/Type.java b/modules/eidas_proxy-sevice/src/main/java/at/asitplus/eidas/specific/modules/msproxyservice/dto/attributes/Type.java index f66bb799..6a06a5b5 100644 --- a/modules/eidas_proxy-sevice/src/main/java/at/asitplus/eidas/specific/modules/msproxyservice/dto/attributes/Type.java +++ b/modules/eidas_proxy-sevice/src/main/java/at/asitplus/eidas/specific/modules/msproxyservice/dto/attributes/Type.java @@ -22,8 +22,7 @@ import lombok.Data; public class Type { /** - * true if this attribute is part of MDS, otherwise - * false + * true if this attribute is part of MDS, otherwise false. */ @JsonProperty("mds") private Boolean mds; @@ -50,7 +49,7 @@ public class Type { NONE("none"); private final String value; - private final static Map CONSTANTS = new HashMap<>(); + private static final Map CONSTANTS = new HashMap<>(); static { for (final Type.Mandator c : values()) { @@ -72,6 +71,12 @@ public class Type { return this.value; } + /** + * Build {@link Mandator} from textual representation. + * + * @param value textual representation + * @return Type of the mandator + */ @JsonCreator public static Type.Mandator fromValue(String value) { final Type.Mandator constant = CONSTANTS.get(value); diff --git a/modules/eidas_proxy-sevice/src/test/java/at/asitplus/eidas/specific/modules/msproxyservice/test/protocol/EidasProxyServiceControllerTest.java b/modules/eidas_proxy-sevice/src/test/java/at/asitplus/eidas/specific/modules/msproxyservice/test/protocol/EidasProxyServiceControllerTest.java index ef1abbcd..b491c2bf 100644 --- a/modules/eidas_proxy-sevice/src/test/java/at/asitplus/eidas/specific/modules/msproxyservice/test/protocol/EidasProxyServiceControllerTest.java +++ b/modules/eidas_proxy-sevice/src/test/java/at/asitplus/eidas/specific/modules/msproxyservice/test/protocol/EidasProxyServiceControllerTest.java @@ -329,7 +329,7 @@ public class EidasProxyServiceControllerTest { assertTrue("mandateprofiles not empty", spConfig.getMandateProfiles().isEmpty()); assertEquals("MandateMode", SpMandateModes.NONE, spConfig.getMandateMode()); - assertEquals("requested IDA attributes", 3, spConfig.getRequestedAttributes().size()); + assertEquals("requested IDA attributes", 4, spConfig.getRequestedAttributes().size()); } diff --git a/ms_specific_proxyservice/src/test/java/at/asitplus/eidas/specific/proxy/test/FullStartUpAndProcessTest.java b/ms_specific_proxyservice/src/test/java/at/asitplus/eidas/specific/proxy/test/FullStartUpAndProcessTest.java index bc6f5317..2fe7ee05 100644 --- a/ms_specific_proxyservice/src/test/java/at/asitplus/eidas/specific/proxy/test/FullStartUpAndProcessTest.java +++ b/ms_specific_proxyservice/src/test/java/at/asitplus/eidas/specific/proxy/test/FullStartUpAndProcessTest.java @@ -384,7 +384,7 @@ public class FullStartUpAndProcessTest { assertEquals("wrong number of extension elements", 1, authnReq.getExtensions().getOrderedChildren().size()); assertEquals("wrong number of requested attributes", - 4, authnReq.getExtensions().getOrderedChildren().get(0).getOrderedChildren().size()); + 5, authnReq.getExtensions().getOrderedChildren().get(0).getOrderedChildren().size()); return authnReq.getID(); } -- cgit v1.2.3 From ac8f3011f2278c1c02e59f7cc1054b7d0168b034 Mon Sep 17 00:00:00 2001 From: Thomas <> Date: Thu, 7 Jul 2022 11:43:09 +0200 Subject: chore(cache): catch a more generic exception in Transaction-Cache health check --- .../specific/core/storage/EidasCacheTransactionStoreDecorator.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'modules/core_common_webapp') 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 index 5a59a4e0..44547d95 100644 --- 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 @@ -63,7 +63,7 @@ public class EidasCacheTransactionStoreDecorator implements ITransactionStorage, } - } catch (final EaafException e) { + } catch (final Exception e) { log.warn("Montioring: Can not read/write to storage.", e); return Health.down().down(e).build(); -- cgit v1.2.3