KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > geronimo > security > realm > providers > LDAPLoginModule


1 /**
2  * Licensed to the Apache Software Foundation (ASF) under one or more
3  * contributor license agreements. See the NOTICE file distributed with
4  * this work for additional information regarding copyright ownership.
5  * The ASF licenses this file to You under the Apache License, Version 2.0
6  * (the "License"); you may not use this file except in compliance with
7  * the License. You may obtain a copy of the License at
8  *
9  * http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  */

17
18 package org.apache.geronimo.security.realm.providers;
19
20 import java.io.IOException JavaDoc;
21 import java.text.MessageFormat JavaDoc;
22 import java.util.ArrayList JavaDoc;
23 import java.util.HashSet JavaDoc;
24 import java.util.Hashtable JavaDoc;
25 import java.util.Iterator JavaDoc;
26 import java.util.List JavaDoc;
27 import java.util.Map JavaDoc;
28 import java.util.Set JavaDoc;
29
30 import javax.naming.AuthenticationException JavaDoc;
31 import javax.naming.Context JavaDoc;
32 import javax.naming.Name JavaDoc;
33 import javax.naming.NameParser JavaDoc;
34 import javax.naming.NamingEnumeration JavaDoc;
35 import javax.naming.NamingException JavaDoc;
36 import javax.naming.directory.Attribute JavaDoc;
37 import javax.naming.directory.Attributes JavaDoc;
38 import javax.naming.directory.DirContext JavaDoc;
39 import javax.naming.directory.InitialDirContext JavaDoc;
40 import javax.naming.CommunicationException JavaDoc;
41 import javax.naming.directory.SearchControls JavaDoc;
42 import javax.naming.directory.SearchResult JavaDoc;
43 import javax.security.auth.Subject JavaDoc;
44 import javax.security.auth.callback.Callback JavaDoc;
45 import javax.security.auth.callback.CallbackHandler JavaDoc;
46 import javax.security.auth.callback.NameCallback JavaDoc;
47 import javax.security.auth.callback.PasswordCallback JavaDoc;
48 import javax.security.auth.callback.UnsupportedCallbackException JavaDoc;
49 import javax.security.auth.login.LoginException JavaDoc;
50 import javax.security.auth.login.FailedLoginException JavaDoc;
51 import javax.security.auth.spi.LoginModule JavaDoc;
52
53 import org.apache.commons.logging.Log;
54 import org.apache.commons.logging.LogFactory;
55
56 import org.apache.geronimo.security.realm.providers.GeronimoGroupPrincipal;
57 import org.apache.geronimo.security.realm.providers.GeronimoUserPrincipal;
58
59
60 public class LDAPLoginModule implements LoginModule JavaDoc {
61
62     private static Log log = LogFactory.getLog(LDAPLoginModule.class);
63
64     private Subject JavaDoc subject;
65     private CallbackHandler JavaDoc handler;
66
67     private static final String JavaDoc INITIAL_CONTEXT_FACTORY = "initialContextFactory";
68     private static final String JavaDoc CONNECTION_URL = "connectionURL";
69     private static final String JavaDoc CONNECTION_USERNAME = "connectionUsername";
70     private static final String JavaDoc CONNECTION_PASSWORD = "connectionPassword";
71     private static final String JavaDoc CONNECTION_PROTOCOL = "connectionProtocol";
72     private static final String JavaDoc AUTHENTICATION = "authentication";
73     private static final String JavaDoc USER_BASE = "userBase";
74     private static final String JavaDoc USER_SEARCH_MATCHING = "userSearchMatching";
75     private static final String JavaDoc USER_SEARCH_SUBTREE = "userSearchSubtree";
76     private static final String JavaDoc ROLE_BASE = "roleBase";
77     private static final String JavaDoc ROLE_NAME = "roleName";
78     private static final String JavaDoc ROLE_SEARCH_MATCHING = "roleSearchMatching";
79     private static final String JavaDoc ROLE_SEARCH_SUBTREE = "roleSearchSubtree";
80     private static final String JavaDoc USER_ROLE_NAME = "userRoleName";
81
82     private String JavaDoc initialContextFactory;
83     private String JavaDoc connectionURL;
84     private String JavaDoc connectionUsername;
85     private String JavaDoc connectionPassword;
86     private String JavaDoc connectionProtocol;
87     private String JavaDoc authentication;
88     private String JavaDoc userBase;
89     private String JavaDoc userSearchMatching;
90     private String JavaDoc userPassword;
91     private String JavaDoc roleBase;
92     private String JavaDoc roleName;
93     private String JavaDoc roleSearchMatching;
94     private String JavaDoc userSearchSubtree;
95     private String JavaDoc roleSearchSubtree;
96     private String JavaDoc userRoleName;
97
98     private String JavaDoc cbUsername;
99     private String JavaDoc cbPassword;
100
101     protected DirContext JavaDoc context = null;
102
103     private MessageFormat JavaDoc userSearchMatchingFormat;
104     private MessageFormat JavaDoc roleSearchMatchingFormat;
105
106     private boolean userSearchSubtreeBool = false;
107     private boolean roleSearchSubtreeBool = false;
108
109     Set JavaDoc groups = new HashSet JavaDoc();
110
111     public void initialize(Subject JavaDoc subject, CallbackHandler JavaDoc callbackHandler, Map JavaDoc sharedState, Map JavaDoc options) {
112         this.subject = subject;
113         this.handler = callbackHandler;
114         initialContextFactory = (String JavaDoc) options.get(INITIAL_CONTEXT_FACTORY);
115         connectionURL = (String JavaDoc) options.get(CONNECTION_URL);
116         connectionUsername = (String JavaDoc) options.get(CONNECTION_USERNAME);
117         connectionPassword = (String JavaDoc) options.get(CONNECTION_PASSWORD);
118         connectionProtocol = (String JavaDoc) options.get(CONNECTION_PROTOCOL);
119         authentication = (String JavaDoc) options.get(AUTHENTICATION);
120         userBase = (String JavaDoc) options.get(USER_BASE);
121         userSearchMatching = (String JavaDoc) options.get(USER_SEARCH_MATCHING);
122         userSearchSubtree = (String JavaDoc) options.get(USER_SEARCH_SUBTREE);
123         roleBase = (String JavaDoc) options.get(ROLE_BASE);
124         roleName = (String JavaDoc) options.get(ROLE_NAME);
125         roleSearchMatching = (String JavaDoc) options.get(ROLE_SEARCH_MATCHING);
126         roleSearchSubtree = (String JavaDoc) options.get(ROLE_SEARCH_SUBTREE);
127         userRoleName = (String JavaDoc) options.get(USER_ROLE_NAME);
128         userSearchMatchingFormat = new MessageFormat JavaDoc(userSearchMatching);
129         roleSearchMatchingFormat = new MessageFormat JavaDoc(roleSearchMatching);
130         userSearchSubtreeBool = new Boolean JavaDoc(userSearchSubtree).booleanValue();
131         roleSearchSubtreeBool = new Boolean JavaDoc(roleSearchSubtree).booleanValue();
132     }
133
134     public boolean login() throws LoginException JavaDoc {
135         Callback JavaDoc[] callbacks = new Callback JavaDoc[2];
136
137         callbacks[0] = new NameCallback JavaDoc("User name");
138         callbacks[1] = new PasswordCallback JavaDoc("Password", false);
139         try {
140             handler.handle(callbacks);
141         } catch (IOException JavaDoc ioe) {
142             throw (LoginException JavaDoc) new LoginException JavaDoc().initCause(ioe);
143         } catch (UnsupportedCallbackException JavaDoc uce) {
144             throw (LoginException JavaDoc) new LoginException JavaDoc().initCause(uce);
145         }
146         cbUsername = ((NameCallback JavaDoc) callbacks[0]).getName();
147         cbPassword = new String JavaDoc(((PasswordCallback JavaDoc) callbacks[1]).getPassword());
148
149         if (cbUsername == null || "".equals(cbUsername)
150             || cbPassword == null || "".equals(cbPassword)) {
151             return false;
152         }
153
154         try {
155             boolean result = authenticate(cbUsername, cbPassword);
156             if(!result) {
157                 throw new FailedLoginException JavaDoc();
158             } else {
159                 return true;
160             }
161         } catch (Exception JavaDoc e) {
162             throw (LoginException JavaDoc) new LoginException JavaDoc("LDAP Error").initCause(e);
163         }
164     }
165
166     public boolean logout() throws LoginException JavaDoc {
167         cbUsername = null;
168         cbPassword = null;
169         //todo: should remove principals added by commit
170
return true;
171     }
172
173     public boolean commit() throws LoginException JavaDoc {
174         Set JavaDoc principals = subject.getPrincipals();
175         principals.add(new GeronimoUserPrincipal(cbUsername));
176         Iterator JavaDoc iter = groups.iterator();
177         while (iter.hasNext()) {
178             principals.add(iter.next());
179         }
180         return true;
181     }
182
183     public boolean abort() throws LoginException JavaDoc {
184         cbUsername = null;
185         cbPassword = null;
186         return true;
187     }
188
189     protected void close(DirContext JavaDoc context) {
190         try {
191             context.close();
192         } catch (Exception JavaDoc e) {
193             log.error(e);
194         }
195     }
196
197     protected boolean authenticate(String JavaDoc username, String JavaDoc password) throws Exception JavaDoc {
198
199         DirContext JavaDoc context = null;
200         context = open();
201
202         try {
203
204             String JavaDoc filter = userSearchMatchingFormat.format(new String JavaDoc[]{username});
205             SearchControls JavaDoc constraints = new SearchControls JavaDoc();
206             if (userSearchSubtreeBool) {
207                 constraints.setSearchScope(SearchControls.SUBTREE_SCOPE);
208             } else {
209                 constraints.setSearchScope(SearchControls.ONELEVEL_SCOPE);
210             }
211
212             //setup attributes
213
ArrayList JavaDoc list = new ArrayList JavaDoc();
214             if (userRoleName != null) {
215                 list.add(userRoleName);
216             }
217             String JavaDoc[] attribs = new String JavaDoc[list.size()];
218             list.toArray(attribs);
219             constraints.setReturningAttributes(attribs);
220
221
222             NamingEnumeration JavaDoc results = context.search(userBase, filter, constraints);
223
224             if (results == null || !results.hasMore()) {
225                 return false;
226             }
227
228             SearchResult JavaDoc result = (SearchResult JavaDoc) results.next();
229
230             if (results.hasMore()) {
231                 //ignore for now
232
}
233             NameParser JavaDoc parser = context.getNameParser("");
234             Name JavaDoc contextName = parser.parse(context.getNameInNamespace());
235             Name JavaDoc baseName = parser.parse(userBase);
236             Name JavaDoc entryName = parser.parse(result.getName());
237             Name JavaDoc name = contextName.addAll(baseName);
238             name = name.addAll(entryName);
239             String JavaDoc dn = name.toString();
240
241             Attributes JavaDoc attrs = result.getAttributes();
242             if (attrs == null) {
243                 return false;
244             }
245             ArrayList JavaDoc roles = null;
246             if (userRoleName != null) {
247                 roles = addAttributeValues(userRoleName, attrs, roles);
248             }
249
250             //check the credentials by binding to server
251
if (bindUser(context, dn, password)) {
252                 //if authenticated add more roles
253
roles = getRoles(context, dn, username, roles);
254                 for (int i = 0; i < roles.size(); i++) {
255                     groups.add(new GeronimoGroupPrincipal((String JavaDoc) roles.get(i)));
256                 }
257             } else {
258                 return false;
259             }
260         } catch (CommunicationException JavaDoc e) {
261
262         } catch (NamingException JavaDoc e) {
263             if (context != null) {
264                 close(context);
265             }
266             return false;
267         }
268
269
270         return true;
271     }
272
273     protected ArrayList JavaDoc getRoles(DirContext JavaDoc context, String JavaDoc dn, String JavaDoc username, ArrayList JavaDoc currentRoles) throws NamingException JavaDoc {
274         ArrayList JavaDoc list = currentRoles;
275         if (list == null) {
276             list = new ArrayList JavaDoc();
277         }
278         if (roleName == null || "".equals(roleName)) {
279             return list;
280         }
281         String JavaDoc filter = roleSearchMatchingFormat.format(new String JavaDoc[]{doRFC2254Encoding(dn), username});
282
283         SearchControls JavaDoc constraints = new SearchControls JavaDoc();
284         if (roleSearchSubtreeBool) {
285             constraints.setSearchScope(SearchControls.SUBTREE_SCOPE);
286         } else {
287             constraints.setSearchScope(SearchControls.ONELEVEL_SCOPE);
288         }
289         NamingEnumeration JavaDoc results =
290                 context.search(roleBase, filter, constraints);
291         while (results.hasMore()) {
292             SearchResult JavaDoc result = (SearchResult JavaDoc) results.next();
293             Attributes JavaDoc attrs = result.getAttributes();
294             if (attrs == null) {
295                 continue;
296             }
297             list = addAttributeValues(roleName, attrs, list);
298         }
299         return list;
300
301     }
302
303
304     protected String JavaDoc doRFC2254Encoding(String JavaDoc inputString) {
305         StringBuffer JavaDoc buf = new StringBuffer JavaDoc(inputString.length());
306         for (int i = 0; i < inputString.length(); i++) {
307             char c = inputString.charAt(i);
308             switch (c) {
309                 case '\\':
310                     buf.append("\\5c");
311                     break;
312                 case '*':
313                     buf.append("\\2a");
314                     break;
315                 case '(':
316                     buf.append("\\28");
317                     break;
318                 case ')':
319                     buf.append("\\29");
320                     break;
321                 case '\0':
322                     buf.append("\\00");
323                     break;
324                 default:
325                     buf.append(c);
326                     break;
327             }
328         }
329         return buf.toString();
330     }
331
332     protected boolean bindUser(DirContext JavaDoc context, String JavaDoc dn, String JavaDoc password) throws NamingException JavaDoc {
333         boolean isValid = false;
334         Attributes JavaDoc attr;
335
336         context.addToEnvironment(Context.SECURITY_PRINCIPAL, dn);
337         context.addToEnvironment(Context.SECURITY_CREDENTIALS, password);
338         try {
339             attr = context.getAttributes("", null);
340             isValid = true;
341         } catch (AuthenticationException JavaDoc e) {
342             isValid = false;
343             log.debug("Authentication failed for dn=" + dn);
344         }
345
346         if (connectionUsername != null) {
347             context.addToEnvironment(Context.SECURITY_PRINCIPAL,
348                                      connectionUsername);
349         } else {
350             context.removeFromEnvironment(Context.SECURITY_PRINCIPAL);
351         }
352
353         if (connectionPassword != null) {
354             context.addToEnvironment(Context.SECURITY_CREDENTIALS,
355                                      connectionPassword);
356         } else {
357             context.removeFromEnvironment(Context.SECURITY_CREDENTIALS);
358         }
359
360         return isValid;
361     }
362
363     private String JavaDoc getAttributeValue(String JavaDoc attrId, Attributes JavaDoc attrs)
364             throws NamingException JavaDoc {
365
366         if (attrId == null || attrs == null) {
367             return null;
368         }
369
370         Attribute JavaDoc attr = attrs.get(attrId);
371         if (attr == null) {
372             return (null);
373         }
374         Object JavaDoc value = attr.get();
375         if (value == null) {
376             return (null);
377         }
378         String JavaDoc valueString = null;
379         if (value instanceof byte[]) {
380             valueString = new String JavaDoc((byte[]) value);
381         } else {
382             valueString = value.toString();
383         }
384         return valueString;
385     }
386
387     private ArrayList JavaDoc addAttributeValues(String JavaDoc attrId, Attributes JavaDoc attrs, ArrayList JavaDoc values)
388             throws NamingException JavaDoc {
389
390         if (attrId == null || attrs == null) {
391             return values;
392         }
393         if (values == null) {
394             values = new ArrayList JavaDoc();
395         }
396         Attribute JavaDoc attr = attrs.get(attrId);
397         if (attr == null) {
398             return (values);
399         }
400         NamingEnumeration JavaDoc e = attr.getAll();
401         while (e.hasMore()) {
402             String JavaDoc value = (String JavaDoc) e.next();
403             values.add(value);
404         }
405         return values;
406     }
407
408     protected DirContext JavaDoc open() throws NamingException JavaDoc {
409         if (context != null) {
410             return context;
411         }
412
413         try {
414             Hashtable JavaDoc env = new Hashtable JavaDoc();
415             env.put(Context.INITIAL_CONTEXT_FACTORY, initialContextFactory);
416             if (connectionUsername != null || !"".equals(connectionUsername)) {
417                 env.put(Context.SECURITY_PRINCIPAL, connectionUsername);
418             }
419             if (connectionPassword != null || !"".equals(connectionPassword)) {
420                 env.put(Context.SECURITY_CREDENTIALS, connectionPassword);
421             }
422             env.put(Context.SECURITY_PROTOCOL, connectionProtocol);
423             env.put(Context.PROVIDER_URL, connectionURL);
424             env.put(Context.SECURITY_AUTHENTICATION, authentication);
425             context = new InitialDirContext JavaDoc(env);
426
427         } catch (NamingException JavaDoc e) {
428             log.error(e);
429             throw e;
430         }
431         return context;
432     }
433
434 }
435
Popular Tags