001
014
015 package com.liferay.portal.security.ldap;
016
017 import com.liferay.portal.kernel.log.Log;
018 import com.liferay.portal.kernel.log.LogFactoryUtil;
019 import com.liferay.portal.kernel.log.LogUtil;
020 import com.liferay.portal.kernel.util.ArrayUtil;
021 import com.liferay.portal.kernel.util.GetterUtil;
022 import com.liferay.portal.kernel.util.PropertiesUtil;
023 import com.liferay.portal.kernel.util.PropsKeys;
024 import com.liferay.portal.kernel.util.StringBundler;
025 import com.liferay.portal.kernel.util.StringPool;
026 import com.liferay.portal.kernel.util.StringUtil;
027 import com.liferay.portal.kernel.util.Validator;
028 import com.liferay.portal.util.PrefsPropsUtil;
029 import com.liferay.portal.util.PropsValues;
030
031 import java.util.ArrayList;
032 import java.util.List;
033 import java.util.Properties;
034
035 import javax.naming.Binding;
036 import javax.naming.CompositeName;
037 import javax.naming.Context;
038 import javax.naming.Name;
039 import javax.naming.NamingEnumeration;
040 import javax.naming.OperationNotSupportedException;
041 import javax.naming.directory.Attribute;
042 import javax.naming.directory.Attributes;
043 import javax.naming.directory.SearchControls;
044 import javax.naming.directory.SearchResult;
045 import javax.naming.ldap.Control;
046 import javax.naming.ldap.InitialLdapContext;
047 import javax.naming.ldap.LdapContext;
048 import javax.naming.ldap.PagedResultsControl;
049 import javax.naming.ldap.PagedResultsResponseControl;
050
051
062 public class PortalLDAPUtil {
063
064 public static LdapContext getContext(long ldapServerId, long companyId)
065 throws Exception {
066
067 String postfix = LDAPSettingsUtil.getPropertyPostfix(ldapServerId);
068
069 String baseProviderURL = PrefsPropsUtil.getString(
070 companyId, PropsKeys.LDAP_BASE_PROVIDER_URL + postfix);
071 String pricipal = PrefsPropsUtil.getString(
072 companyId, PropsKeys.LDAP_SECURITY_PRINCIPAL + postfix);
073 String credentials = PrefsPropsUtil.getString(
074 companyId, PropsKeys.LDAP_SECURITY_CREDENTIALS + postfix);
075
076 return getContext(companyId, baseProviderURL, pricipal, credentials);
077 }
078
079 public static LdapContext getContext(
080 long companyId, String providerURL, String principal,
081 String credentials)
082 throws Exception {
083
084 Properties env = new Properties();
085
086 env.put(
087 Context.INITIAL_CONTEXT_FACTORY,
088 PrefsPropsUtil.getString(
089 companyId, PropsKeys.LDAP_FACTORY_INITIAL));
090 env.put(Context.PROVIDER_URL, providerURL);
091 env.put(Context.SECURITY_PRINCIPAL, principal);
092 env.put(Context.SECURITY_CREDENTIALS, credentials);
093 env.put(
094 Context.REFERRAL,
095 PrefsPropsUtil.getString(companyId, PropsKeys.LDAP_REFERRAL));
096
097
098
099 env.put("com.sun.jndi.ldap.connect.pool", "true");
100 env.put("com.sun.jndi.ldap.connect.pool.maxsize","50");
101 env.put("com.sun.jndi.ldap.connect.pool.timeout", "10000");
102
103 LogUtil.debug(_log, env);
104
105 LdapContext ldapContext = null;
106
107 try {
108 ldapContext = new InitialLdapContext(env, null);
109 }
110 catch (Exception e) {
111 if (_log.isWarnEnabled()) {
112 _log.warn("Failed to bind to the LDAP server");
113 }
114
115 if (_log.isDebugEnabled()) {
116 _log.debug(e, e);
117 }
118 }
119
120 return ldapContext;
121 }
122
123 public static Binding getGroup(
124 long ldapServerId, long companyId, String groupName)
125 throws Exception {
126
127 String postfix = LDAPSettingsUtil.getPropertyPostfix(ldapServerId);
128
129 LdapContext ldapContext = getContext(ldapServerId, companyId);
130
131 NamingEnumeration<SearchResult> enu = null;
132
133 try {
134 if (ldapContext == null) {
135 return null;
136 }
137
138 String baseDN = PrefsPropsUtil.getString(
139 companyId, PropsKeys.LDAP_BASE_DN + postfix);
140
141 Properties groupMappings = LDAPSettingsUtil.getGroupMappings(
142 ldapServerId, companyId);
143
144 StringBundler filter = new StringBundler(5);
145
146 filter.append(StringPool.OPEN_PARENTHESIS);
147 filter.append(groupMappings.getProperty("groupName"));
148 filter.append(StringPool.EQUAL);
149 filter.append(groupName);
150 filter.append(StringPool.CLOSE_PARENTHESIS);
151
152 SearchControls searchControls = new SearchControls(
153 SearchControls.SUBTREE_SCOPE, 1, 0, null, false, false);
154
155 enu = ldapContext.search(baseDN, filter.toString(), searchControls);
156 }
157 catch (Exception e) {
158 throw e;
159 }
160 finally {
161 if (ldapContext != null) {
162 ldapContext.close();
163 }
164 }
165
166 if (enu.hasMoreElements()) {
167 Binding binding = enu.nextElement();
168
169 enu.close();
170
171 return binding;
172 }
173 else {
174 return null;
175 }
176 }
177
178 public static Attributes getGroupAttributes(
179 long ldapServerId, long companyId, LdapContext ldapContext,
180 String fullDistinguishedName)
181 throws Exception {
182
183 return getGroupAttributes(ldapServerId, companyId, ldapContext,
184 fullDistinguishedName, false);
185 }
186
187 public static Attributes getGroupAttributes(
188 long ldapServerId, long companyId, LdapContext ldapContext,
189 String fullDistinguishedName, boolean includeReferenceAttributes)
190 throws Exception {
191
192 Properties groupMappings = LDAPSettingsUtil.getGroupMappings(
193 ldapServerId, companyId);
194
195 List<String> mappedGroupAttributeIds = new ArrayList<String>();
196
197 mappedGroupAttributeIds.add(groupMappings.getProperty("groupName"));
198 mappedGroupAttributeIds.add(groupMappings.getProperty("description"));
199
200 if (includeReferenceAttributes) {
201 mappedGroupAttributeIds.add(groupMappings.getProperty("user"));
202 }
203
204 return _getAttributes(
205 ldapContext, fullDistinguishedName,
206 mappedGroupAttributeIds.toArray(new String[0]));
207 }
208
209 public static byte[] getGroups(
210 long companyId, LdapContext ldapContext, byte[] cookie,
211 int maxResults, String baseDN, String groupFilter,
212 List<SearchResult> searchResults)
213 throws Exception {
214
215 return searchLDAP(
216 companyId, ldapContext, cookie, maxResults, baseDN, groupFilter,
217 null, searchResults);
218 }
219
220 public static byte[] getGroups(
221 long companyId, LdapContext ldapContext, byte[] cookie,
222 int maxResults, String baseDN, String groupFilter,
223 String[] attributeIds, List<SearchResult> searchResults)
224 throws Exception {
225
226 return searchLDAP(
227 companyId, ldapContext, cookie, maxResults, baseDN, groupFilter,
228 attributeIds, searchResults);
229 }
230
231 public static byte[] getGroups(
232 long ldapServerId, long companyId, LdapContext ldapContext,
233 byte[] cookie, int maxResults, List<SearchResult> searchResults)
234 throws Exception {
235
236 String postfix = LDAPSettingsUtil.getPropertyPostfix(ldapServerId);
237
238 String baseDN = PrefsPropsUtil.getString(
239 companyId, PropsKeys.LDAP_BASE_DN + postfix);
240 String groupFilter = PrefsPropsUtil.getString(
241 companyId, PropsKeys.LDAP_IMPORT_GROUP_SEARCH_FILTER + postfix);
242
243 return getGroups(
244 companyId, ldapContext, cookie, maxResults, baseDN, groupFilter,
245 searchResults);
246 }
247
248 public static byte[] getGroups(
249 long ldapServerId, long companyId, LdapContext ldapContext,
250 byte[] cookie, int maxResults, String[] attributeIds,
251 List<SearchResult> searchResults)
252 throws Exception {
253
254 String postfix = LDAPSettingsUtil.getPropertyPostfix(ldapServerId);
255
256 String baseDN = PrefsPropsUtil.getString(
257 companyId, PropsKeys.LDAP_BASE_DN + postfix);
258 String groupFilter = PrefsPropsUtil.getString(
259 companyId, PropsKeys.LDAP_IMPORT_GROUP_SEARCH_FILTER + postfix);
260
261 return getGroups(
262 companyId, ldapContext, cookie, maxResults, baseDN, groupFilter,
263 attributeIds, searchResults);
264 }
265
266 public static String getGroupsDN(long ldapServerId, long companyId)
267 throws Exception {
268
269 String postfix = LDAPSettingsUtil.getPropertyPostfix(ldapServerId);
270
271 return PrefsPropsUtil.getString(
272 companyId, PropsKeys.LDAP_GROUPS_DN + postfix);
273 }
274
275 public static long getLdapServerId(long companyId, String screenName)
276 throws Exception {
277
278 long[] ldapServerIds = StringUtil.split(
279 PrefsPropsUtil.getString(companyId, "ldap.server.ids"), 0L);
280
281 for (long ldapServerId : ldapServerIds) {
282 if (hasUser(ldapServerId, companyId, screenName)) {
283 return ldapServerId;
284 }
285 }
286
287 if (ldapServerIds.length > 0) {
288 return ldapServerIds[0];
289 }
290
291 return 0;
292 }
293
294 public static Attribute getMultivaluedAttribute(
295 long companyId, LdapContext ldapContext, String baseDN,
296 String filter, Attribute attribute)
297 throws Exception {
298
299 if (attribute.size() > 0) {
300 return attribute;
301 }
302
303 String[] attributeIds = {_getNextRange(attribute.getID())};
304
305 while (true) {
306 List<SearchResult> searchResults = new ArrayList<SearchResult>();
307
308 searchLDAP(
309 companyId, ldapContext, new byte[0], 0, baseDN, filter,
310 attributeIds, searchResults);
311
312 if (searchResults.size() != 1) {
313 break;
314 }
315
316 SearchResult searchResult = searchResults.get(0);
317
318 Attributes attributes = searchResult.getAttributes();
319
320 if (attributes.size() != 1) {
321 break;
322 }
323
324 NamingEnumeration<? extends Attribute> enu = attributes.getAll();
325
326 if (!enu.hasMoreElements()) {
327 break;
328 }
329
330 Attribute curAttribute = enu.nextElement();
331
332 for (int i = 0; i < curAttribute.size(); i++) {
333 attribute.add(curAttribute.get(i));
334 }
335
336 if (StringUtil.endsWith(curAttribute.getID(), StringPool.STAR) ||
337 (curAttribute.size() < PropsValues.LDAP_RANGE_SIZE)) {
338
339 break;
340 }
341
342 attributeIds[0] = _getNextRange(attributeIds[0]);
343 }
344
345 return attribute;
346 }
347
348 public static String getNameInNamespace(
349 long ldapServerId, long companyId, Binding binding)
350 throws Exception {
351
352 String postfix = LDAPSettingsUtil.getPropertyPostfix(ldapServerId);
353
354 String baseDN = PrefsPropsUtil.getString(
355 companyId, PropsKeys.LDAP_BASE_DN + postfix);
356
357 String name = binding.getName();
358
359 if (name.startsWith(StringPool.QUOTE) &&
360 name.endsWith(StringPool.QUOTE)) {
361
362 name = name.substring(1, name.length() - 1);
363 }
364
365 if (Validator.isNull(baseDN)) {
366 return name.toString();
367 }
368 else {
369 return name.concat(StringPool.COMMA).concat(baseDN);
370 }
371 }
372
373 public static Binding getUser(
374 long ldapServerId, long companyId, String screenName)
375 throws Exception {
376
377 String postfix = LDAPSettingsUtil.getPropertyPostfix(ldapServerId);
378
379 LdapContext ldapContext = getContext(ldapServerId, companyId);
380
381 NamingEnumeration<SearchResult> enu = null;
382
383 try {
384 if (ldapContext == null) {
385 return null;
386 }
387
388 String baseDN = PrefsPropsUtil.getString(
389 companyId, PropsKeys.LDAP_BASE_DN + postfix);
390
391 Properties userMappings = LDAPSettingsUtil.getUserMappings(
392 ldapServerId, companyId);
393
394 StringBundler filter = new StringBundler(5);
395
396 filter.append(StringPool.OPEN_PARENTHESIS);
397 filter.append(userMappings.getProperty("screenName"));
398 filter.append(StringPool.EQUAL);
399 filter.append(screenName);
400 filter.append(StringPool.CLOSE_PARENTHESIS);
401
402 SearchControls searchControls = new SearchControls(
403 SearchControls.SUBTREE_SCOPE, 1, 0, null, false, false);
404
405 enu = ldapContext.search(baseDN, filter.toString(), searchControls);
406 }
407 catch (Exception e) {
408 throw e;
409 }
410 finally {
411 if (ldapContext != null) {
412 ldapContext.close();
413 }
414 }
415
416 if (enu.hasMoreElements()) {
417 Binding binding = enu.nextElement();
418
419 enu.close();
420
421 return binding;
422 }
423 else {
424 return null;
425 }
426 }
427
428 public static Attributes getUserAttributes(
429 long ldapServerId, long companyId, LdapContext ldapContext,
430 String fullDistinguishedName)
431 throws Exception {
432
433 Properties userMappings = LDAPSettingsUtil.getUserMappings(
434 ldapServerId, companyId);
435 Properties userExpandoMappings =
436 LDAPSettingsUtil.getUserExpandoMappings(
437 ldapServerId, companyId);
438
439 PropertiesUtil.merge(userMappings, userExpandoMappings);
440
441 Properties contactMappings = LDAPSettingsUtil.getContactMappings(
442 ldapServerId, companyId);
443 Properties contactExpandoMappings =
444 LDAPSettingsUtil.getContactExpandoMappings(ldapServerId, companyId);
445
446 PropertiesUtil.merge(contactMappings, contactExpandoMappings);
447
448 PropertiesUtil.merge(userMappings, contactMappings);
449
450 String[] mappedUserAttributeIds = ArrayUtil.toStringArray(
451 userMappings.values().toArray(new Object[userMappings.size()]));
452
453 return _getAttributes(
454 ldapContext, fullDistinguishedName, mappedUserAttributeIds);
455 }
456
457 public static byte[] getUsers(
458 long companyId, LdapContext ldapContext, byte[] cookie,
459 int maxResults, String baseDN, String userFilter,
460 List<SearchResult> searchResults)
461 throws Exception {
462
463 return searchLDAP(
464 companyId, ldapContext, cookie, maxResults, baseDN, userFilter,
465 null, searchResults);
466 }
467
468 public static byte[] getUsers(
469 long companyId, LdapContext ldapContext, byte[] cookie,
470 int maxResults, String baseDN, String userFilter,
471 String[] attributeIds, List<SearchResult> searchResults)
472 throws Exception {
473
474 return searchLDAP(
475 companyId, ldapContext, cookie, maxResults, baseDN, userFilter,
476 attributeIds, searchResults);
477 }
478
479 public static byte[] getUsers(
480 long ldapServerId, long companyId, LdapContext ldapContext,
481 byte[] cookie, int maxResults, List<SearchResult> searchResults)
482 throws Exception {
483
484 String postfix = LDAPSettingsUtil.getPropertyPostfix(ldapServerId);
485
486 String baseDN = PrefsPropsUtil.getString(
487 companyId, PropsKeys.LDAP_BASE_DN + postfix);
488 String userFilter = PrefsPropsUtil.getString(
489 companyId, PropsKeys.LDAP_IMPORT_USER_SEARCH_FILTER + postfix);
490
491 return getUsers(
492 companyId, ldapContext, cookie, maxResults, baseDN, userFilter,
493 searchResults);
494 }
495
496 public static byte[] getUsers(
497 long ldapServerId, long companyId, LdapContext ldapContext,
498 byte[] cookie, int maxResults, String[] attributeIds,
499 List<SearchResult> searchResults)
500 throws Exception {
501
502 String postfix = LDAPSettingsUtil.getPropertyPostfix(ldapServerId);
503
504 String baseDN = PrefsPropsUtil.getString(
505 companyId, PropsKeys.LDAP_BASE_DN + postfix);
506 String userFilter = PrefsPropsUtil.getString(
507 companyId, PropsKeys.LDAP_IMPORT_USER_SEARCH_FILTER + postfix);
508
509 return getUsers(
510 companyId, ldapContext, cookie, maxResults, baseDN, userFilter,
511 attributeIds, searchResults);
512 }
513
514 public static String getUsersDN(long ldapServerId, long companyId)
515 throws Exception {
516
517 String postfix = LDAPSettingsUtil.getPropertyPostfix(ldapServerId);
518
519 return PrefsPropsUtil.getString(
520 companyId, PropsKeys.LDAP_USERS_DN + postfix);
521 }
522
523 public static boolean hasUser(
524 long ldapServerId, long companyId, String screenName)
525 throws Exception {
526
527 if (getUser(ldapServerId, companyId, screenName) != null) {
528 return true;
529 }
530 else {
531 return false;
532 }
533 }
534
535 public static boolean isGroupMember(
536 long ldapServerId, long companyId, String groupDN, String userDN)
537 throws Exception {
538
539 LdapContext ldapContext = getContext(ldapServerId, companyId);
540
541 try {
542 if (ldapContext == null) {
543 return false;
544 }
545
546 Properties groupMappings = LDAPSettingsUtil.getGroupMappings(
547 ldapServerId, companyId);
548
549 StringBundler filter = new StringBundler(5);
550
551 filter.append(StringPool.OPEN_PARENTHESIS);
552 filter.append(groupMappings.getProperty(GroupConverterKeys.USER));
553 filter.append(StringPool.EQUAL);
554 filter.append(userDN);
555 filter.append(StringPool.CLOSE_PARENTHESIS);
556
557 SearchControls searchControls = new SearchControls(
558 SearchControls.SUBTREE_SCOPE, 1, 0, null, false, false);
559
560 NamingEnumeration<SearchResult> enu = ldapContext.search(
561 groupDN, filter.toString(), searchControls);
562
563 if (enu.hasMoreElements()) {
564 return true;
565 }
566 }
567 catch (Exception e) {
568 throw e;
569 }
570 finally {
571 if (ldapContext != null) {
572 ldapContext.close();
573 }
574 }
575
576 return false;
577 }
578
579 public static byte[] searchLDAP(
580 long companyId, LdapContext ldapContext, byte[] cookie,
581 int maxResults, String baseDN, String filter,
582 String[] attributeIds, List<SearchResult> searchResults)
583 throws Exception {
584
585 SearchControls searchControls = new SearchControls(
586 SearchControls.SUBTREE_SCOPE, maxResults, 0, attributeIds, false,
587 false);
588
589 try {
590 if (cookie != null) {
591 if (cookie.length == 0) {
592 ldapContext.setRequestControls(
593 new Control[] {
594 new PagedResultsControl(
595 PropsValues.LDAP_PAGE_SIZE, Control.CRITICAL)
596 });
597 }
598 else {
599 ldapContext.setRequestControls(
600 new Control[] {
601 new PagedResultsControl(
602 PropsValues.LDAP_PAGE_SIZE, cookie,
603 Control.CRITICAL)
604 });
605 }
606
607 NamingEnumeration<SearchResult> enu = ldapContext.search(
608 baseDN, filter, searchControls);
609
610 while (enu.hasMoreElements()) {
611 searchResults.add(enu.nextElement());
612 }
613
614 enu.close();
615
616 return _getCookie(ldapContext.getResponseControls());
617 }
618 }
619 catch (OperationNotSupportedException onse) {
620 ldapContext.setRequestControls(null);
621
622 NamingEnumeration<SearchResult> enu = ldapContext.search(
623 baseDN, filter, searchControls);
624
625 while (enu.hasMoreElements()) {
626 searchResults.add(enu.nextElement());
627 }
628
629 enu.close();
630 }
631 finally {
632 ldapContext.setRequestControls(null);
633 }
634
635 return null;
636 }
637
638 private static Attributes _getAttributes(
639 LdapContext ldapContext, String fullDistinguishedName,
640 String[] attributeIds)
641 throws Exception {
642
643 Name fullDN = new CompositeName().add(fullDistinguishedName);
644
645 Attributes attributes = null;
646
647 String[] auditAttributeIds = {
648 "creatorsName", "createTimestamp", "modifiersName",
649 "modifyTimestamp"
650 };
651
652 if (attributeIds == null) {
653
654
655
656 attributes = ldapContext.getAttributes(fullDN);
657
658 NamingEnumeration<? extends Attribute> enu =
659 ldapContext.getAttributes(fullDN, auditAttributeIds).getAll();
660
661 while (enu.hasMoreElements()) {
662 attributes.put(enu.nextElement());
663 }
664
665 enu.close();
666 }
667 else {
668
669
670
671 int attributeCount = attributeIds.length + auditAttributeIds.length;
672
673 String[] allAttributeIds = new String[attributeCount];
674
675 System.arraycopy(
676 attributeIds, 0, allAttributeIds, 0, attributeIds.length);
677 System.arraycopy(
678 auditAttributeIds, 0, allAttributeIds, attributeIds.length,
679 auditAttributeIds.length);
680
681 attributes = ldapContext.getAttributes(fullDN, allAttributeIds);
682 }
683
684 return attributes;
685 }
686
687 private static byte[] _getCookie(Control[] controls) {
688 if (controls == null) {
689 return null;
690 }
691
692 for (Control control : controls) {
693 if (control instanceof PagedResultsResponseControl) {
694 PagedResultsResponseControl pagedResultsResponseControl =
695 (PagedResultsResponseControl)control;
696
697 return pagedResultsResponseControl.getCookie();
698 }
699 }
700
701 return null;
702 }
703
704 private static String _getNextRange(String attributeId) {
705 String originalAttributeId = null;
706 int start = 0;
707 int end = 0;
708
709 int x = attributeId.indexOf(StringPool.SEMICOLON);
710
711 if (x < 0) {
712 originalAttributeId = attributeId;
713 end = PropsValues.LDAP_RANGE_SIZE - 1;
714 }
715 else {
716 int y = attributeId.indexOf(StringPool.EQUAL, x);
717 int z = attributeId.indexOf(StringPool.DASH, y);
718
719 originalAttributeId = attributeId.substring(0, x);
720 start = GetterUtil.getInteger(attributeId.substring(y + 1, z));
721 end = GetterUtil.getInteger(attributeId.substring(z + 1));
722
723 start += PropsValues.LDAP_RANGE_SIZE;
724 end += PropsValues.LDAP_RANGE_SIZE;
725 }
726
727 StringBundler sb = new StringBundler(6);
728
729 sb.append(originalAttributeId);
730 sb.append(StringPool.SEMICOLON);
731 sb.append("range=");
732 sb.append(start);
733 sb.append(StringPool.DASH);
734 sb.append(end);
735
736 return sb.toString();
737 }
738
739 private static Log _log = LogFactoryUtil.getLog(PortalLDAPUtil.class);
740
741 }