1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.apache.jetspeed.security.spi.impl.ldap;
18
19 import javax.naming.Name;
20 import javax.naming.NameParser;
21 import javax.naming.NamingEnumeration;
22 import javax.naming.NamingException;
23 import javax.naming.directory.DirContext;
24 import javax.naming.directory.SearchControls;
25 import javax.naming.directory.SearchResult;
26 import javax.naming.ldap.LdapContext;
27
28 import org.apache.commons.lang.StringUtils;
29 import org.apache.commons.logging.Log;
30 import org.apache.commons.logging.LogFactory;
31 import org.apache.jetspeed.security.InvalidDnException;
32 import org.apache.jetspeed.security.InvalidPasswordException;
33 import org.apache.jetspeed.security.InvalidUidException;
34 import org.apache.jetspeed.security.SecurityException;
35
36 /***
37 * <p>
38 * Abstract ldap dao.
39 * </p>
40 *
41 * @author <a href="mailto:mike.long@dataline.com">Mike Long </a>, <a
42 * href="mailto:dlestrat@apache.org">David Le Strat</a>
43 */
44 public abstract class AbstractLdapDao
45 {
46
47 private static final Log logger = LogFactory.getLog(AbstractLdapDao.class);
48
49 /*** The ldap binding configuration. */
50 private LdapBindingConfig ldapBindingConfig = null;
51
52 /*** Reference to remote server context */
53 protected LdapContext ctx;
54
55 /***
56 * <p>
57 * Default constructor.
58 * </p>
59 */
60 public AbstractLdapDao()
61 {
62 throw new UnsupportedOperationException("Must be instantiated with LDAP binding configuration.");
63 }
64
65 /***
66 * <p>
67 * Initializes the dao.
68 * </p>
69 *
70 * @param ldapConfig Holds the ldap configuration.
71 * @throws SecurityException
72 */
73 public AbstractLdapDao(LdapBindingConfig ldapConfig) throws SecurityException
74 {
75 this.ldapBindingConfig = ldapConfig;
76 bindToServer(ldapConfig.getRootDn(), ldapConfig.getRootPassword());
77 }
78
79 /***
80 * <p>
81 * Binds to the ldap server.
82 * </p>
83 *
84 * @param rootDn
85 * @param rootPassword
86 * @throws SecurityException
87 */
88 protected void bindToServer(String rootDn, String rootPassword) throws SecurityException
89 {
90 if ( ctx == null )
91 {
92 validateDn(rootDn);
93 validatePassword(rootPassword);
94
95 ctx = LdapContextProxy.createProxy(ldapBindingConfig);
96 }
97 }
98
99 /***
100 * <p>
101 * Gets the sub context name.
102 * </p>
103 *
104 * @param dn The domain name.
105 * @return The sub context name.
106 * @throws NamingException
107 */
108 protected String getSubcontextName(final String dn) throws NamingException
109 {
110 NameParser parser = ctx.getNameParser("");
111 Name name = parser.parse(dn);
112 String rootStr = ctx.getNameInNamespace();
113 Name root = parser.parse(rootStr);
114
115 if (name.startsWith(root))
116 {
117 Name rname = name.getSuffix(root.size());
118
119 return rname.toString();
120 }
121
122 return dn;
123 }
124
125 /***
126 * <p>
127 * Validate the domain name.
128 * </p>
129 *
130 * @param dn The domain name.
131 */
132 protected void validateDn(final String dn) throws SecurityException
133 {
134 if (StringUtils.isEmpty(dn))
135 {
136 throw new InvalidDnException();
137 }
138 }
139
140 /***
141 * <p>
142 * Valiate the users password.
143 * </p>
144 *
145 * @param password The user.
146 */
147 protected void validatePassword(final String password) throws SecurityException
148 {
149 if (StringUtils.isEmpty(password))
150 {
151 throw new InvalidPasswordException();
152 }
153 }
154
155 /***
156 * @return The factors that determine the scope of the search and what gets returned as a result
157 * of the search.
158 */
159 protected SearchControls setSearchControls()
160 {
161 SearchControls controls = new SearchControls();
162 controls.setReturningAttributes(getKnownAttributes());
163 controls.setSearchScope(SearchControls.SUBTREE_SCOPE);
164 controls.setReturningObjFlag(true);
165
166 return controls;
167 }
168
169 /***
170 * <p>
171 * Searches the LDAP server for the user with the specified userid (uid attribute).
172 * </p>
173 *
174 * @return the user's DN
175 */
176 public String lookupByUid(final String uid) throws SecurityException
177 {
178 validateUid(uid);
179
180 try
181 {
182 SearchControls cons = setSearchControls();
183 NamingEnumeration searchResults = searchByWildcardedUid(uid, cons);
184
185 return getFirstDnForUid(searchResults);
186 }
187 catch (NamingException e)
188 {
189 throw new SecurityException(e);
190 }
191 }
192
193
194 /***
195 * <p>
196 * Gets the first matching user for the given uid.
197 * </p>
198 *
199 * @param searchResults The {@link NamingEnumeration}.
200 * @return the user's DN of the first use in the list. Null if no users were found.
201 * @throws NamingException Throws a {@link NamingException}.
202 */
203 private String getFirstDnForUid(NamingEnumeration searchResults) throws NamingException
204 {
205 String userDn = null;
206 while ((null != searchResults) && searchResults.hasMore())
207 {
208 SearchResult searchResult = (SearchResult) searchResults.next();
209 userDn = searchResult.getName();
210 }
211 return userDn;
212 }
213
214 /***
215 * <p>
216 * Validate the uid.
217 * </p>
218 *
219 * @param uid The uid.
220 */
221 protected void validateUid(String uid) throws SecurityException
222 {
223 String pattern = ".*//(.*|.*//[.*|.*//{.*|.*////.*|.*//^.*|.*//$.*|.*//|.*|.*//).*|.*//?.*|.*//*.*|.*//+.*|.*//..*";
224 if (StringUtils.isEmpty(uid) || uid.matches(pattern))
225 {
226 throw new InvalidUidException();
227 }
228 }
229
230 /***
231 * <p>
232 * Search uid by wild card.
233 * </p>
234 *
235 * @param filter The filter.
236 * @param cons The {@link SearchControls}
237 * @return The {@link NamingEnumeration}
238 * @throws NamingException Throws a {@link NamingEnumeration}.
239 */
240 protected NamingEnumeration searchByWildcardedUid(final String filter, SearchControls cons) throws NamingException
241 {
242
243 String query = "";
244 if (StringUtils.isEmpty(getSearchSuffix())) {
245 query = "(" + getEntryPrefix() + "=" + (StringUtils.isEmpty(filter) ? "*" : filter) + ")";
246 } else {
247 query = "(&(" + getEntryPrefix() + "=" + (StringUtils.isEmpty(filter) ? "*" : filter) + ")" + getSearchSuffix() + ")";
248 }
249 logger.debug("searchByWildCardedUid = " + query);
250
251 cons.setSearchScope(getSearchScope());
252
253 String searchBase = StringUtils.replace(getSearchDomain(), "," + getRootContext(), "");
254 NamingEnumeration results = ((DirContext) ctx).search(searchBase,query , cons);
255
256 return results;
257 }
258
259 /***
260 * <p>
261 * Search uid by wild card.
262 * </p>
263 *
264 * @param filter The filter.
265 * @param cons The {@link SearchControls}
266 * @return The {@link NamingEnumeration}
267 * @throws NamingException Throws a {@link NamingEnumeration}.
268 */
269 protected NamingEnumeration searchGroupByWildcardedUid(final String filter, SearchControls cons) throws NamingException
270 {
271
272 String query = "";
273 if (StringUtils.isEmpty(getGroupFilter())) {
274 query = "(" + getGroupIdAttribute() + "=" + (StringUtils.isEmpty(filter) ? "*" : filter) + ")";
275 } else {
276 query = "(&(" + getGroupIdAttribute() + "=" + (StringUtils.isEmpty(filter) ? "*" : filter) + ")" + getGroupFilter() + ")";
277 }
278
279 String searchBase = "";
280 if (!StringUtils.isEmpty(getGroupFilterBase()))
281 searchBase+=getGroupFilterBase();
282 cons.setSearchScope(getSearchScope());
283 NamingEnumeration results = ((DirContext) ctx).search(searchBase,query , cons);
284
285 return results;
286 }
287
288 /***
289 * <p>
290 * Search uid by wild card.
291 * </p>
292 *
293 * @param filter The filter.
294 * @param cons The {@link SearchControls}
295 * @return The {@link NamingEnumeration}
296 * @throws NamingException Throws a {@link NamingEnumeration}.
297 */
298 protected NamingEnumeration searchRoleByWildcardedUid(final String filter, SearchControls cons) throws NamingException
299 {
300 String query = "";
301 if (StringUtils.isEmpty(getRoleFilter())) {
302 query = "(" + getRoleIdAttribute() + "=" + (StringUtils.isEmpty(filter) ? "*" : filter) + ")";
303 } else {
304 query = "(&(" + getRoleIdAttribute() + "=" + (StringUtils.isEmpty(filter) ? "*" : filter) + ")" + getRoleFilter() + ")";
305 }
306
307 String searchBase = "";
308 if (!StringUtils.isEmpty(getRoleFilterBase()))
309 searchBase+=getRoleFilterBase();
310 cons.setSearchScope(getSearchScope());
311 NamingEnumeration results = ((DirContext) ctx).search(searchBase,query , cons);
312
313 return results;
314 }
315
316 /***
317 * <p>
318 * Returns the default Group suffix dn.
319 * </p>
320 *
321 * @return The defaultDnSuffix.
322 */
323 protected String getGroupFilterBase()
324 {
325 return this.ldapBindingConfig.getGroupFilterBase();
326 }
327
328 /***
329 * <p>
330 * Returns the default Group suffix dn.
331 * </p>
332 *
333 * @return The defaultDnSuffix.
334 */
335 protected String[] getGroupObjectClasses()
336 {
337 return this.ldapBindingConfig.getGroupObjectClasses();
338 }
339
340
341 /***
342 * <p>
343 * Returns the default Group suffix dn.
344 * </p>
345 *
346 * @return The defaultDnSuffix.
347 */
348 protected String getRoleFilterBase()
349 {
350 return this.ldapBindingConfig.getRoleFilterBase();
351 }
352
353 /***
354 * <p>
355 * Returns the default Group suffix dn.
356 * </p>
357 *
358 * @return The defaultDnSuffix.
359 */
360 protected String[] getRoleObjectClasses()
361 {
362 return this.ldapBindingConfig.getRoleObjectClasses();
363 }
364
365 /***
366 * <p>
367 * Returns the default Group suffix dn.
368 * </p>
369 *
370 * @return The defaultDnSuffix.
371 */
372 protected String getUserFilterBase()
373 {
374 return this.ldapBindingConfig.getUserFilterBase();
375 }
376
377 /***
378 * <p>
379 * Returns the default Group suffix dn.
380 * </p>
381 *
382 * @return The defaultDnSuffix.
383 */
384 protected String getGroupFilter()
385 {
386 return this.ldapBindingConfig.getGroupFilter();
387 }
388
389
390 /***
391 * <p>
392 * Returns the default Group suffix dn.
393 * </p>
394 *
395 * @return The defaultDnSuffix.
396 */
397 protected String getRoleFilter()
398 {
399 return this.ldapBindingConfig.getRoleFilter();
400 }
401
402
403
404 /***
405 * <p>
406 * Returns the root context.
407 * </p>
408 *
409 * @return The root context.
410 */
411 protected String getRootContext()
412 {
413 return this.ldapBindingConfig.getRootContext();
414 }
415
416 /***
417 * <p>
418 * A template method that returns the LDAP entry prefix of the concrete DAO.
419 * </p>
420 *
421 * TODO : this should be in spring config
422 *
423 * @return a String containing the LDAP entry prefix name.
424 */
425 protected abstract String getEntryPrefix();
426
427 /***
428 * <p>
429 * A template method that returns the LDAP entry prefix of the concrete DAO.
430 * </p>
431 *
432 * TODO : this should be in spring config
433 *
434 * @return a String containing the LDAP entry prefix name.
435 */
436 protected abstract String getSearchSuffix();
437
438 /***
439 * <p>
440 * The domain in wich to perform a search
441 * </p>
442 *
443 * TODO : this should be in spring config
444 *
445 * @return a String containing the LDAP entry prefix name.
446 */
447 protected abstract String getSearchDomain();
448
449 protected String getUserFilter()
450 {
451 return this.ldapBindingConfig.getUserFilter();
452 }
453
454 protected String[] getUserObjectClasses()
455 {
456 return this.ldapBindingConfig.getUserObjectClasses();
457 }
458
459 protected String getGroupMembershipAttribute()
460 {
461 return this.ldapBindingConfig.getGroupMembershipAttributes();
462 }
463
464 protected String getUserGroupMembershipAttribute()
465 {
466 return this.ldapBindingConfig.getUserGroupMembershipAttributes();
467 }
468
469
470 protected String getGroupMembershipForRoleAttribute()
471 {
472 return this.ldapBindingConfig.getGroupMembershipForRoleAttributes();
473 }
474
475 protected String getRoleGroupMembershipForRoleAttribute()
476 {
477 return this.ldapBindingConfig.getRoleGroupMembershipForRoleAttributes();
478 }
479
480 protected String getRoleMembershipAttribute()
481 {
482 return this.ldapBindingConfig.getRoleMembershipAttributes();
483 }
484
485 protected String getUserRoleMembershipAttribute()
486 {
487 return this.ldapBindingConfig.getUserRoleMembershipAttributes();
488 }
489
490 protected String getRoleIdAttribute()
491 {
492 return this.ldapBindingConfig.getRoleIdAttribute();
493 }
494
495 protected String getGroupIdAttribute()
496 {
497 return this.ldapBindingConfig.getGroupIdAttribute();
498 }
499
500 protected String getUserIdAttribute()
501 {
502 return this.ldapBindingConfig.getUserIdAttribute();
503 }
504
505 protected String getUidAttribute()
506 {
507 return this.ldapBindingConfig.getUidAttribute();
508 }
509
510 protected int getSearchScope()
511 {
512 return Integer.parseInt(this.ldapBindingConfig.getMemberShipSearchScope());
513 }
514
515 protected String getRoleUidAttribute()
516 {
517 return this.ldapBindingConfig.getRoleUidAttribute();
518 }
519
520 protected String getGroupUidAttribute()
521 {
522 return this.ldapBindingConfig.getGroupUidAttribute();
523 }
524
525 protected String getUserUidAttribute()
526 {
527 return this.ldapBindingConfig.getUserUidAttribute();
528 }
529
530 protected String getGroupObjectRequiredAttributeClasses()
531 {
532 return this.ldapBindingConfig.getGroupObjectRequiredAttributeClasses();
533 }
534
535 protected String getRoleObjectRequiredAttributeClasses()
536 {
537 return this.ldapBindingConfig.getRoleObjectRequiredAttributeClasses();
538 }
539
540 protected String[] getUserAttributes()
541 {
542 return this.ldapBindingConfig.getUserAttributes();
543 }
544
545 protected String[] getGroupAttributes()
546 {
547 return this.ldapBindingConfig.getGroupAttributes();
548 }
549
550 protected String[] getRoleAttributes()
551 {
552 return this.ldapBindingConfig.getRoleAttributes();
553 }
554
555 protected String getUserPasswordAttribute() {
556 return this.ldapBindingConfig.getUserPasswordAttribute();
557 }
558
559 protected String[] getKnownAttributes() {
560 return this.ldapBindingConfig.getKnownAttributes();
561 }
562
563 protected abstract String[] getObjectClasses();
564 protected abstract String[] getAttributes();
565 }