net.shibboleth.idp.saml.attribute.mapping.AbstractSAMLAttributeDesignatorsMapper.java Source code

Java tutorial

Introduction

Here is the source code for net.shibboleth.idp.saml.attribute.mapping.AbstractSAMLAttributeDesignatorsMapper.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.saml.attribute.mapping;

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

import javax.annotation.Nonnull;
import javax.annotation.Nullable;

import net.shibboleth.idp.attribute.AttributeEncoder;
import net.shibboleth.idp.attribute.IdPAttribute;
import net.shibboleth.idp.attribute.resolver.AttributeDefinition;
import net.shibboleth.idp.attribute.resolver.AttributeResolver;
import net.shibboleth.idp.saml.attribute.encoding.AttributeDesignatorMapperProcessor;
import net.shibboleth.utilities.java.support.annotation.constraint.NonnullElements;
import net.shibboleth.utilities.java.support.annotation.constraint.NotEmpty;
import net.shibboleth.utilities.java.support.component.AbstractIdentifiableInitializableComponent;
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.opensaml.saml.saml1.core.AttributeDesignator;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.google.common.base.Supplier;
import com.google.common.collect.ArrayListMultimap;
import com.google.common.collect.HashMultimap;
import com.google.common.collect.Multimap;

/**
 * The class contains the mechanics to go from a list of {@link AttributeDesignator}s to a {@link Multimap} of
 * {@link String},{@link IdPAttribute} (or derived, or null). The representation as a {@link Multimap} is useful for
 * filtering situations and is exploited by the AttributeInMetadata filter.
 * 
 * @param <OutType> some sort of representation of an IdP attribute
 */
public abstract class AbstractSAMLAttributeDesignatorsMapper<OutType extends IdPAttribute> extends
        AbstractIdentifiableInitializableComponent implements AttributesMapper<AttributeDesignator, OutType> {

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

    /** The mappers we can apply. */
    @Nonnull
    @NonnullElements
    private Collection<AttributeMapper<AttributeDesignator, OutType>> mappers;

    /** The String used to prefix log message. */
    @Nullable
    private String logPrefix;

    /** Default Constructor. */
    public AbstractSAMLAttributeDesignatorsMapper() {
        mappers = Collections.emptyList();
    }

    /**
     * Constructor to create the mapping from an existing resolver.
     * 
     * <p>This code inverts the {@link AttributeEncoder} (internal attribute -> SAML Attributes) into
     * {@link AttributeMapper} (SAML [AttributeDesignators] -> internal [Requested] Attributes). <br/>
     * to generate the {@link AbstractSAMLAttributeDesignatorMapper} (with no
     * {@link AbstractSAMLAttributeDesignatorMapper#getAttributeIds()}. These are accumulated into a {@link Multimap},
     * where the key is the {@link AbstractSAMLAttributeDesignatorMapper} and the values are the (IdP) attribute names.
     * The collection of {@link AttributeMapper}s can then be extracted from the map, and the appropriate internal names
     * added (these being the value of the {@link Multimap})</p>
     * 
     * @param resolver the resolver
     * @param id the ID
     * @param mapperFactory factory to generate new mappers of the correct type.
     */
    public AbstractSAMLAttributeDesignatorsMapper(@Nonnull final AttributeResolver resolver,
            @Nonnull @NotEmpty final String id,
            @Nonnull final Supplier<AbstractSAMLAttributeDesignatorMapper<OutType>> mapperFactory) {

        setId(id);
        mappers = Collections.emptyList();

        final Multimap<AbstractSAMLAttributeDesignatorMapper<OutType>, String> theMappers = HashMultimap.create();

        for (final AttributeDefinition attributeDef : resolver.getAttributeDefinitions().values()) {
            for (final AttributeEncoder encoder : attributeDef.getAttributeEncoders()) {
                if (encoder instanceof AttributeDesignatorMapperProcessor) {
                    // There is an appropriate reverse mapper.
                    final AttributeDesignatorMapperProcessor factory = (AttributeDesignatorMapperProcessor) encoder;
                    final AbstractSAMLAttributeDesignatorMapper<OutType> mapper = mapperFactory.get();
                    factory.populateAttributeMapper(mapper);

                    theMappers.put(mapper, attributeDef.getId());
                }
            }
        }

        mappers = new ArrayList<>(theMappers.values().size());

        for (final Entry<AbstractSAMLAttributeDesignatorMapper<OutType>, Collection<String>> entry : theMappers
                .asMap().entrySet()) {

            final AbstractSAMLAttributeDesignatorMapper<OutType> mapper = entry.getKey();
            mapper.setAttributeIds(new ArrayList<>(entry.getValue()));
            mappers.add(mapper);
        }
    }

    /**
     * Get the mappers.
     * 
     * @return Returns the mappers.
     */
    @Nonnull
    @NonnullElements
    public Collection<AttributeMapper<AttributeDesignator, OutType>> getMappers() {
        return mappers;
    }

    /**
     * Set the attribute mappers into the lookup map.
     * 
     * @param theMappers The mappers to set.
     */
    public void setMappers(@Nonnull Collection<AttributeMapper<AttributeDesignator, OutType>> theMappers) {
        mappers = Constraint.isNotNull(theMappers, "Mappers list cannot be null");
    }

    /** {@inheritDoc} */
    @Override
    @Nonnull
    @NonnullElements
    public Multimap<String, OutType> mapAttributes(
            @Nonnull @NonnullElements final List<AttributeDesignator> prototypes) {

        final Multimap<String, OutType> result = ArrayListMultimap.create();

        for (final AttributeDesignator prototype : prototypes) {
            for (final AttributeMapper<AttributeDesignator, OutType> mapper : mappers) {

                final Map<String, OutType> mappedAttributes = mapper.mapAttribute(prototype);

                log.debug("{} SAML attribute '{}' mapped to {} attributes by mapper '{}'", getLogPrefix(),
                        prototype.getAttributeName(), mappedAttributes.size(), mapper.getId());

                for (final Entry<String, OutType> entry : mappedAttributes.entrySet()) {
                    result.put(entry.getKey(), entry.getValue());
                }
            }
        }
        return result;
    }

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

        logPrefix = null;
        for (final AttributeMapper mapper : mappers) {
            ComponentSupport.initialize(mapper);
        }
    }

    /**
     * Return a string which is to be prepended to all log messages.
     * 
     * @return "Attribute Mappers '<ID>' :"
     */
    @Nonnull
    @NotEmpty
    private String getLogPrefix() {
        String s = logPrefix;
        if (null == s) {
            s = new StringBuilder("Attribute Mappers : '").append(getId()).append("':").toString();
            logPrefix = s;
        }
        return s;
    }

}