1
14
15 package com.liferay.portal.security.ldap;
16
17 import com.liferay.portal.kernel.log.Log;
18 import com.liferay.portal.kernel.log.LogFactoryUtil;
19 import com.liferay.portal.kernel.log.LogUtil;
20 import com.liferay.portal.kernel.util.ArrayUtil;
21 import com.liferay.portal.kernel.util.GetterUtil;
22 import com.liferay.portal.kernel.util.PropertiesUtil;
23 import com.liferay.portal.kernel.util.PropsKeys;
24 import com.liferay.portal.kernel.util.StringBundler;
25 import com.liferay.portal.kernel.util.StringPool;
26 import com.liferay.portal.kernel.util.StringUtil;
27 import com.liferay.portal.kernel.util.Validator;
28 import com.liferay.portal.util.PrefsPropsUtil;
29 import com.liferay.portal.util.PropsValues;
30
31 import java.util.ArrayList;
32 import java.util.List;
33 import java.util.Properties;
34
35 import javax.naming.Binding;
36 import javax.naming.CompositeName;
37 import javax.naming.Context;
38 import javax.naming.Name;
39 import javax.naming.NamingEnumeration;
40 import javax.naming.OperationNotSupportedException;
41 import javax.naming.directory.Attribute;
42 import javax.naming.directory.Attributes;
43 import javax.naming.directory.SearchControls;
44 import javax.naming.directory.SearchResult;
45 import javax.naming.ldap.Control;
46 import javax.naming.ldap.InitialLdapContext;
47 import javax.naming.ldap.LdapContext;
48 import javax.naming.ldap.PagedResultsControl;
49 import javax.naming.ldap.PagedResultsResponseControl;
50
51
63 public class PortalLDAPUtil {
64
65 public static LdapContext getContext(long ldapServerId, long companyId)
66 throws Exception {
67
68 String postfix = LDAPSettingsUtil.getPropertyPostfix(ldapServerId);
69
70 String baseProviderURL = PrefsPropsUtil.getString(
71 companyId, PropsKeys.LDAP_BASE_PROVIDER_URL + postfix);
72 String pricipal = PrefsPropsUtil.getString(
73 companyId, PropsKeys.LDAP_SECURITY_PRINCIPAL + postfix);
74 String credentials = PrefsPropsUtil.getString(
75 companyId, PropsKeys.LDAP_SECURITY_CREDENTIALS + postfix);
76
77 return getContext(companyId, baseProviderURL, pricipal, credentials);
78 }
79
80 public static LdapContext getContext(
81 long companyId, String providerURL, String principal,
82 String credentials)
83 throws Exception {
84
85 Properties env = new Properties();
86
87 env.put(
88 Context.INITIAL_CONTEXT_FACTORY,
89 PrefsPropsUtil.getString(
90 companyId, PropsKeys.LDAP_FACTORY_INITIAL));
91 env.put(Context.PROVIDER_URL, providerURL);
92 env.put(Context.SECURITY_PRINCIPAL, principal);
93 env.put(Context.SECURITY_CREDENTIALS, credentials);
94 env.put(
95 Context.REFERRAL,
96 PrefsPropsUtil.getString(companyId, PropsKeys.LDAP_REFERRAL));
97
98
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 Attributes getGroupAttributes(
125 long ldapServerId, long companyId, LdapContext ldapContext,
126 String fullDistinguishedName)
127 throws Exception {
128
129 return getGroupAttributes(ldapServerId, companyId, ldapContext,
130 fullDistinguishedName, false);
131 }
132
133 public static Attributes getGroupAttributes(
134 long ldapServerId, long companyId, LdapContext ldapContext,
135 String fullDistinguishedName, boolean includeReferenceAttributes)
136 throws Exception {
137
138 Properties groupMappings = LDAPSettingsUtil.getGroupMappings(
139 ldapServerId, companyId);
140
141 List<String> mappedGroupAttributeIds = new ArrayList<String>();
142
143 mappedGroupAttributeIds.add(groupMappings.getProperty("groupName"));
144 mappedGroupAttributeIds.add(groupMappings.getProperty("description"));
145
146 if (includeReferenceAttributes) {
147 mappedGroupAttributeIds.add(groupMappings.getProperty("user"));
148 }
149
150 return _getAttributes(
151 ldapContext, fullDistinguishedName,
152 mappedGroupAttributeIds.toArray(new String[0]));
153 }
154
155 public static List<SearchResult> getGroups(
156 long companyId, LdapContext ldapContext, int maxResults,
157 String baseDN, String groupFilter)
158 throws Exception {
159
160 return searchLDAP(
161 companyId, ldapContext, maxResults, baseDN, groupFilter, null);
162 }
163
164 public static List<SearchResult> getGroups(
165 long ldapServerId, long companyId, LdapContext ldapContext,
166 int maxResults)
167 throws Exception {
168
169 String postfix = LDAPSettingsUtil.getPropertyPostfix(ldapServerId);
170
171 String baseDN = PrefsPropsUtil.getString(
172 companyId, PropsKeys.LDAP_BASE_DN + postfix);
173 String groupFilter = PrefsPropsUtil.getString(
174 companyId, PropsKeys.LDAP_IMPORT_GROUP_SEARCH_FILTER + postfix);
175
176 return getGroups(
177 companyId, ldapContext, maxResults, baseDN, groupFilter);
178 }
179
180 public static long getLdapServerId(long companyId, String screenName)
181 throws Exception {
182
183 long[] ldapServerIds = StringUtil.split(
184 PrefsPropsUtil.getString(companyId, "ldap.server.ids"), 0L);
185
186 for (long ldapServerId : ldapServerIds) {
187 if (hasUser(ldapServerId, companyId, screenName)) {
188 return ldapServerId;
189 }
190 }
191
192 if (ldapServerIds.length > 0) {
193 return ldapServerIds[0];
194 }
195
196 return 0;
197 }
198
199 public static Attribute getMultivaluedAttribute(
200 long companyId, LdapContext ldapContext, String baseDN,
201 String filter, Attribute attribute)
202 throws Exception {
203
204 if (attribute.size() > 0) {
205 return attribute;
206 }
207
208 String[] attributeIds = {_getNextRange(attribute.getID())};
209
210 while (true) {
211 List<SearchResult> searchResults = searchLDAP(
212 companyId, ldapContext, 0, baseDN, filter, attributeIds);
213
214 if (searchResults.size() != 1) {
215 break;
216 }
217
218 SearchResult searchResult = searchResults.get(0);
219
220 Attributes attributes = searchResult.getAttributes();
221
222 if (attributes.size() != 1) {
223 break;
224 }
225
226 NamingEnumeration<? extends Attribute> enu = attributes.getAll();
227
228 if (!enu.hasMoreElements()) {
229 break;
230 }
231
232 Attribute curAttribute = enu.nextElement();
233
234 for (int i = 0; i < curAttribute.size(); i++) {
235 attribute.add(curAttribute.get(i));
236 }
237
238 if (StringUtil.endsWith(curAttribute.getID(), StringPool.STAR) ||
239 (curAttribute.size() < PropsValues.LDAP_RANGE_SIZE)) {
240
241 break;
242 }
243
244 attributeIds[0] = _getNextRange(attributeIds[0]);
245 }
246
247 return attribute;
248 }
249
250 public static String getNameInNamespace(
251 long ldapServerId, long companyId, Binding binding)
252 throws Exception {
253
254 String postfix = LDAPSettingsUtil.getPropertyPostfix(ldapServerId);
255
256 String baseDN = PrefsPropsUtil.getString(
257 companyId, PropsKeys.LDAP_BASE_DN + postfix);
258
259 String name = binding.getName();
260
261 if (name.startsWith(StringPool.QUOTE) &&
262 name.endsWith(StringPool.QUOTE)) {
263
264 name = name.substring(1, name.length() - 1);
265 }
266
267 if (Validator.isNull(baseDN)) {
268 return name.toString();
269 }
270 else {
271 return name.concat(StringPool.COMMA).concat(baseDN);
272 }
273 }
274
275 public static Binding getUser(
276 long ldapServerId, long companyId, String screenName)
277 throws Exception {
278
279 String postfix = LDAPSettingsUtil.getPropertyPostfix(ldapServerId);
280
281 LdapContext ldapContext = getContext(ldapServerId, companyId);
282
283 NamingEnumeration<SearchResult> enu = null;
284
285 try {
286 if (ldapContext == null) {
287 return null;
288 }
289
290 String baseDN = PrefsPropsUtil.getString(
291 companyId, PropsKeys.LDAP_BASE_DN + postfix);
292
293 Properties userMappings = LDAPSettingsUtil.getUserMappings(
294 ldapServerId, companyId);
295
296 StringBundler filter = new StringBundler(5);
297
298 filter.append(StringPool.OPEN_PARENTHESIS);
299 filter.append(userMappings.getProperty("screenName"));
300 filter.append(StringPool.EQUAL);
301 filter.append(screenName);
302 filter.append(StringPool.CLOSE_PARENTHESIS);
303
304 SearchControls cons = new SearchControls(
305 SearchControls.SUBTREE_SCOPE, 1, 0, null, false, false);
306
307 enu = ldapContext.search(baseDN, filter.toString(), cons);
308 }
309 catch (Exception e) {
310 throw e;
311 }
312 finally {
313 if (ldapContext != null) {
314 ldapContext.close();
315 }
316 }
317
318 if (enu.hasMoreElements()) {
319 Binding binding = enu.nextElement();
320
321 enu.close();
322
323 return binding;
324 }
325 else {
326 return null;
327 }
328 }
329
330 public static Attributes getUserAttributes(
331 long ldapServerId, long companyId, LdapContext ldapContext,
332 String fullDistinguishedName)
333 throws Exception {
334
335 Properties userMappings = LDAPSettingsUtil.getUserMappings(
336 ldapServerId, companyId);
337 Properties userExpandoMappings =
338 LDAPSettingsUtil.getUserExpandoMappings(
339 ldapServerId, companyId);
340
341 PropertiesUtil.merge(userMappings, userExpandoMappings);
342
343 Properties contactMappings = LDAPSettingsUtil.getContactMappings(
344 ldapServerId, companyId);
345 Properties contactExpandoMappings =
346 LDAPSettingsUtil.getContactExpandoMappings(ldapServerId, companyId);
347
348 PropertiesUtil.merge(contactMappings, contactExpandoMappings);
349
350 PropertiesUtil.merge(userMappings, contactMappings);
351
352 String[] mappedUserAttributeIds = ArrayUtil.toStringArray(
353 userMappings.values().toArray(new Object[userMappings.size()]));
354
355 return _getAttributes(
356 ldapContext, fullDistinguishedName, mappedUserAttributeIds);
357 }
358
359 public static List<SearchResult> getUsers(
360 long companyId, LdapContext ldapContext, int maxResults,
361 String baseDN, String userFilter)
362 throws Exception {
363
364 return searchLDAP(
365 companyId, ldapContext, maxResults, baseDN, userFilter, null);
366 }
367
368 public static List<SearchResult> getUsers(
369 long ldapServerId, long companyId, LdapContext ldapContext,
370 int maxResults)
371 throws Exception {
372
373 String postfix = LDAPSettingsUtil.getPropertyPostfix(ldapServerId);
374
375 String baseDN = PrefsPropsUtil.getString(
376 companyId, PropsKeys.LDAP_BASE_DN + postfix);
377 String userFilter = PrefsPropsUtil.getString(
378 companyId, PropsKeys.LDAP_IMPORT_USER_SEARCH_FILTER + postfix);
379
380 return getUsers(companyId, ldapContext, maxResults, baseDN, userFilter);
381 }
382
383 public static String getUsersDN(long ldapServerId, long companyId)
384 throws Exception {
385
386 String postfix = LDAPSettingsUtil.getPropertyPostfix(ldapServerId);
387
388 return PrefsPropsUtil.getString(
389 companyId, PropsKeys.LDAP_USERS_DN + postfix);
390 }
391
392 public static boolean hasUser(
393 long ldapServerId, long companyId, String screenName)
394 throws Exception {
395
396 if (getUser(ldapServerId, companyId, screenName) != null) {
397 return true;
398 }
399 else {
400 return false;
401 }
402 }
403
404 public static List<SearchResult> searchLDAP(
405 long companyId, LdapContext ldapContext, int maxResults,
406 String baseDN, String filter, String[] attributeIds)
407 throws Exception {
408
409 List<SearchResult> searchResults = new ArrayList<SearchResult>();
410
411 SearchControls cons = new SearchControls(
412 SearchControls.SUBTREE_SCOPE, maxResults, 0, attributeIds, false,
413 false);
414
415 try {
416 byte[] cookie = new byte[0];
417
418 while (cookie != null) {
419 if (cookie.length == 0) {
420 ldapContext.setRequestControls(
421 new Control[] {
422 new PagedResultsControl(
423 PropsValues.LDAP_PAGE_SIZE, Control.CRITICAL)
424 });
425 }
426 else {
427 ldapContext.setRequestControls(
428 new Control[] {
429 new PagedResultsControl(
430 PropsValues.LDAP_PAGE_SIZE, cookie,
431 Control.CRITICAL)
432 });
433 }
434
435 NamingEnumeration<SearchResult> enu = ldapContext.search(
436 baseDN, filter, cons);
437
438 while (enu.hasMoreElements()) {
439 searchResults.add(enu.nextElement());
440 }
441
442 enu.close();
443
444 cookie = _getCookie(ldapContext.getResponseControls());
445 }
446 }
447 catch (OperationNotSupportedException onse) {
448 ldapContext.setRequestControls(null);
449
450 NamingEnumeration<SearchResult> enu = ldapContext.search(
451 baseDN, filter, cons);
452
453 while (enu.hasMoreElements()) {
454 searchResults.add(enu.nextElement());
455 }
456
457 enu.close();
458 }
459 finally {
460 ldapContext.setRequestControls(null);
461 }
462
463 return searchResults;
464 }
465
466 private static Attributes _getAttributes(
467 LdapContext ldapContext, String fullDistinguishedName,
468 String[] attributeIds)
469 throws Exception {
470
471 Name fullDN = new CompositeName().add(fullDistinguishedName);
472
473 Attributes attributes = null;
474
475 String[] auditAttributeIds = {
476 "creatorsName", "createTimestamp", "modifiersName",
477 "modifyTimestamp"
478 };
479
480 if (attributeIds == null) {
481
482
484 attributes = ldapContext.getAttributes(fullDN);
485
486 NamingEnumeration<? extends Attribute> enu =
487 ldapContext.getAttributes(fullDN, auditAttributeIds).getAll();
488
489 while (enu.hasMoreElements()) {
490 attributes.put(enu.nextElement());
491 }
492
493 enu.close();
494 }
495 else {
496
497
499 int attributeCount = attributeIds.length + auditAttributeIds.length;
500
501 String[] allAttributeIds = new String[attributeCount];
502
503 System.arraycopy(
504 attributeIds, 0, allAttributeIds, 0, attributeIds.length);
505 System.arraycopy(
506 auditAttributeIds, 0, allAttributeIds, attributeIds.length,
507 auditAttributeIds.length);
508
509 attributes = ldapContext.getAttributes(fullDN, allAttributeIds);
510 }
511
512 return attributes;
513 }
514
515 private static byte[] _getCookie(Control[] controls) {
516 if (controls == null) {
517 return null;
518 }
519
520 for (Control control : controls) {
521 if (control instanceof PagedResultsResponseControl) {
522 PagedResultsResponseControl pagedResultsResponseControl =
523 (PagedResultsResponseControl)control;
524
525 return pagedResultsResponseControl.getCookie();
526 }
527 }
528
529 return null;
530 }
531
532 private static String _getNextRange(String attributeId) {
533 String originalAttributeId = null;
534 int start = 0;
535 int end = 0;
536
537 int x = attributeId.indexOf(StringPool.SEMICOLON);
538
539 if (x < 0) {
540 originalAttributeId = attributeId;
541 end = PropsValues.LDAP_RANGE_SIZE - 1;
542 }
543 else {
544 int y = attributeId.indexOf(StringPool.EQUAL, x);
545 int z = attributeId.indexOf(StringPool.DASH, y);
546
547 originalAttributeId = attributeId.substring(0, x);
548 start = GetterUtil.getInteger(attributeId.substring(y + 1, z));
549 end = GetterUtil.getInteger(attributeId.substring(z + 1));
550
551 start += PropsValues.LDAP_RANGE_SIZE;
552 end += PropsValues.LDAP_RANGE_SIZE;
553 }
554
555 StringBundler sb = new StringBundler(6);
556
557 sb.append(originalAttributeId);
558 sb.append(StringPool.SEMICOLON);
559 sb.append("range=");
560 sb.append(start);
561 sb.append(StringPool.DASH);
562 sb.append(end);
563
564 return sb.toString();
565 }
566
567 private static Log _log = LogFactoryUtil.getLog(PortalLDAPUtil.class);
568
569 }