de.innovationgate.webgate.api.auth.FileAuthenticationModule.java Source code

Java tutorial

Introduction

Here is the source code for de.innovationgate.webgate.api.auth.FileAuthenticationModule.java

Source

/*******************************************************************************
 * Copyright 2009, 2010 Innovation Gate GmbH. All Rights Reserved.
 * 
 * This file is part of the OpenWGA server platform.
 * 
 * OpenWGA is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 * 
 * In addition, a special exception is granted by the copyright holders
 * of OpenWGA called "OpenWGA plugin exception". You should have received
 * a copy of this exception along with OpenWGA in file COPYING.
 * If not, see <http://www.openwga.com/gpl-plugin-exception>.
 * 
 * OpenWGA 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 General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with OpenWGA in file COPYING.
 * If not, see <http://www.gnu.org/licenses/>.
 ******************************************************************************/
package de.innovationgate.webgate.api.auth;

import java.io.File;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.apache.log4j.Logger;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;

import de.innovationgate.utils.WGUtils;
import de.innovationgate.webgate.api.WGDatabase;
import de.innovationgate.webgate.api.WGFactory;

/**
 * This authentication module takes an XML file as base where users and groups are defined:
 * 
 * <!-- This is a demostration file for a definition xml for users and groups. The attribute "allowanonymous" controls, if anonymous access to databases will be allowed -->
 * <users allowanonymous="true">
 *   <!-- 
 *   The user definition:
 *   name: Full distinguished and unique name of this user
 *   password: Her password to sign on
 *   mail: Mail address used for workflow notifications
 *   aliases: name aliases divided by comma. She can also logon using these. You should check for uniqueness of them too
 *   -->
 *   <user name="John Doe" password="mypass" mail="john.doe@mycompany.com" aliases="John,jd"/>
 *   <user name="Jane Doe" password="anotherpass" mail="jane.doe@mycompany.com" aliases="Jane,jad"/>   
 *   
 *   <!--
 *   The group definition:
 *   name: Full distinguished (and only) name of this group.
 *   members: Name of member users. Name aliases will do but you should use the fully distinguished name 
 *            for lookup speed and readability. You cannot use names of other groups in here.
 *   -->
 *   <group name="admins" members="John Doe,Jane Doe"/>
 * </users>
 */
public class FileAuthenticationModule implements AuthenticationModule, PasswordCachingAuthenticationModule {

    public static final String AUTHMODULE_KEY = "file";

    public static final Logger LOG = Logger.getLogger("wga.api.auth.file");

    /**
     * Sysproperty to specify a base path for XML config files.
     */
    public static final String SYSPROPERTY_AUTH_FOLDER = "de.innovationgate.wga.auth.folder";
    private boolean _allowAnonymous;

    private long _lastModified;

    private Map _users = new HashMap();

    private File _file = null;

    private String _fileName;

    private List _authenticationSourceListeners = new ArrayList();

    /**
     * Creation option to specify the XML config file location. 
     * If sysproperty de.innovationgate.wga.auth.folder is set, this is evaluated relative to it. 
     */
    public static final String AUTH_FILE = "auth.file";

    class User {

        private String _mail;
        private String _pwd;
        private Set _aliases;
        private Set _groups = new HashSet();
        private String _name;

        public User(String name, String pwd, String mail, Set aliases) {
            _name = name;
            _pwd = pwd;
            _mail = mail;
            _aliases = aliases;
        }

        /**
         * @return
         */
        public Set getAliases() {
            return _aliases;
        }

        /**
         * @return
         */
        public String getName() {
            return _name;
        }

        public void addGroup(String name) {
            _groups.add(name);
        }

        /**
         * @return
         */
        public String getPwd() {
            return _pwd;
        }

        /**
         * @return
         */
        public Set getGroups() {
            return _groups;
        }

        /**
         * @return
         */
        public String getMail() {
            return _mail;
        }

    }

    class Group {

        private String _name;

        private List _members;

        public Group(String name, List members) {
            _name = name;
            _members = members;
        }

        /**
         * @return
         */
        public List getMembers() {
            return _members;
        }

        /**
         * @return
         */
        public String getName() {
            return _name;
        }

    }

    class Session implements AuthenticationSession {

        private Set _names;

        private boolean _valid = true;

        private User _user;

        public Session(User user) {
            _user = user;
            _names = _user.getAliases();
            _names.add(_user.getName());
        }

        /* (Kein Javadoc)
         * @see de.innovationgate.webgate.api.auth.AuthenticationSession#getDistinguishedName()
         */
        public String getDistinguishedName() {
            return _user.getName();
        }

        /* (Kein Javadoc)
         * @see de.innovationgate.webgate.api.auth.AuthenticationSession#getMailAddress()
         */
        public String getMailAddress() {
            return _user.getMail();
        }

        /* (Kein Javadoc)
         * @see de.innovationgate.webgate.api.auth.AuthenticationSession#getNames()
         */
        public Set getNames() {
            return _names;
        }

        /* (Kein Javadoc)
         * @see de.innovationgate.webgate.api.auth.AuthenticationSession#getGroups()
         */
        public Set getGroups() {
            return _user.getGroups();
        }

        /* (Kein Javadoc)
         * @see de.innovationgate.webgate.api.auth.AuthenticationSession#logout()
         */
        public void logout() {
            _valid = false;
        }

        /* (Kein Javadoc)
         * @see de.innovationgate.webgate.api.auth.AuthenticationSession#isValid()
         */
        public boolean isValid() {
            return _valid;
        }

        public String getSessionToken() {
            return null;
        }
    }

    class AnonymousSession extends Session {
        public AnonymousSession() {
            super(new User(WGDatabase.ANONYMOUS_USER, null, null, new HashSet()));
        }
    }

    /* (Kein Javadoc)
     * @see de.innovationgate.webgate.api.auth.AuthenticationModule#init(java.util.Map)
     */
    public void init(Map params, WGDatabase db) throws ConfigurationException {

        _fileName = (String) params.get(AUTH_FILE);
        if (_fileName == null) {
            throw new ConfigurationException("Authentication file not specified");
        }

        String authFolder = System.getProperty(SYSPROPERTY_AUTH_FOLDER, null);
        if (authFolder != null) {
            _file = new File(new File(authFolder), _fileName);
        }

        if (_file == null || !_file.exists()) {
            _file = new File(_fileName);
        }

        if (!_file.exists()) {
            throw new ConfigurationException("XML authentication file does not exist: " + _fileName);
        }

        update(_file);
    }

    /**
     * @param _file
     */
    private synchronized void update(File _file) {

        try {
            // Parse doc
            SAXReader reader = new SAXReader();
            reader.setIncludeExternalDTDDeclarations(false);
            reader.setIncludeInternalDTDDeclarations(false);
            reader.setValidation(false);
            Document doc = reader.read(_file);

            // Flags
            _allowAnonymous = Boolean.valueOf(doc.getRootElement().attributeValue("allowanonymous")).booleanValue();

            // Read users
            Map users = new HashMap();
            Iterator userNodes = doc.selectNodes("/users/user").iterator();
            Element userNode;
            while (userNodes.hasNext()) {
                userNode = (Element) userNodes.next();
                String name = userNode.attributeValue("name");
                String password = userNode.attributeValue("password");
                String mail = userNode.attributeValue("mail");
                String aliasesStr = userNode.attributeValue("aliases");
                Set aliases = new HashSet();
                if (aliasesStr != null) {
                    aliases.addAll(WGUtils.deserializeCollection(aliasesStr, ",", true));
                }
                users.put(name, new User(name, password, mail, aliases));
            }
            _users = users;

            // Read Groups
            Map groups = new HashMap();
            Iterator groupNodes = doc.selectNodes("/users/group").iterator();
            Element groupNode;
            while (groupNodes.hasNext()) {
                groupNode = (Element) groupNodes.next();
                String name = groupNode.attributeValue("name");
                List members = WGUtils.deserializeCollection(groupNode.attributeValue("members"), ",", true);
                Group group = new Group(name, members);
                groups.put(name, group);
                notifyMembers(group);
            }

            // Call listeners
            synchronized (_authenticationSourceListeners) {
                Iterator listeners = _authenticationSourceListeners.iterator();
                while (listeners.hasNext()) {
                    ((AuthenticationSourceListener) listeners.next()).authenticationDataChanged();
                }
            }
        } catch (DocumentException e) {
            WGFactory.getLogger().error("Error parsing authentication file '" + getAuthenticationSource()
                    + "': Error in XML: " + e.getMessage());
        }
    }

    /**
     * @param group
     */
    private void notifyMembers(Group group) {

        Iterator members = group.getMembers().iterator();
        String memberName;
        User user;
        while (members.hasNext()) {
            memberName = (String) members.next();
            user = findUser(memberName);
            if (user != null) {
                user.addGroup(group.getName());
            } else {
                WGFactory.getLogger().error("Error parsing authentication file '" + getAuthenticationSource()
                        + "': User '" + memberName + "' not defined");
            }

        }

    }

    private User findUser(String memberName) {

        // First try to find by name - fastest
        User user = (User) _users.get(memberName);
        if (user != null) {
            return user;
        }

        // Then try to find by alias - slow
        Iterator users = _users.values().iterator();
        while (users.hasNext()) {
            user = (User) users.next();
            if (user.getAliases().contains(memberName)) {
                return user;
            }
        }

        return null;

    }

    /* (Kein Javadoc)
     * @see de.innovationgate.webgate.api.auth.AuthenticationModule#login(java.lang.String, java.lang.String)
     */
    public AuthenticationSession login(String user, Object credentials) throws AuthenticationException {

        String password = (String) credentials;

        if (user.equals(WGDatabase.ANONYMOUS_USER)) {
            if (_allowAnonymous) {
                return new AnonymousSession();
            } else {
                LOG.warn("Failed login from anonymous user: Anonymous login not allowed ("
                        + getAuthenticationSource() + ")");
                return null;
            }
        }

        if (_file.lastModified() > _lastModified) {
            synchronized (this) {
                _lastModified = _file.lastModified();
                update(_file);
            }
        }

        User userObj = findUser(user);
        if (userObj == null) {
            LOG.warn("Failed login for '" + user + "': Unknown user (" + getAuthenticationSource() + ")");
            return null;
        }

        if (!userObj.getPwd().equals(password)) {
            LOG.warn("Failed login for '" + user + "': Wrong password (" + getAuthenticationSource() + ")");
            return null;
        }

        return new Session(userObj);

    }

    /* (Kein Javadoc)
     * @see de.innovationgate.webgate.api.auth.AuthenticationModule#clearCache()
     */
    public void clearCache() {
        update(_file);
    }

    /* (Kein Javadoc)
     * @see de.innovationgate.webgate.api.auth.AuthenticationModule#getAuthenticationSource()
     */
    public String getAuthenticationSource() {
        return "File-Authentication - " + _file.getAbsolutePath();
    }

    /* (Kein Javadoc)
     * @see de.innovationgate.webgate.api.auth.AuthenticationModule#getEMailAddress(java.lang.String)
     */
    public String getEMailAddress(String user) {

        User userObj = findUser(user);
        if (userObj != null) {
            return userObj.getMail();
        } else {
            return null;
        }

    }

    /* (non-Javadoc)
     * @see de.innovationgate.webgate.api.auth.AuthenticationModule#isPoolable()
     */
    public boolean isPoolable() {
        return true;
    }

    /* (non-Javadoc)
     * @see de.innovationgate.webgate.api.auth.AuthenticationModule#addAuthenticationSourceListener(de.innovationgate.webgate.api.auth.AuthenticationSourceListener)
     */
    public void addAuthenticationSourceListener(AuthenticationSourceListener listener) {
        synchronized (_authenticationSourceListeners) {
            _authenticationSourceListeners.add(listener);
        }
    }

    /* (non-Javadoc)
     * @see de.innovationgate.webgate.api.auth.AuthenticationModule#removeAuthenticationSourceListener(de.innovationgate.webgate.api.auth.AuthenticationSourceListener)
     */
    public void removeAuthenticationSourceListener(AuthenticationSourceListener listener) {
        synchronized (_authenticationSourceListeners) {
            _authenticationSourceListeners.remove(listener);
        }

    }

    /* (non-Javadoc)
     * @see de.innovationgate.webgate.api.auth.AuthenticationModule#getAllowedCredentialClasses()
     */
    public Class[] getAllowedCredentialClasses() {
        return new Class[] { String.class };
    }

    /*
     *  (non-Javadoc)
     * @see de.innovationgate.webgate.api.auth.AuthenticationModule#isQueryable(java.lang.String)
     */
    public boolean isQueryable(String queryType) {
        return false;
    }

    /*
     *  (non-Javadoc)
     * @see de.innovationgate.webgate.api.auth.AuthenticationModule#query(java.lang.Object, java.lang.String)
     */
    public Object query(Object query, String queryType) {
        return null;
    }

    public void destroy() {
    }

    public boolean isGeneratesSessionToken() {
        return false;
    }

    public void dropPasswordCache(String loginName) {
        clearCache();
    }

}