// --- BEGIN COPYRIGHT BLOCK ---
// This program 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; version 2 of the License.
//
// 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 General Public License for more details.
//
// You should have received a copy of the GNU General Public License along
// with this program; if not, write to the Free Software Foundation, Inc.,
// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
//
// (C) 2007 Red Hat, Inc.
// All rights reserved.
// --- END COPYRIGHT BLOCK ---
package com.netscape.cmscore.ldapconn;
import java.util.Hashtable;
import netscape.ldap.LDAPConnection;
import netscape.ldap.LDAPException;
import com.netscape.certsrv.apps.CMS;
import com.netscape.certsrv.base.EBaseException;
import com.netscape.certsrv.base.IConfigStore;
import com.netscape.certsrv.ldap.ILdapAuthInfo;
import com.netscape.cmsutil.password.IPasswordStore;
/**
* class for reading ldap authentication info from config store
*/
public class LdapAuthInfo implements ILdapAuthInfo {
protected int mType = -1;
protected String[] mParms = null;
private boolean mInited = false;
private static Hashtable passwords = new Hashtable();
/**
* must call init(config) after this constructor.
*/
public LdapAuthInfo() {
}
/**
* constructs ldap auth info directly from config store.
*/
public LdapAuthInfo(IConfigStore config) throws EBaseException {
init(config);
}
/**
* constructs ldap auth info directly from config store, and verifies
* the password by attempting to connect to the server.
*/
public LdapAuthInfo(IConfigStore config, String host, int port, boolean secure)
throws EBaseException {
init(config, host, port, secure);
}
public String getPasswordFromStore(String prompt) {
String pwd = null;
CMS.debug("LdapAuthInfo: getPasswordFromStore: try to get it from password store");
// hey - should use password store interface to allow different implementations
// but the problem is, other parts of the system just go directly to the file
// so calling CMS.getPasswordStore() will give you an outdated one
/*
IConfigStore mainConfig = CMS.getConfigStore();
String pwdFile = mainConfig.getString("passwordFile");
FileConfigStore pstore = new FileConfigStore(pwdFile);
*/
IPasswordStore pwdStore = CMS.getPasswordStore();
CMS.debug("LdapAuthInfo: getPasswordFromStore: about to get from passwored store: " + prompt);
// support publishing dirsrv with different pwd than internaldb
// Finally, interactively obtain the password from the user
if (pwdStore != null) {
CMS.debug("LdapAuthInfo: getPasswordFromStore: password store available");
pwd = pwdStore.getPassword(prompt);
// pwd = pstore.getString(prompt);
if (pwd == null) {
CMS.debug("LdapAuthInfo: getPasswordFromStore: password for " + prompt +
" not found, trying internaldb");
// pwd = pstore.getString("internaldb");
pwd = pwdStore.getPassword("internaldb"); // last resort
} else
CMS.debug("LdapAuthInfo: getPasswordFromStore: password found for prompt in password store");
} else
CMS.debug("LdapAuthInfo: getPasswordFromStore: password store not available: pwdStore is null");
return pwd;
}
/**
* initialize this class from the config store.
*/
public void init(IConfigStore config) throws EBaseException {
init(config, null, 0, true);
}
/**
* initialize this class from the config store, and verify the password.
*
* @param host The host that the directory server is running on.
* This will be used to verify the password by attempting to connect.
* If it is null
, the password will not be verified.
* @param port The port that the directory server is running on.
*/
public void init(IConfigStore config, String host, int port, boolean secure)
throws EBaseException {
CMS.debug("LdapAuthInfo: init()");
if (mInited) {
CMS.debug("LdapAuthInfo: already initialized");
return; // XXX throw exception here ?
}
CMS.debug("LdapAuthInfo: init begins");
String authTypeStr = config.getString(PROP_LDAPAUTHTYPE);
if (authTypeStr.equals(LDAP_BASICAUTH_STR)) {
// is the password found in memory?
boolean inMem = false;
mType = LDAP_AUTHTYPE_BASICAUTH;
mParms = new String[2];
mParms[0] = config.getString(PROP_BINDDN);
// Passwords should only be written to the file for testing,
// never in production
mParms[1] = config.getString(PROP_BINDPW, null);
// Next, see if this password has been requested before
String prompt = config.getString(PROP_BINDPW_PROMPT, null);
if (prompt == null) {
prompt = "LDAP Authentication";
CMS.debug("LdapAuthInfo: init: prompt is null, change to " + prompt);
} else
CMS.debug("LdapAuthInfo: init: prompt is " + prompt);
if (mParms[1] == null) {
CMS.debug("LdapAuthInfo: init: try getting from memory cache");
mParms[1] = (String) passwords.get(prompt);
if (mParms[1] != null) {
inMem = true;
CMS.debug("LdapAuthInfo: init: got password from memory");
} else
CMS.debug("LdapAuthInfo: init: password not in memory");
} else
CMS.debug("LdapAuthInfo: init: found password from config");
if (mParms[1] == null) {
mParms[1] = getPasswordFromStore(prompt);
} else {
CMS.debug("LdapAuthInfo: init: password found for prompt.");
}
// verify the password
if ((mParms[1] != null) && (!mParms[1].equals("")) && (host == null ||
authInfoOK(host, port, secure, mParms[0], mParms[1]))) {
// The password is OK or uncheckable
CMS.debug("LdapAuthInfo: password ok: store in memory cache");
passwords.put(prompt, mParms[1]);
} else {
if (mParms[1] == null)
CMS.debug("LdapAuthInfo: password not found");
else {
CMS.debug("LdapAuthInfo: password does not work");
/* what do you know? Our IPasswordStore does not have a remove function.
pstore.remove("internaldb");
*/
if (inMem) {
// this is for the case when admin changes pwd
// from console
mParms[1] = getPasswordFromStore(prompt);
if (authInfoOK(host, port, secure, mParms[0], mParms[1])) {
CMS.debug("LdapAuthInfo: password ok: store in memory cache");
passwords.put(prompt, mParms[1]);
}
}
}
}
} else if (authTypeStr.equals(LDAP_SSLCLIENTAUTH_STR)) {
mType = LDAP_AUTHTYPE_SSLCLIENTAUTH;
mParms = new String[1];
mParms[0] = config.getString(PROP_CLIENTCERTNICKNAME, null);
} else {
throw new IllegalArgumentException(
"Unknown Ldap authentication type " + authTypeStr);
}
mInited = true;
CMS.debug("LdapAuthInfo: init ends");
}
public void reset() {
try {
conn.disconnect();
} catch (LDAPException e) {
}
}
/**
* Verifies the distinguished name and password by attempting to
* authenticate to the server. If we connect to the server but cannot
* authenticate, we conclude that the DN or password is invalid. If
* we cannot connect at all, we don't know, so we return true
* (there's no sense asking for the password again since we can't verify
* it anyway). If we connect and authenticate successfully, we know
* the DN and password are correct, so we return true.
*/
private static LDAPConnection conn = new LDAPConnection();
private static boolean
authInfoOK(String host, int port, boolean secure, String dn, String pw) {
// We dont perform auth checking if we are in SSL mode.
if (secure)
return true;
boolean connected = false, authenticated = false;
try {
conn.connect(host, port);
connected = true;
conn.authenticate(dn, pw);
authenticated = true;
} catch (LDAPException e) {
}
/**
* There is a bug in LDAP SDK. VM will crash on NT if
* we connect and disconnect too many times.
**/
/**
* if( connected ) {
* try {
* conn.disconnect();
* } catch( LDAPException e ) { }
* }
**/
if (connected && !authenticated) {
return false;
} else {
return true;
}
}
/**
* get authentication type.
*
* @return one of:
* LdapAuthInfo.LDAP_AUTHTYPE_BASICAUTH or
* LdapAuthInfo.LDAP_AUTHTYPE_SSLCLIENTAUTH
*/
public int getAuthType() {
return mType;
}
/**
* get params for authentication
*
* @return array of parameters for this authentication.
*/
public String[] getParms() {
return (String[]) mParms.clone();
}
/**
* add password
*/
public void addPassword(String prompt, String pw) {
try {
passwords.put(prompt, pw);
} catch (Exception e) {
}
}
/**
* remove password
*/
public void removePassword(String prompt) {
try {
passwords.remove(prompt);
} catch (Exception e) {
}
}
}