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