All Downloads are FREE. Search and download functionalities are using the official Maven repository.

se.swedenconnect.opensaml.sweid.saml2.validation.SwedishEidAttributeStatementValidator Maven / Gradle / Ivy

There is a newer version: 2.2.2
Show newest version
/*
 * Copyright 2016-2024 Sweden Connect
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * 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.
 */
package se.swedenconnect.opensaml.sweid.saml2.validation;

import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;

import org.opensaml.core.xml.XMLObject;
import org.opensaml.saml.common.assertion.AssertionValidationException;
import org.opensaml.saml.common.assertion.ValidationContext;
import org.opensaml.saml.common.assertion.ValidationResult;
import org.opensaml.saml.saml2.core.Assertion;
import org.opensaml.saml.saml2.core.Attribute;
import org.opensaml.saml.saml2.core.AttributeStatement;
import org.opensaml.saml.saml2.core.Statement;
import org.opensaml.saml.saml2.metadata.EntityDescriptor;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import se.swedenconnect.opensaml.common.validation.CoreValidatorParameters;
import se.swedenconnect.opensaml.saml2.assertion.validation.AbstractAttributeStatementValidator;
import se.swedenconnect.opensaml.saml2.attribute.AttributeUtils;
import se.swedenconnect.opensaml.saml2.metadata.scope.ScopeUtils;
import se.swedenconnect.opensaml.sweid.saml2.attribute.AttributeSet;
import se.swedenconnect.opensaml.sweid.saml2.attribute.AttributesValidationException;

/**
 * Validator for {@link AttributeStatement}s.
 *
 * 

* Supports the following {@link ValidationContext} static parameters: *

*
    *
  • {@link #REQUIRED_ATTRIBUTE_SET}: Optional. Holds a {@link AttributeSet} that tells which attributes we require to * find in the assertion.
  • *
  • {@link #REQUIRED_ATTRIBUTES}: Optional. Holds a collection of strings that are the attribute names that we * require to find in the assertion.
  • *
  • {@link #SCOPED_ATTRIBUTES}: Optional. Carries a {@link Collection} of strings holding attribute names of * requested attributes.
  • *
* *

* Note that the two above parameters may be combined. If no parameter for requested attributes is passed, no validation * will be performed. *

* * @author Martin Lindström ([email protected]) */ public class SwedishEidAttributeStatementValidator extends AbstractAttributeStatementValidator { /** * Key for a validation context parameter. Carries a {@link AttributeSet} holding the required attributes. */ public static final String REQUIRED_ATTRIBUTE_SET = CoreValidatorParameters.STD_PREFIX + ".RequiredAttributeSet"; /** * Key for a validation context parameter. Carries a {@link Collection} of strings holding attribute names of * requested attributes. */ public static final String REQUIRED_ATTRIBUTES = CoreValidatorParameters.STD_PREFIX + ".RequiredAttributes"; /** * Key for a validation context parameter. Carries a {@link Collection} of strings holding the attribute names for * attributes that are "scoped". */ public static final String SCOPED_ATTRIBUTES = CoreValidatorParameters.STD_PREFIX + ".ScopedAttributes"; /** Class logger. */ private static final Logger log = LoggerFactory.getLogger(SwedishEidAttributeStatementValidator.class); /** {@inheritDoc} */ @Override public ValidationResult validate(final Statement statement, final Assertion assertion, final ValidationContext context) throws AssertionValidationException { final ValidationResult result = super.validate(statement, assertion, context); if (result != ValidationResult.VALID) { return result; } final AttributeStatement attributeStatement = (AttributeStatement) statement; final List attributes = Optional.ofNullable(AttributeStatement.class.cast(statement).getAttributes()) .orElse(Collections.emptyList()); return this.validateScopedAttributes(attributes, attributeStatement, assertion, context); } /** * Validates that the required attributes have been received by using the optional context parameter * {@link #REQUIRED_ATTRIBUTE_SET} that holds an {@link AttributeSet} and/or the list of attribute names from the * parameter {@link SwedishEidAttributeStatementValidator#REQUIRED_ATTRIBUTES}. */ @Override protected ValidationResult validateRequiredAttributes(final List attributes, final AttributeStatement statement, final Assertion assertion, final ValidationContext context) { final AttributeSet attributeSet = (AttributeSet) context.getStaticParameters().get(REQUIRED_ATTRIBUTE_SET); if (attributeSet != null) { try { attributeSet.validateAttributes(assertion, null); } catch (final AttributesValidationException e) { log.info("Required attributes check failed: {}", e.getMessage()); context.getValidationFailureMessages().add(e.getMessage()); return ValidationResult.INVALID; } } final Collection requiredAttributes = this.getRequiredAttributes(context); if (requiredAttributes != null) { for (final String attr : requiredAttributes) { if (!attributes.stream().filter(a -> attr.equals(a.getName())).findAny().isPresent()) { final String msg = String.format("Required attribute '%s' was not part of the attribute statement", attr); log.info("Required attributes check failed: {}", msg); context.getValidationFailureMessages().add(msg); return ValidationResult.INVALID; } } } if (attributeSet == null && requiredAttributes.isEmpty()) { log.debug("No required attributes were supplied - can not check if required attributes were delivered"); } return ValidationResult.VALID; } /** * Returns the required attributes. * * @param context the validation context * @return a collection of attribute names (never {@code null}) */ protected Collection getRequiredAttributes(final ValidationContext context) { @SuppressWarnings("unchecked") final Collection attributes = (Collection) context.getStaticParameters().get(REQUIRED_ATTRIBUTES); return attributes != null ? attributes : Collections.emptyList(); } /** * Validates that the issuing IdP has been authorized to issue scoped attributes. * * @param attributes a list of the attributes * @param statement the statement * @param assertion the assertion * @param context the validation context * @return a validation result */ protected ValidationResult validateScopedAttributes(final List attributes, final AttributeStatement statement, final Assertion assertion, final ValidationContext context) { @SuppressWarnings("unchecked") final Collection scopedAttributes = (Collection) context.getStaticParameters().get(SCOPED_ATTRIBUTES); if (scopedAttributes == null || scopedAttributes.isEmpty()) { // Nothing to check return ValidationResult.VALID; } final List attributesToCheck = attributes.stream() .filter(a -> a.getName() != null && scopedAttributes.contains(a.getName())) .collect(Collectors.toList()); if (attributesToCheck.isEmpty()) { // No attributes to check ... return ValidationResult.VALID; } // For the check we need the IdP metadata ... // final EntityDescriptor idpMetadata = (EntityDescriptor) context.getStaticParameters().get(CoreValidatorParameters.IDP_METADATA); if (idpMetadata == null) { final String msg = String.format("Could not check scoped attributes. '%s' parameter is missing", CoreValidatorParameters.IDP_METADATA); log.debug(msg); context.getValidationFailureMessages().add(msg); return ValidationResult.INDETERMINATE; } final List authorizedScopes = ScopeUtils.getScopeExtensions(idpMetadata); for (final Attribute scopedAttribute : attributesToCheck) { if (!ScopeUtils.isAuthorized(scopedAttribute, authorizedScopes)) { final String msg = String.format("IdP '%s' is not authorized to issue scoped attribute '%s' for domain '%s'", idpMetadata.getEntityID(), scopedAttribute.getName(), ScopeUtils.getScopedDomain(AttributeUtils.getAttributeStringValue(scopedAttribute))); log.debug(msg); context.getValidationFailureMessages().add(msg); return ValidationResult.INVALID; } } return ValidationResult.VALID; } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy