/*
 * $Header: /home/cvspublic/jakarta-slide/proposals/tamino/src/ssx/org/apache/slide/urm/authenticator/impl/ssx/URMAuthenticatorSSX.java,v 1.6 2005/03/02 10:53:32 eckehard Exp $
 * $Revision: 1.6 $
 * $Date: 2005/03/02 10:53:32 $
 *
 * ====================================================================
 *
 * Copyright 1999-2004 The Apache Software Foundation.
 *
 * 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 org.apache.slide.urm.authenticator.impl.ssx;

import com.softwareag.ssx.userdb.SSXAuthenticatedUser;
import com.softwareag.ssx.userdb.SSXAuthenticationFailsException;
import com.softwareag.ssx.userdb.SSXConnectionCloseFailedException;
import com.softwareag.ssx.userdb.SSXUnknownUserException;
import com.softwareag.ssx.userdb.SSXUserDB;
import com.softwareag.ssx.userdb.SSXUserDBConstants;
import com.softwareag.ssx.userdb.SSXUserDBException;
import com.softwareag.ssx.userdb.SSXUserDBFactory;
import com.softwareag.ssx.userdb.SSXUserDBNotImplementedException;
import java.util.Hashtable;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import org.apache.slide.urm.accesscontroler.impl.URMAclAdministratorImpl;
import org.apache.slide.urm.authenticator.URMAuthenticationFailsException;
import org.apache.slide.urm.authenticator.URMAuthenticator;
import org.apache.slide.urm.authenticator.URMAuthenticatorException;
import org.apache.slide.urm.authenticator.impl.URMAdministratorImpl;
import org.apache.slide.urm.common.URMCloseConnectionException;
import org.apache.slide.urm.common.URMConfigurationException;
import org.apache.slide.urm.common.URMConfigurator;
import org.apache.slide.urm.common.URMPrincipal;
import org.apache.slide.urm.common.impl.URMConfiguratorUtil;
import org.apache.slide.urm.common.impl.URMPrincipalImpl;
import org.apache.slide.urm.utils.messagelogger.MessageLogger;

/**
 * @author eckehard.hermann@softwareag.com
 * @author dieter.kessler@softwareag.com
 * @author zsolt.sasvarie@softwareag.com
 */
public class URMAuthenticatorSSX extends URMAuthenticator {

    private static org.apache.log4j.Logger msLogger =
        org.apache.log4j.Logger.getLogger(URMAuthenticatorSSX.class.getName());
        
    private static final String CONF_AUTHENTICATOR = "Authenticator";
    private static final String CONF_ADMINISTRATOR = "Administrator";
    
    private static Hashtable msUserDbInitPropNamesTable = null;
    private static Hashtable msAdminInitPropNamesTable  = null;
    
    static {
		String[] userDbPropStringKeys = {
		   /*0*/ "cacheTime", "cacheSize", "denyTime", "denyCount",
		   /*4*/ "nativeLogFile", "nativeLogLevel", "defaultGroup", "defaultDomain",
		   /*8*/ "serverHost", "serverPort", "personBindDn", "groupBindDn",
		   /*12*/"personObjClass", "groupObjClass", "personGrpAttr", "groupPrsAttr",
		   /*16*/"userIdField", "groupIdField", "passwdField", "addPersonAttr",
		   /*20*/"addGroupAttr", "personPropAttr", "groupPropAttr", "serverType",
		   /*24*/"databaseUri", "connectionPerOperation",
		   /*26*/"authDaemonPath", "winUserExist",
		   /*28*/"winCheckLocalGroups", "useLogonUseron2000", null}; //"allowDomainAsBasebindDn"
        
	   int[] userDbPropIntKeys = {
		   /*0*/ SSXUserDBConstants.SSX_UDB_IPT_VALIDTIME, SSXUserDBConstants.SSX_UDB_IPT_MAXUSERS,
		   /*2*/ SSXUserDBConstants.SSX_UDB_IPT_DENYTIME, SSXUserDBConstants.SSX_UDB_IPT_DENYCOUNT,
		   /*4*/ SSXUserDBConstants.SSX_UDB_IPT_LOGFILE, SSXUserDBConstants.SSX_UDB_IPT_LOGLEVEL,
		   /*6*/ SSXUserDBConstants.SSX_UDB_IPT_DEFAULTGROUP, SSXUserDBConstants.SSX_UDB_IPT_DEFAULTDOMAIN,
		   /*8*/ SSXUserDBConstants.SSX_UDB_IPT_SERVERHOST, SSXUserDBConstants.SSX_UDB_IPT_SERVERPORT,
		   /*10*/SSXUserDBConstants.SSX_UDB_IPT_PERSON_BASE_BINDDN, SSXUserDBConstants.SSX_UDB_IPT_GROUP_BASE_BINDDN,
		   /*12*/SSXUserDBConstants.SSX_UDB_IPT_PERSON_OBJECTCLASS, SSXUserDBConstants.SSX_UDB_IPT_GROUP_OBJECTCLASS,
		   /*14*/SSXUserDBConstants.SSX_UDB_IPT_PERSON_GRP_ATTR, SSXUserDBConstants.SSX_UDB_IPT_GROUP_PRS_ATTR,
		   /*16*/SSXUserDBConstants.SSX_UDB_IPT_USERID_FIELD, SSXUserDBConstants.SSX_UDB_IPT_GROUPID_FIELD,
		   /*18*/SSXUserDBConstants.SSX_UDB_IPT_PASSWD_FIELD, SSXUserDBConstants.SSX_UDB_IPT_ADD_PERSON_ATTR,
		   /*20*/SSXUserDBConstants.SSX_UDB_IPT_ADD_GROUP_ATTR, SSXUserDBConstants.SSX_UDB_IPT_PERSON_PROPERTY_ATTR,
		   /*22*/SSXUserDBConstants.SSX_UDB_IPT_GROUP_PROPERTY_ATTR, SSXUserDBConstants.SSX_UDB_IPT_SERVER_TYPE,
		   /*24*/SSXUserDBConstants.SSX_UDB_IPT_DATABASEURI, SSXUserDBConstants.SSX_UDB_IPT_CREATE_CONNECTION_PER_OPERATION,
		   /*26*/SSXUserDBConstants.SSX_UDB_IPT_AUTHD_PATH, SSXUserDBConstants.SSX_UDB_IPT_WIN_AUTH_USER_EXIST,
		   /*28*/SSXUserDBConstants.SSX_UDB_IPT_WIN_CHECK_LOCAL_GROUPS, SSXUserDBConstants.SSX_UDB_IPT_WIN_LOGONUSER_ON_2000, 0};
            
        msUserDbInitPropNamesTable = new Hashtable();
        for (int i = 0; userDbPropStringKeys[i] != null; ++i)
            msUserDbInitPropNamesTable.put(userDbPropStringKeys[i], new Integer(userDbPropIntKeys[i]));

        String[] adminPropStringKeys = {
            /*0*/ "allUsersCacheTime", "allUsersCacheSize", "allGroupsCacheTime", "allGroupsCacheSize",
            /*4*/ "groupMembersCacheTime", "groupMembersCacheSize", "groupsOfUserCacheTime", "groupsOfUserCacheSize",
            /*8*/ "userPropsCacheTime", "userPropsCacheSize", "allCacheTime", "allCacheSize",
            /*12*/"defaultDomain", null};
        
        int[] adminPropIntKeys = {
            /*0*/ SSXUserDBConstants.SSX_ADMIN_IPT_ALLUSERS_VALIDTIME, SSXUserDBConstants.SSX_ADMIN_IPT_ALLUSERS_MAXELEMENT,
            /*2*/ SSXUserDBConstants.SSX_ADMIN_IPT_ALLGROUPS_VALIDTIME, SSXUserDBConstants.SSX_ADMIN_IPT_ALLGROUPS_MAXELEMENT,
            /*4*/ SSXUserDBConstants.SSX_ADMIN_IPT_GROUPMEMBERS_VALIDTIME, SSXUserDBConstants.SSX_ADMIN_IPT_GROUPMEMBERS_MAXELEMENT,
            /*6*/ SSXUserDBConstants.SSX_ADMIN_IPT_GROUPSOFUSER_VALIDTIME, SSXUserDBConstants.SSX_ADMIN_IPT_GROUPSOFUSER_MAXELEMENT,
            /*8*/ SSXUserDBConstants.SSX_ADMIN_IPT_PROPERTIES_VALIDTIME, SSXUserDBConstants.SSX_ADMIN_IPT_PROPERTIES_MAXELEMENT,
            /*10*/SSXUserDBConstants.SSX_ADMIN_IPT_VALIDTIME_FORALL, SSXUserDBConstants.SSX_ADMIN_IPT_MAXELEMENT_FORALL,
            /*12*/SSXUserDBConstants.SSX_ADMIN_EX_IPT_DEFAULTDOMAIN, 0};
    
        msAdminInitPropNamesTable = new Hashtable();
        for (int i = 0; adminPropStringKeys[i] != null; ++i)
            msAdminInitPropNamesTable.put(adminPropStringKeys[i], new Integer(adminPropIntKeys[i]));
    }
    
    private SSXUserDB mSsxUserDb = null;
    private URMConfigurator mAdministratorProperties = null;

    public URMAuthenticatorSSX(URMConfigurator userdbConf)
                throws URMConfigurationException, URMAuthenticatorException {
        if (msLogger.isInfoEnabled())
            MessageLogger.logMessage(msLogger, "URMCOI0019", "URMAuthenticatorSSX");
        // create user database
        conf = userdbConf;
        if (!userdbConf.getName().equals(CONF_AUTHENTICATOR)) {
            Map mainprops = userdbConf.getSubConfigurators();
            conf = mainprops != null ? (URMConfigurator)mainprops.get(CONF_AUTHENTICATOR) : null;
        }
        if (conf == null)
            throw new URMConfigurationException(
                MessageLogger.getAndLogMessage(msLogger, "URMSUC0001", CONF_AUTHENTICATOR));
        Iterator attrs = URMConfiguratorUtil.getAttributeList(conf, msLogger);
                
        String authtype = null;
        Properties ssxprops = new Properties();
        while (attrs.hasNext()) {
            URMConfigurator attrconf = ((URMConfigurator)attrs.next());
            Properties attr = attrconf.getProperties();
            
            if (attr == null)
                continue;
            String attrname = attr.getProperty("name");

            if (attrname == null)
                continue;
            
            if (attrname.equalsIgnoreCase("authType")) {
                authtype =  attr.getProperty("value");
                continue;
            }
            
            if (attrname.equalsIgnoreCase("sensitive")) {
            	String sensitive_str =  attr.getProperty("value");
            	if (sensitive_str != null) sensitive = new Boolean(sensitive_str).booleanValue();
                continue;
            }
            String attrval = attr.getProperty("value");//debug
 
            Integer attrkey = (Integer)msUserDbInitPropNamesTable.get(attrname);
            if (attrkey == null || attrkey.intValue() == 0)
                MessageLogger.logMessage(msLogger, "URMSUE0002", attrname);
            else {
				ssxprops.put(attrkey, attrval);
        	}
        }
        mAdministratorProperties = conf.getSubConfigurator("Administrator");
        attrs = URMConfiguratorUtil.getAttributeList(mAdministratorProperties.getSubConfigurator("UserDatabase"), msLogger);
        while (attrs != null && attrs.hasNext()) {
            URMConfigurator attrconf = ((URMConfigurator)attrs.next());
            Properties attr = attrconf.getProperties();
            if (attr == null)
                continue;
            String attrname = attr.getProperty("name");
            if (attrname == null)
                continue;
            Integer attrkey = (Integer)msAdminInitPropNamesTable.get(attrname);
            if (attrkey == null || attrkey.intValue() == 0)
                MessageLogger.logMessage(msLogger, "URMSUE0002", attrname);
            else
                ssxprops.put(attrkey, attr.getProperty("value"));
        }

        if (authtype == null)
            throw new URMConfigurationException(
                MessageLogger.getAndLogMessage(msLogger, "URMSUC0003"));
        
        // reading native property conf
        conf = mAdministratorProperties.getSubConfigurator("UserDatabase/NativeProperties");
        if (conf != null) {
            URMConfigurator nativeconf = conf.getSubConfigurator("User");
            if (conf != null) {
                String tmp = getLdapPropertyAttrs(nativeconf);
                if (tmp != null)
                    ssxprops.put(new Integer(SSXUserDBConstants.SSX_UDB_IPT_PERSON_PROPERTY_ATTR), tmp);
            }
            nativeconf = conf.getSubConfigurator("Group");
            if (conf != null) {
                String tmp = getLdapPropertyAttrs(nativeconf);
                if (tmp != null)
                    ssxprops.put(new Integer(SSXUserDBConstants.SSX_UDB_IPT_GROUP_PROPERTY_ATTR), tmp);
            }
        }
        
        try {
            SSXUserDBFactory udb_fact = SSXUserDBFactory.newInstance(authtype);
            mSsxUserDb = udb_fact.newUserDB(ssxprops);
        } catch (SSXUserDBException e) {
            throw new URMConfigurationException(msLogger, "F", e);
        }
    }
    
    private String getLdapPropertyAttrs(URMConfigurator conf) {
        Map map = conf.getSubConfigurators();
        Object obj = map != null ? map.get("Property") : null;
        if (obj == null)
            return null;
        String name = null, writeable = null;
        if (obj instanceof URMConfigurator) {
            Properties prop = ((URMConfigurator)obj).getProperties();
            if (prop != null) {
                name = prop.getProperty("name");
                writeable = prop.getProperty("writeable");
                if (name != null)
                    return name + ":" + (writeable.equalsIgnoreCase("true") ? "w" : "r");
            }
        }
        else if (obj instanceof List) {
            String retstr = "";
            for (Iterator iter = ((List)obj).iterator(); iter.hasNext();) {
                Properties prop = ((URMConfigurator)iter.next()).getProperties();
                if (prop != null) {
                    name = prop.getProperty("name");
                    writeable = prop.getProperty("writeable");
                    if (name != null) {
                        if (retstr.length() > 0)
                            retstr += ",";
                        retstr += name + ":" + (writeable.equalsIgnoreCase("true") ? "w" : "r");
                    }
                }
            }
            if (retstr.length() > 0)
                return retstr;
        }
        return null;
    }
    
    public URMPrincipal authenticateUser(String user, char[] password)
            throws URMAuthenticationFailsException, URMAuthenticatorException,
                    URMConfigurationException, URMCloseConnectionException {
        return this.authenticateUser(user, password, null);
    }

    public URMPrincipal authenticateUser(String user, char[] password, String domain)
            throws URMAuthenticationFailsException, URMAuthenticatorException,
                    URMConfigurationException, URMCloseConnectionException {
        try {
            SSXAuthenticatedUser auth_user = mSsxUserDb.authenticateUser(user, password, domain);
            if (auth_user == null)
                return null;
            Object owner = new Object();
            URMAdministratorImpl admin = new URMAdministratorImpl(mAdministratorProperties,
                                                    mSsxUserDb, user, password, domain, owner);
            auth_user.close();
            URMAclAdministratorImpl acladmin = new URMAclAdministratorImpl(mAdministratorProperties,
                                                    user, password, domain, owner);
            return new URMPrincipalImpl(user, password, domain, admin, acladmin);
        } catch (SSXUserDBNotImplementedException e) {
            throw new URMAuthenticatorException(msLogger, "F", e);
        } catch (SSXUnknownUserException e) {
            throw new URMAuthenticationFailsException(msLogger, "I", e);
        } catch (SSXAuthenticationFailsException e) {
            throw new URMAuthenticationFailsException(msLogger, "I", e);
        } catch (SSXConnectionCloseFailedException e) {
            throw new URMCloseConnectionException(msLogger, "E", e);
        } catch (SSXUserDBException e) {
            throw new URMAuthenticatorException(msLogger, "F", e);
        }
    }

}


