diff options
author | Thomas <> | 2022-03-08 19:06:10 +0100 |
---|---|---|
committer | Thomas <> | 2022-03-08 19:06:10 +0100 |
commit | 7bf7c3c03fd3a1efeaf3f8e3dd75922e2f5f9921 (patch) | |
tree | 6e4ec82475f4f30275d3e0a0305ad3c2d340e0d3 /modules/eidas_proxy-sevice/src/main | |
parent | 300bd1b44f521a2b33c259be1f8d21eba58c1a31 (diff) | |
download | National_eIDAS_Gateway-7bf7c3c03fd3a1efeaf3f8e3dd75922e2f5f9921.tar.gz National_eIDAS_Gateway-7bf7c3c03fd3a1efeaf3f8e3dd75922e2f5f9921.tar.bz2 National_eIDAS_Gateway-7bf7c3c03fd3a1efeaf3f8e3dd75922e2f5f9921.zip |
refactor(core): move all project libs into sub-project 'modules'
Diffstat (limited to 'modules/eidas_proxy-sevice/src/main')
11 files changed, 1080 insertions, 0 deletions
diff --git a/modules/eidas_proxy-sevice/src/main/java/at/asitplus/eidas/specific/modules/msproxyservice/EidasProxyMessageSource.java b/modules/eidas_proxy-sevice/src/main/java/at/asitplus/eidas/specific/modules/msproxyservice/EidasProxyMessageSource.java new file mode 100644 index 00000000..23390da8 --- /dev/null +++ b/modules/eidas_proxy-sevice/src/main/java/at/asitplus/eidas/specific/modules/msproxyservice/EidasProxyMessageSource.java @@ -0,0 +1,22 @@ +package at.asitplus.eidas.specific.modules.msproxyservice; + +import java.util.Arrays; +import java.util.List; + +import at.gv.egiz.eaaf.core.api.logging.IMessageSourceLocation; + +/** + * i18n Message-Source for eIDAS Proxy-Service messages. + * + * @author tlenz + * + */ +public class EidasProxyMessageSource implements IMessageSourceLocation { + + @Override + public List<String> getMessageSourceLocation() { + return Arrays.asList("classpath:messages/eidasproxy_messages"); + + } + +} diff --git a/modules/eidas_proxy-sevice/src/main/java/at/asitplus/eidas/specific/modules/msproxyservice/MsProxyServiceConstants.java b/modules/eidas_proxy-sevice/src/main/java/at/asitplus/eidas/specific/modules/msproxyservice/MsProxyServiceConstants.java new file mode 100644 index 00000000..f6a88aa3 --- /dev/null +++ b/modules/eidas_proxy-sevice/src/main/java/at/asitplus/eidas/specific/modules/msproxyservice/MsProxyServiceConstants.java @@ -0,0 +1,54 @@ +package at.asitplus.eidas.specific.modules.msproxyservice; + +import at.asitplus.eidas.specific.modules.auth.eidas.v2.Constants; +import at.gv.egiz.eaaf.core.api.data.EaafConfigConstants; + +/** + * Constants for MS-specific eIDAS Proxy-Service. + * + * @author tlenz + * + */ +public class MsProxyServiceConstants { + + // general constants + public static final String TEMPLATE_SP_UNIQUE_ID = "eidasProxyAuth_from_{0}_type_{1}"; + + // configuration constants + public static final String CONIG_PROPS_EIDAS_PROXY_NODE_ENTITYID = Constants.CONIG_PROPS_EIDAS_NODE + + ".proxy.entityId"; + public static final String CONIG_PROPS_EIDAS_PROXY_NODE_FORWARD_URL = Constants.CONIG_PROPS_EIDAS_NODE + + ".proxy.forward.endpoint"; + + // mandate configuration + public static final String CONIG_PROPS_EIDAS_PROXY_MANDATES_ENABLED = + Constants.CONIG_PROPS_EIDAS_PREFIX + ".proxy.mandates.enabled"; + public static final String CONIG_PROPS_EIDAS_PROXY_MANDATES_PROFILE_DEFAULT_NATURAL = + Constants.CONIG_PROPS_EIDAS_PREFIX + ".proxy.mandates.profiles.natural.default"; + public static final String CONIG_PROPS_EIDAS_PROXY_MANDATES_PROFILE_DEFAULT_LEGAL = + Constants.CONIG_PROPS_EIDAS_PREFIX + ".proxy.mandates.profiles.legal.default"; + + + public static final String CONIG_PROPS_EIDAS_PROXY_WORKAROUND_MANDATES_LEGAL_PERSON = + Constants.CONIG_PROPS_EIDAS_PREFIX + ".proxy.workaround.mandates.legalperson"; + + // specific eIDAS-Connector configuration + public static final String CONIG_PROPS_CONNECTOR_PREFIX = "connector"; + public static final String CONIG_PROPS_CONNECTOR_UNIQUEID = EaafConfigConstants.SERVICE_UNIQUEIDENTIFIER; + public static final String CONIG_PROPS_CONNECTOR_COUNTRYCODE = "countryCode"; + public static final String CONIG_PROPS_CONNECTOR_MANDATES_ENABLED = "mandates.enabled"; + public static final String CONIG_PROPS_CONNECTOR_MANDATES_PROFILE_NATURAL = "mandates.natural"; + public static final String CONIG_PROPS_CONNECTOR_MANDATES_PROFILE_LEGAL = "mandates.legal"; + public static final String CONIG_PROPS_CONNECTOR_VALIDATION_ATTR_MDS = "validation.attributes.mds"; + + + //http end-points + public static final String EIDAS_HTTP_ENDPOINT_IDP_POST = "/eidas/light/idp/post"; + public static final String EIDAS_HTTP_ENDPOINT_IDP_REDIRECT = "/eidas/light/idp/redirect"; + + private MsProxyServiceConstants() { + //private constructor for class with only constant values + + } + +} diff --git a/modules/eidas_proxy-sevice/src/main/java/at/asitplus/eidas/specific/modules/msproxyservice/MsProxyServiceSpringResourceProvider.java b/modules/eidas_proxy-sevice/src/main/java/at/asitplus/eidas/specific/modules/msproxyservice/MsProxyServiceSpringResourceProvider.java new file mode 100644 index 00000000..d36e4712 --- /dev/null +++ b/modules/eidas_proxy-sevice/src/main/java/at/asitplus/eidas/specific/modules/msproxyservice/MsProxyServiceSpringResourceProvider.java @@ -0,0 +1,52 @@ +/* + * Copyright 2018 A-SIT Plus GmbH + * AT-specific eIDAS Connector has been developed in a cooperation between EGIZ, + * A-SIT Plus GmbH, A-SIT, and Graz University of Technology. + * + * Licensed under the EUPL, Version 1.2 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "License"); + * You may not use this work except in compliance with the License. + * You may obtain a copy of the License at: + * https://joinup.ec.europa.eu/news/understanding-eupl-v12 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. +*/ + +package at.asitplus.eidas.specific.modules.msproxyservice; + +import org.springframework.core.io.ClassPathResource; +import org.springframework.core.io.Resource; + +import at.gv.egiz.components.spring.api.SpringResourceProvider; + +public class MsProxyServiceSpringResourceProvider implements SpringResourceProvider { + + @Override + public String getName() { + return "MS-specific eIDAS Proxy-Service module"; + } + + @Override + public String[] getPackagesToScan() { + return null; + + } + + @Override + public Resource[] getResourcesToLoad() { + final ClassPathResource eidasProxyServiceConfig = + new ClassPathResource("/spring/eidas_proxy-service.beans.xml", MsProxyServiceSpringResourceProvider.class); + + return new Resource[] { eidasProxyServiceConfig }; + } + +} diff --git a/modules/eidas_proxy-sevice/src/main/java/at/asitplus/eidas/specific/modules/msproxyservice/exception/EidasProxyServiceException.java b/modules/eidas_proxy-sevice/src/main/java/at/asitplus/eidas/specific/modules/msproxyservice/exception/EidasProxyServiceException.java new file mode 100644 index 00000000..43592a28 --- /dev/null +++ b/modules/eidas_proxy-sevice/src/main/java/at/asitplus/eidas/specific/modules/msproxyservice/exception/EidasProxyServiceException.java @@ -0,0 +1,19 @@ +package at.asitplus.eidas.specific.modules.msproxyservice.exception; + +import at.gv.egiz.eaaf.core.exceptions.EaafException; + +public class EidasProxyServiceException extends EaafException { + + private static final long serialVersionUID = 1L; + + public EidasProxyServiceException(String errorId, Object[] params) { + super(errorId, params); + + } + + public EidasProxyServiceException(String errorId, Object[] params, Throwable e) { + super(errorId, params, e); + + } + +} diff --git a/modules/eidas_proxy-sevice/src/main/java/at/asitplus/eidas/specific/modules/msproxyservice/protocol/EidasProxyServiceController.java b/modules/eidas_proxy-sevice/src/main/java/at/asitplus/eidas/specific/modules/msproxyservice/protocol/EidasProxyServiceController.java new file mode 100644 index 00000000..e24c753e --- /dev/null +++ b/modules/eidas_proxy-sevice/src/main/java/at/asitplus/eidas/specific/modules/msproxyservice/protocol/EidasProxyServiceController.java @@ -0,0 +1,443 @@ +package at.asitplus.eidas.specific.modules.msproxyservice.protocol; + +import java.io.IOException; +import java.text.MessageFormat; +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; +import java.util.UUID; +import java.util.stream.Collectors; + +import javax.servlet.ServletException; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.apache.commons.lang.StringEscapeUtils; +import org.apache.commons.lang3.StringUtils; +import org.opensaml.saml.saml2.core.NameIDType; +import org.opensaml.saml.saml2.core.StatusCode; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Controller; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; + +import com.google.common.collect.ImmutableSortedSet; + +import at.asitplus.eidas.specific.core.MsEidasNodeConstants; +import at.asitplus.eidas.specific.core.config.ServiceProviderConfiguration; +import at.asitplus.eidas.specific.modules.auth.eidas.v2.Constants; +import at.asitplus.eidas.specific.modules.auth.eidas.v2.service.EidasAttributeRegistry; +import at.asitplus.eidas.specific.modules.msproxyservice.MsProxyServiceConstants; +import at.asitplus.eidas.specific.modules.msproxyservice.exception.EidasProxyServiceException; +import at.asitplus.eidas.specific.modules.msproxyservice.utils.EidasProxyServiceUtils; +import at.gv.egiz.components.eventlog.api.EventConstants; +import at.gv.egiz.eaaf.core.api.IRequest; +import at.gv.egiz.eaaf.core.api.data.EaafConfigConstants; +import at.gv.egiz.eaaf.core.api.data.EaafConstants; +import at.gv.egiz.eaaf.core.api.data.ExtendedPvpAttributeDefinitions.SpMandateModes; +import at.gv.egiz.eaaf.core.api.idp.IModulInfo; +import at.gv.egiz.eaaf.core.api.idp.ISpConfiguration; +import at.gv.egiz.eaaf.core.exceptions.EaafException; +import at.gv.egiz.eaaf.core.exceptions.GuiBuildException; +import at.gv.egiz.eaaf.core.impl.idp.controller.AbstractController; +import at.gv.egiz.eaaf.core.impl.utils.KeyValueUtils; +import eu.eidas.auth.commons.EIDASSubStatusCode; +import eu.eidas.auth.commons.EidasParameterKeys; +import eu.eidas.auth.commons.light.ILightRequest; +import eu.eidas.auth.commons.light.impl.LightResponse; +import eu.eidas.auth.commons.light.impl.LightResponse.Builder; +import eu.eidas.auth.commons.light.impl.ResponseStatus; +import eu.eidas.specificcommunication.SpecificCommunicationDefinitionBeanNames; +import eu.eidas.specificcommunication.exception.SpecificCommunicationException; +import eu.eidas.specificcommunication.protocol.SpecificCommunicationService; +import lombok.extern.slf4j.Slf4j; + +/** + * End-point implementation for authentication requests from eIDAS Proxy-Service + * to MS-specific eIDAS Proxy-Service. + * + * @author tlenz + * + */ +@Slf4j +@Controller +public class EidasProxyServiceController extends AbstractController implements IModulInfo { + + private static final String ERROR_01 = "eidas.proxyservice.01"; + private static final String ERROR_02 = "eidas.proxyservice.02"; + private static final String ERROR_03 = "eidas.proxyservice.03"; + private static final String ERROR_04 = "eidas.proxyservice.04"; + private static final String ERROR_05 = "eidas.proxyservice.05"; + private static final String ERROR_07 = "eidas.proxyservice.07"; + private static final String ERROR_08 = "eidas.proxyservice.08"; + private static final String ERROR_09 = "eidas.proxyservice.09"; + private static final String ERROR_10 = "eidas.proxyservice.10"; + private static final String ERROR_11 = "eidas.proxyservice.11"; + + public static final String PROTOCOL_ID = "eidasProxy"; + + @Autowired EidasAttributeRegistry attrRegistry; + @Autowired ProxyServiceAuthenticationAction responseAction; + + /** + * End-point that receives authentication requests from eIDAS Node. + * + * @param httpReq Http request + * @param httpResp Http response + * @throws IOException In case of general error + * @throws EaafException In case of a validation or processing error + */ + @RequestMapping(value = { + MsProxyServiceConstants.EIDAS_HTTP_ENDPOINT_IDP_POST, + MsProxyServiceConstants.EIDAS_HTTP_ENDPOINT_IDP_REDIRECT + }, + method = { RequestMethod.POST, RequestMethod.GET }) + public void receiveEidasAuthnRequest(HttpServletRequest httpReq, HttpServletResponse httpResp) + throws IOException, + EaafException { + log.trace("Receive request on eidas proxy-service end-points"); + ProxyServicePendingRequest pendingReq = null; + try { + // get token from Request + final String tokenBase64 = httpReq.getParameter(EidasParameterKeys.TOKEN.toString()); + if (StringUtils.isEmpty(tokenBase64)) { + log.warn("NO eIDAS message token found."); + throw new EidasProxyServiceException(ERROR_02, null); + + } + log.trace("Receive eIDAS-node token: {}. Searching authentication request from eIDAS Proxy-Service ...", + tokenBase64); + + // read authentication request from shared cache + final SpecificCommunicationService specificProxyCommunicationService = + (SpecificCommunicationService) applicationContext.getBean( + SpecificCommunicationDefinitionBeanNames.SPECIFIC_PROXYSERVICE_COMMUNICATION_SERVICE + .toString()); + final ILightRequest eidasRequest = specificProxyCommunicationService.getAndRemoveRequest( + tokenBase64, + ImmutableSortedSet.copyOf(attrRegistry.getCoreAttributeRegistry().getAttributes())); + if (eidasRequest == null) { + log.info("Find no eIDAS Authn. Request with stated token."); + throw new EidasProxyServiceException(ERROR_11, null); + + } + + log.debug("Received eIDAS auth. request from: {}, Initializing authentication environment ... ", + eidasRequest.getSpCountryCode() != null ? eidasRequest.getSpCountryCode() : "'missing SP-country'"); + log.trace("Received eIDAS requst: {}", eidasRequest); + + // create pendingRequest object + pendingReq = applicationContext.getBean(ProxyServicePendingRequest.class); + pendingReq.initialize(httpReq, authConfig); + pendingReq.setModule(getName()); + + // log 'transaction created' event + revisionsLogger.logEvent(EventConstants.TRANSACTION_CREATED, + pendingReq.getUniqueTransactionIdentifier()); + revisionsLogger.logEvent(pendingReq.getUniqueSessionIdentifier(), + pendingReq.getUniqueTransactionIdentifier(), EventConstants.TRANSACTION_IP, + httpReq.getRemoteAddr()); + + // validate eIDAS Authn. request and set into pending-request + validateEidasAuthnRequest(eidasRequest); + pendingReq.setEidasRequest(eidasRequest); + + // generate Service-Provider configuration from eIDAS request + final ISpConfiguration spConfig = generateSpConfigurationFromEidasRequest(eidasRequest); + + // validate eIDAS Authn. request by using eIDAS Connector specifc parameters + validateEidasAuthnRequest(spConfig, eidasRequest); + + // populate pendingRequest with parameters + pendingReq.setOnlineApplicationConfiguration(spConfig); + pendingReq.setSpEntityId(spConfig.getUniqueIdentifier()); + pendingReq.setPassiv(false); + pendingReq.setForce(true); + + // AuthnRequest needs authentication + pendingReq.setNeedAuthentication(true); + + // set protocol action, which should be executed after authentication + pendingReq.setAction(ProxyServiceAuthenticationAction.class.getName()); + + // switch to session authentication + protAuthService.performAuthentication(httpReq, httpResp, pendingReq); + + } catch (final EidasProxyServiceException e) { + throw e; + + } catch (final SpecificCommunicationException e) { + log.error("Can not read eIDAS Authn request from shared cache. Reason: {}", e.getMessage()); + throw new EidasProxyServiceException(ERROR_03, new Object[] { e.getMessage() }, e); + + } catch (final Throwable e) { + // write revision log entries + if (pendingReq != null) { + revisionsLogger.logEvent(pendingReq, EventConstants.TRANSACTION_ERROR, + pendingReq.getUniqueTransactionIdentifier()); + } + + throw new EidasProxyServiceException(ERROR_01, new Object[] { e.getMessage() }, e); + } + + } + + @Override + public boolean generateErrorMessage(Throwable e, HttpServletRequest httpReq, HttpServletResponse httpResp, + IRequest pendingReq) throws Throwable { + if (pendingReq instanceof ProxyServicePendingRequest) { + try { + ILightRequest eidasReq = ((ProxyServicePendingRequest) pendingReq).getEidasRequest(); + + //build eIDAS response + Builder lightRespBuilder = LightResponse.builder(); + lightRespBuilder.id(UUID.randomUUID().toString()); + lightRespBuilder.inResponseToId(eidasReq.getId()); + lightRespBuilder.relayState(eidasReq.getRelayState()); + lightRespBuilder.issuer(authConfig.getBasicConfiguration( + MsProxyServiceConstants.CONIG_PROPS_EIDAS_PROXY_NODE_ENTITYID)); + lightRespBuilder.subject(UUID.randomUUID().toString()); + lightRespBuilder.subjectNameIdFormat(NameIDType.TRANSIENT); + lightRespBuilder.status(ResponseStatus.builder() + .statusCode(StatusCode.RESPONDER) + .subStatusCode(EIDASSubStatusCode.AUTHN_FAILED_URI.getValue()) + .statusMessage(StringEscapeUtils.escapeXml(e.getLocalizedMessage())) + .build()); + + // forward to eIDAS Proxy-Service + responseAction.forwardToEidasProxy(pendingReq, httpReq, httpResp, lightRespBuilder.build()); + + return true; + + } catch (ServletException | IOException | GuiBuildException e1) { + log.warn("Forward error to eIDAS Proxy-Service FAILED. Handle error localy ... ", e1); + + } + + } else { + log.error("eIDAS Proxy-Service authentication requires PendingRequest of Type: {}", + ProxyServicePendingRequest.class.getName()); + + } + + return false; + + } + + @Override + public String getName() { + return EidasProxyServiceController.class.getName(); + + } + + @Override + public String getAuthProtocolIdentifier() { + return PROTOCOL_ID; + + } + + @Override + public boolean validate(HttpServletRequest request, HttpServletResponse response, IRequest pending) { + return true; + + } + + /** + * Generic validation of incoming eIDAS request. + * + * @param eidasRequest Incoming eIDAS authentication request + * @throws EidasProxyServiceException In case of a validation error + */ + private void validateEidasAuthnRequest(ILightRequest eidasRequest) throws EidasProxyServiceException { + if (StringUtils.isEmpty(eidasRequest.getIssuer())) { + throw new EidasProxyServiceException(ERROR_05, null); + + } + + // TODO: validate some other stuff + + } + + /** + * eIDAS Connector specific validation of incoming eIDAS request. + * + * @param eidasRequest Incoming eIDAS authentication request + * @param spConfig eIDAS Connector configuration + * @throws EidasProxyServiceException In case of a validation error + */ + private void validateEidasAuthnRequest(ISpConfiguration spConfig, ILightRequest eidasRequest) + throws EidasProxyServiceException { + // check if natural-person and legal-person attributes requested in parallel + if (spConfig.isConfigurationValue(MsProxyServiceConstants.CONIG_PROPS_CONNECTOR_VALIDATION_ATTR_MDS, true) + && EidasProxyServiceUtils.isLegalPersonRequested(eidasRequest) + && EidasProxyServiceUtils.isNaturalPersonRequested(eidasRequest)) { + throw new EidasProxyServiceException(ERROR_08, null); + + } + + // TODO: validate some other stuff + + } + + /** + * Generate a dummy Service-Provider configuration for processing. + * + * @param eidasRequest Incoming eIDAS authentication request + * @return Service-Provider configuration that can be used for authentication + * @throws EidasProxyServiceException In case of a configuration error + */ + private ISpConfiguration generateSpConfigurationFromEidasRequest(ILightRequest eidasRequest) + throws EidasProxyServiceException { + try { + + Map<String, String> connectorConfigMap = extractRawConnectorConfiguration(eidasRequest); + + // check if country-code is available + String spCountry = connectorConfigMap.get(MsProxyServiceConstants.CONIG_PROPS_CONNECTOR_COUNTRYCODE); + if (StringUtils.isEmpty(spCountry)) { + throw new EidasProxyServiceException(ERROR_07, null); + + } + + // build FriendyName from CountryCode and SPType + connectorConfigMap.put(MsEidasNodeConstants.PROP_CONFIG_SP_FRIENDLYNAME, + MessageFormat.format(MsProxyServiceConstants.TEMPLATE_SP_UNIQUE_ID, + spCountry, eidasRequest.getSpType())); + + // build Service-Provider configuration object + final ServiceProviderConfiguration spConfig = new ServiceProviderConfiguration(connectorConfigMap, authConfig); + + // build bPK target from Country-Code + final String ccCountry = authConfig.getBasicConfiguration(Constants.CONIG_PROPS_EIDAS_NODE_COUNTRYCODE, + Constants.DEFAULT_MS_NODE_COUNTRY_CODE); + spConfig.setBpkTargetIdentifier( + EaafConstants.URN_PREFIX_EIDAS + ccCountry + "+" + spCountry); + + // set required LoA from eIDAS request + spConfig.setRequiredLoA( + eidasRequest.getLevelsOfAssurance().stream().map(el -> el.getValue()).collect(Collectors.toList())); + + //build mandate profiles for this specific request + buildMandateProfileConfiguration(spConfig, eidasRequest); + + return spConfig; + + } catch (EidasProxyServiceException e) { + throw e; + + } catch (final EaafException e) { + throw new EidasProxyServiceException(ERROR_04, new Object[] { e.getMessage() }, e); + + } + } + + + private Map<String, String> extractRawConnectorConfiguration(ILightRequest eidasRequest) { + Map<String, String> allConnectorConfigs = authConfig.getBasicConfigurationWithPrefix( + MsProxyServiceConstants.CONIG_PROPS_CONNECTOR_PREFIX); + if (log.isTraceEnabled()) { + log.trace("Full-connector configuration:"); + allConnectorConfigs.entrySet().stream().forEach( + el -> log.trace("Key: {} -> Value: {}", el.getKey(), el.getValue())); + + } + + + Map<String, String> connectorConfig = allConnectorConfigs.entrySet().stream() + .filter(el -> el.getKey().endsWith(MsEidasNodeConstants.PROP_CONFIG_SP_UNIQUEIDENTIFIER) + && el.getValue().equals(eidasRequest.getIssuer())) + .findFirst() + .map(el -> KeyValueUtils.getSubSetWithPrefix(allConnectorConfigs, + KeyValueUtils.getParentKey(el.getKey()) + KeyValueUtils.KEY_DELIMITER)) + .orElse(new HashMap<>()); + + + if (connectorConfig.isEmpty()) { + log.debug("No specific configuration for eIDAS Connector: {} Using default configuration ... ", + eidasRequest.getIssuer()); + + // set EntityId of the requesting eIDAS Connector + connectorConfig.put(EaafConfigConstants.SERVICE_UNIQUEIDENTIFIER, eidasRequest.getIssuer()); + + // set country-code from eIDAS request + connectorConfig.put(MsProxyServiceConstants.CONIG_PROPS_CONNECTOR_COUNTRYCODE, + eidasRequest.getSpCountryCode()); + + // set default mandate configuration + connectorConfig.put(MsProxyServiceConstants.CONIG_PROPS_CONNECTOR_MANDATES_ENABLED, + String.valueOf(authConfig.getBasicConfigurationBoolean( + MsProxyServiceConstants.CONIG_PROPS_EIDAS_PROXY_MANDATES_ENABLED, false))); + connectorConfig.put(MsProxyServiceConstants.CONIG_PROPS_CONNECTOR_MANDATES_PROFILE_NATURAL, + authConfig.getBasicConfiguration( + MsProxyServiceConstants.CONIG_PROPS_EIDAS_PROXY_MANDATES_PROFILE_DEFAULT_NATURAL)); + connectorConfig.put(MsProxyServiceConstants.CONIG_PROPS_CONNECTOR_MANDATES_PROFILE_LEGAL, + authConfig.getBasicConfiguration( + MsProxyServiceConstants.CONIG_PROPS_EIDAS_PROXY_MANDATES_PROFILE_DEFAULT_LEGAL)); + + } else { + log.debug("Find specific configuration for eIDAS Connector: {}", eidasRequest.getIssuer()); + + } + + return connectorConfig; + + } + + + private void buildMandateProfileConfiguration(ServiceProviderConfiguration spConfig, ILightRequest eidasRequest) + throws EidasProxyServiceException { + // check if mandates are enabled + if (spConfig.isConfigurationValue(MsProxyServiceConstants.CONIG_PROPS_CONNECTOR_MANDATES_ENABLED, false)) { + injectMandateInfosIntoSpConfig(spConfig, eidasRequest); + + } else { + if (EidasProxyServiceUtils.isLegalPersonRequested(eidasRequest)) { + throw new EidasProxyServiceException(ERROR_09, null); + + } + + spConfig.setMandateProfiles(Collections.emptyList()); + spConfig.setMandateMode(SpMandateModes.NONE); + + } + + } + + private void injectMandateInfosIntoSpConfig(ServiceProviderConfiguration spConfig, + ILightRequest eidasRequest) throws EidasProxyServiceException { + log.trace("eIDAS Proxy-Service allows mandates for Connector: {}. Selecting profiles ... ", + spConfig.getUniqueIdentifier()); + + //check if legal person is requested + if (EidasProxyServiceUtils.isLegalPersonRequested(eidasRequest)) { + spConfig.setMandateProfiles(KeyValueUtils.getListOfCsvValues( + spConfig.getConfigurationValue(MsProxyServiceConstants.CONIG_PROPS_CONNECTOR_MANDATES_PROFILE_LEGAL))); + spConfig.setMandateMode(SpMandateModes.LEGAL_FORCE); + + if (spConfig.getMandateProfiles().isEmpty()) { + throw new EidasProxyServiceException(ERROR_10, null); + + } + + } else if (EidasProxyServiceUtils.isNaturalPersonRequested(eidasRequest)) { + spConfig.setMandateProfiles(KeyValueUtils.getListOfCsvValues( + spConfig.getConfigurationValue(MsProxyServiceConstants.CONIG_PROPS_CONNECTOR_MANDATES_PROFILE_NATURAL))); + + spConfig.setMandateMode(SpMandateModes.NATURAL); + + } + + + if (spConfig.getMandateProfiles().isEmpty()) { + log.debug("No mandate-profiles for issure: {}. Set mandate-mode to 'none'", + spConfig.getUniqueIdentifier()); + spConfig.setMandateMode(SpMandateModes.NONE); + + } else { + log.debug("Set mandate-profiles: {} to request from issuer: {}", + spConfig.getMandateProfiles(), spConfig.getUniqueIdentifier()); + + } + + } +} diff --git a/modules/eidas_proxy-sevice/src/main/java/at/asitplus/eidas/specific/modules/msproxyservice/protocol/ProxyServiceAuthenticationAction.java b/modules/eidas_proxy-sevice/src/main/java/at/asitplus/eidas/specific/modules/msproxyservice/protocol/ProxyServiceAuthenticationAction.java new file mode 100644 index 00000000..15524005 --- /dev/null +++ b/modules/eidas_proxy-sevice/src/main/java/at/asitplus/eidas/specific/modules/msproxyservice/protocol/ProxyServiceAuthenticationAction.java @@ -0,0 +1,374 @@ +package at.asitplus.eidas.specific.modules.msproxyservice.protocol; + +import java.io.IOException; +import java.util.UUID; + +import javax.annotation.PostConstruct; +import javax.servlet.ServletException; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.apache.commons.lang3.StringUtils; +import org.opensaml.saml.saml2.core.NameIDType; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.ApplicationContext; +import org.springframework.core.io.ResourceLoader; +import org.springframework.web.util.UriComponentsBuilder; + +import at.asitplus.eidas.specific.core.MsEidasNodeConstants; +import at.asitplus.eidas.specific.core.gui.StaticGuiBuilderConfiguration; +import at.asitplus.eidas.specific.modules.auth.eidas.v2.Constants; +import at.asitplus.eidas.specific.modules.auth.eidas.v2.service.EidasAttributeRegistry; +import at.asitplus.eidas.specific.modules.msproxyservice.MsProxyServiceConstants; +import at.asitplus.eidas.specific.modules.msproxyservice.exception.EidasProxyServiceException; +import at.asitplus.eidas.specific.modules.msproxyservice.utils.EidasProxyServiceUtils; +import at.gv.egiz.eaaf.core.api.IRequest; +import at.gv.egiz.eaaf.core.api.data.PvpAttributeDefinitions; +import at.gv.egiz.eaaf.core.api.gui.ISpringMvcGuiFormBuilder; +import at.gv.egiz.eaaf.core.api.idp.IAction; +import at.gv.egiz.eaaf.core.api.idp.IAuthData; +import at.gv.egiz.eaaf.core.api.idp.IConfiguration; +import at.gv.egiz.eaaf.core.api.idp.IEidAuthData; +import at.gv.egiz.eaaf.core.api.idp.slo.SloInformationInterface; +import at.gv.egiz.eaaf.core.exceptions.EaafConfigurationException; +import at.gv.egiz.eaaf.core.exceptions.EaafException; +import at.gv.egiz.eaaf.core.exceptions.GuiBuildException; +import at.gv.egiz.eaaf.core.impl.data.SloInformationImpl; +import eu.eidas.auth.commons.EidasParameterKeys; +import eu.eidas.auth.commons.attribute.AttributeDefinition; +import eu.eidas.auth.commons.attribute.ImmutableAttributeMap; +import eu.eidas.auth.commons.light.ILightRequest; +import eu.eidas.auth.commons.light.ILightResponse; +import eu.eidas.auth.commons.light.impl.LightResponse; +import eu.eidas.auth.commons.light.impl.LightResponse.Builder; +import eu.eidas.auth.commons.light.impl.ResponseStatus; +import eu.eidas.auth.commons.tx.BinaryLightToken; +import eu.eidas.specificcommunication.BinaryLightTokenHelper; +import eu.eidas.specificcommunication.SpecificCommunicationDefinitionBeanNames; +import eu.eidas.specificcommunication.exception.SpecificCommunicationException; +import eu.eidas.specificcommunication.protocol.SpecificCommunicationService; +import lombok.extern.slf4j.Slf4j; + +/** + * Result action of a successfully performed eIDAS Proxy-Service authentication. + * + * @author tlenz + * + */ +@Slf4j +public class ProxyServiceAuthenticationAction implements IAction { + + private static final String PROXYSERVICE_AUTH_ACTION_NAME = "MS-specific eIDAS-Proxy action"; + + @Autowired + ApplicationContext context; + @Autowired + IConfiguration basicConfig; + @Autowired + ResourceLoader resourceLoader; + @Autowired + ISpringMvcGuiFormBuilder guiBuilder; + @Autowired + EidasAttributeRegistry attrRegistry; + + @Override + public SloInformationInterface processRequest(IRequest pendingReq, HttpServletRequest httpReq, + HttpServletResponse httpResp, IAuthData authData) throws EaafException { + if (pendingReq instanceof ProxyServicePendingRequest) { + try { + ILightRequest eidasReq = ((ProxyServicePendingRequest) pendingReq).getEidasRequest(); + + //build eIDAS response + Builder lightRespBuilder = LightResponse.builder(); + lightRespBuilder.id(UUID.randomUUID().toString()); + lightRespBuilder.inResponseToId(eidasReq.getId()); + lightRespBuilder.relayState(eidasReq.getRelayState()); + + lightRespBuilder.status(ResponseStatus.builder() + .statusCode(Constants.SUCCESS_URI) + .build()); + + //TODO: check if we can use transient subjectNameIds + lightRespBuilder.subject(UUID.randomUUID().toString()); + lightRespBuilder.subjectNameIdFormat(NameIDType.TRANSIENT); + + //TODO: + lightRespBuilder.issuer(basicConfig.getBasicConfiguration( + MsProxyServiceConstants.CONIG_PROPS_EIDAS_PROXY_NODE_ENTITYID)); + lightRespBuilder.levelOfAssurance(authData.getEidasQaaLevel()); + lightRespBuilder.attributes(buildAttributesFromAuthData(authData, eidasReq)); + + // set SLO response object of EAAF framework + final SloInformationImpl sloInformation = new SloInformationImpl(); + sloInformation.setProtocolType(pendingReq.requestedModule()); + sloInformation + .setSpEntityID(pendingReq.getServiceProviderConfiguration().getUniqueIdentifier()); + + // forward to eIDAS Proxy-Service + forwardToEidasProxy(pendingReq, httpReq, httpResp, lightRespBuilder.build()); + + return sloInformation; + + } catch (ServletException | IOException | GuiBuildException e) { + throw new EidasProxyServiceException("eidas.proxyservice.06", null, e); + + } + + } else { + log.error("eIDAS Proxy-Service authentication requires PendingRequest of Type: {}", + ProxyServicePendingRequest.class.getName()); + throw new EaafException("eidas.proxyservice.99"); + + } + } + + @Override + public boolean needAuthentication(IRequest req, HttpServletRequest httpReq, HttpServletResponse httpResp) { + return true; + + } + + @Override + public String getDefaultActionName() { + return PROXYSERVICE_AUTH_ACTION_NAME; + + } + + + /** + * Forward eIDAS Light response to eIDAS node. + * + * @param pendingReq Current pending request. + * @param httpReq Current HTTP request + * @param httpResp Current HTTP response + * @param lightResponse eIDAS LightResponse + * @throws EaafConfigurationException In case of a configuration error + * @throws IOException In case of a general error + * @throws GuiBuildException In case of a GUI rendering error, if http POST binding is used + * @throws ServletException In case of a general error + */ + public void forwardToEidasProxy(IRequest pendingReq, HttpServletRequest httpReq, + HttpServletResponse httpResp, LightResponse lightResponse) throws EaafConfigurationException, IOException, + GuiBuildException, ServletException { + + // put request into shared cache + final BinaryLightToken token = putResponseInCommunicationCache(lightResponse); + final String tokenBase64 = BinaryLightTokenHelper.encodeBinaryLightTokenBase64(token); + + // select forward URL regarding the selected environment + final String forwardUrl = basicConfig.getBasicConfiguration( + MsProxyServiceConstants.CONIG_PROPS_EIDAS_PROXY_NODE_FORWARD_URL); + + if (StringUtils.isEmpty(forwardUrl)) { + log.warn("NO ForwardURL defined in configuration. Can NOT forward to eIDAS node! Process stops"); + throw new EaafConfigurationException("config.08", + new Object[] { MsProxyServiceConstants.CONIG_PROPS_EIDAS_PROXY_NODE_FORWARD_URL }); + + } + log.debug("ForwardURL: " + forwardUrl + " selected to forward eIDAS request"); + + if (basicConfig.getBasicConfiguration( + Constants.CONIG_PROPS_EIDAS_NODE_FORWARD_METHOD, + Constants.FORWARD_METHOD_GET).equals(Constants.FORWARD_METHOD_GET)) { + + log.debug("Use http-redirect for eIDAS node forwarding ... "); + // send redirect + final UriComponentsBuilder redirectUrl = UriComponentsBuilder.fromHttpUrl(forwardUrl); + redirectUrl.queryParam(EidasParameterKeys.TOKEN.toString(), tokenBase64); + httpResp.sendRedirect(redirectUrl.build().encode().toString()); + + } else { + log.debug("Use http-post for eIDAS node forwarding ... "); + final StaticGuiBuilderConfiguration config = new StaticGuiBuilderConfiguration( + basicConfig, + pendingReq, + Constants.TEMPLATE_POST_FORWARD_NAME, + null, + resourceLoader); + + config.putCustomParameter(null, Constants.TEMPLATE_POST_FORWARD_ENDPOINT, forwardUrl); + config.putCustomParameter(null, Constants.TEMPLATE_POST_FORWARD_TOKEN_NAME, + EidasParameterKeys.TOKEN.toString()); + config.putCustomParameter(null, Constants.TEMPLATE_POST_FORWARD_TOKEN_VALUE, + tokenBase64); + + guiBuilder.build(httpReq, httpResp, config, "Forward to eIDASNode form"); + + } + } + + @PostConstruct + private void checkConfiguration() { + //TODO: validate configuration on start-up + + } + + + private ImmutableAttributeMap buildAttributesFromAuthData(IAuthData authData, + ILightRequest eidasReq) { + IEidAuthData eidAuthData = (IEidAuthData) authData; + if (eidAuthData.isUseMandate()) { + log.debug("Building eIDAS Proxy-Service response with mandate ... "); + final ImmutableAttributeMap.Builder attributeMap = ImmutableAttributeMap.builder(); + injectRepesentativeInformation(attributeMap, eidAuthData); + injectMandatorInformation(attributeMap, eidAuthData); + + // work-around that injects nat. person subject to bypass validation on eIDAS Node + injectJurPersonWorkaroundIfRequired(attributeMap, eidasReq, authData); + + return attributeMap.build(); + + } else { + log.debug("Building eIDAS Proxy-Service response without mandates ... "); + return buildAttributesWithoutMandate(eidAuthData); + + } + } + + private void injectMandatorInformation( + ImmutableAttributeMap.Builder attributeMap, IEidAuthData eidAuthData) { + String natMandatorId = eidAuthData.getGenericData( + MsEidasNodeConstants.ATTR_EIDAS_NAT_MANDATOR_PERSONAL_IDENTIFIER, String.class); + + if (StringUtils.isNotEmpty(natMandatorId)) { + log.debug("Injecting natural mandator informations ... "); + final AttributeDefinition<?> attrDefPersonalId = attrRegistry.getCoreAttributeRegistry().getByFriendlyName( + Constants.eIDAS_ATTR_PERSONALIDENTIFIER).first(); + final AttributeDefinition<?> attrDefFamilyName = attrRegistry.getCoreAttributeRegistry().getByFriendlyName( + Constants.eIDAS_ATTR_CURRENTFAMILYNAME).first(); + final AttributeDefinition<?> attrDefGivenName = attrRegistry.getCoreAttributeRegistry().getByFriendlyName( + Constants.eIDAS_ATTR_CURRENTGIVENNAME).first(); + final AttributeDefinition<?> attrDefDateOfBirth = attrRegistry.getCoreAttributeRegistry().getByFriendlyName( + Constants.eIDAS_ATTR_DATEOFBIRTH).first(); + + attributeMap.put(attrDefPersonalId, natMandatorId); + attributeMap.put(attrDefFamilyName, eidAuthData.getGenericData( + PvpAttributeDefinitions.MANDATE_NAT_PER_FAMILY_NAME_NAME, String.class)); + attributeMap.put(attrDefGivenName, eidAuthData.getGenericData( + PvpAttributeDefinitions.MANDATE_NAT_PER_GIVEN_NAME_NAME, String.class)); + attributeMap.put(attrDefDateOfBirth, eidAuthData.getGenericData( + PvpAttributeDefinitions.MANDATE_NAT_PER_BIRTHDATE_NAME, String.class)); + + } else { + log.debug("Injecting legal mandator informations ... "); + final AttributeDefinition<?> commonName = attrRegistry.getCoreAttributeRegistry().getByFriendlyName( + Constants.eIDAS_ATTR_LEGALNAME).first(); + final AttributeDefinition<?> legalPersonId = attrRegistry.getCoreAttributeRegistry().getByFriendlyName( + Constants.eIDAS_ATTR_LEGALPERSONIDENTIFIER).first(); + + attributeMap.put(commonName, eidAuthData.getGenericData( + PvpAttributeDefinitions.MANDATE_LEG_PER_FULL_NAME_NAME, String.class)); + attributeMap.put(legalPersonId, eidAuthData.getGenericData( + MsEidasNodeConstants.ATTR_EIDAS_JUR_MANDATOR_PERSONAL_IDENTIFIER, String.class)); + + } + } + + private void injectRepesentativeInformation( + ImmutableAttributeMap.Builder attributeMap, IEidAuthData eidAuthData) { + final AttributeDefinition<?> attrDefPersonalId = attrRegistry.getCoreAttributeRegistry().getByFriendlyName( + Constants.eIDAS_ATTR_REPRESENTATIVE_PERSONALIDENTIFIER).first(); + final AttributeDefinition<?> attrDefFamilyName = attrRegistry.getCoreAttributeRegistry().getByFriendlyName( + Constants.eIDAS_ATTR_REPRESENTATIVE_CURRENTFAMILYNAME).first(); + final AttributeDefinition<?> attrDefGivenName = attrRegistry.getCoreAttributeRegistry().getByFriendlyName( + Constants.eIDAS_ATTR_REPRESENTATIVE_CURRENTGIVENNAME).first(); + final AttributeDefinition<?> attrDefDateOfBirth = attrRegistry.getCoreAttributeRegistry().getByFriendlyName( + Constants.eIDAS_ATTR_REPRESENTATIVE_DATEOFBIRTH).first(); + + attributeMap.put(attrDefPersonalId, + eidAuthData.getGenericData(MsEidasNodeConstants.ATTR_EIDAS_PERSONAL_IDENTIFIER, String.class)); + attributeMap.put(attrDefFamilyName, eidAuthData.getFamilyName()); + attributeMap.put(attrDefGivenName, eidAuthData.getGivenName()); + + //TODO: throw an error in case of SZR Date with month or day = "00" + attributeMap.put(attrDefDateOfBirth, eidAuthData.getDateOfBirth()); + + } + + /** + * Work-around to inject representative information as nat. person subject to bypass eIDAS Node validation. + * + * <p><b>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.</b></p> + * + * @param attributeMap Attribute set for eIDAS response + * @param eidasReq Incoming eIDAS request + * @param authData Authentication data + */ + private void injectJurPersonWorkaroundIfRequired( + ImmutableAttributeMap.Builder attributeMap, ILightRequest eidasReq, IAuthData authData) { + if (isLegalPersonWorkaroundActive() && isLegalPersonMandateAvailable(authData) + && EidasProxyServiceUtils.isNaturalPersonRequested(eidasReq) + && EidasProxyServiceUtils.isLegalPersonRequested(eidasReq)) { + log.debug("Injecting representative information as nat. person subject to bypass eIDAS Node validation"); + attributeMap.putAll(buildAttributesWithoutMandate(authData)); + + } + } + + private ImmutableAttributeMap buildAttributesWithoutMandate(IAuthData eidAuthData) { + //TODO: throw an error in case of SZR Date with month or day = "00" + return buildAttributesWithoutMandate( + eidAuthData.getGenericData(MsEidasNodeConstants.ATTR_EIDAS_PERSONAL_IDENTIFIER, String.class), + eidAuthData.getFamilyName(), + eidAuthData.getGivenName(), + eidAuthData.getDateOfBirth()); + + } + + private ImmutableAttributeMap buildAttributesWithoutMandate(String personalIdentifier, String familyName, + String givenName, String dateOfBirth) { + final AttributeDefinition<?> attrDefPersonalId = attrRegistry.getCoreAttributeRegistry().getByFriendlyName( + Constants.eIDAS_ATTR_PERSONALIDENTIFIER).first(); + final AttributeDefinition<?> attrDefFamilyName = attrRegistry.getCoreAttributeRegistry().getByFriendlyName( + Constants.eIDAS_ATTR_CURRENTFAMILYNAME).first(); + final AttributeDefinition<?> attrDefGivenName = attrRegistry.getCoreAttributeRegistry().getByFriendlyName( + Constants.eIDAS_ATTR_CURRENTGIVENNAME).first(); + final AttributeDefinition<?> attrDefDateOfBirth = attrRegistry.getCoreAttributeRegistry().getByFriendlyName( + Constants.eIDAS_ATTR_DATEOFBIRTH).first(); + + final ImmutableAttributeMap.Builder attributeMap = + ImmutableAttributeMap.builder() + .put(attrDefPersonalId, personalIdentifier) + .put(attrDefFamilyName, familyName) + .put(attrDefGivenName, givenName) + .put(attrDefDateOfBirth, dateOfBirth); + + return attributeMap.build(); + + } + + private BinaryLightToken putResponseInCommunicationCache(ILightResponse lightResponse) + throws ServletException { + final BinaryLightToken binaryLightToken; + try { + final SpecificCommunicationService springManagedSpecificConnectorCommunicationService = + (SpecificCommunicationService) context.getBean( + SpecificCommunicationDefinitionBeanNames.SPECIFIC_PROXYSERVICE_COMMUNICATION_SERVICE + .toString()); + + binaryLightToken = springManagedSpecificConnectorCommunicationService.putResponse(lightResponse); + + } catch (final SpecificCommunicationException e) { + log.error("Unable to process specific request"); + throw new ServletException(e); + + } + + return binaryLightToken; + } + + private boolean isLegalPersonWorkaroundActive() { + return basicConfig.getBasicConfigurationBoolean( + MsProxyServiceConstants.CONIG_PROPS_EIDAS_PROXY_WORKAROUND_MANDATES_LEGAL_PERSON, + false); + + } + + private boolean isLegalPersonMandateAvailable(IAuthData authData) { + return StringUtils.isNoneEmpty(authData.getGenericData( + MsEidasNodeConstants.ATTR_EIDAS_JUR_MANDATOR_PERSONAL_IDENTIFIER, String.class)); + + } + +} diff --git a/modules/eidas_proxy-sevice/src/main/java/at/asitplus/eidas/specific/modules/msproxyservice/protocol/ProxyServicePendingRequest.java b/modules/eidas_proxy-sevice/src/main/java/at/asitplus/eidas/specific/modules/msproxyservice/protocol/ProxyServicePendingRequest.java new file mode 100644 index 00000000..a3b5007a --- /dev/null +++ b/modules/eidas_proxy-sevice/src/main/java/at/asitplus/eidas/specific/modules/msproxyservice/protocol/ProxyServicePendingRequest.java @@ -0,0 +1,28 @@ +package at.asitplus.eidas.specific.modules.msproxyservice.protocol; + +import org.springframework.beans.factory.config.BeanDefinition; +import org.springframework.context.annotation.Scope; +import org.springframework.stereotype.Component; + +import at.gv.egiz.eaaf.core.impl.idp.controller.protocols.RequestImpl; +import eu.eidas.auth.commons.light.ILightRequest; +import lombok.Getter; +import lombok.Setter; + +/** + * Pending-request of an authentication process from eIDAS Proxy-Service. + * + * @author tlenz + * + */ +@Component("ProxyServicePendingRequest") +@Scope(value = BeanDefinition.SCOPE_PROTOTYPE) +public class ProxyServicePendingRequest extends RequestImpl { + + private static final long serialVersionUID = 4227378344716277935L; + + @Getter + @Setter + ILightRequest eidasRequest; + +} diff --git a/modules/eidas_proxy-sevice/src/main/java/at/asitplus/eidas/specific/modules/msproxyservice/utils/EidasProxyServiceUtils.java b/modules/eidas_proxy-sevice/src/main/java/at/asitplus/eidas/specific/modules/msproxyservice/utils/EidasProxyServiceUtils.java new file mode 100644 index 00000000..4cd7ba6c --- /dev/null +++ b/modules/eidas_proxy-sevice/src/main/java/at/asitplus/eidas/specific/modules/msproxyservice/utils/EidasProxyServiceUtils.java @@ -0,0 +1,45 @@ +package at.asitplus.eidas.specific.modules.msproxyservice.utils; + +import at.asitplus.eidas.specific.modules.auth.eidas.v2.Constants; +import eu.eidas.auth.commons.light.ILightRequest; + +/** + * Common utils for eIDAS Proxy-Service implementation. + * + * @author tlenz + * + */ +public class EidasProxyServiceUtils { + + /** + * Check if legal person subject is requested by eIDAS Connector. + * + * @param eidasRequest Authentication request from eIDAS Connector. + * @return <code>true</code> if <i>LegalPersonIdentifier</i> is requested, otherwise <code>false</code>lse + */ + public static boolean isLegalPersonRequested(ILightRequest eidasRequest) { + return eidasRequest.getRequestedAttributes().entrySet().stream() + .filter(el -> el.getKey().getFriendlyName().equals(Constants.eIDAS_ATTR_LEGALPERSONIDENTIFIER)) + .findFirst() + .isPresent(); + + } + + /** + * Check if natural person subject is requested by eIDAS Connector. + * + * @param eidasRequest Authentication request from eIDAS Connector. + * @return <code>true</code> if <i>PersonIdentifier</i> is requested, otherwise <code>false</code>lse + */ + public static boolean isNaturalPersonRequested(ILightRequest eidasRequest) { + return eidasRequest.getRequestedAttributes().entrySet().stream() + .filter(el -> el.getKey().getFriendlyName().equals(Constants.eIDAS_ATTR_PERSONALIDENTIFIER)) + .findFirst() + .isPresent(); + + } + + private EidasProxyServiceUtils() { + //hide constructor for class with static methods only + } +} diff --git a/modules/eidas_proxy-sevice/src/main/resources/META-INF/services/at.gv.egiz.components.spring.api.SpringResourceProvider b/modules/eidas_proxy-sevice/src/main/resources/META-INF/services/at.gv.egiz.components.spring.api.SpringResourceProvider new file mode 100644 index 00000000..9158d2e6 --- /dev/null +++ b/modules/eidas_proxy-sevice/src/main/resources/META-INF/services/at.gv.egiz.components.spring.api.SpringResourceProvider @@ -0,0 +1 @@ +at.asitplus.eidas.specific.modules.msproxyservice.MsProxyServiceSpringResourceProvider
\ No newline at end of file diff --git a/modules/eidas_proxy-sevice/src/main/resources/messages/eidasproxy_messages.properties b/modules/eidas_proxy-sevice/src/main/resources/messages/eidasproxy_messages.properties new file mode 100644 index 00000000..3f92d58a --- /dev/null +++ b/modules/eidas_proxy-sevice/src/main/resources/messages/eidasproxy_messages.properties @@ -0,0 +1,14 @@ +eidas.proxyservice.01=General error on request-validation from national eIDAS Proxy-Service +eidas.proxyservice.02=Authentication request contains not communication token. +eidas.proxyservice.03=General error during eIDAS-Node communication. Reason: {} +eidas.proxyservice.04=Validation of eIDAS Authn request failed. Reason: {} +eidas.proxyservice.05=No eIDAS-Connector Issuer in Authn. request. Authentication not possible +eidas.proxyservice.06=Can not build eIDAS Proxy-Service response. Authentication FAILED. +eidas.proxyservice.07=Can not determine eIDAS-Connector CountryCode. Authentication not possible +eidas.proxyservice.08=Validation of eIDAS Authn request failed. Reason: Legal person and natural person can not be requested at once. +eidas.proxyservice.09=eIDAS authentication not possible, because legal person is requested but mandates are disabled in general +eidas.proxyservice.10=eIDAS authentication not possible, because legal person is requested but not mandate profiles are defined +eidas.proxyservice.11=No Authentication request with stated communication token. + + +eidas.proxyservice.99=Internal error during eIDAS Proxy-Service authentication
\ No newline at end of file diff --git a/modules/eidas_proxy-sevice/src/main/resources/spring/eidas_proxy-service.beans.xml b/modules/eidas_proxy-sevice/src/main/resources/spring/eidas_proxy-service.beans.xml new file mode 100644 index 00000000..2055b5a9 --- /dev/null +++ b/modules/eidas_proxy-sevice/src/main/resources/spring/eidas_proxy-service.beans.xml @@ -0,0 +1,28 @@ +<?xml version="1.0" encoding="UTF-8"?> +<beans xmlns="http://www.springframework.org/schema/beans" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xmlns:context="http://www.springframework.org/schema/context" + xmlns:tx="http://www.springframework.org/schema/tx" + xmlns:aop="http://www.springframework.org/schema/aop" + xsi:schemaLocation="http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.1.xsd + http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd + http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.1.xsd + http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd"> + + <context:annotation-config /> + + <bean id="ProxyServicePendingRequest" + class="at.asitplus.eidas.specific.modules.msproxyservice.protocol.ProxyServicePendingRequest" + scope="prototype"/> + + <bean id="ProxyServiceAuthenticationAction" + class="at.asitplus.eidas.specific.modules.msproxyservice.protocol.ProxyServiceAuthenticationAction"/> + + <bean id="msSpecificProxyController" + class="at.asitplus.eidas.specific.modules.msproxyservice.protocol.EidasProxyServiceController"/> + + <bean id="eidasProxyMessageSource" + class="at.asitplus.eidas.specific.modules.msproxyservice.EidasProxyMessageSource"/> + + +</beans>
\ No newline at end of file |