Package de.innovationgate.wgpublisher.auth

Source Code of de.innovationgate.wgpublisher.auth.CSAuthModule$CSGroupMembershipResolver

/*******************************************************************************
* 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.wgpublisher.auth;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.security.NoSuchAlgorithmException;
import java.security.cert.CertificateFactory;
import java.security.cert.X509CRL;
import java.security.cert.X509Certificate;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Hashtable;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.Set;

import javax.naming.Context;
import javax.naming.NamingException;
import javax.naming.directory.DirContext;
import javax.naming.directory.InitialDirContext;

import org.apache.log4j.Logger;

import de.innovationgate.utils.CertificateValidationUtils;
import de.innovationgate.utils.GroupMembershipResolver;
import de.innovationgate.utils.GroupResolvingException;
import de.innovationgate.utils.WGUtils;
import de.innovationgate.webgate.api.WGAPIException;
import de.innovationgate.webgate.api.WGArea;
import de.innovationgate.webgate.api.WGCSSJSModule;
import de.innovationgate.webgate.api.WGContent;
import de.innovationgate.webgate.api.WGContentEvent;
import de.innovationgate.webgate.api.WGContentEventListener;
import de.innovationgate.webgate.api.WGDatabase;
import de.innovationgate.webgate.api.WGException;
import de.innovationgate.webgate.api.WGFactory;
import de.innovationgate.webgate.api.WGFileContainer;
import de.innovationgate.webgate.api.WGScriptModule;
import de.innovationgate.webgate.api.WGStructEntry;
import de.innovationgate.webgate.api.WGStructEntryList;
import de.innovationgate.webgate.api.WGUnavailableException;
import de.innovationgate.webgate.api.auth.AuthenticationException;
import de.innovationgate.webgate.api.auth.AuthenticationSession;
import de.innovationgate.webgate.api.auth.AuthenticationSourceListener;
import de.innovationgate.webgate.api.auth.CertAuthCapableAuthModule;
import de.innovationgate.webgate.api.auth.ConfigurationException;
import de.innovationgate.wgpublisher.WGACore;
import de.innovationgate.wgpublisher.WGACoreEvent;
import de.innovationgate.wgpublisher.WGACoreEventListener;
import de.innovationgate.wgpublisher.expressions.ExpressionEngine;
import de.innovationgate.wgpublisher.expressions.ExpressionEngineFactory;
import de.innovationgate.wgpublisher.expressions.ExpressionResult;
import de.innovationgate.wgpublisher.webtml.utils.TMLContext;

public class CSAuthModule implements CoreAwareAuthModule, CertAuthCapableAuthModule, WGACoreEventListener, WGContentEventListener {
 
    public static final Logger LOG = Logger.getLogger("wga.api.auth.cs");
   
  public static final String DEFAULT_GROUPSROOT = "authgroups";
    public static final String DEFAULT_USERSROOT = "authusers";
    /**
     * The database to take auth information from is yet unknown
     */
    public static final int STATUS_AUTHDB_UNKNOWN = 0;
   
   
    /**
     * The database to take auth information from is known, prepared but not yet connected,
     * so the auth module didn't yet collect login data
     */
    public static final int STATUS_AUTHDB_PREPARED = 1;
   
    /**
     * The database to take auth information from is known and the login data has been fetched
     */
    public static final int STATUS_READY = 2;
   
    public class GroupMembership {
       
        private String _name;
        private Set  _groups;
       
        public GroupMembership(String name) {
            _name = name;
            _groups = new HashSet();
           
        }

        /**
         * @return Returns the members.
         */
        public Set getGroups() {
            return _groups;
        }
       
        public void addGroup(String group) {
            _groups.add(group);
        }

        /**
         * @return Returns the name.
         */
        public String getName() {
            return _name;
        }
       
       
    }
   
    public class CSGroupMembershipResolver extends GroupMembershipResolver {

        private Map _groupMemberships;

        public CSGroupMembershipResolver(Map groupMemberships) {
            _groupMemberships = groupMemberships;
        }
       
        public Set resolveDirectMembership(String member) throws GroupResolvingException {
           
            GroupMembership membership = (GroupMembership) _groupMemberships.get(member.toLowerCase());
            if (membership != null) {
                return membership.getGroups();
            }
            else {
                return new HashSet();
            }
           
        }
       
    }

    public Set<String> _groupInformation = new HashSet<String>();

    public class AuthCollector implements Runnable {

        public static final String CSAUTH_PROPERTIES_FILE = "csauth.properties";

        public void run() {

            synchronized (CSAuthModule.this) {
           
                try {
                    _currentCollectorThread = Thread.currentThread();
                    WGDatabase db = (WGDatabase) _core.getContentdbs().get(_dbkey);
                    if (db == null) {
                        _core.getLog().error("Cannot collect authentications from db '" + _dbkey + "' because the db is not connected");
                        return;
                    }
                   
                    db.openSession();
                    db.getSessionContext().setTask("CS Authentication Module - Login collection task");
                   
                    // Try to read configuration
                    readConfigurationProperties(db);
   
                    // Collect logins
                    if (_scriptCollect != null) {
                        doCustomCollect(db);
                    }
                    else {
                        doDefaultCollect(db);
                    }
                   
                    // Notify listeners
                    synchronized (_listeners) {
                        Iterator listeners = _listeners.iterator();
                        while (listeners.hasNext()) {
                            ((AuthenticationSourceListener) listeners.next()).authenticationDataChanged();
                        }
                    }
                   
                }
                catch (WGUnavailableException e) {
                    _core.getLog().error("Cannot collect authentications from db '" + _dbkey + "' because the db is currently unavailable");
                }
                catch (Exception e) {
                    _core.getLog().error("Error collecting authentications from db' " + _dbkey + "'", e);
                }
                finally {
                    _currentCollectorThread = null;               
                    WGFactory.getInstance().closeSessions();
                }
               
            }

        }

        private void readConfigurationProperties(WGDatabase db) throws WGAPIException {
            try {
                WGFileContainer system = db.getFileContainer("system");
                if (system == null) {
                    return;
                }
               
                if (system.hasFile(CSAUTH_PROPERTIES_FILE)) {
                    Properties props = new Properties();
                    props.load(system.getFileData(CSAUTH_PROPERTIES_FILE));
                    configure(props);
                    _internalConfiguration = true;
                }
            }
            catch (IOException e) {
                _core.getLog().error("Unable to read csauth configuration from file " + CSAUTH_PROPERTIES_FILE, e);
            }
           
        }

        private void doDefaultCollect(WGDatabase db) throws WGException {

           
            Map newLoginInformation = new HashMap();
            Set newGroupInformation = new HashSet();
           
            // collect group struct entries / if any exist
            Map groupMembership = new HashMap();
            if (_groupsRootDoc != null) {
                WGStructEntryList groupStructEntries = null;
                WGContent rootContent = db.getContentByName(_groupsRootDoc);
                if (rootContent != null) {
                    groupStructEntries = rootContent.getStructEntry().getChildEntries();
                }
   
                if (groupStructEntries == null) {
                    WGArea area = db.getArea(_groupsRootDoc);
                    if (area != null) {
                        groupStructEntries = area.getRootEntries();
                    }
                }
   
                if (groupStructEntries == null) {
                    throw new WGException("Root doc name '" + _groupsRootDoc + "' is neither the unique name of a content nor an area name. Please check if the default language " + db.getDefaultLanguage() + " of this database matches the language of group documents.");
                }
   
                // Recurse through group docs
                Iterator structsIt = groupStructEntries.iterator();
                while (structsIt.hasNext()) {
                    recurseGroupDocuments((WGStructEntry) structsIt.next(), groupMembership, newGroupInformation);
                }
            }

            // Collect user struct entries {
            WGStructEntryList structEntries = null;
            WGContent rootContent = db.getContentByName(_userRootDoc);
            if (rootContent != null) {
                structEntries = rootContent.getStructEntry().getChildEntries();
            }

            if (structEntries == null) {
                WGArea area = db.getArea(_userRootDoc);
                if (area != null) {
                    structEntries = area.getRootEntries();
                }
            }

            if (structEntries == null) {
                throw new WGException("Root doc name '" + _userRootDoc + "' is neither the unique name of a content nor an area name. Please check if the default language " + db.getDefaultLanguage() + " of this database matches the language of user documents.");
            }

            // Recurse through user docs
            Iterator structsIt = structEntries.iterator();
            while (structsIt.hasNext()) {
                recurseLoginDocuments((WGStructEntry) structsIt.next(), newLoginInformation);
            }

           
           
            // Merge users with group memberships
            CSGroupMembershipResolver membershipResolver = new CSGroupMembershipResolver(groupMembership);
            Iterator loginsIt = newLoginInformation.keySet().iterator();
            String loginName;
            Login login;
            while (loginsIt.hasNext()) {
                loginName = (String) loginsIt.next();
                login = (Login) newLoginInformation.get(loginName);
                try {
                    login.addGroups(membershipResolver.resolveMembership(loginName));
                }
                catch (GroupResolvingException e) {
                    _core.getLog().error("Error resolving group member ship for user name '" + loginName + "'", e);
                }
            }
           
            _loginInformation = newLoginInformation;
            _groupInformation = newGroupInformation;

        }

        private void recurseGroupDocuments(WGStructEntry entry, Map groupMembership, Set<String> groupInformation) throws WGAPIException {
           
            // Look for content with necessary items. Fetch logins if available
            WGContent content = entry.getReleasedContent(entry.getDatabase().getDefaultLanguage());
            if (content != null && isGroupDefinition(content)) {
                fetchDefaultGroupsFromDocument(groupMembership, content, groupInformation);
            }
            // Recurse thru children
            Iterator children = entry.getChildEntries().iterator();
            while (children.hasNext()) {
                recurseGroupDocuments((WGStructEntry) children.next(), groupMembership, groupInformation);
            }
           
        }

        private boolean isGroupDefinition(WGContent content) throws WGAPIException {
           
            if (!content.hasItem(_groupnameItem) || !content.hasItem(_membersItem)) {
                return false;
            }
           
            if (content.hasItem(_enabledItem) && !content.getItemText(_enabledItem).equals("true")) {
                return false;
            }
           
            return true;
        }

        private void fetchDefaultGroupsFromDocument(Map groupMemberships, WGContent content, Set<String> groupInformation) throws WGAPIException {
           
            String groupname = content.getItemText(_groupnameItem);
            groupInformation.add(groupname);
           
            List members = content.getItemValueList(_membersItem);
            if (members == null) {
                members = new ArrayList();
            }
           
            Iterator membersIt = members.iterator();
            String member;
            while (membersIt.hasNext()) {
                member = (String) membersIt.next();
                GroupMembership membership = (GroupMembership) groupMemberships.get(member.toLowerCase());
                if (membership == null) {
                     membership = new GroupMembership(member);
                     groupMemberships.put(member.toLowerCase(), membership);
                }
                membership.addGroup(groupname);
            }
           

           
           
        }

        private void recurseLoginDocuments(WGStructEntry entry, Map logins) throws WGAPIException {

            // Look for content with necessary items. Fetch logins if available
            WGContent content = entry.getReleasedContent(entry.getDatabase().getDefaultLanguage());
            if (content != null && isLoginDefinition(content)) {
                fetchDefaultLoginsFromDocument(logins, content);
            }

            // Recurse thru children
            Iterator children = entry.getChildEntries().iterator();
            while (children.hasNext()) {
                recurseLoginDocuments((WGStructEntry) children.next(), logins);
            }

        }

        private boolean isLoginDefinition(WGContent content) throws WGAPIException {
           
            if (!content.hasItem(_usernameItem) || !content.hasItem(_passwordItem)) {
                return false;
            }
           
            if (content.hasItem(_enabledItem) && content.getItemText(_enabledItem)!=null && !content.getItemText(_enabledItem).equals("true")) {
                return false;
            }
           
            return true;
        }

        private void fetchDefaultLoginsFromDocument(Map logins, WGContent content) throws WGAPIException {
            String password = content.getItemText(_passwordItem);
            String username = content.getItemText(_usernameItem);
            String email = content.getItemText(_emailItem);
            List nameAliases = content.getItemValueList(_aliasesItem);
            if (nameAliases == null) {
                nameAliases = new ArrayList();
            }
            Login login = new Login(username, password, email, content.getDocumentKey(), new HashSet(nameAliases));
            for (String labeledName : _labeledNames) {
                if (content.hasItem(labeledName)) {
                    login.addLabeledName(labeledName, content.getItemValue(labeledName));
                }
            }
           
            putLogin(logins, login);
        }

        private void putLogin(Map logins, Login login) {

            // Test if this username is already in use
            String distName = login.getDistinguishedName();
            Login oldLogin = (Login) logins.get(distName);
            if (oldLogin != null) {
                // Both names are first user names. New one wins
                if (distName.equals(oldLogin.getDistinguishedName())) {
                    _core.getLog().warn(
                            "Auth db '" + _dbkey + "': First user name '" + distName + "' is multiply defined by document '" + oldLogin.getDocumentkey() + "' and '"
                                    + login.getDocumentkey() + "'");
                }

                // New name is first user name, old is not. New wins
                else {
                    _core.getLog().warn(
                            "Auth db '" + _dbkey + "': First user name '" + oldLogin.getDistinguishedName() + "' is also defined as alias by document '" + oldLogin.getDocumentkey()
                                    + "'. The alias will be overwritten.");
                }
            }
            putLoginName(logins, login, distName);

            // Put login under aliases
            Iterator aliases = login.getAliases().iterator();
            String alias;
            while (aliases.hasNext()) {
                alias = (String) aliases.next();
                if (alias.trim().equals("")) {
                    continue;
                }

                // Test if this name is already in use
                oldLogin = (Login) logins.get(alias);
                if (oldLogin != null) {

                    // Old name is first user name, new is not. Old wins
                    // (exiting method)
                    if (oldLogin.getDistinguishedName().equals(alias)) {
                        _core.getLog().warn(
                                "Auth db '" + _dbkey + "': First user name '" + distName + "' is also defined as alias by document '" + login.getDocumentkey()
                                        + "'. The alias will be overwritten.");
                        continue;
                    }

                    // Both are aliases. New wins
                    else {
                        _core.getLog().warn(
                                "Auth db '" + _dbkey + "': Alias '" +  alias + "' from document '" + login.getDocumentkey() + "' is also defined as alias by document '" + oldLogin.getDocumentkey()
                                        + "'. The alias of the second document will be overwritten.");
                    }
                }
                putLoginName(logins, login, alias);
            }

        }

        private void putLoginName(Map logins, Login login, String name) {
            logins.put(name.toLowerCase(), login);
        }

        private void doCustomCollect(WGDatabase db) throws WGException {

            Map newLoginInformation = new HashMap();
            Set newGroupInformation = new HashSet();

            // Get collect script
            WGCSSJSModule mod = db.getCSSJSModule(_scriptCollect, WGScriptModule.CODETYPE_TMLSCRIPT);
            if (mod == null) {
                throw new WGException("Database '" + _dbkey + "' does not contain a TMLScript module of name '" + _scriptCollect + "'");
            }

            if (!mod.getCodeType().equals(WGCSSJSModule.CODETYPE_TMLSCRIPT)) {
                throw new WGException("Script module '" + _scriptCollect + "' in Database '" + _dbkey + "' is not of type TMLScript");
            }

            // Build a TMLScript runtime
            ExpressionEngine engine = ExpressionEngineFactory.getTMLScriptEngine();
            TMLContext context = new TMLContext(db.getDummyContent(db.getDefaultLanguage()), _core, null, null);
            Map objects = new HashMap();
            objects.put("logins", newLoginInformation);
            objects.put("groups", newGroupInformation);

            // Execute script
            ExpressionResult result = engine.evaluateExpression(mod.getCode(), context, ExpressionEngine.TYPE_SCRIPT, objects);
            if (result.isError()) {
                throw new WGException("Error executing collect script", result.getException());
            }

            _loginInformation =  newLoginInformation;
            _groupInformation = newGroupInformation;

        }

    }

    public static final String COPTION_DBKEY = "auth.cs.dbkey";

    public static final String COPTION_ROOTDOC_USERS = "auth.cs.rootdoc.users";
    public static final String COPTION_ROOTDOC_GROUPS = "auth.cs.rootdoc.groups";

    public static final String COPTION_SCRIPT_COLLECT = "auth.cs.script.collect";

    public static final String COPTION_ITEM_USERNAME = "auth.cs.item.username";
    public static final String COPTION_ITEM_GROUPNAME = "auth.cs.item.groupname";
    public static final String COPTION_ITEM_GROUPMEMBERS = "auth.cs.item.groupmembers";
    public static final String COPTION_ITEM_PASSWORD = "auth.cs.item.password";
    public static final String COPTION_ITEM_ALIASES = "auth.cs.item.aliases";
    public static final String COPTION_ITEM_EMAIL = "auth.cs.item.email";
    public static final String COPTION_ITEM_ENABLED = "auth.cs.item.enabled";
   
    public static final String COPTION_LABELED_NAMES = "auth.cs.labelednames";
   
    public static final String COPTION_COLLECT_CONDITION = "auth.cs.collect.condition";

    public static final String DEFAULTITEM_EMAIL = "EMail";

    public static final String DEFAULTITEM_USERALIASES = "UserAliases";

    public static final String DEFAULTITEM_PASSWORD = "Password";

    public static final String DEFAULTITEM_USERNAME = "UserName";
    public static final String DEFAULTITEM_GROUPNAME = "GroupName";
    public static final String DEFAULTITEM_MEMBERS = "Members";
    public static final String DEFAULTITEM_ENABLED = "Enabled";

    private WGACore _core;

    private Map<String,Login> _loginInformation = new HashMap<String,Login>();

    private String _dbkey;

    private String _userRootDoc = DEFAULT_USERSROOT;
    private volatile int _status = STATUS_AUTHDB_UNKNOWN;
    private String _groupsRootDoc = DEFAULT_GROUPSROOT;
    private WGDatabase _registeredDB = null;

    private String _scriptCollect;

    private String _usernameItem = DEFAULTITEM_USERNAME;

    private String _passwordItem = DEFAULTITEM_PASSWORD;

    private String _aliasesItem = DEFAULTITEM_USERALIASES;

    private String _emailItem = DEFAULTITEM_EMAIL;
   
    private String _enabledItem = DEFAULTITEM_ENABLED;

    private String _membersItem = DEFAULTITEM_MEMBERS;

    private String _groupnameItem = DEFAULTITEM_GROUPNAME;
   
    private String _collectCondition = null;
   
    private boolean _internalConfiguration = false;
   
    private Set<String> _labeledNames = new HashSet<String>();

   
    private List _listeners = new ArrayList();


    private Thread _currentCollectorThread = null;

    private X509Certificate _currentCA;

    private long _currentCALastModified;

    private String _certCA = null;

    private String _certCRL = null;

    private long _currentCRLLastModified;

    private X509CRL _currentCRL;

    private boolean _certAuth = false;

   
    /**
     * Enable certificate authentication
     */
    public static final String COPTION_CERTAUTH = "auth.cs.certauth";
   
    /**
     * Filename of the CA to be used to verify clientcertificates
     */
    public static final String COPTION_CA = "auth.cs.ca";

    /**
     * Filename of the CRL for the given CA
     */
    public static final String COPTION_CRL = "auth.cs.crl";



   

    public void init(Map params, WGDatabase db) throws ConfigurationException {
        _dbkey = ((String) params.get(COPTION_DBKEY)).toLowerCase();
       
        configure(params);

        if (_dbkey == null) {
            throw new ConfigurationException("The dbkey of the authentication db is not specified");
        }

        if (_scriptCollect == null && _userRootDoc == null) {
            throw new ConfigurationException("Either a collection script or a root document for login documents must be specified");
        }

        // Try to fetch target db at this time. May get connected later
        registerWithTargetDatabase((WGDatabase) _core.getContentdbs().get(_dbkey));

    }

    private void configure(Map params) {
       
        if (params.containsKey(COPTION_ROOTDOC_USERS)) {
            _userRootDoc = (String) params.get(COPTION_ROOTDOC_USERS);
        }
       
        if (params.containsKey(COPTION_ROOTDOC_GROUPS)) {
            _groupsRootDoc = (String) params.get(COPTION_ROOTDOC_GROUPS);
        }
       
        _scriptCollect = (String) params.get(COPTION_SCRIPT_COLLECT);
        _collectCondition = (String) params.get(COPTION_COLLECT_CONDITION);
       
        if (params.containsKey(COPTION_ITEM_USERNAME)) {
            _usernameItem = (String) params.get(COPTION_ITEM_USERNAME);
        }
        if (params.containsKey(COPTION_ITEM_PASSWORD)) {
            _passwordItem = (String) params.get(COPTION_ITEM_PASSWORD);
        }
        if (params.containsKey(COPTION_ITEM_ALIASES)) {
            _aliasesItem = (String) params.get(COPTION_ITEM_ALIASES);
        }
        if (params.containsKey(COPTION_ITEM_EMAIL)) {
            _emailItem = (String) params.get(COPTION_ITEM_EMAIL);
        }
        if (params.containsKey(COPTION_ITEM_ENABLED)) {
            _enabledItem = (String) params.get(COPTION_ITEM_ENABLED);
        }
        if (params.containsKey(COPTION_ITEM_GROUPNAME)) {
            _groupnameItem = (String) params.get(COPTION_ITEM_GROUPNAME);
        }
        if (params.containsKey(COPTION_ITEM_GROUPMEMBERS)) {
            _membersItem = (String) params.get(COPTION_ITEM_GROUPMEMBERS);
        }
       
        if (params.containsKey(COPTION_CERTAUTH)) {
            _certAuth = Boolean.parseBoolean((String) params.get(COPTION_CERTAUTH));
        }
       
        if (params.containsKey(COPTION_CA)) {
            _certCA = (String) params.get(COPTION_CA);
        }
        if (params.containsKey(COPTION_CRL)) {
            _certCRL = (String) params.get(COPTION_CRL);
        }
        if (params.containsKey(COPTION_LABELED_NAMES)) {
            _labeledNames.addAll(WGUtils.deserializeCollection((String) params.get(COPTION_LABELED_NAMES), ","));
        }
    }

    private void registerWithTargetDatabase(WGDatabase dbTarget) {
        if (dbTarget != null && dbTarget.getDbReference().equals(_dbkey)) {
           
            dbTarget.addContentEventListener(this);
            _registeredDB = dbTarget;
           
            // If not yet connected, we will wait for our first login to collect
            if (!dbTarget.isConnected()) {
                _status = STATUS_AUTHDB_PREPARED;
                return;
            }
           
       
            try {
                runAuthCollector().join();
            }
            catch (InterruptedException e) {
            }
        }
    }

    private void unregisterFromTargetDatabase(WGDatabase dbTarget) {
        if (dbTarget != null && dbTarget.getDbReference().equals(_dbkey)) {
            dbTarget.removeContentEventListener(this);
            _registeredDB = null;
        }
    }

    public AuthenticationSession login(X509Certificate cert) throws AuthenticationException {
       
        if (_status == STATUS_AUTHDB_UNKNOWN) {
            throw new AuthenticationException("Authentication was unable to collect data for valid logins yet. Please ensure that source database '" + _dbkey + "' is enabled and can be connected.");
        }
       
        if (_status == STATUS_AUTHDB_PREPARED) {
            try {
                runAuthCollector().join();
            }
            catch (InterruptedException e) {
            }
        }
       
        String user = cert.getSubjectDN().toString();
        Login login = (Login) getLogin(user);
       
        if (login != null) {
            return login;
        }
        else {
            LOG.warn("Failed login for '" + user + "': Unknown user (" + getAuthenticationSource() + ")");
            return null;
        }
       
    }
   
    public AuthenticationSession login(String user, Object credentials) throws AuthenticationException {
       
        if (_status == STATUS_AUTHDB_UNKNOWN) {
            throw new AuthenticationException("Authentication was unable to collect data for valid logins yet. Please ensure that source database '" + _dbkey + "' is enabled and can be connected.");
        }
       
        if (_status == STATUS_AUTHDB_PREPARED) {
            try {
                runAuthCollector().join();
            }
            catch (InterruptedException e) {
            }
        }
       
        try {
            String password  = String.valueOf(credentials);
            Login login = (Login) getLogin(user);
            if (login != null) {
                String hashedPassword = WGUtils.hashPassword(password);
                if (login.getPassword() != null && login.getPassword().equals(hashedPassword)) {
                    return login;
                }
                else {
                    LOG.warn("Failed login for '" + user + "': Wrong password (" + getAuthenticationSource() + ")");
                }
            }
            else {
                LOG.warn("Failed login for '" + user + "': Unknown user (" + getAuthenticationSource() + ")");
            }
            return null;
        }
        catch (NoSuchAlgorithmException e) {
            throw new AuthenticationException("Neccessary password hash algorithm not available: " + e.getMessage());
        }
      
    }
   
    private CSUserGroupInfo buildUserInfo(Login login){

    CSUserGroupInfo newUserEntry = new CSUserGroupInfo();
    newUserEntry.setIsUser(true);
    newUserEntry.setIsGroup(false);
    newUserEntry.setFullQualifiedName(login.getDistinguishedName());
    newUserEntry.setAliasNames(login.getAliases());
    newUserEntry.getAttributes().put("mail", login.getMailAddress());
        newUserEntry.getAttributes().put("groups", login.getGroups());
        newUserEntry.getAttributes().put("documentKey", login.getDocumentkey());
    if (login.getLabeledNames() != null) {
        newUserEntry.getAttributes().putAll(login.getLabeledNames());
        newUserEntry.getLabeledNames().putAll(login.getLabeledNames());
    }
   
    return newUserEntry;
       
    }

    private Object getLogin(String user) {
        return _loginInformation.get(user.toLowerCase());
    }
   


    public String getEMailAddress(String user) {

        Object loginObj = getLogin(user);
        if (loginObj != null && loginObj instanceof Login) {
            return ((Login) loginObj).getMailAddress();
        }
        else {
            return null;
        }

    }



    public void clearCache() {
    }

    public String getAuthenticationSource() {
        return "Content-Store-Authentication against database " + _dbkey + (_internalConfiguration ? " (internaly configured)" : " (user documents under '" + _userRootDoc + "')");
    }

    public void setCore(WGACore core) {
        _core = core;
        core.addEventListener(this);

    }

    public void contentStoreConnected(WGACoreEvent event) {
        registerWithTargetDatabase(event.getDatabase());
    }

    public void contentStoreDisconnected(WGACoreEvent event) {
        unregisterFromTargetDatabase(event.getDatabase());
    }



    private synchronized Thread runAuthCollector() {
        Thread collectorThread = new Thread(new AuthCollector());
        collectorThread.start();
        _status = STATUS_READY;
        return collectorThread;
    }

    public boolean isTemporary() {
        return false;
    }

    public void contentCreated(WGContentEvent contentEvent) {
    }

    public boolean contentSaved(WGContentEvent contentEvent) {
        return true;
    }

    public void contentHasBeenSaved(WGContentEvent event) {
        runAuthCollectorByEvent(event);
    }

    public void contentHasBeenDeleted(WGContentEvent event) {
        runAuthCollector();
    }
   
    public void runAuthCollectorByEvent(WGContentEvent event) {
       
        if (_collectCondition != null) {
           
            try {
                WGContent content = event.getContent();
                if (content == null) {
                    content = (WGContent) event.getDatabase().getDocumentByDocumentKey(event.getDocumentKey());
                }
           
                if (content != null) {
                    TMLContext context = new TMLContext(event.getContent(), _core, null, null);
                    Map objects = new HashMap();
       
                    // Execute script
                    ExpressionEngine engine = ExpressionEngineFactory.getTMLScriptEngine();
                    ExpressionResult result = engine.evaluateExpression(_collectCondition, context, ExpressionEngine.TYPE_EXPRESSION, objects);
                    if (result.isError()) {
                        _core.getLog().error("Error auth collector condition script", result.getException());
                        return;
                    }
                    else if (result.isFalse()) {
                        return;
                    }
                }
            }
            catch (WGAPIException e) {
                _core.getLog().error("Error runAuthCollectorByEvent.", e);
                return;
            }
        }
       
        runAuthCollector();
    }

    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 (_listeners) {
            _listeners.add(listener);
        }
       
    }

    /* (non-Javadoc)
     * @see de.innovationgate.webgate.api.auth.AuthenticationModule#removeAuthenticationSourceListener(de.innovationgate.webgate.api.auth.AuthenticationSourceListener)
     */
    public void removeAuthenticationSourceListener(AuthenticationSourceListener listener) {
        synchronized (_listeners) {
            _listeners.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) {
        if(queryType.equals(QUERY_USERS_AND_GROUPS)) {
          return true;
        }
        else if (queryType.equals(QUERY_USER_DN)) {
            return true;
        }
       
      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) {
        if(queryType.equals(QUERY_USERS_AND_GROUPS)) {
          return findUsersAndGroups((String) query);
        }
        else if (queryType.equals(QUERY_USER_DN)) {
            return fetchUserByDN((String) query);
        }
      return null;
   
   
    private Object fetchUserByDN(String query) {

        Login login = _loginInformation.get(query.toLowerCase());
        if (login != null && login.getDistinguishedName().equalsIgnoreCase(query)) {
            return buildUserInfo(login);
        }
        else {
            return null;
        }
       
    }

    /**
     * retrieves all users and groups with the given prefix in nameAttributes
     * @param prefix to search for
     * @return a list of de.innovationgate.webgate.api.auth.UserGroupInfo
     */
    private List<CSUserGroupInfo> findUsersAndGroups(String prefix) {
      ArrayList<CSUserGroupInfo> results = new ArrayList<CSUserGroupInfo>();
      String current;
     
    Iterator<String> it = _loginInformation.keySet().iterator();
    while(it.hasNext()){
      current = (String) it.next();
      if(current.indexOf(prefix)!=-1){
          Login login = _loginInformation.get(current);
        results.add(buildUserInfo(login));
      }
    }
   
    it = _groupInformation.iterator();
    while (it.hasNext()) {
        current = (String) it.next();
        if(current.indexOf(prefix)!=-1){
            results.add(buildGroupInfo(current));
        }
    }
   
   
    return results;
     
    }

    private CSUserGroupInfo buildGroupInfo(String groupName) {
       
        CSUserGroupInfo newUserEntry = new CSUserGroupInfo();
        newUserEntry.setIsUser(false);
        newUserEntry.setIsGroup(true);
        newUserEntry.setFullQualifiedName(groupName);
        return newUserEntry;
    }

    /**
     * @return Returns the status.
     */
    public int getStatus() {
        return _status;
    }

    public void shutdownPostDisconnect(WGACoreEvent event) {
    }

    public void shutdownPreDisconnect(WGACoreEvent event) {
    }

    public void startupPostConnect(WGACoreEvent event) {
    }

    public void startupPreConnect(WGACoreEvent event) {
    }
   
    public void destroy() {
       
        if (_core != null) {
            _core.removeEventListener(this);
            _core = null;
        }
       
        if (_registeredDB != null) {
            _registeredDB.removeContentEventListener(this);
            _registeredDB = null;
        }
       
    }

    public boolean isGeneratesSessionToken() {
        return false;
    }

    /**
     * returns the unique name of the root document for users
     * @return
     */
  public String getUserRootDoc() {
    return _userRootDoc;
  }
 
  /**
   * returns the unique name of the root document for groups
   * @return
   */
  public String getGroupsRootDoc() {
    return _groupsRootDoc;
  }
 
  /**
   * returns the dbkey of the authentication source
   * @return
   */
  public String getDbkey() {
    return _dbkey;
  }
 
  /**
   * returns the script code for custom collection
   * @return
   */
  public String getScriptCollect() {
    return _scriptCollect;
  }

  /**
   * returns the username item
   * @return
   */
  public String getUsernameItem() {
    return _usernameItem;
  }

  /**
   * returns the password item name
   * @return
   */
  public String getPasswordItem() {
    return _passwordItem;
  }

  /**
   * returns the alias item name
   * @return
   */
  public String getAliasesItem() {
    return _aliasesItem;
  }
 
  /**
   * returns the email item name
   * @return
   */
  public String getEmailItem() {
    return _emailItem;
  }
 
  /**
   * returns the enabled item name
   * @return
   */
  public String getEnabledItem() {
    return _enabledItem;
  }
 
  /**
   * returns the members item name
   * @return
   */
  public String getMembersItem() {
    return _membersItem;
  }
 
  /**
   * returns the groupname item
   * @return
   */
  public String getGroupnameItem() {
    return _groupnameItem;
  }
 
  /**
   * returns the collect condition
   * @return
   */
  public String getCollectCondition() {
    return _collectCondition;
  }

    public Thread getCurrentCollectorThread() {
        return _currentCollectorThread;
    }

    public void contentHasBeenMoved(WGContentEvent event) {
        runAuthCollectorByEvent(event);
    }
   
    private void loadCA(File caFile) throws AuthenticationException {
        try {
            CertificateFactory certificatefactory = CertificateFactory.getInstance("X.509");
            FileInputStream fin = new FileInputStream(caFile);
            _currentCA = (X509Certificate) certificatefactory.generateCertificate(fin);
            _currentCALastModified = caFile.lastModified();
            fin.close();
        }
        catch (Exception e) {
            String message = "Could not load CA '" + caFile.getPath() + "'";
            WGFactory.getLogger().error(message, e);
            throw new AuthenticationException(message, e);
        }

        // verify crl is signed by ca
        try {
            getCRL().verify(_currentCA.getPublicKey());
        }
        catch (Exception e) {
            String message = "CRL '" + caFile.getPath() + "' could not be verified against given CA.";
            WGFactory.getLogger().error(message, e);
            throw new AuthenticationException(message, e);
        }
    }
   
    /**
     * Returns the certificate authority for certificate authentication
     *
     * @throws AuthenticationException
     */
    public X509Certificate getCA() throws AuthenticationException {
        if (_certCA == null) {
            throw new AuthenticationException("CA is not configured properly for auth source: " + getAuthenticationSource());
        }
        File caFile = _core.getWGAFile(_certCA);
        if (caFile.exists()) {
            // check if CA is already loaded
            if (_currentCA != null) {
                // check if CA has been changed
                if (caFile.lastModified() != _currentCALastModified) {
                    // reload ca
                    loadCA(caFile);
                }
            }
            else {
                // load ca
                loadCA(caFile);
            }
            return _currentCA;
        }
        else {
            String message = "Could not find CA '" + _certCA + "'. No such file.";
            WGFactory.getLogger().error(message);
            throw new AuthenticationException(message);
        }
    }
   
    private void loadCRL(File crlFile) throws AuthenticationException {
        try {
            CertificateFactory certificatefactory = CertificateFactory.getInstance("X.509");
            FileInputStream fin = new FileInputStream(crlFile);
            _currentCRL = (X509CRL) certificatefactory.generateCRL(fin);
            _currentCRLLastModified = crlFile.lastModified();
            fin.close();
        }
        catch (Exception e) {
            String message = "Could not load CRL '" + crlFile.getPath() + "'";
            WGFactory.getLogger().error(message, e);
            throw new AuthenticationException(message, e);
        }

        // verify crl is signed by expected ca
        try {
            _currentCRL.verify(getCA().getPublicKey());
        }
        catch (Exception e) {
            String message = "CRL '" + crlFile.getPath() + "' could not be verified against given CA.";
            WGFactory.getLogger().error(message, e);
            throw new AuthenticationException(message, e);
        }
    }
   
    /**
     * Returns the certificate revoke list for certificate authentication
     *
     * @throws AuthenticationException
     */
    public X509CRL getCRL() throws AuthenticationException {
        if (_certCRL == null) {
            throw new AuthenticationException("CRL is not configured properly for auth source: " + getAuthenticationSource());
        }
        File crlFile = _core.getWGAFile(_certCRL);
        if (crlFile.exists()) {
            // check if CRL is already loaded
            if (_certCRL != null) {
                // check if CRL has been changed
                if (crlFile.lastModified() != _currentCRLLastModified) {
                    // reload crl
                    loadCRL(crlFile);
                }
            }
            else {
                // load crl
                loadCRL(crlFile);
            }
            return _currentCRL;
        }
        else {
            String message = "Could not find CRL '" + _certCRL + "'. No such file.";
            WGFactory.getLogger().error(message);
            throw new AuthenticationException(message);
        }
    }

    public boolean isCertAuthEnabled() {
        return _certAuth;
    }

    public void contentStatusChanged(WGContentEvent event) {
    }
}
TOP

Related Classes of de.innovationgate.wgpublisher.auth.CSAuthModule$CSGroupMembershipResolver

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.