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
061 public class PortalLDAPUtil {
062
063 public static LdapContext getContext(long ldapServerId, long companyId)
064 throws Exception {
065
066 String postfix = LDAPSettingsUtil.getPropertyPostfix(ldapServerId);
067
068 String baseProviderURL = PrefsPropsUtil.getString(
069 companyId, PropsKeys.LDAP_BASE_PROVIDER_URL + postfix);
070 String pricipal = PrefsPropsUtil.getString(
071 companyId, PropsKeys.LDAP_SECURITY_PRINCIPAL + postfix);
072 String credentials = PrefsPropsUtil.getString(
073 companyId, PropsKeys.LDAP_SECURITY_CREDENTIALS + postfix);
074
075 return getContext(companyId, baseProviderURL, pricipal, credentials);
076 }
077
078 public static LdapContext getContext(
079 long companyId, String providerURL, String principal,
080 String credentials)
081 throws Exception {
082
083 Properties env = new Properties();
084
085 env.put(
086 Context.INITIAL_CONTEXT_FACTORY,
087 PrefsPropsUtil.getString(
088 companyId, PropsKeys.LDAP_FACTORY_INITIAL));
089 env.put(Context.PROVIDER_URL, providerURL);
090 env.put(Context.SECURITY_PRINCIPAL, principal);
091 env.put(Context.SECURITY_CREDENTIALS, credentials);
092 env.put(
093 Context.REFERRAL,
094 PrefsPropsUtil.getString(companyId, PropsKeys.LDAP_REFERRAL));
095
096
097
098 env.put("com.sun.jndi.ldap.connect.pool", "true");
099 env.put("com.sun.jndi.ldap.connect.pool.maxsize","50");
100 env.put("com.sun.jndi.ldap.connect.pool.timeout", "10000");
101
102 LogUtil.debug(_log, env);
103
104 LdapContext ldapContext = null;
105
106 try {
107 ldapContext = new InitialLdapContext(env, null);
108 }
109 catch (Exception e) {
110 if (_log.isWarnEnabled()) {
111 _log.warn("Failed to bind to the LDAP server");
112 }
113
114 if (_log.isDebugEnabled()) {
115 _log.debug(e, e);
116 }
117 }
118
119 return ldapContext;
120 }
121
122 public static Attributes getGroupAttributes(
123 long ldapServerId, long companyId, LdapContext ldapContext,
124 String fullDistinguishedName)
125 throws Exception {
126
127 return getGroupAttributes(ldapServerId, companyId, ldapContext,
128 fullDistinguishedName, false);
129 }
130
131 public static Attributes getGroupAttributes(
132 long ldapServerId, long companyId, LdapContext ldapContext,
133 String fullDistinguishedName, boolean includeReferenceAttributes)
134 throws Exception {
135
136 Properties groupMappings = LDAPSettingsUtil.getGroupMappings(
137 ldapServerId, companyId);
138
139 List<String> mappedGroupAttributeIds = new ArrayList<String>();
140
141 mappedGroupAttributeIds.add(groupMappings.getProperty("groupName"));
142 mappedGroupAttributeIds.add(groupMappings.getProperty("description"));
143
144 if (includeReferenceAttributes) {
145 mappedGroupAttributeIds.add(groupMappings.getProperty("user"));
146 }
147
148 return _getAttributes(
149 ldapContext, fullDistinguishedName,
150 mappedGroupAttributeIds.toArray(new String[0]));
151 }
152
153 public static byte[] getGroups(
154 long companyId, LdapContext ldapContext, byte[] cookie,
155 int maxResults, String baseDN, String groupFilter,
156 List<SearchResult> searchResults)
157 throws Exception {
158
159 return searchLDAP(
160 companyId, ldapContext, cookie, maxResults, baseDN, groupFilter,
161 null, searchResults);
162 }
163
164 public static byte[] getGroups(
165 long ldapServerId, long companyId, LdapContext ldapContext,
166 byte[] cookie, int maxResults, List<SearchResult> searchResults)
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, cookie, maxResults, baseDN, groupFilter,
178 searchResults);
179 }
180
181 public static long getLdapServerId(long companyId, String screenName)
182 throws Exception {
183
184 long[] ldapServerIds = StringUtil.split(
185 PrefsPropsUtil.getString(companyId, "ldap.server.ids"), 0L);
186
187 for (long ldapServerId : ldapServerIds) {
188 if (hasUser(ldapServerId, companyId, screenName)) {
189 return ldapServerId;
190 }
191 }
192
193 if (ldapServerIds.length > 0) {
194 return ldapServerIds[0];
195 }
196
197 return 0;
198 }
199
200 public static Attribute getMultivaluedAttribute(
201 long companyId, LdapContext ldapContext, String baseDN,
202 String filter, Attribute attribute)
203 throws Exception {
204
205 if (attribute.size() > 0) {
206 return attribute;
207 }
208
209 String[] attributeIds = {_getNextRange(attribute.getID())};
210
211 while (true) {
212 List<SearchResult> searchResults = new ArrayList<SearchResult>();
213
214 searchLDAP(
215 companyId, ldapContext, new byte[0], 0, baseDN, filter,
216 attributeIds, searchResults);
217
218 if (searchResults.size() != 1) {
219 break;
220 }
221
222 SearchResult searchResult = searchResults.get(0);
223
224 Attributes attributes = searchResult.getAttributes();
225
226 if (attributes.size() != 1) {
227 break;
228 }
229
230 NamingEnumeration<? extends Attribute> enu = attributes.getAll();
231
232 if (!enu.hasMoreElements()) {
233 break;
234 }
235
236 Attribute curAttribute = enu.nextElement();
237
238 for (int i = 0; i < curAttribute.size(); i++) {
239 attribute.add(curAttribute.get(i));
240 }
241
242 if (StringUtil.endsWith(curAttribute.getID(), StringPool.STAR) ||
243 (curAttribute.size() < PropsValues.LDAP_RANGE_SIZE)) {
244
245 break;
246 }
247
248 attributeIds[0] = _getNextRange(attributeIds[0]);
249 }
250
251 return attribute;
252 }
253
254 public static String getNameInNamespace(
255 long ldapServerId, long companyId, Binding binding)
256 throws Exception {
257
258 String postfix = LDAPSettingsUtil.getPropertyPostfix(ldapServerId);
259
260 String baseDN = PrefsPropsUtil.getString(
261 companyId, PropsKeys.LDAP_BASE_DN + postfix);
262
263 String name = binding.getName();
264
265 if (name.startsWith(StringPool.QUOTE) &&
266 name.endsWith(StringPool.QUOTE)) {
267
268 name = name.substring(1, name.length() - 1);
269 }
270
271 if (Validator.isNull(baseDN)) {
272 return name.toString();
273 }
274 else {
275 return name.concat(StringPool.COMMA).concat(baseDN);
276 }
277 }
278
279 public static Binding getUser(
280 long ldapServerId, long companyId, String screenName)
281 throws Exception {
282
283 String postfix = LDAPSettingsUtil.getPropertyPostfix(ldapServerId);
284
285 LdapContext ldapContext = getContext(ldapServerId, companyId);
286
287 NamingEnumeration<SearchResult> enu = null;
288
289 try {
290 if (ldapContext == null) {
291 return null;
292 }
293
294 String baseDN = PrefsPropsUtil.getString(
295 companyId, PropsKeys.LDAP_BASE_DN + postfix);
296
297 Properties userMappings = LDAPSettingsUtil.getUserMappings(
298 ldapServerId, companyId);
299
300 StringBundler filter = new StringBundler(5);
301
302 filter.append(StringPool.OPEN_PARENTHESIS);
303 filter.append(userMappings.getProperty("screenName"));
304 filter.append(StringPool.EQUAL);
305 filter.append(screenName);
306 filter.append(StringPool.CLOSE_PARENTHESIS);
307
308 SearchControls searchControls = new SearchControls(
309 SearchControls.SUBTREE_SCOPE, 1, 0, null, false, false);
310
311 enu = ldapContext.search(baseDN, filter.toString(), searchControls);
312 }
313 catch (Exception e) {
314 throw e;
315 }
316 finally {
317 if (ldapContext != null) {
318 ldapContext.close();
319 }
320 }
321
322 if (enu.hasMoreElements()) {
323 Binding binding = enu.nextElement();
324
325 enu.close();
326
327 return binding;
328 }
329 else {
330 return null;
331 }
332 }
333
334 public static Attributes getUserAttributes(
335 long ldapServerId, long companyId, LdapContext ldapContext,
336 String fullDistinguishedName)
337 throws Exception {
338
339 Properties userMappings = LDAPSettingsUtil.getUserMappings(
340 ldapServerId, companyId);
341 Properties userExpandoMappings =
342 LDAPSettingsUtil.getUserExpandoMappings(
343 ldapServerId, companyId);
344
345 PropertiesUtil.merge(userMappings, userExpandoMappings);
346
347 Properties contactMappings = LDAPSettingsUtil.getContactMappings(
348 ldapServerId, companyId);
349 Properties contactExpandoMappings =
350 LDAPSettingsUtil.getContactExpandoMappings(ldapServerId, companyId);
351
352 PropertiesUtil.merge(contactMappings, contactExpandoMappings);
353
354 PropertiesUtil.merge(userMappings, contactMappings);
355
356 String[] mappedUserAttributeIds = ArrayUtil.toStringArray(
357 userMappings.values().toArray(new Object[userMappings.size()]));
358
359 return _getAttributes(
360 ldapContext, fullDistinguishedName, mappedUserAttributeIds);
361 }
362
363 public static byte[] getUsers(
364 long companyId, LdapContext ldapContext, byte[] cookie,
365 int maxResults, String baseDN, String userFilter,
366 List<SearchResult> searchResults)
367 throws Exception {
368
369 return searchLDAP(
370 companyId, ldapContext, cookie, maxResults, baseDN, userFilter,
371 null, searchResults);
372 }
373
374 public static byte[] getUsers(
375 long ldapServerId, long companyId, LdapContext ldapContext,
376 byte[] cookie, int maxResults, List<SearchResult> searchResults)
377 throws Exception {
378
379 String postfix = LDAPSettingsUtil.getPropertyPostfix(ldapServerId);
380
381 String baseDN = PrefsPropsUtil.getString(
382 companyId, PropsKeys.LDAP_BASE_DN + postfix);
383 String userFilter = PrefsPropsUtil.getString(
384 companyId, PropsKeys.LDAP_IMPORT_USER_SEARCH_FILTER + postfix);
385
386 return getUsers(
387 companyId, ldapContext, cookie, maxResults, baseDN, userFilter,
388 searchResults);
389 }
390
391 public static String getUsersDN(long ldapServerId, long companyId)
392 throws Exception {
393
394 String postfix = LDAPSettingsUtil.getPropertyPostfix(ldapServerId);
395
396 return PrefsPropsUtil.getString(
397 companyId, PropsKeys.LDAP_USERS_DN + postfix);
398 }
399
400 public static boolean hasUser(
401 long ldapServerId, long companyId, String screenName)
402 throws Exception {
403
404 if (getUser(ldapServerId, companyId, screenName) != null) {
405 return true;
406 }
407 else {
408 return false;
409 }
410 }
411
412 public static byte[] searchLDAP(
413 long companyId, LdapContext ldapContext, byte[] cookie,
414 int maxResults, String baseDN, String filter,
415 String[] attributeIds, List<SearchResult> searchResults)
416 throws Exception {
417
418 SearchControls searchControls = new SearchControls(
419 SearchControls.SUBTREE_SCOPE, maxResults, 0, attributeIds, false,
420 false);
421
422 try {
423 if (cookie != null) {
424 if (cookie.length == 0) {
425 ldapContext.setRequestControls(
426 new Control[] {
427 new PagedResultsControl(
428 PropsValues.LDAP_PAGE_SIZE, Control.CRITICAL)
429 });
430 }
431 else {
432 ldapContext.setRequestControls(
433 new Control[] {
434 new PagedResultsControl(
435 PropsValues.LDAP_PAGE_SIZE, cookie,
436 Control.CRITICAL)
437 });
438 }
439
440 NamingEnumeration<SearchResult> enu = ldapContext.search(
441 baseDN, filter, searchControls);
442
443 while (enu.hasMoreElements()) {
444 searchResults.add(enu.nextElement());
445 }
446
447 enu.close();
448
449 return _getCookie(ldapContext.getResponseControls());
450 }
451 }
452 catch (OperationNotSupportedException onse) {
453 ldapContext.setRequestControls(null);
454
455 NamingEnumeration<SearchResult> enu = ldapContext.search(
456 baseDN, filter, searchControls);
457
458 while (enu.hasMoreElements()) {
459 searchResults.add(enu.nextElement());
460 }
461
462 enu.close();
463 }
464 finally {
465 ldapContext.setRequestControls(null);
466 }
467
468 return null;
469 }
470
471 private static Attributes _getAttributes(
472 LdapContext ldapContext, String fullDistinguishedName,
473 String[] attributeIds)
474 throws Exception {
475
476 Name fullDN = new CompositeName().add(fullDistinguishedName);
477
478 Attributes attributes = null;
479
480 String[] auditAttributeIds = {
481 "creatorsName", "createTimestamp", "modifiersName",
482 "modifyTimestamp"
483 };
484
485 if (attributeIds == null) {
486
487
488
489 attributes = ldapContext.getAttributes(fullDN);
490
491 NamingEnumeration<? extends Attribute> enu =
492 ldapContext.getAttributes(fullDN, auditAttributeIds).getAll();
493
494 while (enu.hasMoreElements()) {
495 attributes.put(enu.nextElement());
496 }
497
498 enu.close();
499 }
500 else {
501
502
503
504 int attributeCount = attributeIds.length + auditAttributeIds.length;
505
506 String[] allAttributeIds = new String[attributeCount];
507
508 System.arraycopy(
509 attributeIds, 0, allAttributeIds, 0, attributeIds.length);
510 System.arraycopy(
511 auditAttributeIds, 0, allAttributeIds, attributeIds.length,
512 auditAttributeIds.length);
513
514 attributes = ldapContext.getAttributes(fullDN, allAttributeIds);
515 }
516
517 return attributes;
518 }
519
520 private static byte[] _getCookie(Control[] controls) {
521 if (controls == null) {
522 return null;
523 }
524
525 for (Control control : controls) {
526 if (control instanceof PagedResultsResponseControl) {
527 PagedResultsResponseControl pagedResultsResponseControl =
528 (PagedResultsResponseControl)control;
529
530 return pagedResultsResponseControl.getCookie();
531 }
532 }
533
534 return null;
535 }
536
537 private static String _getNextRange(String attributeId) {
538 String originalAttributeId = null;
539 int start = 0;
540 int end = 0;
541
542 int x = attributeId.indexOf(StringPool.SEMICOLON);
543
544 if (x < 0) {
545 originalAttributeId = attributeId;
546 end = PropsValues.LDAP_RANGE_SIZE - 1;
547 }
548 else {
549 int y = attributeId.indexOf(StringPool.EQUAL, x);
550 int z = attributeId.indexOf(StringPool.DASH, y);
551
552 originalAttributeId = attributeId.substring(0, x);
553 start = GetterUtil.getInteger(attributeId.substring(y + 1, z));
554 end = GetterUtil.getInteger(attributeId.substring(z + 1));
555
556 start += PropsValues.LDAP_RANGE_SIZE;
557 end += PropsValues.LDAP_RANGE_SIZE;
558 }
559
560 StringBundler sb = new StringBundler(6);
561
562 sb.append(originalAttributeId);
563 sb.append(StringPool.SEMICOLON);
564 sb.append("range=");
565 sb.append(start);
566 sb.append(StringPool.DASH);
567 sb.append(end);
568
569 return sb.toString();
570 }
571
572 private static Log _log = LogFactoryUtil.getLog(PortalLDAPUtil.class);
573
574 }