package org.esupportail.cas.server.handlers.ldap;
import java.util.Iterator;
import java.util.LinkedList;
import javax.naming.NamingEnumeration;
import javax.naming.NamingException;
import javax.naming.directory.DirContext;
import javax.naming.directory.SearchControls;
import javax.naming.directory.SearchResult;
import org.dom4j.Element;
import org.esupportail.cas.server.util.RedundantHandler;
/**
*
This class implements an LDAP server class.
* It can authenticate users by:
*
* - searching into the LDAP directory to guess the user's
* DN thanks to its username;
* - binding to the same LDAP directory with the DN found
* previously and the password provided by the user.
*
* It is used by BindLdapHandler.
*
* @author Pascal Aubry
* @author Jean-Baptiste Daniel
*/
public final class BindLdapServer extends LdapServer {
/**
* Constructor.
*
* @param handlerDebug debugging mode of the handler
* @param handler the handler the server will be used by
* @param serverElement the XML element that declares the server
* @throws Exception Exception
*/
public BindLdapServer(
final Boolean handlerDebug,
final RedundantHandler handler,
final Element serverElement) throws Exception {
super(handlerDebug, handler, serverElement);
traceBegin();
traceEnd();
}
/**
* Try to authenticate a user (by searching and then binding to
* the LDAP directory).
*
* @param username the user's name
* @param password the user's password
*
* @return Server.AUTHENTICATE_SUCCESS, Server.AUTHENTICATE_NOAUTH
* or Server.AUTHENTICATE_FAILURE.
*/
public int authenticate(final String username,
final String password) {
traceBegin();
// retrieve the handler we are working for
BindLdapHandler handler = (BindLdapHandler) getHandler();
// connect as a privileged user
DirContext searchContext = connect(handler.getBindDn(), handler.getBindPassword());
if (getConnectError() != CONNECT_SUCCESS) {
trace("Could not bind as a privileged user.");
if (searchContext != null) {
try {
trace("Closing LDAP connection...");
searchContext.close();
} catch (NamingException e) {
trace("Could not close connection.");
}
}
traceEnd("AUTHENTICATE_FAILURE");
return AUTHENTICATE_FAILURE;
}
// Initialize search constraints parameters
// 1. search scope to OBJECT_SCOPE (0), ONELEVEL_SCOPE (1), or
// SUBTREE_SCOPE (2).
String scope = handler.getScope();
int scopeValue;
if (scope.equals("base")) {
scopeValue = 0;
} else if (scope.equals("one")) {
scopeValue = 1;
} else {
scopeValue = 2;
}
// Attributes to return, null -> all; "" -> nothing
final String[] returnedAttributes = {
"dn"
};
// create a new searchControl object with the parameters we have set
trace("Creating search constraints...");
SearchControls constraints = new SearchControls(
scopeValue,
// Maximum number to return, 0 -> no limit
1000,
// Number of ms to wait before return, 0 -> infinite
1000,
// attributes to return
returnedAttributes,
// return the object bound to the name
false,
// deference the link during search
false);
// search in the LDAP directory
constraints.setSearchScope(SearchControls.SUBTREE_SCOPE);
try {
trace("Searching in the LDAP directory...");
NamingEnumeration results = searchContext.search(handler.getSearchBase(),
replaceTokens(handler.getFilter(), username),
constraints);
// for each result, store the dn in an array
LinkedList dnList = new LinkedList();
try {
while (results != null && results.hasMore()) {
// get the resulting DN from the results
SearchResult searchResult = (SearchResult) results.next();
String name= searchResult.getName();
String dnName= name + ',' + handler.getSearchBase();
dnList.add( dnName );
}
} catch(javax.naming.PartialResultException pre) {
trace("Warning: (" + pre.getClass().getName() + "): " + pre.getMessage());
}
trace("Closing LDAP connection...");
searchContext.close();
searchContext = null;
// count the number of results
if (dnList.size() == 0) {
trace("Username not found.");
} else {
if (!handler.areMultipleAccountsEnabled() && (dnList.size() > 1)) {
trace("Multiple accounts are not allowed (use ).");
} else {
for (Iterator i = dnList.iterator(); i.hasNext();) {
String dn = (String) i.next();
// try to bind to the LDAP directory
trace("try to bind as DN '" + dn + "'...");
connectAndClose(dn, password);
switch (getConnectError()) {
case CONNECT_SUCCESS:
trace("Bind succeeded.");
traceEnd("AUTHENTICATE_SUCCESS");
return AUTHENTICATE_SUCCESS;
case CONNECT_NOAUTH:
// could not connect, nothing to be done
break;
default:
trace("Bind failed.");
traceEnd("AUTHENTICATE_FAILURE");
return AUTHENTICATE_FAILURE;
}
}
}
}
} catch (Exception e) {
trace("Failure (" + e.getClass().getName() + "): " + e.getMessage());
}
if (searchContext != null) {
try {
searchContext.close();
} catch (NamingException e) {
trace("Could not close connection.");
}
}
traceEnd("AUTHENTICATE_NOAUTH");
return AUTHENTICATE_NOAUTH;
}
}