ch.simuonline.idh.attribute.resolver.spring.dc.aq.impl.AttributeQueryDataConnectorParser.java Source code

Java tutorial

Introduction

Here is the source code for ch.simuonline.idh.attribute.resolver.spring.dc.aq.impl.AttributeQueryDataConnectorParser.java

Source

/*
 * 
 * Copyright 2016 Simon Gfeller
 *
 * 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 ch.simuonline.idh.attribute.resolver.spring.dc.aq.impl;

import java.io.FileInputStream;
import java.security.PrivateKey;
import java.security.cert.X509Certificate;
import java.util.List;

import javax.annotation.Nonnull;
import javax.xml.namespace.QName;

import org.opensaml.security.crypto.KeySupport;
import org.opensaml.security.x509.X509Support;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.ManagedList;
import org.springframework.beans.factory.xml.ParserContext;
import org.w3c.dom.Element;

import ch.simuonline.idh.attribute.resolver.dc.aq.AQAttribute;
import ch.simuonline.idh.attribute.resolver.dc.aq.AttributeQueryBuilder;
import ch.simuonline.idh.attribute.resolver.dc.aq.AttributeQueryDataConnector;
import ch.simuonline.idh.attribute.resolver.dc.aq.AttributeQueryKeyManager;
import ch.simuonline.idh.attribute.resolver.dc.aq.LDAPTargetDeterminationStrategy;
import ch.simuonline.idh.attribute.resolver.dc.aq.MySQLTargetDeterminationStrategy;
import net.shibboleth.ext.spring.util.SpringSupport;
import net.shibboleth.idp.attribute.resolver.spring.ResolverPluginDependencyParser;
import net.shibboleth.idp.attribute.resolver.spring.dc.impl.AbstractDataConnectorParser;
import net.shibboleth.utilities.java.support.logic.Constraint;
import net.shibboleth.utilities.java.support.primitive.StringSupport;
import net.shibboleth.utilities.java.support.xml.AttributeSupport;
import net.shibboleth.utilities.java.support.xml.ElementSupport;

/**
 * 
 * Parser for the {@link AttributeQueryDataConnector}. 
 * Visit {@link https://github.com/gfels4/identity_hub} for more informations.
 * 
 * @author Simon Gfeller
 *
 */
public class AttributeQueryDataConnectorParser extends AbstractDataConnectorParser {

    /** Schema type name. */
    @Nonnull
    public static final QName TYPE_NAME = new QName(AttributeQueryDataConnectorNamespaceHandler.NAMESPACE,
            "AttributeQuery");

    /** Local name of attribute. */
    @Nonnull
    public static final QName ATTRIBUTE_ELEMENT_NAME = new QName(
            AttributeQueryDataConnectorNamespaceHandler.NAMESPACE, "Attribute");

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

    /** {@inheritDoc} */
    @Override
    protected Class<AttributeQueryDataConnector> getNativeBeanClass() {
        return AttributeQueryDataConnector.class;
    }

    /** {@inheritDoc} */
    @Override
    protected void doV2Parse(@Nonnull final Element config, @Nonnull final ParserContext parserContext,
            @Nonnull final BeanDefinitionBuilder builder) {
        log.debug("{} Parsing v2 configuration {}", getLogPrefix(), config);

        final String targetResolvingStrategy = AttributeSupport.getAttributeValue(config,
                new QName("targetDeterminationStrategy"));
        Constraint.isNotNull(StringSupport.trimOrNull(targetResolvingStrategy),
                "The targetDeterminationStrategy can not be null or empty, please adjust entityID from the AQ DataConnector");

        if (targetResolvingStrategy.equals("mysql")) {
            // Constructor is MySQLTargetResolvingStrategy(String url, String username, String password), adding arguments in this order:
            final BeanDefinitionBuilder mysqlTargetResolvingStrategy = BeanDefinitionBuilder
                    .genericBeanDefinition(MySQLTargetDeterminationStrategy.class);

            final String dbURL = AttributeSupport.getAttributeValue(config, new QName("dbURL"));
            Constraint.isNotNull(StringSupport.trimOrNull(dbURL),
                    "The dbURL attribute is required if the targetResolvingStrategy is mysql, please adjust entityID from the AQ DataConnector");
            mysqlTargetResolvingStrategy.addConstructorArgValue(dbURL);

            final String dbUsername = AttributeSupport.getAttributeValue(config, new QName("dbUsername"));
            Constraint.isNotNull(StringSupport.trimOrNull(dbUsername),
                    "The dbUsername attribute is required if the targetResolvingStrategy is mysql, please adjust entityID from the AQ DataConnector");
            mysqlTargetResolvingStrategy.addConstructorArgValue(dbUsername);

            final String dbPassword = AttributeSupport.getAttributeValue(config, new QName("dbPassword"));
            Constraint.isNotNull(StringSupport.trimOrNull(dbPassword),
                    "The dbPassword attribute is required if the targetResolvingStrategy is mysql, please adjust entityID from the AQ DataConnector");
            mysqlTargetResolvingStrategy.addConstructorArgValue(dbPassword);

            builder.addPropertyValue("targetResolvingStrategy", mysqlTargetResolvingStrategy.getBeanDefinition());
        } else if (targetResolvingStrategy.equals("ldap")) {
            final BeanDefinitionBuilder ldapTargetResolvingStrategy = BeanDefinitionBuilder
                    .genericBeanDefinition(LDAPTargetDeterminationStrategy.class);

            final String sourceAttributeID = AttributeSupport.getAttributeValue(config,
                    new QName("sourceAttributeID"));
            Constraint.isNotNull(StringSupport.trimOrNull(sourceAttributeID),
                    "The sourceAttributeID attribute is required if the targetResolvingStrategy is ldap, please adjust entityID from the AQ DataConnector");
            ldapTargetResolvingStrategy.addConstructorArgValue(sourceAttributeID);

            final List<Element> dependencyElements = ElementSupport.getChildElements(config,
                    ResolverPluginDependencyParser.ELEMENT_NAME);
            ldapTargetResolvingStrategy.addPropertyValue("dependencies",
                    SpringSupport.parseCustomElements(dependencyElements, parserContext));

            final String connectorID = AttributeSupport.getAttributeValue(config, new QName("id"));
            Constraint.isNotNull(StringSupport.trimOrNull(sourceAttributeID),
                    "The connectorID can not be empty, please adjust it for the AQ DataConnector");
            ldapTargetResolvingStrategy.addConstructorArgValue(connectorID);

            builder.addPropertyValue("targetResolvingStrategy", ldapTargetResolvingStrategy.getBeanDefinition());

        } else {
            log.error("{} Unsupported targetResolvingStrategy: {}. Change it to mysql or ldap! ", getLogPrefix(),
                    targetResolvingStrategy);
        }

        final BeanDefinitionBuilder attributeQueryBuilder = BeanDefinitionBuilder
                .genericBeanDefinition(AttributeQueryBuilder.class);

        // Parse value of the entityID attribute
        final String issuer = AttributeSupport.getAttributeValue(config, new QName("entityID"));
        Constraint.isNotNull(StringSupport.trimOrNull(issuer),
                "The entityID of the Issuer can not be empty, please adjust entityID from the AQ DataConnector");
        attributeQueryBuilder.addConstructorArgValue(issuer);

        // parsing of the defined AQAttributes for the attribute query
        final List<Element> children = ElementSupport.getChildElements(config, ATTRIBUTE_ELEMENT_NAME);
        final List<BeanDefinition> attributes = new ManagedList<>(children.size());
        for (final Element child : children) {
            final String name = AttributeSupport.getAttributeValue(child, new QName("name"));
            final String friendlyName = AttributeSupport.getAttributeValue(child, new QName("friendlyName"));

            final BeanDefinitionBuilder attribute = BeanDefinitionBuilder.genericBeanDefinition(AQAttribute.class);
            attribute.addConstructorArgValue(name);
            attribute.addConstructorArgValue(friendlyName);
            log.debug("{} Added one AQAttribute to the resolving List. Friendly Name {}, Name {}", getLogPrefix(),
                    friendlyName, name);
            attributes.add(attribute.getBeanDefinition());
        }

        attributeQueryBuilder.addConstructorArgValue(attributes);
        builder.addPropertyValue("attributeQueryBuilder", attributeQueryBuilder.getBeanDefinition());

        final BeanDefinitionBuilder keyManager = BeanDefinitionBuilder
                .genericBeanDefinition(AttributeQueryKeyManager.class);

        // parse the keyLocaton attribute from the AQ DataCOnnector
        final String keyLocation = AttributeSupport.getAttributeValue(config, new QName("keyLocation"));
        Constraint.isNotNull(StringSupport.trimOrNull(keyLocation),
                "Key location can not be empty, please adjust keyLocation from the AQ DataConnector");

        // parse the certLocaton attribute from the AQ DataCOnnector
        final String certLocation = AttributeSupport.getAttributeValue(config, new QName("certLocation"));
        Constraint.isNotNull(StringSupport.trimOrNull(certLocation),
                "Certificate location can not be empty, please adjust certLocation from the AQ DataConnector");

        keyManager.addConstructorArgValue(getPrivateKey(keyLocation));
        keyManager.addConstructorArgValue(getCertificate(certLocation));
        builder.addPropertyValue("attributeQueryKeyManager", keyManager.getBeanDefinition());

        // if the asertionSigned attribute is true, set the value to true
        final String signatureRequired = AttributeSupport.getAttributeValue(config, new QName("assertionSigned"));
        if (signatureRequired != null && signatureRequired.equals("true")) {
            builder.addPropertyValue("signatureRequired", Boolean.TRUE);
        }

        // if the requestedAttributesRequired attribute is true, set the value to true
        final String requireMetadataAttributes = AttributeSupport.getAttributeValue(config,
                new QName("requestedAttributesRequired"));
        if (requireMetadataAttributes != null && requireMetadataAttributes.equals("true")) {
            builder.addPropertyValue("requireMetadataAttributes", Boolean.TRUE);
        }

        builder.setInitMethodName("initialize");
        builder.setDestroyMethodName("destroy");
    }

    /**
     * 
     * This method reads a certificate file and returns a {@link X509Certificate}
     * 
     * @param certLocation the location of the certificate file
     * @return the created {@link X509Certificate}
     */
    private X509Certificate getCertificate(String certLocation) {
        X509Certificate cert = null;

        try {
            FileInputStream fisCertificate = new FileInputStream(certLocation);
            cert = X509Support
                    .decodeCertificate(StringSupport.inputStreamToString(fisCertificate, null).getBytes());
            fisCertificate.close();

        } catch (Exception e) {
            log.debug("{} Couldnt create the X509Certificate: {}", getLogPrefix(), e);
            return null;
        }
        return cert;
    }

    /**
     * 
     * This method reads a private key file and returns a {@link PrivateKey}
     * 
     * @param privateKeyLocation the location of the private key file
     * @return the created {@link PrivateKey}
     */
    private PrivateKey getPrivateKey(String privateKeyLocation) {
        PrivateKey privateKey = null;

        try {
            FileInputStream fisPrivateKey = new FileInputStream(privateKeyLocation);
            privateKey = KeySupport
                    .decodePrivateKey(StringSupport.inputStreamToString(fisPrivateKey, null).getBytes(), null);
            fisPrivateKey.close();

        } catch (Exception e) {
            log.debug("{} Couldnt create the PrivateKey: {}", getLogPrefix(), e);
            return null;
        }
        return privateKey;
    }
}