com.alfaariss.oa.util.idmapper.jndi.JNDIMapper.java Source code

Java tutorial

Introduction

Here is the source code for com.alfaariss.oa.util.idmapper.jndi.JNDIMapper.java

Source

/*
 * Asimba Server
 * 
 * Copyright (C) 2012 Asimba
 * Copyright (C) 2007-2009 Alfa & Ariss B.V.
 * 
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 * 
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 * 
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see www.gnu.org/licenses
 * 
 * Asimba - Serious Open Source SSO - More information on www.asimba.org
 * 
 */
package com.alfaariss.oa.util.idmapper.jndi;

import java.util.Hashtable;

import javax.naming.Context;
import javax.naming.InvalidNameException;
import javax.naming.Name;
import javax.naming.NamingEnumeration;
import javax.naming.NamingException;
import javax.naming.directory.Attribute;
import javax.naming.directory.Attributes;
import javax.naming.directory.DirContext;
import javax.naming.directory.InitialDirContext;
import javax.naming.directory.InvalidSearchFilterException;
import javax.naming.directory.SearchControls;
import javax.naming.directory.SearchResult;
import javax.naming.ldap.LdapName;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.w3c.dom.Element;

import com.alfaariss.oa.OAException;
import com.alfaariss.oa.SystemErrors;
import com.alfaariss.oa.api.configuration.IConfigurationManager;
import com.alfaariss.oa.api.idmapper.IIDMapper;
import com.alfaariss.oa.util.ldap.JNDIUtil;

/**
 * JNDI id mapper implementation.
 * 
 * @author MHO
 * @author Alfa & Ariss
 * @since 1.3
 */
public class JNDIMapper implements IIDMapper {
    private Log _logger;
    private String _sDNBase;
    private String _sIDAttribute;
    private String _sMapperAttribute;
    private Hashtable<String, String> _htJNDIEnvironment;

    /**
     * Constructor. 
     */
    public JNDIMapper() {
        _logger = LogFactory.getLog(JNDIMapper.class);
        _sDNBase = null;
        _sIDAttribute = null;
        _sMapperAttribute = null;
        _htJNDIEnvironment = null;
    }

    /**
     * @see com.alfaariss.oa.api.idmapper.IIDMapper#map(java.lang.String)
     */
    public String map(String id) throws OAException {
        if (id == null)
            throw new IllegalArgumentException("Could not map: NULL");

        String sReturn = null;
        DirContext oDirContext = null;
        try {
            try {
                oDirContext = new InitialDirContext(_htJNDIEnvironment);
            } catch (NamingException e) {
                _logger.error("Could not create the connection: " + _htJNDIEnvironment, e);
                throw new OAException(SystemErrors.ERROR_RESOURCE_CONNECT);
            }

            try {
                if (_sIDAttribute == null) {//must be null, otherwise you can't do the inverse
                    Name nameLdap = new LdapName(id);
                    if (_sMapperAttribute != null)
                        return getAttributes(oDirContext, _sMapperAttribute, nameLdap);

                    _logger.error("Can't map: no mapper attribute name configured");
                    throw new OAException(SystemErrors.ERROR_RESOURCE_CONNECT);
                }

                sReturn = searchAttributes(oDirContext, _sIDAttribute, _sMapperAttribute, id);
            } catch (InvalidNameException e) {
                _logger.debug("Supplied id isn't a valid LdapName: " + id);
            }

        } catch (OAException e) {
            throw e;
        } catch (Exception e) {
            _logger.fatal("Could not map id: " + id, e);
            throw new OAException(SystemErrors.ERROR_INTERNAL);
        } finally {
            if (oDirContext != null) {
                try {
                    oDirContext.close();
                } catch (NamingException e) {
                    _logger.error("Could not close Dir Context after mapping id: " + id, e);
                }
            }
        }
        return sReturn;
    }

    /**
     * @see com.alfaariss.oa.api.idmapper.IIDMapper#remap(java.lang.String)
     */
    public String remap(String id) throws OAException {
        if (id == null)
            throw new IllegalArgumentException("Could not remap: NULL");

        String sReturn = null;
        DirContext oDirContext = null;
        try {
            try {
                oDirContext = new InitialDirContext(_htJNDIEnvironment);
            } catch (NamingException e) {
                _logger.error("Could not create the connection: " + _htJNDIEnvironment, e);
                throw new OAException(SystemErrors.ERROR_RESOURCE_CONNECT);
            }

            try {
                if (_sMapperAttribute == null) {//must be null, otherwise you can't do the inverse
                    Name nameLdap = new LdapName(id);
                    if (_sIDAttribute != null)
                        return getAttributes(oDirContext, _sIDAttribute, nameLdap);

                    _logger.error("Can't remap: no id attribute name configured");
                    throw new OAException(SystemErrors.ERROR_RESOURCE_CONNECT);
                }

                sReturn = searchAttributes(oDirContext, _sMapperAttribute, _sIDAttribute, id);
            } catch (InvalidNameException e) {
                _logger.debug("Supplied id isn't a valid LdapName: " + id);
            }

        } catch (OAException e) {
            throw e;
        } catch (Exception e) {
            _logger.fatal("Could not remap id: " + id, e);
            throw new OAException(SystemErrors.ERROR_INTERNAL);
        } finally {
            if (oDirContext != null) {
                try {
                    oDirContext.close();
                } catch (NamingException e) {
                    _logger.error("Could not close Dir Context after searching for mapped id: " + id, e);
                }
            }
        }
        return sReturn;
    }

    /**
     * @see com.alfaariss.oa.api.idmapper.IIDMapper#start(com.alfaariss.oa.api.configuration.IConfigurationManager, org.w3c.dom.Element)
     */
    public void start(IConfigurationManager configManager, Element config) throws OAException {
        try {
            Element eResource = configManager.getSection(config, "resource");
            if (eResource == null) {
                _logger.error("No 'resource' section found in configuration");
                throw new OAException(SystemErrors.ERROR_CONFIG_READ);
            }

            Element eDN = configManager.getSection(eResource, "dn");
            if (eDN == null) {
                _logger.error("No 'dn' section found in 'resource' section in configuration");
                throw new OAException(SystemErrors.ERROR_CONFIG_READ);
            }

            _sDNBase = configManager.getParam(eDN, "base");
            if (_sDNBase == null) {
                _logger.error("No 'dn' item found in 'base' section in configuration");
                throw new OAException(SystemErrors.ERROR_CONFIG_READ);
            }

            Element eID = configManager.getSection(eDN, "id");
            if (eID == null) {
                _logger.warn("No 'id' section found in 'dn' section in configuration");
                _logger.info("Mapping from Distinguished Name (supplied id must be a Distinguished Name)");
                _sIDAttribute = null;
            } else {
                _sIDAttribute = configManager.getParam(eID, "attribute");
                if (_sIDAttribute == null) {
                    _logger.error("No 'attribute' item found in 'id' section in configuration");
                    throw new OAException(SystemErrors.ERROR_CONFIG_READ);
                }
            }

            Element eMapper = configManager.getSection(eDN, "mapper");
            if (eMapper == null) {
                if (_sIDAttribute == null) {
                    _logger.error(
                            "Invalid id mapper configuration: No 'mapper' section and no 'id' section found in 'dn' section in configuration");
                    throw new OAException(SystemErrors.ERROR_CONFIG_READ);
                }

                _logger.warn("No 'mapper' section found in 'dn' section in configuration");
                _logger.info("Mapping to Distinguished Name (the Distinguished Name of the searched attribute)");
                _sMapperAttribute = null;
            } else {
                _sMapperAttribute = configManager.getParam(eMapper, "attribute");
                if (_sMapperAttribute == null) {
                    _logger.error("No 'attribute' item found in 'mapper' section in configuration");
                    throw new OAException(SystemErrors.ERROR_CONFIG_READ);
                }
            }

            _htJNDIEnvironment = readJNDIContext(configManager, eResource);

            //test connection
            new InitialDirContext(_htJNDIEnvironment);
        } catch (OAException e) {
            throw e;
        } catch (Exception e) {
            _logger.fatal("Could not initialize object", e);
            throw new OAException(SystemErrors.ERROR_INTERNAL);
        }
    }

    /**
     * @see com.alfaariss.oa.api.idmapper.IIDMapper#stop()
     */
    public void stop() {
        if (_htJNDIEnvironment != null)
            _htJNDIEnvironment.clear();
        _sDNBase = null;
        _sIDAttribute = null;
        _sMapperAttribute = null;
    }

    /**
     * Reads JNDI connection information from the configuration.
     * <br>
     * Creates an <code>Hashtable</code> containing the JNDI environment variables.
     * @param oConfigurationManager The configuration manager
     * @param eConfig the configuration section
     * @return <code>DirContext</code> that contains the JNDI connection
     * @throws OAException if configuration reading fails
     */
    private Hashtable<String, String> readJNDIContext(IConfigurationManager oConfigurationManager, Element eConfig)
            throws OAException {
        Hashtable<String, String> htEnvironment = new Hashtable<String, String>(11);

        try {
            Element eSecurityPrincipal = oConfigurationManager.getSection(eConfig, "security_principal");
            if (eSecurityPrincipal == null) {
                _logger.error("No 'security_principal' section found in 'resource' configuration");
                throw new OAException(SystemErrors.ERROR_CONFIG_READ);
            }

            String sPrincipal = oConfigurationManager.getParam(eSecurityPrincipal, "dn");
            if (sPrincipal == null) {
                _logger.error("No item 'dn' item found in configuration");
                throw new OAException(SystemErrors.ERROR_CONFIG_READ);
            }

            String sPassword = oConfigurationManager.getParam(eSecurityPrincipal, "password");
            if (sPassword == null) {
                _logger.error("No 'password' item found in configuration ");
                throw new OAException(SystemErrors.ERROR_CONFIG_READ);
            }

            String sDriver = oConfigurationManager.getParam(eConfig, "driver");
            if (sDriver == null) {
                _logger.error("No 'driver' item found in configuration");
                throw new OAException(SystemErrors.ERROR_CONFIG_READ);
            }

            String sUrl = oConfigurationManager.getParam(eConfig, "url");
            if (sUrl == null) {
                _logger.error("No valid config item 'url' found in configuration");
                throw new OAException(SystemErrors.ERROR_CONFIG_READ);
            }

            if (sUrl.length() >= 5 && sUrl.substring(0, 5).equalsIgnoreCase("ldaps")) {
                // Request SSL transport
                htEnvironment.put(Context.SECURITY_PROTOCOL, "ssl");
                _logger.info("SSL enabled");
            } else {
                _logger.info("SSL disabled");
            }

            htEnvironment.put(Context.INITIAL_CONTEXT_FACTORY, sDriver);
            htEnvironment.put(Context.SECURITY_AUTHENTICATION, "simple");
            htEnvironment.put(Context.SECURITY_PRINCIPAL, sPrincipal);
            htEnvironment.put(Context.SECURITY_CREDENTIALS, sPassword);
            htEnvironment.put(Context.PROVIDER_URL, sUrl);
        } catch (OAException e) {
            throw e;
        } catch (Exception e) {
            _logger.error("Could not create a connection", e);
            throw new OAException(SystemErrors.ERROR_INTERNAL);
        }
        return htEnvironment;
    }

    private String getAttributes(DirContext oDirContext, String sMapperAttribute, Name name) throws OAException {
        String sReturn = null;
        try {
            if (sMapperAttribute == null) {
                _logger.error("No attribute name to map to supplied");
                throw new OAException(SystemErrors.ERROR_INTERNAL);
            }

            Attributes attributes = null;
            try {
                attributes = oDirContext.getAttributes(name, new String[] { sMapperAttribute });
            } catch (InvalidSearchFilterException e) {
                StringBuffer sbFailed = new StringBuffer("Could not resolve attribute '");
                sbFailed.append(sMapperAttribute);
                sbFailed.append("' while retrieving attributes for id: ");
                sbFailed.append(name);
                _logger.error(sbFailed.toString(), e);
                throw new OAException(SystemErrors.ERROR_RESOURCE_RETRIEVE);
            }

            Attribute attrMapping = attributes.get(sMapperAttribute);
            if (attrMapping == null) {
                _logger.debug("Attribute not found: " + sMapperAttribute);
            } else {
                Object oValue = attrMapping.get();
                if (!(oValue instanceof String)) {
                    StringBuffer sbError = new StringBuffer("Returned value for attribute '");
                    sbError.append(sMapperAttribute);
                    sbError.append("' has a value which is not of type 'String'");
                    _logger.error(sbError.toString());
                    throw new OAException(SystemErrors.ERROR_RESOURCE_RETRIEVE);
                }
                sReturn = (String) oValue;
            }
        } catch (OAException e) {
            throw e;
        } catch (NamingException e) {
            _logger.debug("Failed to fetch mapping attribute for id: " + name);
        } catch (Exception e) {
            _logger.fatal("Could not retrieve fields for id: " + name, e);
            throw new OAException(SystemErrors.ERROR_INTERNAL);
        }
        return sReturn;
    }

    private String searchAttributes(DirContext oDirContext, String sIDAttribute, String sMapperAttribute, String id)
            throws OAException {
        String sReturn = null;
        NamingEnumeration oNamingEnumeration = null;
        try {
            if (sIDAttribute == null) {
                _logger.error("No attribute name to map from supplied");
                throw new OAException(SystemErrors.ERROR_INTERNAL);
            }

            StringBuffer sbQuery = new StringBuffer("(");
            sbQuery.append(sIDAttribute);
            sbQuery.append("=");
            sbQuery.append(JNDIUtil.escapeLDAPSearchFilter(id));
            sbQuery.append(")");
            String sSearchQuery = sbQuery.toString();

            String sSearchFor = sMapperAttribute;
            if (sSearchFor == null)
                sSearchFor = "*";

            SearchControls oScope = new SearchControls();
            oScope.setSearchScope(SearchControls.SUBTREE_SCOPE);
            oScope.setReturningAttributes(new String[] { sSearchFor });

            try {
                oNamingEnumeration = oDirContext.search(_sDNBase, sSearchQuery, oScope);
            } catch (InvalidSearchFilterException e) {
                StringBuffer sbFailed = new StringBuffer("Wrong filter: ");
                sbFailed.append(sSearchQuery);
                sbFailed.append(" while searching for attributes for id: ");
                sbFailed.append(id);
                _logger.error(sbFailed.toString(), e);
                throw new OAException(SystemErrors.ERROR_RESOURCE_RETRIEVE);
            }

            if (!oNamingEnumeration.hasMore()) {
                _logger.debug("No result when searching for: " + sSearchQuery);
            } else {
                SearchResult oSearchResult = (SearchResult) oNamingEnumeration.next();

                if (sMapperAttribute == null) {
                    sReturn = oSearchResult.getName();
                    sReturn += "," + _sDNBase;
                } else {
                    Attributes oSearchedAttributes = oSearchResult.getAttributes();
                    Attribute attrMapping = oSearchedAttributes.get(sMapperAttribute);
                    if (attrMapping == null) {
                        _logger.debug("Mapping attribute not found: " + sMapperAttribute);
                    } else {
                        Object oValue = attrMapping.get();
                        if (!(oValue instanceof String)) {
                            StringBuffer sbError = new StringBuffer("Returned value for mapping attribute '");
                            sbError.append(_sMapperAttribute);
                            sbError.append("' has a value which is not of type 'String'");
                            _logger.error(sbError.toString());
                            throw new OAException(SystemErrors.ERROR_RESOURCE_RETRIEVE);
                        }
                        sReturn = (String) oValue;
                    }
                }
            }
        } catch (OAException e) {
            throw e;
        } catch (NamingException e) {
            _logger.debug("Failed to fetch mapping attribute for id: " + id, e);
        } catch (Exception e) {
            _logger.fatal("Could not retrieve fields for id: " + id, e);
            throw new OAException(SystemErrors.ERROR_INTERNAL);
        } finally {
            if (oNamingEnumeration != null) {
                try {
                    oNamingEnumeration.close();
                } catch (Exception e) {
                    _logger.error("Could not close Naming Enumeration after searching for id: " + id, e);
                }
            }
        }
        return sReturn;
    }
}