Package org.opensaml.saml2.metadata.provider

Source Code of org.opensaml.saml2.metadata.provider.SignatureValidationFilter

/*
* Copyright [2007] [University Corporation for Advanced Internet Development, Inc.]
*
* 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 org.opensaml.saml2.metadata.provider;

import java.util.Iterator;

import org.opensaml.saml2.metadata.EntitiesDescriptor;
import org.opensaml.saml2.metadata.EntityDescriptor;
import org.opensaml.security.SAMLSignatureProfileValidator;
import org.opensaml.xml.XMLObject;
import org.opensaml.xml.security.CriteriaSet;
import org.opensaml.xml.security.SecurityException;
import org.opensaml.xml.security.credential.UsageType;
import org.opensaml.xml.security.criteria.UsageCriteria;
import org.opensaml.xml.signature.SignableXMLObject;
import org.opensaml.xml.signature.Signature;
import org.opensaml.xml.signature.SignatureTrustEngine;
import org.opensaml.xml.validation.ValidationException;
import org.opensaml.xml.validation.Validator;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
* A metadata filter that validates XML signatures.
*/
public class SignatureValidationFilter implements MetadataFilter {
   
    /** Class logger. */
    private final Logger log = LoggerFactory.getLogger(SignatureValidationFilter.class);

    /** Trust engine used to validate a signature. */
    private SignatureTrustEngine signatureTrustEngine;

    /** Indicates whether signed metadata is required. */
    private boolean requireSignature;
   
    /** Set of externally specified default criteria for input to the trust engine. */
    private CriteriaSet defaultCriteria;
   
    /** Pre-validator for XML Signature instances. */
    private Validator<Signature> sigValidator;

    /**
     * Constructor.
     *
     * @param engine the trust engine used to validate signatures on incoming metadata.
     */
    public SignatureValidationFilter(SignatureTrustEngine engine) {
        if (engine == null) {
            throw new IllegalArgumentException("Signature trust engine may not be null");
        }

        signatureTrustEngine = engine;
        sigValidator = new SAMLSignatureProfileValidator();
    }
   
    /**
     * Constructor.
     *
     * @param engine the trust engine used to validate signatures on incoming metadata.
     * @param signatureValidator optional pre-validator used to validate Signature elements prior to the actual
     *            cryptographic validation operation
     */
    public SignatureValidationFilter(SignatureTrustEngine engine, Validator<Signature> signatureValidator) {
        if (engine == null) {
            throw new IllegalArgumentException("Signature trust engine may not be null");
        }

        signatureTrustEngine = engine;
        sigValidator = signatureValidator;
    }

    /**
     * Gets the trust engine used to validate signatures on incoming metadata.
     *
     * @return trust engine used to validate signatures on incoming metadata
     */
    public SignatureTrustEngine getSignatureTrustEngine() {
        return signatureTrustEngine;
    }
   
    /**
     * Get the validator used to perform pre-validation on Signature tokens.
     *
     * @return the configured Signature validator, or null
     */
    public Validator<Signature> getSignaturePrevalidator() {
        return sigValidator;
    }

    /**
     * Gets whether incoming metadata is required to be signed.
     *
     * @return whether incoming metadata is required to be signed
     */
    public boolean getRequireSignature() {
        return requireSignature;
    }

    /**
     * Sets whether incoming metadata is required to be signed.
     *
     * @param require whether incoming metadata is required to be signed
     */
    public void setRequireSignature(boolean require) {
        requireSignature = require;
    }
    /**
     * Get the set of default criteria used as input to the trust engine.
     *
     * @return the criteria set
     */
    public CriteriaSet getDefaultCriteria() {
        return defaultCriteria;
    }
   
    /**
     * Set the set of default criteria used as input to the trust engine.
     *
     * @param newCriteria the new criteria set to use
     */
    public void setDefaultCriteria(CriteriaSet newCriteria) {
        defaultCriteria = newCriteria;
    }

    /** {@inheritDoc} */
    public void doFilter(XMLObject metadata) throws FilterException {
        SignableXMLObject signableMetadata = (SignableXMLObject) metadata;

        if (!signableMetadata.isSigned()){
            if (getRequireSignature()) {
                throw new FilterException("Metadata was unsigned and signatures are required.");
            } else {
                if (signableMetadata instanceof EntityDescriptor) {
                    log.trace("Root EntityDescriptor was not signed, filter processing terminated");
                    return;
                } else {
                    log.trace("Root EntitiesDescriptor was not signed, continuing filter processing of children");
                }
            }
        }
       
        if (signableMetadata instanceof EntityDescriptor) {
            EntityDescriptor entityDescriptor = (EntityDescriptor) signableMetadata;
            verifySignature(entityDescriptor, entityDescriptor.getEntityID(), false);
        } else if (signableMetadata instanceof EntitiesDescriptor) {
            processEntityGroup((EntitiesDescriptor) signableMetadata);
        } else {
            log.error("Internal error, metadata object was of an unsupported type: {}", metadata.getClass().getName());
        }
    }
   
    /**
     * Process the signatures on the specified EntitiesDescriptor and any signed children.
     *
     * If signature verification fails on a child, it will be removed from the entities descriptor group.
     *
     * @param entitiesDescriptor the EntitiesDescriptor to be processed
     * @throws FilterException thrown if an error occurs during the signature verification process
     *                          on the root EntitiesDescriptor specified
     */
    protected void processEntityGroup(EntitiesDescriptor entitiesDescriptor) throws FilterException {
        log.trace("Processing EntitiesDescriptor group: {}", entitiesDescriptor.getName());
       
        if (entitiesDescriptor.isSigned()) {
            verifySignature(entitiesDescriptor, entitiesDescriptor.getName(), true);
        }
       
        Iterator<EntityDescriptor> entityIter = entitiesDescriptor.getEntityDescriptors().iterator();
        while (entityIter.hasNext()) {
            EntityDescriptor entityChild = entityIter.next();
            if (!entityChild.isSigned()) {
                log.trace("EntityDescriptor member '{}' was not signed, skipping signature processing...",
                        entityChild.getEntityID());
                continue;
            } else {
                log.trace("Processing signed EntityDescriptor member: {}", entityChild.getEntityID());
            }
           
            try {
                verifySignature(entityChild, entityChild.getEntityID(), false);
            } catch (FilterException e) {
               log.error("EntityDescriptor '{}' failed signature verification, removing from metadata provider",
                       entityChild.getEntityID());
               entityIter.remove();
            }
        }
       
        Iterator<EntitiesDescriptor> entitiesIter = entitiesDescriptor.getEntitiesDescriptors().iterator();
        while(entitiesIter.hasNext()) {
            EntitiesDescriptor entitiesChild = entitiesIter.next();
            log.trace("Processing EntitiesDescriptor member: {}", entitiesChild.getName());
            try {
                processEntityGroup(entitiesChild);
            } catch (FilterException e) {
               log.error("EntitiesDescriptor '{}' failed signature verification, removing from metadata provider",
                       entitiesChild.getName());
               entityIter.remove();
            }
        }
       
    }

    /**
     * Evaluate the signature on the signed metadata instance.
     *
     * @param signedMetadata the metadata object whose signature is to be verified
     * @param metadataEntryName the EntityDescriptor entityID or EntitiesDescriptor Name
     *                          of the signature being evaluated
     * @param isEntityGroup flag indicating whether the signed object is a metadata group (EntitiesDescriptor),
     *                      primarily useful for constructing a criteria set for the trust engine
     * @throws FilterException thrown if the metadata entry's signature can not be established as trusted,
     *                         or if an error occurs during the signature verification process
     */
    protected void verifySignature(SignableXMLObject signedMetadata, String metadataEntryName,
            boolean isEntityGroup) throws FilterException {
       
        log.debug("Verifying signature on metadata entry: {}", metadataEntryName);
       
        Signature signature = signedMetadata.getSignature();
        if (signature == null) {
            // We shouldn't ever be calling this on things that aren't actually signed, but just to be safe...
            log.warn("Signature was null, skipping processing on metadata entry: {}", metadataEntryName);
            return;
        }
       
        performPreValidation(signature, metadataEntryName);
       
        CriteriaSet criteriaSet = buildCriteriaSet(signedMetadata, metadataEntryName, isEntityGroup);
       
        try {
            if ( getSignatureTrustEngine().validate(signature, criteriaSet) ) {
                log.trace("Signature trust establishment succeeded for metadata entry {}", metadataEntryName);
                return;
            } else {
                log.error("Signature trust establishment failed for metadata entry {}", metadataEntryName);
                throw new FilterException("Signature trust establishment failed for metadata entry");
            }
        } catch (SecurityException e) {
            // Treat evaluation errors as fatal
            log.error("Error processing signature verification for metadata entry '{}': {} ",
                    metadataEntryName, e.getMessage());
            throw new FilterException("Error processing signature verification for metadata entry", e);
        }
    }

    /**
     * Perform pre-validation on the Signature token.
     *
     * @param signature the signature to evaluate
     * @param metadataEntryName the EntityDescriptor entityID or EntitiesDescriptor Name
     *                          of the signature being evaluated
     * @throws FilterException thrown if the signature element fails pre-validation
     */
    protected void performPreValidation(Signature signature, String metadataEntryName) throws FilterException {
        if (getSignaturePrevalidator() != null) {
            try {
                getSignaturePrevalidator().validate(signature);
            } catch (ValidationException e) {
                log.error("Signature on metadata entry '{}' failed signature pre-validation", metadataEntryName);
                throw new FilterException("Metadata instance signature failed signature pre-validation", e);
            }
        }
    }
   
    /**
     * Build the criteria set which will be used as input to the configured trust engine.
     *
     * @param signedMetadata the metadata element whose signature is being verified
     * @param metadataEntryName the EntityDescriptor entityID or EntitiesDescriptor Name
     *                          of the signature being evaluated
     * @param isEntityGroup flag indicating whether the signed object is a metadata group (EntitiesDescriptor)
     * @return the newly constructed criteria set
     */
    protected CriteriaSet buildCriteriaSet(SignableXMLObject signedMetadata,
            String metadataEntryName, boolean isEntityGroup) {
       
        CriteriaSet newCriteriaSet = new CriteriaSet();
       
        if (getDefaultCriteria() != null) {
            newCriteriaSet.addAll( getDefaultCriteria() );
        }
       
        //TODO how to handle adding dynamic entity ID (or other) criteria (if at all?),
       
        if (!newCriteriaSet.contains(UsageCriteria.class)) {
            newCriteriaSet.add( new UsageCriteria(UsageType.SIGNING) );
        }
       
        return newCriteriaSet;
    }
}
TOP

Related Classes of org.opensaml.saml2.metadata.provider.SignatureValidationFilter

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.