001: package org.esupportail.cas.server.handlers.ldap;
002:
003: import java.util.Iterator;
004: import java.util.LinkedList;
005:
006: import javax.naming.NamingEnumeration;
007: import javax.naming.NamingException;
008: import javax.naming.directory.DirContext;
009: import javax.naming.directory.SearchControls;
010: import javax.naming.directory.SearchResult;
011:
012: import org.dom4j.Element;
013: import org.esupportail.cas.server.util.RedundantHandler;
014:
015: /**
016: * <p>This class implements an LDAP server class.</p>
017: * <p>It can authenticate users by:</p>
018: * <ol>
019: * <li>searching into the LDAP directory to guess the user's
020: * DN thanks to its username;</li>
021: * <li>binding to the same LDAP directory with the DN found
022: * previously and the password provided by the user.</li>
023: * </ol>
024: * <p>It is used by BindLdapHandler.</p>
025: *
026: * @author Pascal Aubry <pascal.aubry at univ-rennes1.fr>
027: * @author Jean-Baptiste Daniel <danielj at sourceforge.net>
028: */
029: public final class BindLdapServer extends LdapServer {
030:
031: /**
032: * Constructor.
033: *
034: * @param handlerDebug debugging mode of the handler
035: * @param handler the handler the server will be used by
036: * @param serverElement the XML element that declares the server
037: * @throws Exception Exception
038: */
039: public BindLdapServer(final Boolean handlerDebug,
040: final RedundantHandler handler, final Element serverElement)
041: throws Exception {
042: super (handlerDebug, handler, serverElement);
043: traceBegin();
044: traceEnd();
045: }
046:
047: /**
048: * Try to authenticate a user (by searching and then binding to
049: * the LDAP directory).
050: *
051: * @param username the user's name
052: * @param password the user's password
053: *
054: * @return Server.AUTHENTICATE_SUCCESS, Server.AUTHENTICATE_NOAUTH
055: * or Server.AUTHENTICATE_FAILURE.
056: */
057: public int authenticate(final String username, final String password) {
058: traceBegin();
059:
060: // retrieve the handler we are working for
061: BindLdapHandler handler = (BindLdapHandler) getHandler();
062:
063: // connect as a privileged user
064: DirContext searchContext = connect(handler.getBindDn(), handler
065: .getBindPassword());
066: if (getConnectError() != CONNECT_SUCCESS) {
067: trace("Could not bind as a privileged user.");
068: if (searchContext != null) {
069: try {
070: trace("Closing LDAP connection...");
071: searchContext.close();
072: } catch (NamingException e) {
073: trace("Could not close connection.");
074: }
075: }
076: traceEnd("AUTHENTICATE_FAILURE");
077: return AUTHENTICATE_FAILURE;
078: }
079:
080: // Initialize search constraints parameters
081:
082: // 1. search scope to OBJECT_SCOPE (0), ONELEVEL_SCOPE (1), or
083: // SUBTREE_SCOPE (2).
084: String scope = handler.getScope();
085: int scopeValue;
086: if (scope.equals("base")) {
087: scopeValue = 0;
088: } else if (scope.equals("one")) {
089: scopeValue = 1;
090: } else {
091: scopeValue = 2;
092: }
093:
094: // Attributes to return, null -> all; "" -> nothing
095: final String[] returnedAttributes = { "cn" };
096:
097: // create a new searchControl object with the parameters we have set
098: trace("Creating search constraints...");
099: SearchControls constraints = new SearchControls(scopeValue,
100: // Maximum number to return, 0 -> no limit
101: 1000,
102: // Number of ms to wait before return, 0 -> infinite
103: 1000,
104: // attributes to return
105: returnedAttributes,
106: // return the object bound to the name
107: false,
108: // deference the link during search
109: false);
110:
111: // search in the LDAP directory
112: constraints.setSearchScope(SearchControls.SUBTREE_SCOPE);
113: try {
114: trace("Searching in the LDAP directory...");
115: NamingEnumeration results = searchContext.search(handler
116: .getSearchBase(), replaceTokens(
117: handler.getFilter(), username), constraints);
118: // for each result, store the dn in an array
119: LinkedList dnList = new LinkedList();
120: while (results != null && results.hasMore()) {
121: // get the resulting DN from the results
122: SearchResult searchResult = (SearchResult) results
123: .next();
124: dnList.add(searchResult.getName() + ','
125: + handler.getSearchBase());
126: }
127: trace("Closing LDAP connection...");
128: searchContext.close();
129: searchContext = null;
130:
131: // count the number of results
132: if (dnList.size() == 0) {
133: trace("Username not found.");
134: } else {
135: if (!handler.areMultipleAccountsEnabled()
136: && (dnList.size() > 1)) {
137: trace("Multiple accounts are not allowed (use <enable_multiple_accounts>).");
138: } else {
139: for (Iterator i = dnList.iterator(); i.hasNext();) {
140: String dn = (String) i.next();
141:
142: // try to bind to the LDAP directory
143: trace("try to bind as DN '" + dn + "'...");
144: connectAndClose(dn, password);
145:
146: switch (getConnectError()) {
147: case CONNECT_SUCCESS:
148: trace("Bind succeeded.");
149: traceEnd("AUTHENTICATE_SUCCESS");
150: return AUTHENTICATE_SUCCESS;
151: case CONNECT_NOAUTH:
152: // could not connect, nothing to be done
153: break;
154: default:
155: trace("Bind failed.");
156: traceEnd("AUTHENTICATE_FAILURE");
157: return AUTHENTICATE_FAILURE;
158: }
159: }
160: }
161: }
162: } catch (Exception e) {
163: trace("Failure (" + e.getClass().getName() + "): "
164: + e.getMessage());
165: }
166:
167: if (searchContext != null) {
168: try {
169: searchContext.close();
170: } catch (NamingException e) {
171: trace("Could not close connection.");
172: }
173: }
174:
175: traceEnd("AUTHENTICATE_NOAUTH");
176: return AUTHENTICATE_NOAUTH;
177: }
178:
179: }
|