net.shibboleth.idp.attribute.filter.AttributeFilterImpl.java Source code

Java tutorial

Introduction

Here is the source code for net.shibboleth.idp.attribute.filter.AttributeFilterImpl.java

Source

/*
 * Licensed to the University Corporation for Advanced Internet Development, 
 * Inc. (UCAID) under one or more contributor license agreements.  See the 
 * NOTICE file distributed with this work for additional information regarding
 * copyright ownership. The UCAID licenses this file to You 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 net.shibboleth.idp.attribute.filter;

import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Map;

import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import javax.annotation.concurrent.ThreadSafe;

import net.shibboleth.idp.attribute.IdPAttribute;
import net.shibboleth.idp.attribute.filter.context.AttributeFilterContext;
import net.shibboleth.idp.attribute.filter.context.AttributeFilterWorkContext;
import net.shibboleth.idp.service.AbstractServiceableComponent;
import net.shibboleth.utilities.java.support.annotation.constraint.NonnullElements;
import net.shibboleth.utilities.java.support.annotation.constraint.NotEmpty;
import net.shibboleth.utilities.java.support.annotation.constraint.NullableElements;
import net.shibboleth.utilities.java.support.annotation.constraint.Unmodifiable;
import net.shibboleth.utilities.java.support.collection.CollectionSupport;
import net.shibboleth.utilities.java.support.component.ComponentInitializationException;
import net.shibboleth.utilities.java.support.component.ComponentSupport;
import net.shibboleth.utilities.java.support.logic.Constraint;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.google.common.base.Predicates;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Iterables;

//TODO(lajoie) perf metrics

/** Service that filters out attributes and values based upon loaded policies. */
@ThreadSafe
public class AttributeFilterImpl extends AbstractServiceableComponent<AttributeFilter> implements AttributeFilter {

    /** Class logger. */
    private final Logger log = LoggerFactory.getLogger(AttributeFilterImpl.class);

    /** Filter policies used by this engine. */
    private final List<AttributeFilterPolicy> filterPolicies;

    /** Log prefix. */
    private String logPrefix;

    /**
     * Constructor.
     * 
     * @param engineId ID of this engine
     * @param policies filter policies used by this engine
     */
    public AttributeFilterImpl(@Nonnull @NotEmpty String engineId,
            @Nullable @NullableElements final Collection<AttributeFilterPolicy> policies) {
        setId(engineId);

        ArrayList<AttributeFilterPolicy> checkedPolicies = new ArrayList<AttributeFilterPolicy>();
        CollectionSupport.addIf(checkedPolicies, policies, Predicates.notNull());
        filterPolicies = ImmutableList.copyOf(Iterables.filter(checkedPolicies, Predicates.notNull()));
    }

    /**
     * Gets the immutable collection of filter policies.
     * 
     * @return immutable collection of filter policies
     */
    @Override
    @Nonnull
    @NonnullElements
    @Unmodifiable
    public List<AttributeFilterPolicy> getFilterPolicies() {
        return filterPolicies;
    }

    /**
     * Filters attributes and values. This filtering process may remove attributes and values but must never add them.
     * 
     * @param filterContext context containing the attributes to be filtered and collecting the results of the filtering
     *            process
     * 
     * @throws AttributeFilterException thrown if there is a problem retrieving or applying the attribute filter policy
     */
    @Override
    public void filterAttributes(@Nonnull final AttributeFilterContext filterContext)
            throws AttributeFilterException {
        ComponentSupport.ifNotInitializedThrowUninitializedComponentException(this);
        ComponentSupport.ifDestroyedThrowDestroyedComponentException(this);

        Constraint.isNotNull(filterContext, "Attribute filter context can not be null");
        Map<String, IdPAttribute> prefilteredAttributes = filterContext.getPrefilteredIdPAttributes();

        // Create work context to hold intermediate results.
        filterContext.getSubcontext(AttributeFilterWorkContext.class, true);

        log.debug("{} beginning process of filtering the following {} attributes: {}",
                new Object[] { getLogPrefix(), prefilteredAttributes.size(), prefilteredAttributes.keySet(), });

        final List<AttributeFilterPolicy> policies = getFilterPolicies();
        for (AttributeFilterPolicy policy : policies) {
            policy.apply(filterContext);
        }

        IdPAttribute filteredAttribute;
        for (String attributeId : filterContext.getPrefilteredIdPAttributes().keySet()) {
            final Collection filteredAttributeValues = getFilteredValues(attributeId, filterContext);
            if (null != filteredAttributeValues && !filteredAttributeValues.isEmpty()) {
                try {
                    filteredAttribute = prefilteredAttributes.get(attributeId).clone();
                } catch (CloneNotSupportedException e) {
                    throw new AttributeFilterException(e);
                }
                filteredAttribute.setValues(filteredAttributeValues);
                filterContext.getFilteredIdPAttributes().put(filteredAttribute.getId(), filteredAttribute);
            }
        }
    }

    /**
     * Gets the permitted values for the given attribute from the
     * {@link AttributeFilterContext#getPermittedIdPAttributeValues()} and removes all denied values given in the
     * {@link AttributeFilterContext#getDeniedAttributeValues()}.
     * 
     * @param attributeId ID of the attribute whose values are to be retrieved
     * @param filterContext current attribute filter context
     * 
     * @return null if no values were permitted to be released, an empty collection if values were permitted but then
     *         all were removed by deny policies, a collection containing permitted values
     */
    @Nullable
    protected Collection getFilteredValues(@Nonnull @NotEmpty final String attributeId,
            @Nonnull final AttributeFilterContext filterContext) {
        Constraint.isNotNull(attributeId, "attributeId can not be null");
        Constraint.isNotNull(filterContext, "filterContext can not be null");

        final AttributeFilterWorkContext filterWorkContext = filterContext
                .getSubcontext(AttributeFilterWorkContext.class, false);
        Constraint.isNotNull(filterWorkContext, "Attribute filter work context can not be null");

        final Collection filteredAttributeValues = filterWorkContext.getPermittedIdPAttributeValues()
                .get(attributeId);

        if (filteredAttributeValues == null || filteredAttributeValues.isEmpty()) {
            log.debug("Attribute filtering engine '{}': no policy permitted release of attribute {} values",
                    getId(), attributeId);
            return null;
        }

        if (filterWorkContext.getDeniedAttributeValues().containsKey(attributeId)) {
            filteredAttributeValues.removeAll(filterWorkContext.getDeniedAttributeValues().get(attributeId));
        }

        if (filteredAttributeValues.isEmpty()) {
            log.debug("Attribute filtering engine '{}': deny policies filtered out all values for attribute '{}'",
                    getId(), attributeId);
        } else {
            log.debug("Attribute filtering engine '{}': {} values for attribute '{}' remained after filtering",
                    new Object[] { filteredAttributeValues.size(), attributeId, });
        }

        return filteredAttributeValues;
    }

    /** {@inheritDoc} */
    @Override
    protected void doInitialize() throws ComponentInitializationException {
        super.doInitialize();
        logPrefix = null;
    }

    /**
     * Get the prefix for logging.
     * 
     * @return Returns the logPrefix.
     */
    protected String getLogPrefix() {
        String result;

        result = logPrefix;
        if (null == result) {
            result = new StringBuffer("Attribute filtering engine '").append(getId()).append("' ").toString();
            logPrefix = result;
        }
        return result;
    }

    /** {@inheritDoc} */
    @Override
    @Nonnull
    public AttributeFilter getComponent() {
        return this;
    }
}