LDAPAuthUtils.java revision 143ce8159ee015167d050d20d91b0e0dc956d347
/**
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
*
* Copyright (c) 2005 Sun Microsystems Inc. All Rights Reserved
*
* The contents of this file are subject to the terms
* of the Common Development and Distribution License
* (the License). You may not use this file except in
* compliance with the License.
*
* You can obtain a copy of the License at
* See the License for the specific language governing
* permission and limitations under the License.
*
* When distributing Covered Code, include this CDDL
* Header Notice in each file and include the License file
* at opensso/legal/CDDLv1.0.txt.
* If applicable, add the following below the CDDL Header,
* with the fields enclosed by brackets [] replaced by
* your own identifying information:
* "Portions Copyrighted [year] [name of copyright owner]"
*
* $Id: LDAPAuthUtils.java,v 1.21 2009/12/28 03:01:26 222713 Exp $
*
*/
/**
* Portions Copyrighted 2011-2013 ForgeRock AS
*/
public class LDAPAuthUtils {
private boolean returnUserDN;
//only used for logging
private String userPassword;
private char[] authPassword;
private String expiryTime;
private SearchScope searchScope;
private int heartBeatInterval = 10;
private String heartBeatTimeUnit;
private ModuleState screenState;
private int graceLogins;
private int operationsTimeout = 0;
// JSS integration
private boolean ldapSSL = false;
private boolean beheraEnabled = true;
private boolean trustAll = true;
private boolean isAd = false;
// Resource Bundle used to get l10N message
private ResourceBundle bundle;
private final static int NO_EXPIRY_TIME = -1;
private final static int MIN_CONNECTION_POOL_SIZE = 1;
private final static int MAX_CONNECTION_POOL_SIZE = 10;
private final static String CONNECTION_POOL_SIZE_ATTR =
"iplanet-am-auth-ldap-connection-pool-size";
private final static String CONNECTION_POOL_DEFAULT_SIZE_ATTR =
"iplanet-am-auth-ldap-connection-pool-default-size";
private static int minDefaultPoolSize = MIN_CONNECTION_POOL_SIZE;
private static int maxDefaultPoolSize = MAX_CONNECTION_POOL_SIZE;
// contains host:port:min:max
private boolean isDynamicUserEnabled;
static {
try {
// Gets the Admin SSOToken.
// This API figures out admin DN and password and constructs
// the SSOToken.
"iPlanetAMAuthService", dUserToken);
if (index != -1) {
try {
} catch (NumberFormatException ex) {
}
try {
} catch (NumberFormatException ex) {
}
if (maxDefaultPoolSize < minDefaultPoolSize) {
" than min size");
}
} else {
}
}
}
/**
* Constructor initializing the basic parameters.
*
* @param configName Unique identifier for this auth module.
* @param primaryServers List of primary servers.
* @param secondaryServers List of secondary servers.
* @param ldapSSL <code>true</code> if it is SSL.
* @param bundle ResourceBundle to be used for getting localized messages.
* @param baseDN Directory Base DN.
* @param debug Debug object.
* @throws LDAPUtilException If the provided search base was invalid.
*/
this.primaryServers = primaryServers;
this.secondaryServers = secondaryServers;
}
}
try {
synchronized(connectionPools) {
if (debug.messageEnabled()) {
}
// Since connection pool for search and authentication
// are different, each gets half the configured size
}
// host:port:min:max
break;
}
}
}
try {
}
} catch (NumberFormatException ex) {
}
}
}
if (debug.messageEnabled()) {
}
if (ldapSSL) {
if (trustAll) {
}
}
final ConnectionFactory connFactory;
if (secondaryServers.isEmpty()) {
} else {
}
if (shutdownMan.acquireValidLock()) {
try {
public void shutdown() {
connFactory.close();
}
});
} finally {
}
}
}
}
}
} catch (GeneralSecurityException gse) {
throw new LDAPUtilException(gse);
}
return connPool;
}
/**
* Authenticates to the LDAP server using user input.
*
* @param user
* @param password
* @exception LDAPUtilException
*/
throws LDAPUtilException {
// password of zero length should be allowed.
throw new LDAPUtilException("PwdInvalid",
}
//retry just once if connection was closing
boolean shouldRetry = false;
do {
try {
return;
}
authenticate();
shouldRetry = false;
} catch (LDAPUtilException e) {
// cases for err=53
// - disconnect in progress
// - backend unavailable (read-only, etc)
// - server locked down
// - reject unauthenticated requests
// - low disk space (updates only)
// - bind with no password (binds only)
// retrying in case "disconnect in progress"
// there should be arg to err 53 from LDAPAuthUtils
// if the flag is already on, then we've already retried.
// not retrying more than once
if (!shouldRetry) {
debug.error("Retying user authentication due to err("+ResultCode.UNWILLING_TO_PERFORM+") '"+errMsg[0]+"'");
// datastore was closing recycled connection. retry.
shouldRetry = true;
} else {
shouldRetry = false;
throw e;
}
} else {
// generic failure. do not retry
throw e;
}
}
} while (shouldRetry);
}
/**
* Returns connection from pool. Re-authenticate if necessary
*
* @return connection that is available to use
*/
}
return cPool.getConnection();
}
/**
* Get connection from pool. Re-authenticate if necessary
* @return connection that is available to use
*/
}
return acPool.getConnection();
}
/**
* Updates to new password by using the parameters passed by the user.
*
* @param oldPwd Current password entered.
* @param password New password entered.
* @param confirmPassword Confirm password.
* @throws LDAPUtilException
*/
public void changePassword(
) throws LDAPUtilException {
return;
}
return;
}
return;
}
try {
if (beheraEnabled) {
}
if (!isAd) {
modConn = getConnection();
} else {
}
// Were there any password policy controls returned?
if (debug.messageEnabled()) {
}
} else {
}
} catch (ErrorResultException ere) {
} else {
if (isAd) {
} else {
}
}
if (debug.messageEnabled()) {
}
return;
// Were there any password policy controls returned?
} else {
}
if (r != null) {
// Were there any password policy controls returned?
}
}
} else {
}
if (debug.warningEnabled()) {
}
} finally {
}
}
}
private String buildUserFilter() {
} else {
}
}
}
}
/**
* Searches and returns user for a specified attribute using parameters
*
* @throws LDAPUtilException
*/
public void searchForUser()
throws LDAPUtilException {
// make some special case where searchScope == BASE
// construct the userDN without searching directory
// assume that there is only one user attribute
if (debug.messageEnabled()) {
"userDN =" + userDN);
}
if (!isDynamicUserEnabled &&
return;
} else if (isDynamicUserEnabled &&
return;
}
} else {
if (debug.messageEnabled()) {
"setting scope=1");
}
}
}
} else {
} else {
}
}
try {
if (debug.messageEnabled()) {
+ "\nscope = " + searchScope);
}
// Search
int userAttrSize=0;
userAttrSize = 2;
} else {
}
}
}
if (debug.messageEnabled()) {
}
int userMatches = 0;
boolean userNamingValueSet=false;
try {
conn = getAdminConnection();
userMatches++;
userNamingValueSet = true;
}
}
}
}
}
}
} else {
//read and ignore references
}
}
} finally {
}
}
userNamingValue == null)) {
if (debug.messageEnabled()) {
}
return;
} else {
if (debug.messageEnabled()) {
"Cannot find entries for " + searchFilter);
}
return;
} else {
}
}
if (userMatches > 1) {
// multiple user matches found
"searchForUser : Multiple matches found for user '" + userId +
"to make sure unique match returned. Contact your " +
"administrator to fix the problem");
throw new LDAPUtilException("multipleUserMatchFound",
}
} catch (ErrorResultIOException erio) {
if (debug.warningEnabled()) {
}
if (debug.warningEnabled()) {
}
return;
}
throw new LDAPUtilException(erio);
} catch (SearchResultReferenceIOException srrio) {
throw new LDAPUtilException(srrio);
} catch (ErrorResultException ere) {
if (debug.warningEnabled()) {
}
if (debug.warningEnabled()) {
}
if (debug.warningEnabled()) {
}
throw new LDAPUtilException("FConnect",
if (debug.warningEnabled()) {
}
throw new LDAPUtilException("FConnect",
throw new LDAPUtilException("noUserMatchFound",
} else {
if (debug.warningEnabled()) {
}
}
}
}
/**
* Connect to LDAP server using parameters specified in
* checks for the password controls and sets to the appropriate states
*/
private void authenticate()
throws LDAPUtilException {
try {
try {
if (beheraEnabled) {
}
conn = getConnection();
} finally {
}
}
// Were there any password policy controls returned?
if (debug.messageEnabled()) {
}
} else {
}
} catch(ErrorResultException ere) {
if (!isAd) {
//there is a warning about the grace logins, so in
//this case the credential was actually wrong
throw new LDAPUtilException("CredInvalid",
} else {
if(debug.messageEnabled()) {
}
}
if (debug.messageEnabled()) {
}
} else {
if (debug.messageEnabled()) {
}
throw new LDAPUtilException("CredInvalid",
}
} else {
} else {
if (debug.messageEnabled()) {
}
throw new LDAPUtilException("CredInvalid",
}
}
if (debug.messageEnabled()) {
}
throw new LDAPUtilException("UsrNotExist",
if (debug.messageEnabled()) {
}
if (debug.messageEnabled()) {
}
// cases for err=53
// - disconnect in progress
// - backend unavailable (read-only, etc)
// - server locked down
// - reject unauthenticated requests
// - low disk space (updates only)
// - bind with no password (binds only)
if (debug.messageEnabled()) {
}
if (debug.messageEnabled()) {
}
} else {
if (debug.messageEnabled()) {
}
}
}
}
return Collections.EMPTY_LIST;
}
Control c;
try {
if (c != null) {
}
} catch (DecodeException de) {
if (debug.warningEnabled()) {
}
}
try {
if (c != null) {
}
} catch (DecodeException de) {
if (debug.warningEnabled()) {
}
}
try {
if (c != null) {
}
} catch (DecodeException de) {
if (debug.warningEnabled()) {
}
}
return controls;
}
switch (result.getPasswordPolicyErrorType()) {
case ACCOUNT_LOCKED:
if (debug.messageEnabled()) {
}
break;
case CHANGE_AFTER_RESET:
if (debug.messageEnabled()) {
}
break;
if (debug.messageEnabled()) {
}
break;
case MUST_SUPPLY_OLD_PASSWORD:
if (debug.messageEnabled()) {
}
break;
case PASSWORD_EXPIRED:
if (debug.messageEnabled()) {
}
break;
case PASSWORD_IN_HISTORY:
if (debug.messageEnabled()) {
}
break;
case PASSWORD_MOD_NOT_ALLOWED:
if (debug.messageEnabled()) {
}
break;
case PASSWORD_TOO_SHORT:
if (debug.messageEnabled()) {
}
break;
case PASSWORD_TOO_YOUNG:
if (debug.messageEnabled()) {
}
break;
}
}
switch (result.getPasswordPolicyWarningType()) {
case GRACE_LOGINS_REMAINING:
if (debug.messageEnabled()) {
}
if (graceLogins != 0) {
} else {
//the password reset would need one more bind, so fail the auth
}
break;
case TIME_BEFORE_EXPIRATION:
if (debug.messageEnabled()) {
}
break;
}
}
}
/**
* checks for an LDAP v3 server whether the control has returned
* if a password has expired or password is expiring and password
* policy is enabled on the server.
*
* @return The PasswordPolicyResult or null if there were no controls
*/
if (control instanceof PasswordExpiredResponseControl) {
} else {
}
}
if (control instanceof PasswordPolicyResponseControl) {
if (policyErrorType != null) {
switch (policyErrorType) {
case ACCOUNT_LOCKED:
} else {
}
break;
case CHANGE_AFTER_RESET:
} else {
}
break;
} else {
}
break;
case MUST_SUPPLY_OLD_PASSWORD:
} else {
}
break;
case PASSWORD_EXPIRED:
} else {
}
break;
case PASSWORD_IN_HISTORY:
} else {
}
break;
case PASSWORD_MOD_NOT_ALLOWED:
} else {
}
break;
case PASSWORD_TOO_SHORT:
} else {
}
break;
case PASSWORD_TOO_YOUNG:
} else {
}
break;
}
}
if (policyWarningType != null) {
switch (policyWarningType) {
case GRACE_LOGINS_REMAINING:
} else {
}
break;
case TIME_BEFORE_EXPIRATION:
} else {
}
break;
}
}
}
if (control instanceof PasswordExpiringResponseControl) {
} else {
}
} else {
} else {
}
}
}
}
}
return result;
}
/**
* Given a specific AD diagnostic message, creates a valid PasswordPolicyResult
*
* @param diagMessage The message from AD describing the status of the account
* @return The correct PasswordPolicyResult or null if not matched
*/
} else if (diagMessage.contains(AD_ACCOUNT_DISABLED) || diagMessage.contains(S4_ACCOUNT_DISABLED)) {
} else {
return null;
}
}
// LDAP parameters are set here .......
/**
* TODO-JAVADOC
*/
if (returnUserDN) {
return userDN;
}
else {
return userNamingValue;
}
}
/**
* TODO-JAVADOC
*/
return uid;
} else {
return name;
}
}
/**
* TODO-JAVADOC
*/
}
userNamingAttr = s;
}
/**
* TODO-JAVADOC
*/
}
}
/**
* TODO-JAVADOC
*/
}
/**
* TODO-JAVADOC
*/
}
/**
* Sets the DN to authenticate as; null or empty for anonymous.
*
* @param authdn the DN to authenticate as
*/
}
/**
* Sets the password for the DN to authenticate as.
*
* @param authpassword the password to use in authentication.
*/
public void setAuthPassword(char[] authpassword) {
}
/**
* Sets the search scope using an integer.
*
* @param scope Search scope (one of <code>SearchScope.BASE_OBJECT</code>,
* <code>SearchScope.SUBORDINATES</code>,
* <code>SearchScope.SINGLE_LEVEL</code>,
* <code>SearchScope.WHOLE_SUBTREE</code>).
*/
searchScope = scope;
}
/**
* Sets if the behera password policy scheme should be used
*
* @param beheraEnabled true if behera is supported
*/
public void setBeheraEnabled(boolean beheraEnabled) {
this.beheraEnabled = beheraEnabled;
}
/**
* Sets the heartbeat interval.
*
* @param heartBeatInterval The heartbeat interval.
*/
public void setHeartBeatInterval(int heartBeatInterval) {
this.heartBeatInterval = heartBeatInterval;
}
/**
* Sets the heartbeat timeunit.
*
* @param heartBeatTimeUnit The timeunit for the heartbeat interval.
*/
this.heartBeatTimeUnit = heartBeatTimeUnit;
}
/**
* Sets the ldap operation timeout.
*
* @param timeout The operation timeout in seconds.
*/
public void setOperationTimeout(int timeout) {
this.operationsTimeout = timeout;
}
/**
* Sets if the directory is Active Directory
*
* @param isAd true if the module is AD
*/
}
/**
* Enabled trust all server certificates
*
* @param trustAll true if we should trust all certs
*/
public void setTrustAll(boolean trustAll) {
}
/**
* Returns the latest screen state.
*
* @return The latest screen state.
*/
public ModuleState getState() {
return screenState;
}
/**
* Sets a screen state for retrieval by a client.
*
* @param code Screen state.
*/
screenState = code;
}
private void setExpTime(int sec) {
expiryTime = null;
} else {
expTime.append(minutes).append(SPACE).append(bundle.getString("minutes")).append(COLON).append(SPACE);
}
}
/**
* Sets a screen state for retrieval by a client.
*
* @return Return the number of seconds until expiration
*/
public String getExpTime() {
return expiryTime;
}
private void setGraceLogins(int graceLogins) {
this.graceLogins = graceLogins;
}
public int getGraceLogins() {
return graceLogins;
}
/**
* TODO-JAVADOC
*/
public void setReturnUserDN(String s) {
if (s.equalsIgnoreCase("true")) {
returnUserDN = true;
} else {
returnUserDN = false;
}
}
/**
* Sets attributes names to be use in the search for the
* user prior to authenticating with the bind. These attributes
* and their values will be set in the <code>userAttributeValues</code>
* Map which may be retrieved via <code>getUserAttributeValues.</code>
*
* @param attributeNames Set of attributes to be retrieved during
* user search.
*/
}
/**
* Returns the attributes and their values obtained from the user
* search during authentication.
*
* @return Map of attribute name to a set of values.
*/
return userAttributeValues;
}
/**
* Sets the value of the dynamic profile creation configured in
* Authentication service.
*
* @param isEnable
*/
public void setDynamicProfileCreationEnabled(boolean isEnable) {
}
/**
* Sets the return attributes for ldap search.
*
* @param attrs Array containing attributes.
*/
}
class PasswordPolicyResult {
private PasswordPolicyErrorType errorResultType;
private int value;
public PasswordPolicyResult() {
// do nothing
}
this.errorResultType = errorResultType;
}
this.warningResultType = warningResultType;
}
this.warningResultType = warningResultType;
}
this.errorResultType = errorResultType;
this.warningResultType = warningResultType;
}
return errorResultType;
}
return warningResultType;
}
this.errorResultType = errorResultType;
}
this.warningResultType = warningResultType;
}
this.warningResultType = warningResultType;
}
public int getValue() {
return value;
}
}
}