eu.eidas.auth.engine.configuration.dom.DOMConfigurationParser.java Source code

Java tutorial

Introduction

Here is the source code for eu.eidas.auth.engine.configuration.dom.DOMConfigurationParser.java

Source

/*
 * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by
 * the European Commission - subsequent versions of the EUPL (the "Licence");
 * You may not use this work except in compliance with the Licence. You may
 * obtain a copy of the Licence at:
 *
 * http://www.osor.eu/eupl/european-union-public-licence-eupl-v.1.1
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the Licence is distributed on an "AS IS" basis, WITHOUT
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 * Licence for the specific language governing permissions and limitations under
 * the Licence.
 */

package eu.eidas.auth.engine.configuration.dom;

import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.util.LinkedHashMap;
import java.util.Map;

import javax.annotation.Nonnull;
import javax.xml.parsers.ParserConfigurationException;

import com.google.common.collect.ImmutableMap;

import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;

import eu.eidas.auth.commons.io.ResourceLocator;
import eu.eidas.auth.commons.xml.DocumentBuilderFactoryUtil;
import eu.eidas.auth.engine.configuration.SamlEngineConfigurationException;
import eu.eidas.util.Preconditions;

/**
 * Parses the SAML engine configuration XML file using DOM.
 */
public final class DOMConfigurationParser {

    static final class InstanceTag {

        static final class Attribute {

            static final String NAME = "name";
        }

        static final class ConfigurationTag {

            static final class Attribute {

                static final String NAME = "name";
            }

            static final class ParameterTag {

                static final class Attribute {

                    static final String NAME = "name";

                    static final String VALUE = "value";
                }

                static final String TAG_NAME = "parameter";
            }

            static final String TAG_NAME = "configuration";
        }

        static final String TAG_NAME = "instance";
    }

    public static final String DEFAULT_CONFIGURATION_FILE = "SamlEngine.xml";

    private static final Logger LOG = LoggerFactory.getLogger(DOMConfigurationParser.class);

    /**
     * Read configuration.
     *
     * @return the map< string, instance engine>
     * @throws SAMLEngineException the EIDASSAML engine runtime exception
     */
    @Nonnull
    public static InstanceMap parseConfiguration(@Nonnull String configurationFileName)
            throws SamlEngineConfigurationException {
        Preconditions.checkNotNull(configurationFileName, "configurationFileName");
        LOG.debug("DOM parsing SAML engine configuration file: \"" + configurationFileName + "\"");
        try {
            // Load configuration file
            URL resource = ResourceLocator.getResource(configurationFileName);
            if (null == resource) {
                String message = "SAML engine configuration file \"" + configurationFileName + "\" cannot be found";
                LOG.error(message);
                throw new SamlEngineConfigurationException(message);
            } else {
                LOG.debug("SAML engine configuration file \"" + configurationFileName + "\" found at \""
                        + resource.toExternalForm() + "\"");
            }
            return parseConfiguration(configurationFileName, resource.openStream());
        } catch (IOException ex) {
            LOG.error(ex.getMessage(), ex);
            throw new SamlEngineConfigurationException(ex);
        }
    }

    /**
     * Read configuration.
     *
     * @return the map< string, instance engine>
     * @throws SAMLEngineException the EIDASSAML engine runtime exception
     */
    @Nonnull
    public static InstanceMap parseConfiguration(@Nonnull String configurationFileName,
            @Nonnull InputStream inputStream) throws SamlEngineConfigurationException {
        Preconditions.checkNotNull(configurationFileName, "configurationFileName");
        Preconditions.checkNotNull(inputStream, "inputStream");
        try {
            Document document;
            try (InputStream engineConf = inputStream) {
                document = DocumentBuilderFactoryUtil.parse(engineConf);
            }
            // Read instance
            NodeList instanceTags = document.getElementsByTagName(InstanceTag.TAG_NAME);

            Map<String, InstanceEntry> instanceEntries = new LinkedHashMap<String, InstanceEntry>();

            for (int i = 0, n = instanceTags.getLength(); i < n; i++) {
                Element instanceTag = (Element) instanceTags.item(i);
                InstanceEntry instanceEntry = parseInstanceEntry(configurationFileName, instanceTag);

                // Add to the list of configurations.
                InstanceEntry previous = instanceEntries.put(instanceEntry.getName(), instanceEntry);

                if (null != previous) {
                    String message = "Duplicate instance entry names \"" + instanceEntry.getName()
                            + "\" in SAML engine configuration file \"" + configurationFileName + "\"";
                    LOG.error(message);
                    throw new SamlEngineConfigurationException(message);
                }
            }

            return new InstanceMap(ImmutableMap.copyOf(instanceEntries));
        } catch (IOException | SAXException | ParserConfigurationException ex) {
            LOG.error(ex.getMessage(), ex);
            throw new SamlEngineConfigurationException(ex);
        }
    }

    @Nonnull
    private static ConfigurationEntry parseConfigurationEntry(@Nonnull String configurationFileName,
            @Nonnull String instanceName, @Nonnull Element configurationTag)
            throws SamlEngineConfigurationException {
        String configurationName = configurationTag.getAttribute(InstanceTag.ConfigurationTag.Attribute.NAME);

        if (StringUtils.isBlank(configurationName)) {
            String message = "SAML engine configuration file \"" + configurationFileName
                    + "\" contains a blank configuration name for instance name \"" + instanceName + "\"";
            LOG.error(message);
            throw new SamlEngineConfigurationException(message);
        }

        // Set configuration name.
        String name = configurationName.trim();
        // Read every parameter for this configuration.
        ImmutableMap<String, String> parameters = parseParameters(configurationFileName, instanceName,
                configurationName, configurationTag);

        return new ConfigurationEntry(name, parameters);
    }

    /**
     * Read configuration.
     *
     * @return the map< string, instance engine>
     * @throws SAMLEngineException the EIDASSAML engine runtime exception
     */
    public static InstanceMap parseDefaultConfiguration() throws SamlEngineConfigurationException {
        return parseConfiguration(DEFAULT_CONFIGURATION_FILE);
    }

    @Nonnull
    private static InstanceEntry parseInstanceEntry(@Nonnull String configurationFileName,
            @Nonnull Element instanceTag) throws SamlEngineConfigurationException {
        // read every configuration.
        String instanceName = instanceTag.getAttribute(InstanceTag.Attribute.NAME);

        if (StringUtils.isBlank(instanceName)) {
            String message = "SAML engine configuration file \"" + configurationFileName
                    + "\" contains a blank instance name";
            LOG.error(message);
            throw new SamlEngineConfigurationException(message);
        }
        instanceName = instanceName.trim();

        NodeList configurationTags = instanceTag.getElementsByTagName(InstanceTag.ConfigurationTag.TAG_NAME);

        Map<String, ConfigurationEntry> configurationEntries = new LinkedHashMap<>();

        for (int i = 0, n = configurationTags.getLength(); i < n; i++) {
            Element configurationTag = (Element) configurationTags.item(i);

            ConfigurationEntry configurationEntry = parseConfigurationEntry(configurationFileName, instanceName,
                    configurationTag);

            ConfigurationEntry previous = configurationEntries.put(configurationEntry.getName(),
                    configurationEntry);
            if (null != previous) {
                String message = "Duplicate configuration entry names \"" + configurationEntry.getName()
                        + "\" in SAML engine configuration file \"" + configurationFileName + "\"";
                LOG.error(message);
                throw new SamlEngineConfigurationException(message);
            }
        }

        return new InstanceEntry(instanceName, ImmutableMap.copyOf(configurationEntries));
    }

    /**
     * Generate parameters.
     *
     * @param configurationTag the configuration node
     * @return the map< string, string>
     */
    @Nonnull
    private static ImmutableMap<String, String> parseParameters(@Nonnull String configurationFileName,
            @Nonnull String instanceName, @Nonnull String configurationName, @Nonnull Element configurationTag)
            throws SamlEngineConfigurationException {
        Map<String, String> parameters = new LinkedHashMap<String, String>();

        NodeList parameterTags = configurationTag
                .getElementsByTagName(InstanceTag.ConfigurationTag.ParameterTag.TAG_NAME);

        for (int i = 0, n = parameterTags.getLength(); i < n; i++) {
            // for every parameter find, process.
            Element parameterTag = (Element) parameterTags.item(i);
            String parameterName = parameterTag
                    .getAttribute(InstanceTag.ConfigurationTag.ParameterTag.Attribute.NAME);
            String parameterValue = parameterTag
                    .getAttribute(InstanceTag.ConfigurationTag.ParameterTag.Attribute.VALUE);

            // verify the content.
            if (StringUtils.isBlank(parameterName)) {
                String message = "SAML engine configuration file \"" + configurationFileName
                        + "\" contains a blank parameter name for configuration name \"" + configurationName
                        + "\" in instance name \"" + instanceName + "\"";
                LOG.error(message);
                throw new SamlEngineConfigurationException(message);
            }
            if (StringUtils.isBlank(parameterValue)) {
                String message = "SAML engine configuration file \"" + configurationFileName
                        + "\" contains parameter name \"" + parameterName
                        + "\" with a blank value for configuration name \"" + configurationName
                        + "\" in instance name \"" + instanceName + "\"";
                LOG.error(message);
                throw new SamlEngineConfigurationException(message);
            }
            String previous = parameters.put(parameterName.trim(), parameterValue.trim());
            if (null != previous) {
                String message = "Duplicate parameter entry names \"" + parameterName
                        + "\" in SAML engine configuration file \"" + configurationFileName
                        + "\" for configuration name \"" + configurationName + "\" in instance name \""
                        + instanceName + "\"";
                LOG.error(message);
                throw new SamlEngineConfigurationException(message);
            }
        }
        return ImmutableMap.copyOf(parameters);
    }

    @Nonnull
    static ImmutableMap<String, String> validateParameters(@Nonnull String instanceName,
            @Nonnull String configurationName, @Nonnull Map<String, String> values)
            throws SamlEngineConfigurationException {
        Map<String, String> parameters = new LinkedHashMap<String, String>();

        for (final Map.Entry<String, String> entry : values.entrySet()) {
            String parameterName = entry.getKey();
            String parameterValue = entry.getValue();

            // verify the content.
            if (StringUtils.isBlank(parameterName)) {
                String message = "SAML engine configuration file contains a blank parameter name for configuration name \""
                        + configurationName + "\" in instance name \"" + instanceName + "\"";
                LOG.error(message);
                throw new SamlEngineConfigurationException(message);
            }
            if (StringUtils.isBlank(parameterValue)) {
                String message = "SAML engine configuration file contains parameter name \"" + parameterName
                        + "\" with a blank value for configuration name \"" + configurationName
                        + "\" in instance name \"" + instanceName + "\"";
                LOG.error(message);
                throw new SamlEngineConfigurationException(message);
            }
            parameters.put(parameterName.trim(), parameterValue.trim());
        }

        return ImmutableMap.copyOf(parameters);
    }

    /**
     * Prevent instantiation.
     */
    private DOMConfigurationParser() {

    }
}