KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > dspace > eperson > LDAPAuthentication


1 /*
2  * LDAPAuthentication.java
3  *
4  * Version: $Revision: 1.2 $
5  *
6  * Date: $Date: 2006/03/10 21:16:38 $
7  *
8  * Copyright (c) 2002-2005, Hewlett-Packard Company and Massachusetts
9  * Institute of Technology. All rights reserved.
10  *
11  * Redistribution and use in source and binary forms, with or without
12  * modification, are permitted provided that the following conditions are
13  * met:
14  *
15  * - Redistributions of source code must retain the above copyright
16  * notice, this list of conditions and the following disclaimer.
17  *
18  * - Redistributions in binary form must reproduce the above copyright
19  * notice, this list of conditions and the following disclaimer in the
20  * documentation and/or other materials provided with the distribution.
21  *
22  * - Neither the name of the Hewlett-Packard Company nor the name of the
23  * Massachusetts Institute of Technology nor the names of their
24  * contributors may be used to endorse or promote products derived from
25  * this software without specific prior written permission.
26  *
27  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
28  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
29  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
30  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
31  * HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
32  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
33  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
34  * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
35  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
36  * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
37  * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
38  * DAMAGE.
39  */

40 package org.dspace.eperson;
41
42 import java.io.IOException JavaDoc;
43 import java.sql.SQLException JavaDoc;
44 import javax.servlet.ServletException JavaDoc;
45 import javax.servlet.http.HttpServlet JavaDoc;
46 import javax.servlet.http.HttpServletRequest JavaDoc;
47 import javax.servlet.http.HttpServletResponse JavaDoc;
48 import javax.servlet.jsp.PageContext JavaDoc;
49 import javax.servlet.jsp.jstl.fmt.LocaleSupport;
50 import java.util.ArrayList JavaDoc;
51 import java.util.Hashtable JavaDoc;
52
53 import org.apache.log4j.Logger;
54 import org.dspace.core.ConfigurationManager;
55 import org.dspace.core.Context;
56 import org.dspace.core.LogManager;
57 import org.dspace.core.ConfigurationManager;
58 import org.dspace.eperson.EPerson;
59 import org.dspace.eperson.Group;
60 import org.dspace.eperson.AuthenticationMethod;
61 import org.dspace.eperson.AuthenticationManager;
62 import org.dspace.authorize.AuthorizeException;
63
64 import javax.naming.directory.*;
65 import javax.naming.*;
66
67 /**
68  * This is UNTESTED, since I do not have LDAP servers available.
69  * It was adpated from LDAPServlet and should replace it.
70  * See the <code>AuthenticationMethod</code> interface for more details.
71  *
72  * As of August 2005 we need a volunteer to complete and test this
73  * implementation. They should add themselves to the author tag below.
74  *
75  * @author Larry Stone
76  * @version $Revision: 1.2 $
77  */

78 public class LDAPAuthentication
79     implements AuthenticationMethod {
80
81     /** log4j category */
82     private static Logger log = Logger.getLogger(LDAPAuthentication.class);
83
84     /**
85      * Let a real auth method return true if it wants.
86      */

87     public boolean canSelfRegister(Context JavaDoc context,
88                                    HttpServletRequest JavaDoc request,
89                                    String JavaDoc username)
90         throws SQLException JavaDoc
91     {
92         // XXX might also want to check that username exists in LDAP.
93

94         return ConfigurationManager.getBooleanProperty("webui.ldap.autoregister");
95     }
96
97     /**
98      * Nothing here, initialization is done when auto-registering.
99      */

100     public void initEPerson(Context JavaDoc context, HttpServletRequest JavaDoc request,
101             EPerson eperson)
102         throws SQLException JavaDoc
103     {
104         // XXX should we try to initialize netid based on email addr,
105
// XXX for eperson created by some other method??
106
}
107
108     /**
109      * Cannot change LDAP password through dspace, right?
110      */

111     public boolean allowSetPassword(Context JavaDoc context,
112                                     HttpServletRequest JavaDoc request,
113                                     String JavaDoc username)
114         throws SQLException JavaDoc
115     {
116         // XXX is this right?
117
return false;
118     }
119
120     /*
121      * This is an explicit method.
122      */

123     public boolean isImplicit()
124     {
125         return false;
126     }
127
128     /*
129      * Nothing here.
130      */

131     public int[] getSpecialGroups(Context JavaDoc context, HttpServletRequest JavaDoc request)
132     {
133         return new int[0];
134     }
135
136     /*
137      * MIT policy on certs and groups, so always short-circuit.
138      *
139      * @return One of:
140      * SUCCESS, BAD_CREDENTIALS, CERT_REQUIRED, NO_SUCH_USER, BAD_ARGS
141      */

142     public int authenticate(Context JavaDoc context,
143                             String JavaDoc netid,
144                             String JavaDoc password,
145                             String JavaDoc realm,
146                             HttpServletRequest JavaDoc request)
147         throws SQLException JavaDoc
148     {
149         log.info(LogManager.getHeader(context, "auth", "attempting trivial auth of user="+netid));
150
151         // Locate the eperson
152
EPerson eperson = null;
153         try
154         {
155             eperson = EPerson.findByNetid(context, netid.toLowerCase());
156         }
157         catch (SQLException JavaDoc e)
158         {
159         }
160         boolean loggedIn = false;
161         SpeakerToLDAP ldap = new SpeakerToLDAP(log);
162
163         // if they entered a netid that matches an eperson
164
if (eperson != null)
165         {
166             // e-mail address corresponds to active account
167
if (eperson.getRequireCertificate())
168                 return CERT_REQUIRED;
169             else if (!eperson.canLogIn())
170                 return BAD_ARGS;
171             {
172                 if (ldap.ldapAuthenticate(netid, password, context))
173                 {
174                     log.info(LogManager
175                         .getHeader(context, "authenticate", "type=ldap"));
176                     return SUCCESS;
177                 }
178                 else
179                    return BAD_CREDENTIALS;
180             }
181         }
182
183         // the user does not already exist so try and authenticate them
184
// with ldap and create an eperson for them
185
else
186         {
187             if (ldap.ldapAuthenticate(netid, password, context))
188             {
189                 // Register the new user automatically
190
log.info(LogManager.getHeader(context,
191                                 "autoregister", "netid=" + netid));
192
193                 if ((ldap.ldapEmail!=null)&&(!ldap.ldapEmail.equals("")))
194                 {
195                     try
196                     {
197                         eperson = EPerson.findByEmail(context, ldap.ldapEmail);
198                         if (eperson!=null)
199                         {
200                             log.info(LogManager.getHeader(context,
201                                     "type=ldap-login", "type=ldap_but_already_email"));
202                             context.setIgnoreAuthorization(true);
203                             eperson.setNetid(netid);
204                             eperson.update();
205                             context.commit();
206                             context.setIgnoreAuthorization(false);
207                             context.setCurrentUser(eperson);
208                             return SUCCESS;
209                         }
210                         else
211                         {
212                             if (canSelfRegister(context, request, netid))
213                             {
214                                 // TEMPORARILY turn off authorisation
215
try
216                                 {
217                                     context.setIgnoreAuthorization(true);
218                                     eperson = EPerson.create(context);
219                                     if ((ldap.ldapEmail!=null)&&(!ldap.ldapEmail.equals(""))) eperson.setEmail(ldap.ldapEmail);
220                                     else eperson.setEmail(netid);
221                                     if ((ldap.ldapGivenName!=null)&&(!ldap.ldapGivenName.equals(""))) eperson.setFirstName(ldap.ldapGivenName);
222                                     if ((ldap.ldapSurname!=null)&&(!ldap.ldapSurname.equals(""))) eperson.setLastName(ldap.ldapSurname);
223                                     if ((ldap.ldapPhone!=null)&&(!ldap.ldapPhone.equals(""))) eperson.setMetadata("phone", ldap.ldapPhone);
224                                     eperson.setNetid(netid);
225                                     eperson.setCanLogIn(true);
226                                     AuthenticationManager.initEPerson(context, request, eperson);
227                                     eperson.update();
228                                     context.commit();
229                                 }
230                                 catch (AuthorizeException e)
231                                 {
232                                     return NO_SUCH_USER;
233                                 }
234                                 finally
235                                 {
236                                     context.setIgnoreAuthorization(false);
237                                 }
238
239                                 log.info(LogManager.getHeader(context, "authenticate",
240                                             "type=ldap-login, created ePerson"));
241                                 return SUCCESS;
242                             }
243                             else
244                             {
245                                 // No auto-registration for valid certs
246
log.info(LogManager.getHeader(context,
247                                                 "failed_login", "type=ldap_but_no_record"));
248                                 return NO_SUCH_USER;
249                             }
250                         }
251                     }
252                     catch (AuthorizeException e)
253                     {
254                         eperson = null;
255                     }
256                     finally
257                     {
258                         context.setIgnoreAuthorization(false);
259                     }
260                 }
261             }
262         }
263         return BAD_ARGS;
264     }
265
266     /**
267      * Internal class to manage LDAP query and results, mainly
268      * because there are multiple values to return.
269      */

270     public class SpeakerToLDAP {
271
272         private Logger log = null;
273
274         /** ldap email result */
275         protected String JavaDoc ldapEmail = null;
276
277         /** ldap name result */
278         protected String JavaDoc ldapGivenName = null;
279         protected String JavaDoc ldapSurname = null;
280         protected String JavaDoc ldapPhone = null;
281
282         SpeakerToLDAP(Logger thelog)
283         {
284             log = thelog;
285         }
286
287         /**
288          * contact the ldap server and attempt to authenticate
289          */

290         protected boolean ldapAuthenticate(String JavaDoc netid, String JavaDoc password, Context JavaDoc context)
291         {
292             if (!password.equals(""))
293             {
294                 String JavaDoc ldap_provider_url = ConfigurationManager.getProperty("ldap.provider_url");
295                 String JavaDoc ldap_id_field = ConfigurationManager.getProperty("ldap.id_field");
296                 String JavaDoc ldap_search_context = ConfigurationManager.getProperty("ldap.search_context");
297                 String JavaDoc ldap_object_context = ConfigurationManager.getProperty("ldap.object_context");
298          
299                 // Set up environment for creating initial context
300
Hashtable JavaDoc env = new Hashtable JavaDoc(11);
301                 env.put(javax.naming.Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory");
302                 env.put(javax.naming.Context.PROVIDER_URL, ldap_provider_url);
303          
304                 // Authenticate
305
env.put(javax.naming.Context.SECURITY_AUTHENTICATION, "simple");
306                 env.put(javax.naming.Context.SECURITY_PRINCIPAL, ldap_id_field+"="+netid+","+ldap_object_context);
307                 env.put(javax.naming.Context.SECURITY_CREDENTIALS, password);
308          
309                 DirContext ctx = null;
310                 try
311                 {
312                     // Create initial context
313
ctx = new InitialDirContext(env);
314          
315                     String JavaDoc ldap_email_field = ConfigurationManager.getProperty("ldap.email_field");
316                     String JavaDoc ldap_givenname_field = ConfigurationManager.getProperty("ldap.givenname_field");
317                     String JavaDoc ldap_surname_field = ConfigurationManager.getProperty("ldap.surname_field");
318                     String JavaDoc ldap_phone_field = ConfigurationManager.getProperty("ldap.phone_field");
319          
320                     Attributes matchAttrs = new BasicAttributes(true);
321                     matchAttrs.put(new BasicAttribute(ldap_id_field, netid));
322          
323                     String JavaDoc attlist[] = {ldap_email_field, ldap_givenname_field, ldap_surname_field, ldap_phone_field};
324          
325                     // look up attributes
326
try
327                     {
328                         NamingEnumeration answer = ctx.search(ldap_search_context, matchAttrs, attlist);
329                         while(answer.hasMore()) {
330                             SearchResult sr = (SearchResult)answer.next();
331                             Attributes atts = sr.getAttributes();
332                             Attribute att;
333          
334                             if (attlist[0]!=null)
335                             {
336                                     att = atts.get(attlist[0]);
337                                     if (att != null) ldapEmail = (String JavaDoc)att.get();
338                             }
339          
340                             if (attlist[1]!=null)
341                             {
342                                     att = atts.get(attlist[1]);
343                                     if (att != null) ldapGivenName = (String JavaDoc)att.get();
344                             }
345          
346                             if (attlist[2]!=null)
347                             {
348                                     att = atts.get(attlist[2]);
349                                     if (att != null) ldapSurname = (String JavaDoc)att.get();
350                             }
351          
352                             if (attlist[3]!=null)
353                             {
354                                     att = atts.get(attlist[3]);
355                                     if (att != null) ldapPhone = (String JavaDoc)att.get();
356                             }
357                         }
358                     }
359                     catch (NamingException e)
360                     {
361                         // if the lookup fails go ahead and create a new record for them because the authentication
362
// succeeded
363
log.warn(LogManager.getHeader(context,
364                                         "ldap_attribute_lookup", "type=failed_search "+e));
365                         return true;
366                     }
367                 }
368                 catch (NamingException e)
369                 {
370                     log.warn(LogManager.getHeader(context,
371                                         "ldap_authentication", "type=failed_auth "+e));
372                     return false;
373                 }
374                 finally
375                 {
376                     // Close the context when we're done
377
try
378                     {
379                         if (ctx != null)
380                             ctx.close();
381                     }
382                     catch (NamingException e)
383                     {
384                     }
385                 }
386             }
387             else
388             {
389                 return false;
390             }
391          
392             return true;
393         }
394
395
396     }
397
398     /*
399      * Returns URL to which to redirect to obtain credentials (either password
400      * prompt or e.g. HTTPS port for client cert.); null means no redirect.
401      *
402      * @param context
403      * DSpace context, will be modified (ePerson set) upon success.
404      *
405      * @param request
406      * The HTTP request that started this operation, or null if not applicable.
407      *
408      * @param response
409      * The HTTP response from the servlet method.
410      *
411      * @return fully-qualified URL
412      */

413     public String JavaDoc loginPageURL(Context JavaDoc context,
414                             HttpServletRequest JavaDoc request,
415                             HttpServletResponse JavaDoc response)
416     {
417         return response.encodeRedirectURL(request.getContextPath() +
418                                           "/ldap-login");
419     }
420
421     /**
422      * Returns message key for title of the "login" page, to use
423      * in a menu showing the choice of multiple login methods.
424      *
425      * @param context
426      * DSpace context, will be modified (ePerson set) upon success.
427      *
428      * @return Message key to look up in i18n message catalog.
429      */

430     public String JavaDoc loginPageTitle(Context JavaDoc context)
431     {
432         return "org.dspace.eperson.LDAPAuthentication.title";
433     }
434 }
435
Popular Tags