KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > blojsom > authorization > ldap > LDAPAuthorizationProvider


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

31 package org.blojsom.authorization.ldap;
32
33 import netscape.ldap.*;
34 import netscape.ldap.factory.JSSESocketFactory;
35 import org.apache.commons.logging.Log;
36 import org.apache.commons.logging.LogFactory;
37 import org.blojsom.BlojsomException;
38 import org.blojsom.ConfigurationException;
39 import org.blojsom.authorization.AuthorizationException;
40 import org.blojsom.authorization.database.DatabaseAuthorizationProvider;
41 import org.blojsom.blog.Blog;
42 import org.blojsom.util.BlojsomUtils;
43
44 import javax.servlet.ServletConfig JavaDoc;
45 import java.util.Map JavaDoc;
46 import java.util.Enumeration JavaDoc;
47
48 /**
49  * LDAPAuthorizationProvider
50  * <p></p>
51  * This implementation authenticates a user against an LDAP server. The user
52  * name must be the same as that of their LDAP user (uid). There are two ways
53  * to configure this in terms of the accepted users. The first is where only
54  * the blog owner can edit the blog. To use this technique, delete the
55  * authorization.properties file from the user's blog directory. The lack of
56  * this file tells the authorization logic to use the blog owner as the UID for
57  * LDAP authentication. The second way provides multiple user editing of a
58  * blog. This second way utilizes the authorization.properties file's user
59  * names (it ignores passwords and other data). Incoming authorization requests
60  * have the user name checked to see if it is listed in the
61  * authorization.properties file (indicating a user who is allowed to edit this
62  * blog). If it is in the list, this username is used as the LDAP UID. This
63  * class/implementation requires LDAP protocol version 3. You must set the
64  * configuration values defined by the BlojsomConstants:
65  * BLOG_LDAP_AUTHORIZATION_SERVER_IP, BLOG_LDAP_AUTHORIZATION_DN_IP, and
66  * BLOG_LDAP_AUTHORIZATION_PORT_IP (optional).
67  * <p></p>
68  * Note, this implementation currently requires the Mozilla LDAP Java SDK. See
69  * http://www.mozilla.org/directory/.
70  *
71  * @author David Czarnecki
72  * @author Christopher Bailey
73  * @version $Id: LDAPAuthorizationProvider.java,v 1.3 2006/09/19 02:17:42 czarneckid Exp $
74  * @since blojsom 3.0
75  */

76 public class LDAPAuthorizationProvider extends DatabaseAuthorizationProvider {
77
78     private static final String JavaDoc BLOG_LDAP_AUTHORIZATION_SERVER_IP = "blog-ldap-authorization-server";
79     private static final String JavaDoc BLOG_LDAP_AUTHORIZATION_PORT_IP = "blog-ldap-authorization-port";
80     private static final String JavaDoc BLOG_LDAP_AUTHORIZATION_DN_IP = "blog-ldap-authorization-dn";
81     private static final String JavaDoc BLOG_LDAP_AUTHORIZATION_UID_IP = "blog-ldap-authorization-uid";
82     private static final String JavaDoc BLOG_LDAP_AUTHORIZATION_BINDING_USER_IP = "blog-ldap-authorization-bindinguser";
83     private static final String JavaDoc BLOG_LDAP_AUTHORIZATION_BINDING_PASSWORD_IP = "blog-ldap-authorization-bindingpassword";
84     private static final String JavaDoc BLOG_LDAP_AUTHORIZATION_USE_SSL = "blog-ldap-authorization-use-ssl";
85
86     private static final String JavaDoc UID_DEFAULT = "uid";
87
88     private Log _logger = LogFactory.getLog(LDAPAuthorizationProvider.class);
89     private String JavaDoc _ldapServer;
90     private int _ldapPort = 389;
91     private String JavaDoc _ldapDN;
92     private String JavaDoc _uidAttributeName = UID_DEFAULT;
93
94     private String JavaDoc _bindingUser = null;
95     private String JavaDoc _bindingPassword = null;
96     private ServletConfig JavaDoc _servletConfig;
97     private boolean _useSSL = false;
98
99     /**
100      * Default constructor
101      */

102     public LDAPAuthorizationProvider() {
103     }
104
105     /**
106      * Set the {@link ServletConfig} for the fetcher to grab initialization parameters
107      *
108      * @param servletConfig {@link ServletConfig}
109      */

110     public void setServletConfig(ServletConfig JavaDoc servletConfig) {
111         _servletConfig = servletConfig;
112     }
113
114     /**
115      * Initialization method for the authorization provider
116      *
117      * @throws BlojsomConfigurationException If there is an error initializing the provider
118      */

119     public void init() throws ConfigurationException {
120         super.init();
121
122         _ldapServer = _servletConfig.getInitParameter(BLOG_LDAP_AUTHORIZATION_SERVER_IP);
123         _ldapDN = _servletConfig.getInitParameter(BLOG_LDAP_AUTHORIZATION_DN_IP);
124         String JavaDoc port = _servletConfig.getInitParameter(BLOG_LDAP_AUTHORIZATION_PORT_IP);
125         if (!BlojsomUtils.checkNullOrBlank(_servletConfig.getInitParameter(BLOG_LDAP_AUTHORIZATION_UID_IP))) {
126             _uidAttributeName = _servletConfig.getInitParameter(BLOG_LDAP_AUTHORIZATION_UID_IP);
127         }
128
129         if (!BlojsomUtils.checkNullOrBlank(_servletConfig.getInitParameter(BLOG_LDAP_AUTHORIZATION_USE_SSL))) {
130             String JavaDoc bool = _servletConfig.getInitParameter(BLOG_LDAP_AUTHORIZATION_USE_SSL);
131             _useSSL = Boolean.valueOf(bool).booleanValue();
132         }
133
134         // We don't setup a credentions map here, because with LDAP, you can't
135
// obtain the user's passwords, you can only check/authenticate against
136
// the LDAP server. Instead, check each time in the authorize method.
137
if (BlojsomUtils.checkNullOrBlank(_ldapServer)) {
138             String JavaDoc msg = "No LDAP authorization server specified.";
139             if (_logger.isErrorEnabled()) {
140                 _logger.error(msg);
141             }
142
143             throw new ConfigurationException(msg);
144         }
145
146         if (BlojsomUtils.checkNullOrBlank(_ldapDN)) {
147             String JavaDoc msg = "No LDAP authorization DN specified.";
148             if (_logger.isErrorEnabled()) {
149                 _logger.error(msg);
150             }
151
152             throw new ConfigurationException(msg);
153         }
154
155         if (!BlojsomUtils.checkNullOrBlank(port)) {
156             try {
157                 _ldapPort = Integer.valueOf(port).intValue();
158                 if ((0 > _ldapPort) || (_ldapPort > 65535)) {
159                     if (_logger.isErrorEnabled()) {
160                         _logger.error("LDAP port is not in valid range [0,65535].");
161                     }
162
163                     throw new NumberFormatException JavaDoc();
164                 }
165             } catch (NumberFormatException JavaDoc nfe) {
166                 String JavaDoc msg = "Invalid LDAP port '" + port + "' specified.";
167                 if (_logger.isErrorEnabled()) {
168                     _logger.error(msg);
169                 }
170
171                 throw new ConfigurationException(msg);
172             }
173         }
174
175         _bindingUser = _servletConfig.getInitParameter(BLOG_LDAP_AUTHORIZATION_BINDING_USER_IP);
176         _bindingPassword = _servletConfig.getInitParameter(BLOG_LDAP_AUTHORIZATION_BINDING_PASSWORD_IP);
177
178         if (_logger.isDebugEnabled()) {
179             _logger.debug("LDAP Authorization Provider server: " + _ldapServer);
180             _logger.debug("LDAP Authorization Provider port: " + _ldapPort);
181             _logger.debug("LDAP Authorization Provider DN: " + _ldapDN);
182             _logger.debug("LDAP Authorization Provider UID: " + _uidAttributeName);
183             _logger.debug("LDAP Authorization Provider binding user: " + _bindingUser);
184             _logger.debug("LDAP Authorization Provider binding password: **********");
185             _logger.debug("LDAP Authorization Provider UseSSL: " + _useSSL);
186
187             _logger.debug("Initialized LDAP authorization provider");
188         }
189     }
190
191     /**
192      * Authorize a username and password for the given {@link Blog}
193      *
194      * @param blog {@link Blog}
195      * @param authorizationContext {@link Map} to be used to provide other information for authorization. This will
196      * change depending on the authorization provider. This parameter is not used in this implementation.
197      * @param username Username. In this implementation, this value must match that of the blog user's ID.
198      * @param password Password
199      * @throws BlojsomException If there is an error authorizing the username and password
200      */

201     public void authorize(Blog blog, Map JavaDoc authorizationContext, String JavaDoc username, String JavaDoc password) throws AuthorizationException {
202         String JavaDoc dn = getDN(username);
203
204         if (BlojsomUtils.checkNullOrBlank(_ldapServer) || BlojsomUtils.checkNullOrBlank(dn)) {
205             String JavaDoc msg = "Authorization failed for blog: " + blog.getBlogId() + " for username: " + username + "; " + "LDAP not properly configured";
206             if (_logger.isErrorEnabled()) {
207                 _logger.error(msg);
208             }
209
210             throw new AuthorizationException(msg);
211         }
212
213         try {
214             LDAPConnection ldapConnection;
215
216             if (_useSSL) {
217                 JSSESocketFactory ldapSocketFactory = new JSSESocketFactory();
218                 ldapConnection = new LDAPConnection(ldapSocketFactory);
219             } else {
220                 ldapConnection = new LDAPConnection();
221             }
222
223             // Connect to the directory server
224
ldapConnection.connect(_ldapServer, _ldapPort);
225
226             if (blog.getUseEncryptedPasswords().booleanValue()) {
227                 password = BlojsomUtils.digestString(password, blog.getDigestAlgorithm());
228             }
229
230             // Use simple authentication. The first argument
231
// specifies the version of the LDAP protocol used.
232
ldapConnection.authenticate(3, dn, password);
233
234             ldapConnection.disconnect();
235             if (_logger.isDebugEnabled()) {
236                 _logger.debug("Successfully authenticated user '" + username + "' via LDAP.");
237             }
238         } catch (LDAPException e) {
239             String JavaDoc reason;
240             switch (e.getLDAPResultCode()) {
241                 // The DN does not correspond to any existing entry
242
case LDAPException.NO_SUCH_OBJECT:
243                     reason = "The specified user does not exist: " + dn;
244                     break;
245                     // The password is incorrect
246
case LDAPException.INVALID_CREDENTIALS:
247                     reason = "Invalid password";
248                     break;
249                     // Some other error occurred
250
default:
251                     reason = "Failed to authenticate as " + dn + ", " + e;
252                     break;
253             }
254
255             String JavaDoc msg = "Authorization failed for blog: " + blog.getBlogId() + " for username: " + username + "; " + reason;
256
257             if (_logger.isErrorEnabled()) {
258                 _logger.error(msg);
259             }
260
261             throw new AuthorizationException(msg);
262         }
263     }
264
265     /**
266      * Get the DN for a given username
267      *
268      * @param username Username
269      * @return DN for a given username or <code>null</code> if there is an exception in lookup
270      */

271     protected String JavaDoc getDN(String JavaDoc username) {
272         try {
273             LDAPConnection ldapConnection;
274
275             if (_useSSL) {
276                 JSSESocketFactory ldapSocketFactory = new JSSESocketFactory();
277                 ldapConnection = new LDAPConnection(ldapSocketFactory);
278             } else {
279                 ldapConnection = new LDAPConnection();
280             }
281
282             // Connect to the directory server
283
ldapConnection.connect(_ldapServer, _ldapPort);
284
285             // Authenticate with the server
286
if (!BlojsomUtils.checkNullOrBlank(_bindingUser) && !BlojsomUtils.checkNullOrBlank(_bindingPassword)) {
287                 if (_logger.isDebugEnabled()) {
288                     _logger.debug("Using LDAP authentication for LDAP connection");
289                 }
290
291                 ldapConnection.authenticate(3, _bindingUser, _bindingPassword);
292             }
293
294             // Search for the dn of the user given the username (uid).
295
String JavaDoc[] attrs = {};
296             LDAPSearchResults res = ldapConnection.search(_ldapDN, LDAPv2.SCOPE_SUB, "(" + _uidAttributeName + "=" + username + ")", attrs, true);
297
298             if (!res.hasMoreElements()) {
299                 // No such user.
300
if (_logger.isDebugEnabled()) {
301                     _logger.debug("User '" + username + "' does not exist in LDAP directory.");
302                 }
303
304                 ldapConnection.disconnect();
305
306                 return null;
307             }
308
309             String JavaDoc dn = res.next().getDN();
310             ldapConnection.disconnect();
311             if (_logger.isDebugEnabled()) {
312                 _logger.debug("Successfully got user DN '" + dn + "' via LDAP.");
313             }
314
315             return dn;
316         } catch (LDAPException e) {
317             // Some exception occurred above; the search for the dn failed.
318
return null;
319         }
320     }
321
322     /**
323      * Get a specific attribute value for a given username
324      *
325      * @param username Username
326      * @param attribute Attribute
327      * @return attribute value for a given username or <code>null</code> if there is an exception in lookup
328      */

329     protected String JavaDoc getAttribute(String JavaDoc username, String JavaDoc attribute) {
330         LDAPConnection ldapConnection = null;
331         String JavaDoc value = null;
332
333         try {
334             // Connect to the server.
335
if (_useSSL) {
336                 JSSESocketFactory ldapSocketFactory = new JSSESocketFactory();
337                 ldapConnection = new LDAPConnection(ldapSocketFactory);
338             } else {
339                 ldapConnection = new LDAPConnection();
340             }
341
342             ldapConnection.connect(_ldapServer, _ldapPort);
343
344             // Authenticate with the server
345
if (!BlojsomUtils.checkNullOrBlank(_bindingUser) && !BlojsomUtils.checkNullOrBlank(_bindingPassword)) {
346                 if (_logger.isDebugEnabled()) {
347                     _logger.debug("Using LDAP authentication for LDAP connection");
348                 }
349
350                 ldapConnection.authenticate(3, _bindingUser, _bindingPassword);
351             }
352
353             // Send the search request.
354
String JavaDoc attrs[] = {attribute};
355             LDAPSearchResults res = ldapConnection.search(_ldapDN, LDAPConnection.SCOPE_SUB, "(" + _uidAttributeName + "=" + username + ")", attrs, false);
356
357             // Iterate through and print out the results.
358
while (res.hasMoreElements()) {
359                 // Get the next directory entry.
360
LDAPEntry findEntry = null;
361
362                 try {
363                     findEntry = res.next();
364                 } catch (LDAPException e) {
365                     if (_logger.isErrorEnabled()) {
366                         _logger.error("Error: " + e.toString());
367                     }
368
369                     continue;
370                 }
371
372                 // Print the DN of the entry.
373
if (_logger.isDebugEnabled()) {
374                     _logger.debug(findEntry.getDN());
375                 }
376
377                 // Get the attributes of the entry
378
LDAPAttributeSet findAttrs = findEntry.getAttributeSet();
379                 Enumeration JavaDoc enumAttrs = findAttrs.getAttributes();
380
381                 if (_logger.isDebugEnabled()) {
382                     _logger.debug("\tAttributes: ");
383                 }
384
385                 // Loop on attributes
386
while (enumAttrs.hasMoreElements()) {
387                     LDAPAttribute anAttr = (LDAPAttribute) enumAttrs.nextElement();
388                     String JavaDoc attrName = anAttr.getName();
389                     if (_logger.isDebugEnabled()) {
390                         _logger.debug("\t\t" + attrName);
391                     }
392
393                     // Loop on values for this attribute
394
Enumeration JavaDoc enumVals = anAttr.getStringValues();
395                     if (enumVals != null) {
396                         while (enumVals.hasMoreElements()) {
397                             String JavaDoc aVal = (String JavaDoc) enumVals.nextElement();
398                             value = aVal;
399
400                             if (_logger.isDebugEnabled()) {
401                                 _logger.debug("\t\t\t" + aVal);
402                             }
403                         }
404                     }
405                 }
406             }
407         } catch (LDAPException e) {
408             if (_logger.isErrorEnabled()) {
409                 _logger.error("Error: " + e.toString());
410             }
411         }
412
413         // Done, so disconnect
414
if ((ldapConnection != null) && ldapConnection.isConnected()) {
415             try {
416                 ldapConnection.disconnect();
417             } catch (LDAPException e) {
418                 if (_logger.isErrorEnabled()) {
419                     _logger.error("Error: " + e.toString());
420                 }
421             }
422         }
423
424         return value;
425     }
426
427     /**
428      * Return the LDAP server name
429      *
430      * @return LDAP server name
431      */

432     protected String JavaDoc getServer() {
433         return _ldapServer;
434     }
435
436     /**
437      * Return the LDAP server port
438      *
439      * @return LDAP server port
440      */

441     protected int getPort() {
442         return _ldapPort;
443     }
444
445     /**
446      * Return the LDAP base DN
447      *
448      * @return LDAP base DN
449      */

450     protected String JavaDoc getBaseDN() {
451         return _ldapDN;
452     }
453 }
454
Popular Tags