aboutsummaryrefslogtreecommitdiff
path: root/eidas_modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/validator/EidasResponseValidator.java
diff options
context:
space:
mode:
Diffstat (limited to 'eidas_modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/validator/EidasResponseValidator.java')
-rw-r--r--eidas_modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/validator/EidasResponseValidator.java175
1 files changed, 175 insertions, 0 deletions
diff --git a/eidas_modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/validator/EidasResponseValidator.java b/eidas_modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/validator/EidasResponseValidator.java
new file mode 100644
index 00000000..053694cf
--- /dev/null
+++ b/eidas_modules/authmodule-eIDAS-v2/src/main/java/at/asitplus/eidas/specific/modules/auth/eidas/v2/validator/EidasResponseValidator.java
@@ -0,0 +1,175 @@
+/*
+ * Copyright 2018 A-SIT Plus GmbH
+ * AT-specific eIDAS Connector has been developed in a cooperation between EGIZ,
+ * A-SIT Plus GmbH, A-SIT, and Graz University of Technology.
+ *
+ * Licensed under the EUPL, Version 1.2 or - as soon they will be approved by
+ * the European Commission - subsequent versions of the EUPL (the "License");
+ * You may not use this work except in compliance with the License.
+ * You may obtain a copy of the License at:
+ * https://joinup.ec.europa.eu/news/understanding-eupl-v12
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * This product combines work with different licenses. See the "NOTICE" text
+ * file for details on the various modules and licenses.
+ * The "NOTICE" text file is part of the distribution. Any derivative works
+ * that you distribute must include a readable copy of the "NOTICE" text file.
+*/
+
+package at.asitplus.eidas.specific.modules.auth.eidas.v2.validator;
+
+import java.util.List;
+
+import org.apache.commons.lang3.StringUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.collect.ImmutableList;
+
+import at.asitplus.eidas.specific.modules.auth.eidas.v2.Constants;
+import at.asitplus.eidas.specific.modules.auth.eidas.v2.exception.EidasValidationException;
+import at.asitplus.eidas.specific.modules.auth.eidas.v2.service.EidasAttributeRegistry;
+import at.asitplus.eidas.specific.modules.auth.eidas.v2.utils.EidasResponseUtils;
+import at.gv.egiz.eaaf.core.api.IRequest;
+import at.gv.egiz.eaaf.core.impl.data.Trible;
+import eu.eidas.auth.commons.attribute.AttributeDefinition;
+import eu.eidas.auth.commons.attribute.AttributeValue;
+import eu.eidas.auth.commons.light.ILightResponse;
+import eu.eidas.auth.commons.protocol.eidas.LevelOfAssurance;
+
+/**
+ * eIDAS Response validator implementation.
+ *
+ * @author tlenz
+ *
+ */
+public class EidasResponseValidator {
+ private static final Logger log = LoggerFactory.getLogger(EidasResponseValidator.class);
+
+ /**
+ * Validate an eIDAS Response according to internal state.
+ *
+ * @param pendingReq Current pending request
+ * @param eidasResponse eIDAS response object
+ * @param spCountry Country-Code of the Service Provider
+ * @param citizenCountryCode Country-Code of the Citizen
+ * @param attrRegistry eIDAS Attribute registry implementation
+ * @throws EidasValidationException In case of an validation error
+ */
+ public static void validateResponse(IRequest pendingReq, ILightResponse eidasResponse, String spCountry,
+ String citizenCountryCode, EidasAttributeRegistry attrRegistry) throws EidasValidationException {
+
+ /*-----------------------------------------------------|
+ * validate received LoA against minimum required LoA |
+ *_____________________________________________________|
+ */
+ final LevelOfAssurance respLoA = LevelOfAssurance.fromString(eidasResponse.getLevelOfAssurance());
+ final List<String> allowedLoAs = pendingReq.getServiceProviderConfiguration().getRequiredLoA();
+ boolean loaValid = false;
+ for (final String allowedLoaString : allowedLoAs) {
+ final LevelOfAssurance allowedLoa = LevelOfAssurance.fromString(allowedLoaString);
+ if (respLoA.numericValue() >= allowedLoa.numericValue()) {
+ log.debug("Response contains valid LoA. Resume process ... ");
+ loaValid = true;
+ break;
+
+ } else {
+ log.trace("Allowed LoA: " + allowedLoaString + " DOES NOT match response LoA: " + eidasResponse
+ .getLevelOfAssurance());
+ }
+
+ }
+
+ if (!loaValid) {
+ log.error("eIDAS Response LevelOfAssurance is lower than the required! "
+ + "(Resp-LoA:{} Req-LoA:{} )", respLoA.getValue(), allowedLoAs.toArray());
+ throw new EidasValidationException("eidas.06", new Object[] { respLoA.getValue() });
+
+ }
+
+ /*-----------------------------------------------------|
+ * validate 'PersonalIdentifier' attribute |
+ *_____________________________________________________|
+ */
+ final AttributeDefinition<?> attrDefinition = attrRegistry.getCoreAttributeRegistry().getByFriendlyName(
+ Constants.eIDAS_ATTR_PERSONALIDENTIFIER).first();
+ final ImmutableList<? extends AttributeValue<?>> attributeValues = eidasResponse.getAttributes()
+ .getAttributeMap().get(attrDefinition).asList();
+ final List<String> personalIdObj = EidasResponseUtils.translateStringListAttribute(attrDefinition,
+ attributeValues);
+
+ // check if attribute exists
+ if (personalIdObj == null || personalIdObj.isEmpty()) {
+ log.warn("eIDAS Response include NO 'PersonalIdentifier' attriubte "
+ + ".... That can be a BIG problem in further processing steps");
+ throw new EidasValidationException("eidas.05", new Object[] { "NO 'PersonalIdentifier' attriubte" });
+
+ } else if (personalIdObj.size() > 1) {
+ log.warn("eIDAS Response include MORE THAN ONE 'PersonalIdentifier' attriubtes "
+ + ".... That can be a BIG problem in further processing steps");
+ throw new EidasValidationException("eidas.05", new Object[] {
+ "MORE THAN ONE 'PersonalIdentifier' attriubtes" });
+
+ } else {
+ final String natPersId = personalIdObj.get(0);
+ // validate attribute value format
+ final Trible<String, String, String> split =
+ EidasResponseUtils.parseEidasPersonalIdentifier(natPersId);
+ if (split == null) {
+ throw new EidasValidationException("eidas.07",
+ new Object[] {
+ Constants.eIDAS_ATTR_PERSONALIDENTIFIER,
+ "Wrong identifier format" });
+
+ } else {
+ // validation according to eIDAS SAML Attribute Profile, Section 2.2.3
+ if (StringUtils.isEmpty(split.getSecond())) {
+ log.warn("eIDAS attribute value for " + Constants.eIDAS_ATTR_PERSONALIDENTIFIER
+ + " includes NO destination country. Value:" + natPersId);
+ throw new EidasValidationException("eidas.07",
+ new Object[] {
+ Constants.eIDAS_ATTR_PERSONALIDENTIFIER,
+ "No or empty destination country" });
+
+ }
+ if (!split.getSecond().equalsIgnoreCase(spCountry)) {
+ log.warn("eIDAS attribute value for " + Constants.eIDAS_ATTR_PERSONALIDENTIFIER
+ + " includes wrong destination country. Value:" + natPersId
+ + " SP-Country:" + spCountry);
+ throw new EidasValidationException("eidas.07",
+ new Object[] {
+ Constants.eIDAS_ATTR_PERSONALIDENTIFIER,
+ "Destination country does not match to SP country" });
+
+ }
+
+ if (StringUtils.isEmpty(split.getFirst())) {
+ log.warn("eIDAS attribute value for " + Constants.eIDAS_ATTR_PERSONALIDENTIFIER
+ + " includes NO citizen country. Value:" + natPersId);
+ throw new EidasValidationException("eidas.07",
+ new Object[] {
+ Constants.eIDAS_ATTR_PERSONALIDENTIFIER,
+ "No or empty citizen country" });
+
+ }
+ if (!split.getFirst().equalsIgnoreCase(citizenCountryCode)) {
+ log.warn("eIDAS attribute value for " + Constants.eIDAS_ATTR_PERSONALIDENTIFIER
+ + " includes a citizen country that does not match to service-provider country. "
+ + " Value:" + natPersId
+ + " citiczen Country:" + spCountry);
+ throw new EidasValidationException("eidas.07",
+ new Object[] {
+ Constants.eIDAS_ATTR_PERSONALIDENTIFIER,
+ "Citizen country does not match to eIDAS-node country that generates the response" });
+
+ }
+ }
+ }
+
+ }
+}