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 contactMappings = LDAPSettingsUtil.getContactMappings(
338 ldapServerId, companyId);
339
340 PropertiesUtil.merge(userMappings, contactMappings);
341
342 String[] mappedUserAttributeIds = ArrayUtil.toStringArray(
343 userMappings.values().toArray(new Object[userMappings.size()]));
344
345 return _getAttributes(
346 ldapContext, fullDistinguishedName, mappedUserAttributeIds);
347 }
348
349 public static List<SearchResult> getUsers(
350 long companyId, LdapContext ldapContext, int maxResults,
351 String baseDN, String userFilter)
352 throws Exception {
353
354 return searchLDAP(
355 companyId, ldapContext, maxResults, baseDN, userFilter, null);
356 }
357
358 public static List<SearchResult> getUsers(
359 long ldapServerId, long companyId, LdapContext ldapContext,
360 int maxResults)
361 throws Exception {
362
363 String postfix = LDAPSettingsUtil.getPropertyPostfix(ldapServerId);
364
365 String baseDN = PrefsPropsUtil.getString(
366 companyId, PropsKeys.LDAP_BASE_DN + postfix);
367 String userFilter = PrefsPropsUtil.getString(
368 companyId, PropsKeys.LDAP_IMPORT_USER_SEARCH_FILTER + postfix);
369
370 return getUsers(companyId, ldapContext, maxResults, baseDN, userFilter);
371 }
372
373 public static String getUsersDN(long ldapServerId, long companyId)
374 throws Exception {
375
376 String postfix = LDAPSettingsUtil.getPropertyPostfix(ldapServerId);
377
378 return PrefsPropsUtil.getString(
379 companyId, PropsKeys.LDAP_USERS_DN + postfix);
380 }
381
382 public static boolean hasUser(
383 long ldapServerId, long companyId, String screenName)
384 throws Exception {
385
386 if (getUser(ldapServerId, companyId, screenName) != null) {
387 return true;
388 }
389 else {
390 return false;
391 }
392 }
393
394 public static List<SearchResult> searchLDAP(
395 long companyId, LdapContext ldapContext, int maxResults,
396 String baseDN, String filter, String[] attributeIds)
397 throws Exception {
398
399 List<SearchResult> searchResults = new ArrayList<SearchResult>();
400
401 SearchControls cons = new SearchControls(
402 SearchControls.SUBTREE_SCOPE, maxResults, 0, attributeIds, false,
403 false);
404
405 try {
406 byte[] cookie = new byte[0];
407
408 while (cookie != null) {
409 if (cookie.length == 0) {
410 ldapContext.setRequestControls(
411 new Control[] {
412 new PagedResultsControl(
413 PropsValues.LDAP_PAGE_SIZE, Control.CRITICAL)
414 });
415 }
416 else {
417 ldapContext.setRequestControls(
418 new Control[] {
419 new PagedResultsControl(
420 PropsValues.LDAP_PAGE_SIZE, cookie,
421 Control.CRITICAL)
422 });
423 }
424
425 NamingEnumeration<SearchResult> enu = ldapContext.search(
426 baseDN, filter, cons);
427
428 while (enu.hasMoreElements()) {
429 searchResults.add(enu.nextElement());
430 }
431
432 enu.close();
433
434 cookie = _getCookie(ldapContext.getResponseControls());
435 }
436 }
437 catch (OperationNotSupportedException onse) {
438 ldapContext.setRequestControls(null);
439
440 NamingEnumeration<SearchResult> enu = ldapContext.search(
441 baseDN, filter, cons);
442
443 while (enu.hasMoreElements()) {
444 searchResults.add(enu.nextElement());
445 }
446
447 enu.close();
448 }
449 finally {
450 ldapContext.setRequestControls(null);
451 }
452
453 return searchResults;
454 }
455
456 private static Attributes _getAttributes(
457 LdapContext ldapContext, String fullDistinguishedName,
458 String[] attributeIds)
459 throws Exception {
460
461 Name fullDN = new CompositeName().add(fullDistinguishedName);
462
463 Attributes attributes = null;
464
465 String[] auditAttributeIds = {
466 "creatorsName", "createTimestamp", "modifiersName",
467 "modifyTimestamp"
468 };
469
470 if (attributeIds == null) {
471
472
474 attributes = ldapContext.getAttributes(fullDN);
475
476 NamingEnumeration<? extends Attribute> enu =
477 ldapContext.getAttributes(fullDN, auditAttributeIds).getAll();
478
479 while (enu.hasMoreElements()) {
480 attributes.put(enu.nextElement());
481 }
482
483 enu.close();
484 }
485 else {
486
487
489 int attributeCount = attributeIds.length + auditAttributeIds.length;
490
491 String[] allAttributeIds = new String[attributeCount];
492
493 System.arraycopy(
494 attributeIds, 0, allAttributeIds, 0, attributeIds.length);
495 System.arraycopy(
496 auditAttributeIds, 0, allAttributeIds, attributeIds.length,
497 auditAttributeIds.length);
498
499 attributes = ldapContext.getAttributes(fullDN, allAttributeIds);
500 }
501
502 return attributes;
503 }
504
505 private static byte[] _getCookie(Control[] controls) {
506 if (controls == null) {
507 return null;
508 }
509
510 for (Control control : controls) {
511 if (control instanceof PagedResultsResponseControl) {
512 PagedResultsResponseControl pagedResultsResponseControl =
513 (PagedResultsResponseControl)control;
514
515 return pagedResultsResponseControl.getCookie();
516 }
517 }
518
519 return null;
520 }
521
522 private static String _getNextRange(String attributeId) {
523 String originalAttributeId = null;
524 int start = 0;
525 int end = 0;
526
527 int x = attributeId.indexOf(StringPool.SEMICOLON);
528
529 if (x < 0) {
530 originalAttributeId = attributeId;
531 end = PropsValues.LDAP_RANGE_SIZE - 1;
532 }
533 else {
534 int y = attributeId.indexOf(StringPool.EQUAL, x);
535 int z = attributeId.indexOf(StringPool.DASH, y);
536
537 originalAttributeId = attributeId.substring(0, x);
538 start = GetterUtil.getInteger(attributeId.substring(y + 1, z));
539 end = GetterUtil.getInteger(attributeId.substring(z + 1));
540
541 start += PropsValues.LDAP_RANGE_SIZE;
542 end += PropsValues.LDAP_RANGE_SIZE;
543 }
544
545 StringBundler sb = new StringBundler(6);
546
547 sb.append(originalAttributeId);
548 sb.append(StringPool.SEMICOLON);
549 sb.append("range=");
550 sb.append(start);
551 sb.append(StringPool.DASH);
552 sb.append(end);
553
554 return sb.toString();
555 }
556
557 private static Log _log = LogFactoryUtil.getLog(PortalLDAPUtil.class);
558
559 }