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