001: /**********************************************************************************
002: * $URL: https://source.sakaiproject.org/svn/providers/tags/sakai_2-4-1/openldap/src/java/es/udl/asic/user/OpenLdapDirectoryProvider.java $
003: * $Id: OpenLdapDirectoryProvider.java 9187 2006-05-09 19:48:15Z ggolden@umich.edu $
004: ***********************************************************************************
005: *
006: * Copyright (c) 2003, 2004, 2005, 2006 The Sakai Foundation.
007: *
008: * Licensed under the Educational Community License, Version 1.0 (the "License");
009: * you may not use this file except in compliance with the License.
010: * You may obtain a copy of the License at
011: *
012: * http://www.opensource.org/licenses/ecl1.php
013: *
014: * Unless required by applicable law or agreed to in writing, software
015: * distributed under the License is distributed on an "AS IS" BASIS,
016: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
017: * See the License for the specific language governing permissions and
018: * limitations under the License.
019: *
020: **********************************************************************************/package es.udl.asic.user;
021:
022: import java.util.Collection;
023: import java.util.Hashtable;
024: import java.util.Iterator;
025:
026: import javax.naming.AuthenticationException;
027: import javax.naming.Context;
028: import javax.naming.NamingEnumeration;
029: import javax.naming.NamingException;
030: import javax.naming.directory.Attributes;
031: import javax.naming.directory.DirContext;
032: import javax.naming.directory.InitialDirContext;
033: import javax.naming.directory.SearchControls;
034: import javax.naming.directory.SearchResult;
035:
036: import org.apache.commons.logging.Log;
037: import org.apache.commons.logging.LogFactory;
038: import org.sakaiproject.user.api.UserDirectoryProvider;
039: import org.sakaiproject.user.api.UserEdit;
040:
041: /**
042: * <p>
043: * An implementation of a Sakai UserDirectoryProvider that authenticates/retrieves users from an OpenLDAP directory.
044: * </p>
045: *
046: * @author ASIC - Udl
047: */
048: public class OpenLdapDirectoryProvider implements UserDirectoryProvider {
049: /** Our log (commons). */
050: private static Log M_log = LogFactory
051: .getLog(OpenLdapDirectoryProvider.class);
052:
053: private String ldapHost = ""; // address of ldap server
054:
055: private int ldapPort = 389; // port to connect to ldap server on
056:
057: private String basePath = "";
058:
059: private Hashtable env = new Hashtable();
060:
061: public void init() {
062: try {
063: M_log.info("init()");
064: } catch (Throwable t) {
065: M_log.warn("init(): ", t);
066: }
067:
068: env.put(Context.INITIAL_CONTEXT_FACTORY,
069: "com.sun.jndi.ldap.LdapCtxFactory");
070: env.put(Context.PROVIDER_URL, getLdapHost() + ":"
071: + getLdapPort());
072: env.put(Context.SECURITY_AUTHENTICATION, "simple");
073: env.put(Context.SECURITY_CREDENTIALS, "secret");
074: }
075:
076: public void destroy() {
077: M_log.info("destroy()");
078: }
079:
080: public boolean authenticateUser(String userLogin, UserEdit edit,
081: String password) {
082: Hashtable env = new Hashtable();
083: InitialDirContext ctx;
084:
085: String INIT_CTX = "com.sun.jndi.ldap.LdapCtxFactory";
086: String MY_HOST = getLdapHost() + ":" + getLdapPort();
087: String cn;
088: boolean returnVal = false;
089:
090: if (!password.equals("")) {
091:
092: env.put(Context.INITIAL_CONTEXT_FACTORY, INIT_CTX);
093: env.put(Context.PROVIDER_URL, MY_HOST);
094: env.put(Context.SECURITY_AUTHENTICATION, "simple");
095: env.put(Context.SECURITY_CREDENTIALS, "secret");
096:
097: String[] returnAttribute = { "ou" };
098: SearchControls srchControls = new SearchControls();
099: srchControls.setReturningAttributes(returnAttribute);
100: srchControls.setSearchScope(SearchControls.SUBTREE_SCOPE);
101:
102: String searchFilter = "(&(objectclass=person)(uid="
103: + userLogin + "))";
104:
105: try {
106: ctx = new InitialDirContext(env);
107: NamingEnumeration answer = ctx.search(getBasePath(),
108: searchFilter, srchControls);
109: String trobat = "false";
110:
111: while (answer.hasMore() && trobat.equals("false")) {
112:
113: SearchResult sr = (SearchResult) answer.next();
114: String dn = sr.getName().toString() + ","
115: + getBasePath();
116:
117: // Second binding
118: Hashtable authEnv = new Hashtable();
119: try {
120: authEnv.put(Context.INITIAL_CONTEXT_FACTORY,
121: INIT_CTX);
122: authEnv.put(Context.PROVIDER_URL, MY_HOST);
123: authEnv.put(Context.SECURITY_AUTHENTICATION,
124: "simple");
125: authEnv.put(Context.SECURITY_PRINCIPAL, sr
126: .getName()
127: + "," + getBasePath());
128: authEnv.put(Context.SECURITY_CREDENTIALS,
129: password);
130: try {
131: DirContext authContext = new InitialDirContext(
132: authEnv);
133: returnVal = true;
134: trobat = "true";
135: authContext.close();
136: } catch (AuthenticationException ae) {
137: M_log.info("Access forbidden");
138: }
139:
140: } catch (NamingException namEx) {
141: M_log.info("User doesn't exist");
142: returnVal = false;
143: namEx.printStackTrace();
144: }
145: }
146: if (trobat.equals("false"))
147: returnVal = false;
148:
149: } catch (NamingException namEx) {
150: namEx.printStackTrace();
151: returnVal = false;
152: }
153: }
154: return returnVal;
155: }
156:
157: public void destroyAuthentication() {
158: }
159:
160: public boolean findUserByEmail(UserEdit edit, String email) {
161:
162: env.put(Context.SECURITY_PRINCIPAL, "");
163: env.put(Context.SECURITY_CREDENTIALS, "");
164: String filter = "(&(objectclass=person)(mail=" + email + "))";
165: return getUserInf(edit, filter);
166: }
167:
168: public boolean getUser(UserEdit edit) {
169:
170: if (!userExists(edit.getEid()))
171: return false;
172:
173: env.put(Context.SECURITY_PRINCIPAL, "");
174: env.put(Context.SECURITY_CREDENTIALS, "");
175: String filter = "(&(objectclass=person)(uid=" + edit.getEid()
176: + "))";
177: return getUserInf(edit, filter);
178: }
179:
180: /**
181: * Access a collection of UserEdit objects; if the user is found, update the information, otherwise remove the UserEdit object from the collection.
182: *
183: * @param users
184: * The UserEdit objects (with id set) to fill in or remove.
185: */
186: public void getUsers(Collection users) {
187: for (Iterator i = users.iterator(); i.hasNext();) {
188: UserEdit user = (UserEdit) i.next();
189: if (!getUser(user)) {
190: i.remove();
191: }
192: }
193: }
194:
195: public boolean updateUserAfterAuthentication() {
196: return false;
197: }
198:
199: public boolean userExists(String id) {
200: env.put(Context.SECURITY_AUTHENTICATION, "simple");
201: env.put(Context.SECURITY_CREDENTIALS, "secret");
202:
203: try {
204: DirContext ctx = new InitialDirContext(env);
205:
206: /*
207: * Setup subtree scope to tell LDAP to recursively descend directory structure during searches.
208: */
209: SearchControls searchControls = new SearchControls();
210: searchControls.setSearchScope(SearchControls.SUBTREE_SCOPE);
211:
212: /*
213: * Setup the directory entry attributes we want to search for. In this case it is the user's ID.
214: */
215:
216: String filter = "(&(objectclass=person)(uid=" + id + "))";
217:
218: /* Execute the search, starting at the directory level of Users */
219:
220: NamingEnumeration hits = ctx.search(getBasePath(), filter,
221: searchControls);
222:
223: /* All we need to know is if there were any hits at all. */
224:
225: if (hits.hasMore()) {
226: hits.close();
227: ctx.close();
228: return true;
229: } else {
230: hits.close();
231: ctx.close();
232: return false;
233: }
234: } catch (Exception e) {
235: e.printStackTrace();
236: return false;
237: }
238: }
239:
240: private boolean getUserInf(UserEdit edit, String filter) {
241:
242: String id = null;
243: String firstName = null;
244: String lastName = null;
245: String employeenumber = null;
246: String email = null;
247: try {
248: DirContext ctx = new InitialDirContext(env);
249:
250: // Setup subtree scope to tell LDAP to recursively descend directory structure
251: // during searches.
252: SearchControls searchControls = new SearchControls();
253: searchControls.setSearchScope(SearchControls.SUBTREE_SCOPE);
254:
255: // We want the user's id, first name and last name ...
256: searchControls.setReturningAttributes(new String[] { "uid",
257: "givenName", "sn" });
258:
259: // Execute the search, starting at the directory level of Users
260: NamingEnumeration results = ctx.search(getBasePath(),
261: filter, searchControls);
262:
263: while (results.hasMore()) {
264: SearchResult result = (SearchResult) results.next();
265: String dn = result.getName().toString() + ","
266: + getBasePath();
267: Attributes attrs = ctx.getAttributes(dn);
268: id = attrs.get("uid").get().toString();
269: String cn = attrs.get("cn").get().toString();
270: firstName = cn.substring(0, cn.indexOf(" "));
271: lastName = cn.substring(cn.indexOf(" "));
272: email = attrs.get("mail").get().toString();
273: }
274:
275: results.close();
276: ctx.close();
277: } catch (Exception ex) {
278: ex.printStackTrace();
279: return false;
280: }
281:
282: edit.setId(id);
283: edit.setFirstName(firstName);
284: edit.setLastName(lastName);
285: edit.setEmail(email);
286: return true;
287: }
288:
289: /**
290: * @return Returns the ldapHost.
291: */
292:
293: public String getLdapHost() {
294: return ldapHost;
295: }
296:
297: /**
298: * @param ldapHost
299: * The ldapHost to set.
300: */
301: public void setLdapHost(String ldapHost) {
302: this .ldapHost = ldapHost;
303: }
304:
305: /**
306: * @return Returns the ldapPort.
307: */
308: public int getLdapPort() {
309: return ldapPort;
310: }
311:
312: /**
313: * @param ldapPort
314: * The ldapPort to set.
315: */
316: public void setLdapPort(int ldapPort) {
317: this .ldapPort = ldapPort;
318: }
319:
320: /**
321: * @return Returns the basePath.
322: */
323: public String getBasePath() {
324: return basePath;
325: }
326:
327: /**
328: * @param basePath
329: * The basePath to set.
330: */
331: public void setBasePath(String basePath) {
332: this .basePath = basePath;
333: }
334:
335: // helper class for storing user data in the hashtable cache
336:
337: /**
338: * {@inheritDoc}
339: */
340: public boolean authenticateWithProviderFirst(String id) {
341: return false;
342: }
343:
344: /**
345: * {@inheritDoc}
346: */
347: public boolean createUserRecord(String id) {
348: return false;
349: }
350: }
|