aboutsummaryrefslogtreecommitdiff
path: root/eidas_modules/eidas_proxy-sevice/src/main/java/at/asitplus/eidas/specific/modules/msproxyservice/protocol/EidasProxyServiceController.java
diff options
context:
space:
mode:
Diffstat (limited to 'eidas_modules/eidas_proxy-sevice/src/main/java/at/asitplus/eidas/specific/modules/msproxyservice/protocol/EidasProxyServiceController.java')
-rw-r--r--eidas_modules/eidas_proxy-sevice/src/main/java/at/asitplus/eidas/specific/modules/msproxyservice/protocol/EidasProxyServiceController.java253
1 files changed, 205 insertions, 48 deletions
diff --git a/eidas_modules/eidas_proxy-sevice/src/main/java/at/asitplus/eidas/specific/modules/msproxyservice/protocol/EidasProxyServiceController.java b/eidas_modules/eidas_proxy-sevice/src/main/java/at/asitplus/eidas/specific/modules/msproxyservice/protocol/EidasProxyServiceController.java
index fda1652e..4b699bae 100644
--- a/eidas_modules/eidas_proxy-sevice/src/main/java/at/asitplus/eidas/specific/modules/msproxyservice/protocol/EidasProxyServiceController.java
+++ b/eidas_modules/eidas_proxy-sevice/src/main/java/at/asitplus/eidas/specific/modules/msproxyservice/protocol/EidasProxyServiceController.java
@@ -4,14 +4,18 @@ import java.io.IOException;
import java.text.MessageFormat;
import java.util.Collections;
import java.util.HashMap;
-import java.util.List;
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;
@@ -19,6 +23,7 @@ import org.springframework.web.bind.annotation.RequestMethod;
import com.google.common.collect.ImmutableSortedSet;
+import at.asitplus.eidas.specific.connector.MsEidasNodeConstants;
import at.asitplus.eidas.specific.connector.config.ServiceProviderConfiguration;
import at.asitplus.eidas.specific.modules.auth.eidas.v2.Constants;
import at.asitplus.eidas.specific.modules.auth.eidas.v2.service.EidasAttributeRegistry;
@@ -28,13 +33,18 @@ 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.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;
@@ -56,11 +66,15 @@ public class EidasProxyServiceController extends AbstractController implements I
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";
+
public static final String PROTOCOL_ID = "eidasProxy";
- @Autowired
- private EidasAttributeRegistry attrRegistry;
+ @Autowired EidasAttributeRegistry attrRegistry;
+ @Autowired ProxyServiceAuthenticationAction responseAction;
/**
* End-point that receives authentication requests from eIDAS Node.
@@ -101,7 +115,8 @@ public class EidasProxyServiceController extends AbstractController implements I
ImmutableSortedSet.copyOf(attrRegistry.getCoreAttributeRegistry().getAttributes()));
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);
@@ -114,6 +129,10 @@ public class EidasProxyServiceController extends AbstractController implements I
pendingReq.getUniqueTransactionIdentifier(), EventConstants.TRANSACTION_IP,
httpReq.getRemoteAddr());
+
+ //TODO: map issuer from eIDAS request to countryCode in special cases
+
+
// validate eIDAS Authn. request and set into pending-request
validateEidasAuthnRequest(eidasRequest);
pendingReq.setEidasRequest(eidasRequest);
@@ -156,10 +175,43 @@ public class EidasProxyServiceController extends AbstractController implements I
}
@Override
- public boolean generateErrorMessage(Throwable e, HttpServletRequest request, HttpServletResponse response,
- IRequest protocolRequest) throws Throwable {
+ 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(statusMessager.mapInternalErrorToExternalError(statusMessager.getResponseErrorCode(e)))
+ .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());
- // TODO: implement error handling for eIDAS Node communication
+ }
+
return false;
}
@@ -189,16 +241,17 @@ public class EidasProxyServiceController extends AbstractController implements I
* @throws EidasProxyServiceException In case of a validation error
*/
private void validateEidasAuthnRequest(ILightRequest eidasRequest) throws EidasProxyServiceException {
- if (StringUtils.isEmpty(eidasRequest.getSpCountryCode())) {
+ if (StringUtils.isEmpty(eidasRequest.getIssuer())) {
throw new EidasProxyServiceException(ERROR_05, null);
}
-
- /*
- * TODO: validate requested attributes --> check if natural-person and
- * legal-person attributes requested in parallel
- */
-
+
+ // check if natural-person and legal-person attributes requested in parallel
+ if (isLegalPersonRequested(eidasRequest) && isNaturalPersonRequested(eidasRequest)) {
+ throw new EidasProxyServiceException(ERROR_08, null);
+
+ }
+
// TODO: validate some other stuff
}
@@ -213,63 +266,167 @@ public class EidasProxyServiceController extends AbstractController implements I
private ISpConfiguration generateSpConfigurationFromEidasRequest(ILightRequest eidasRequest)
throws EidasProxyServiceException {
try {
- final String spCountry = eidasRequest.getSpCountryCode();
- final Map<String, String> spConfigMap = new HashMap<>();
+
+ 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);
- // TODO: how we get the EntityId from eIDAS connector?
- spConfigMap.put(EaafConfigConstants.SERVICE_UNIQUEIDENTIFIER,
+ }
+
+ // build FriendyName from CountryCode and SPType
+ connectorConfigMap.put(MsEidasNodeConstants.PROP_CONFIG_SP_FRIENDLYNAME,
MessageFormat.format(MsProxyServiceConstants.TEMPLATE_SP_UNIQUE_ID,
spCountry, eidasRequest.getSpType()));
- final ServiceProviderConfiguration spConfig = new ServiceProviderConfiguration(spConfigMap, authConfig);
+ // 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()));
- // TODO: check if only mandates are allowed in case of legal person requested
- // --> set force-mandate flag
- spConfig.setMandateProfiles(buildMandateProfileConfiguration(eidasRequest));
-
+ //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 List<String> buildMandateProfileConfiguration(ILightRequest eidasRequest) {
- if (authConfig.getBasicConfigurationBoolean(
- MsProxyServiceConstants.CONIG_PROPS_EIDAS_PROXY_MANDATES_ENABLED, false)) {
- log.trace("eIDAS Proxy-Service allows mandates. Selecting profiles ... ");
-
- /*
- * TODO: split profiles in natural-person and legal-person profiles and select
- * correct one based on requested attributes
- */
- final List<String> spMandateProfiles = authConfig.getBasicConfigurationWithPrefix(
- MsProxyServiceConstants.CONIG_PROPS_EIDAS_PROXY_MANDATES_PROFILE_SPECIFIC)
- .entrySet().stream()
- .filter(el -> el.getKey().endsWith(eidasRequest.getSpCountryCode().toLowerCase()))
- .findFirst()
- .map(el -> KeyValueUtils.getListOfCsvValues(el.getValue()))
- .orElse(KeyValueUtils.getListOfCsvValues(
- authConfig.getBasicConfiguration(
- MsProxyServiceConstants.CONIG_PROPS_EIDAS_PROXY_MANDATES_PROFILE_DEFAULT)));
-
- log.debug("Set mandate-profiles: {} to request from country: {}",
- spMandateProfiles, eidasRequest.getSpCountryCode());
- return spMandateProfiles;
+
+ 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 (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
+ boolean isLegalPersonRequested = isLegalPersonRequested(eidasRequest);
+
+ // set mandate profiles
+ if (isLegalPersonRequested) {
+ spConfig.setMandateProfiles(KeyValueUtils.getListOfCsvValues(
+ spConfig.getConfigurationValue(MsProxyServiceConstants.CONIG_PROPS_CONNECTOR_MANDATES_PROFILE_LEGAL)));
+
+ spConfig.setMandateMode(SpMandateModes.LEGAL_FORCE);
+
+ } else if (isNaturalPersonRequested(eidasRequest)) {
+ spConfig.setMandateProfiles(KeyValueUtils.getListOfCsvValues(
+ spConfig.getConfigurationValue(MsProxyServiceConstants.CONIG_PROPS_CONNECTOR_MANDATES_PROFILE_NATURAL)));
+
+ spConfig.setMandateMode(SpMandateModes.NATURAL);
+
}
- return Collections.emptyList();
+ log.debug("Set mandate-profiles: {} to request from issuer: {}",
+ spConfig.getMandateProfiles(), spConfig.getUniqueIdentifier());
+
+ if (isLegalPersonRequested && spConfig.getMandateProfiles().isEmpty()) {
+ throw new EidasProxyServiceException(ERROR_10, null);
+
+ }
+
}
+ private boolean isLegalPersonRequested(ILightRequest eidasRequest) {
+ return eidasRequest.getRequestedAttributes().entrySet().stream()
+ .filter(el -> el.getKey().getFriendlyName().equals(Constants.eIDAS_ATTR_LEGALPERSONIDENTIFIER))
+ .findFirst()
+ .isPresent();
+
+ }
+
+ private boolean isNaturalPersonRequested(ILightRequest eidasRequest) {
+ return eidasRequest.getRequestedAttributes().entrySet().stream()
+ .filter(el -> el.getKey().getFriendlyName().equals(Constants.eIDAS_ATTR_PERSONALIDENTIFIER))
+ .findFirst()
+ .isPresent();
+
+ }
}