1
22
23 package com.liferay.portal.security.ldap;
24
25 import com.liferay.portal.NoSuchUserException;
26 import com.liferay.portal.NoSuchUserGroupException;
27 import com.liferay.portal.SystemException;
28 import com.liferay.portal.kernel.log.Log;
29 import com.liferay.portal.kernel.log.LogFactoryUtil;
30 import com.liferay.portal.kernel.log.LogUtil;
31 import com.liferay.portal.kernel.util.ArrayUtil;
32 import com.liferay.portal.kernel.util.CalendarFactoryUtil;
33 import com.liferay.portal.kernel.util.DateFormatFactoryUtil;
34 import com.liferay.portal.kernel.util.GetterUtil;
35 import com.liferay.portal.kernel.util.InstancePool;
36 import com.liferay.portal.kernel.util.PropertiesUtil;
37 import com.liferay.portal.kernel.util.PropsKeys;
38 import com.liferay.portal.kernel.util.StringPool;
39 import com.liferay.portal.kernel.util.StringUtil;
40 import com.liferay.portal.kernel.util.Validator;
41 import com.liferay.portal.model.Company;
42 import com.liferay.portal.model.CompanyConstants;
43 import com.liferay.portal.model.Contact;
44 import com.liferay.portal.model.User;
45 import com.liferay.portal.model.UserGroup;
46 import com.liferay.portal.model.UserGroupRole;
47 import com.liferay.portal.security.auth.ScreenNameGenerator;
48 import com.liferay.portal.service.CompanyLocalServiceUtil;
49 import com.liferay.portal.service.ServiceContext;
50 import com.liferay.portal.service.UserGroupLocalServiceUtil;
51 import com.liferay.portal.service.UserLocalServiceUtil;
52 import com.liferay.portal.util.PrefsPropsUtil;
53 import com.liferay.portal.util.PropsValues;
54 import com.liferay.util.ldap.LDAPUtil;
55 import com.liferay.util.ldap.Modifications;
56
57 import java.text.DateFormat;
58 import java.text.ParseException;
59
60 import java.util.ArrayList;
61 import java.util.Calendar;
62 import java.util.Date;
63 import java.util.List;
64 import java.util.Locale;
65 import java.util.Properties;
66
67 import javax.naming.Binding;
68 import javax.naming.CompositeName;
69 import javax.naming.Context;
70 import javax.naming.Name;
71 import javax.naming.NameNotFoundException;
72 import javax.naming.NamingEnumeration;
73 import javax.naming.OperationNotSupportedException;
74 import javax.naming.directory.Attribute;
75 import javax.naming.directory.Attributes;
76 import javax.naming.directory.ModificationItem;
77 import javax.naming.directory.SearchControls;
78 import javax.naming.directory.SearchResult;
79 import javax.naming.ldap.Control;
80 import javax.naming.ldap.InitialLdapContext;
81 import javax.naming.ldap.LdapContext;
82 import javax.naming.ldap.PagedResultsControl;
83 import javax.naming.ldap.PagedResultsResponseControl;
84
85
96 public class PortalLDAPUtil {
97
98 public static final String IMPORT_BY_GROUP = "group";
99
100 public static final String IMPORT_BY_USER = "user";
101
102 public static void exportToLDAP(Contact contact) throws Exception {
103 long companyId = contact.getCompanyId();
104
105 if (!isAuthEnabled(companyId) || !isExportEnabled(companyId)) {
106 return;
107 }
108
109 User user = UserLocalServiceUtil.getUserByContactId(
110 contact.getContactId());
111
112 long ldapServerId = getLdapServerId(companyId, user.getScreenName());
113
114 LdapContext ctx = getContext(ldapServerId, companyId);
115
116 try {
117 if (ctx == null) {
118 return;
119 }
120
121 Properties userMappings = getUserMappings(ldapServerId, companyId);
122 Binding binding = getUser(
123 ldapServerId, contact.getCompanyId(), user.getScreenName());
124 Name name = new CompositeName();
125
126 if (binding == null) {
127
128
130 _getDNName(ldapServerId, companyId, user, userMappings, name);
131
132 LDAPUser ldapUser = (LDAPUser)Class.forName(
133 PropsValues.LDAP_USER_IMPL).newInstance();
134
135 ldapUser.setUser(user, ldapServerId);
136
137 ctx.bind(name, ldapUser);
138 }
139 else {
140
141
143 name.add(getNameInNamespace(ldapServerId, companyId, binding));
144
145 Modifications mods = Modifications.getInstance();
146
147 mods.addItem(
148 userMappings.getProperty("firstName"),
149 contact.getFirstName());
150 mods.addItem(
151 userMappings.getProperty("lastName"),
152 contact.getLastName());
153
154 String fullNameMapping = userMappings.getProperty("fullName");
155
156 if (Validator.isNotNull(fullNameMapping)) {
157 mods.addItem(fullNameMapping, contact.getFullName());
158 }
159
160 String jobTitleMapping = userMappings.getProperty("jobTitle");
161
162 if (Validator.isNotNull(jobTitleMapping)) {
163 mods.addItem(jobTitleMapping, contact.getJobTitle());
164 }
165
166 ModificationItem[] modItems = mods.getItems();
167
168 ctx.modifyAttributes(name, modItems);
169 }
170 }
171 catch (Exception e) {
172 throw e;
173 }
174 finally {
175 if (ctx != null) {
176 ctx.close();
177 }
178 }
179 }
180
181 public static void exportToLDAP(User user) throws Exception {
182 long companyId = user.getCompanyId();
183
184 if (!isAuthEnabled(companyId) || !isExportEnabled(companyId)) {
185 return;
186 }
187
188 long ldapServerId = getLdapServerId(companyId, user.getScreenName());
189
190 LdapContext ctx = getContext(ldapServerId, companyId);
191
192 try {
193 if (ctx == null) {
194 return;
195 }
196
197 Properties userMappings = getUserMappings(ldapServerId, companyId);
198 Binding binding = getUser(
199 ldapServerId, user.getCompanyId(), user.getScreenName());
200 Name name = new CompositeName();
201
202 if (binding == null) {
203
204
206 _getDNName(ldapServerId, companyId, user, userMappings, name);
207
208 LDAPUser ldapUser = (LDAPUser)Class.forName(
209 PropsValues.LDAP_USER_IMPL).newInstance();
210
211 ldapUser.setUser(user, ldapServerId);
212
213 ctx.bind(name, ldapUser);
214
215 binding = getUser(ldapServerId, user.getCompanyId(),
216 user.getScreenName());
217
218 name = new CompositeName();
219 }
220
221
223 name.add(getNameInNamespace(ldapServerId, companyId, binding));
224
225 Modifications mods = Modifications.getInstance();
226
227 mods.addItem(
228 userMappings.getProperty("firstName"), user.getFirstName());
229 mods.addItem(
230 userMappings.getProperty("lastName"), user.getLastName());
231
232 String fullNameMapping = userMappings.getProperty("fullName");
233
234 if (Validator.isNotNull(fullNameMapping)) {
235 mods.addItem(fullNameMapping, user.getFullName());
236 }
237
238 if (user.isPasswordModified() &&
239 Validator.isNotNull(user.getPasswordUnencrypted())) {
240
241 mods.addItem(
242 userMappings.getProperty("password"),
243 user.getPasswordUnencrypted());
244 }
245
246 if (Validator.isNotNull(user.getEmailAddress())) {
247 mods.addItem(
248 userMappings.getProperty("emailAddress"),
249 user.getEmailAddress());
250 }
251
252 String jobTitleMapping = userMappings.getProperty("jobTitle");
253
254 if (Validator.isNotNull(jobTitleMapping)) {
255 mods.addItem(jobTitleMapping, user.getJobTitle());
256 }
257
258 ModificationItem[] modItems = mods.getItems();
259
260 ctx.modifyAttributes(name, modItems);
261 }
262 catch (Exception e) {
263 _log.error(e, e);
264 }
265 finally {
266 if (ctx != null) {
267 ctx.close();
268 }
269 }
270 }
271
272 public static String getAuthSearchFilter(
273 long ldapServerId, long companyId, String emailAddress,
274 String screenName, String userId)
275 throws SystemException {
276
277 String postfix = getPropertyPostfix(ldapServerId);
278
279 String filter = PrefsPropsUtil.getString(
280 companyId, PropsKeys.LDAP_AUTH_SEARCH_FILTER + postfix);
281
282 if (_log.isDebugEnabled()) {
283 _log.debug("Search filter before transformation " + filter);
284 }
285
286 filter = StringUtil.replace(
287 filter,
288 new String[] {
289 "@company_id@", "@email_address@", "@screen_name@", "@user_id@"
290 },
291 new String[] {
292 String.valueOf(companyId), emailAddress, screenName,
293 userId
294 });
295
296 if (_log.isDebugEnabled()) {
297 _log.debug("Search filter after transformation " + filter);
298 }
299
300 return filter;
301 }
302
303 public static LdapContext getContext(long ldapServerId, long companyId)
304 throws Exception {
305
306 String postfix = getPropertyPostfix(ldapServerId);
307
308 String baseProviderURL = PrefsPropsUtil.getString(
309 companyId, PropsKeys.LDAP_BASE_PROVIDER_URL + postfix);
310 String pricipal = PrefsPropsUtil.getString(
311 companyId, PropsKeys.LDAP_SECURITY_PRINCIPAL + postfix);
312 String credentials = PrefsPropsUtil.getString(
313 companyId, PropsKeys.LDAP_SECURITY_CREDENTIALS + postfix);
314
315 return getContext(companyId, baseProviderURL, pricipal, credentials);
316 }
317
318 public static LdapContext getContext(
319 long companyId, String providerURL, String pricipal,
320 String credentials)
321 throws Exception {
322
323 Properties env = new Properties();
324
325 env.put(
326 Context.INITIAL_CONTEXT_FACTORY,
327 PrefsPropsUtil.getString(
328 companyId, PropsKeys.LDAP_FACTORY_INITIAL));
329 env.put(Context.PROVIDER_URL, providerURL);
330 env.put(Context.SECURITY_PRINCIPAL, pricipal);
331 env.put(Context.SECURITY_CREDENTIALS, credentials);
332 env.put(
333 Context.REFERRAL,
334 PrefsPropsUtil.getString(companyId, PropsKeys.LDAP_REFERRAL));
335
336
338 env.put("com.sun.jndi.ldap.connect.pool", "true");
339 env.put("com.sun.jndi.ldap.connect.pool.maxsize","50");
340 env.put("com.sun.jndi.ldap.connect.pool.timeout", "10000");
341
342 LogUtil.debug(_log, env);
343
344 LdapContext ctx = null;
345
346 try {
347 ctx = new InitialLdapContext(env, null);
348 }
349 catch (Exception e) {
350 if (_log.isWarnEnabled()) {
351 _log.warn("Failed to bind to the LDAP server");
352 }
353
354 if (_log.isDebugEnabled()) {
355 _log.debug(e);
356 }
357 }
358
359 return ctx;
360 }
361
362 public static Attributes getGroupAttributes(
363 long ldapServerId, long companyId, LdapContext ctx,
364 String fullDistinguishedName)
365 throws Exception {
366
367 return getGroupAttributes(ldapServerId, companyId, ctx,
368 fullDistinguishedName, false);
369 }
370
371 public static Attributes getGroupAttributes(
372 long ldapServerId, long companyId, LdapContext ctx,
373 String fullDistinguishedName, boolean includeReferenceAttributes)
374 throws Exception {
375
376 Properties groupMappings = getGroupMappings(ldapServerId, companyId);
377
378 List<String> mappedGroupAttributeIds = new ArrayList<String>();
379
380 mappedGroupAttributeIds.add(groupMappings.getProperty("groupName"));
381 mappedGroupAttributeIds.add(groupMappings.getProperty("description"));
382
383 if (includeReferenceAttributes) {
384 mappedGroupAttributeIds.add(groupMappings.getProperty("user"));
385 }
386
387 return _getAttributes(
388 ctx, fullDistinguishedName,
389 mappedGroupAttributeIds.toArray(new String[0]));
390 }
391
392 public static Properties getGroupMappings(long ldapServerId, long companyId)
393 throws Exception {
394
395 String postfix = getPropertyPostfix(ldapServerId);
396
397 Properties groupMappings = PropertiesUtil.load(
398 PrefsPropsUtil.getString(companyId,
399 PropsKeys.LDAP_GROUP_MAPPINGS + postfix));
400
401 LogUtil.debug(_log, groupMappings);
402
403 return groupMappings;
404 }
405
406 public static List<SearchResult> getGroups(
407 long companyId, LdapContext ctx, int maxResults, String baseDN,
408 String groupFilter)
409 throws Exception {
410
411 return _searchLDAP(
412 companyId, ctx, maxResults, baseDN, groupFilter, null);
413 }
414
415 public static List<SearchResult> getGroups(
416 long ldapServerId, long companyId, LdapContext ctx, int maxResults)
417 throws Exception {
418
419 String postfix = getPropertyPostfix(ldapServerId);
420
421 String baseDN = PrefsPropsUtil.getString(
422 companyId, PropsKeys.LDAP_BASE_DN + postfix);
423 String groupFilter = PrefsPropsUtil.getString(
424 companyId, PropsKeys.LDAP_IMPORT_GROUP_SEARCH_FILTER + postfix);
425
426 return getGroups(companyId, ctx, maxResults, baseDN, groupFilter);
427 }
428
429 public static long getLdapServerId(long companyId, String screenName)
430 throws Exception {
431
432 long[] ldapServerIds = StringUtil.split(
433 PrefsPropsUtil.getString(companyId, "ldap.server.ids"), 0L);
434
435 for (long ldapServerId : ldapServerIds) {
436 if (hasUser(ldapServerId, companyId, screenName)) {
437 return ldapServerId;
438 }
439 }
440
441 if (ldapServerIds.length > 0) {
442 return ldapServerIds[0];
443 }
444
445 return 0;
446 }
447
448 public static Attribute getMultivaluedAttribute(
449 long companyId, LdapContext ctx, String baseDN, String filter,
450 Attribute attribute)
451 throws Exception {
452
453 if (attribute.size() > 0) {
454 return attribute;
455 }
456
457 String[] attributeIds = {_getNextRange(attribute.getID())};
458
459 while (true) {
460 List<SearchResult> results = _searchLDAP(
461 companyId, ctx, 0, baseDN, filter, attributeIds);
462
463 if (results.size() != 1) {
464 break;
465 }
466
467 SearchResult result = results.get(0);
468
469 Attributes attributes = result.getAttributes();
470
471 if (attributes.size() != 1) {
472 break;
473 }
474
475 NamingEnumeration<? extends Attribute> enu = attributes.getAll();
476
477 if (!enu.hasMoreElements()) {
478 break;
479 }
480
481 Attribute curAttribute = enu.nextElement();
482
483 for (int i = 0; i < curAttribute.size(); i++) {
484 attribute.add(curAttribute.get(i));
485 }
486
487 if (StringUtil.endsWith(curAttribute.getID(), StringPool.STAR) ||
488 (curAttribute.size() < PropsValues.LDAP_RANGE_SIZE)) {
489
490 break;
491 }
492
493 attributeIds[0] = _getNextRange(attributeIds[0]);
494 }
495
496 return attribute;
497 }
498
499 public static String getNameInNamespace(
500 long ldapServerId, long companyId, Binding binding)
501 throws Exception {
502
503 String postfix = getPropertyPostfix(ldapServerId);
504
505 String baseDN = PrefsPropsUtil.getString(
506 companyId, PropsKeys.LDAP_BASE_DN + postfix);
507
508 String name = binding.getName();
509
510 if (name.startsWith(StringPool.QUOTE) &&
511 name.endsWith(StringPool.QUOTE)) {
512
513 name = name.substring(1, name.length() - 1);
514 }
515
516 if (Validator.isNull(baseDN)) {
517 return name.toString();
518 }
519 else {
520 StringBuilder sb = new StringBuilder();
521
522 sb.append(name);
523 sb.append(StringPool.COMMA);
524 sb.append(baseDN);
525
526 return sb.toString();
527 }
528 }
529
530 public static String getPropertyPostfix(long ldapServerId) {
531 if (ldapServerId > 0) {
532 return StringPool.PERIOD + ldapServerId;
533 }
534
535 return StringPool.BLANK;
536 }
537
538 public static Binding getUser(
539 long ldapServerId, long companyId, String screenName)
540 throws Exception {
541
542 String postfix = getPropertyPostfix(ldapServerId);
543
544 LdapContext ctx = getContext(ldapServerId, companyId);
545
546 NamingEnumeration<SearchResult> enu = null;
547
548 try {
549 if (ctx == null) {
550 return null;
551 }
552
553 String baseDN = PrefsPropsUtil.getString(
554 companyId, PropsKeys.LDAP_BASE_DN + postfix);
555
556 Properties userMappings = getUserMappings(ldapServerId, companyId);
557
558 StringBuilder filter = new StringBuilder();
559
560 filter.append(StringPool.OPEN_PARENTHESIS);
561 filter.append(userMappings.getProperty("screenName"));
562 filter.append(StringPool.EQUAL);
563 filter.append(screenName);
564 filter.append(StringPool.CLOSE_PARENTHESIS);
565
566 SearchControls cons = new SearchControls(
567 SearchControls.SUBTREE_SCOPE, 1, 0, null, false, false);
568
569 enu = ctx.search(baseDN, filter.toString(), cons);
570 }
571 catch (Exception e) {
572 throw e;
573 }
574 finally {
575 if (ctx != null) {
576 ctx.close();
577 }
578 }
579
580 if (enu.hasMoreElements()) {
581 Binding binding = enu.nextElement();
582
583 enu.close();
584
585 return binding;
586 }
587 else {
588 return null;
589 }
590 }
591
592 public static Attributes getUserAttributes(
593 long ldapServerId, long companyId, LdapContext ctx,
594 String fullDistinguishedName)
595 throws Exception {
596
597 Properties userMappings = getUserMappings(ldapServerId, companyId);
598
599 String[] mappedUserAttributeIds = {
600 userMappings.getProperty("screenName"),
601 userMappings.getProperty("emailAddress"),
602 userMappings.getProperty("fullName"),
603 userMappings.getProperty("firstName"),
604 userMappings.getProperty("middleName"),
605 userMappings.getProperty("lastName"),
606 userMappings.getProperty("jobTitle"),
607 userMappings.getProperty("group")
608 };
609
610 return _getAttributes(
611 ctx, fullDistinguishedName, mappedUserAttributeIds);
612 }
613
614 public static Properties getUserMappings(long ldapServerId, long companyId)
615 throws Exception {
616
617 String postfix = getPropertyPostfix(ldapServerId);
618
619 Properties userMappings = PropertiesUtil.load(
620 PrefsPropsUtil.getString(companyId,
621 PropsKeys.LDAP_USER_MAPPINGS + postfix));
622
623 LogUtil.debug(_log, userMappings);
624
625 return userMappings;
626 }
627
628 public static List<SearchResult> getUsers(
629 long companyId, LdapContext ctx, int maxResults, String baseDN,
630 String userFilter)
631 throws Exception {
632
633 return _searchLDAP(
634 companyId, ctx, maxResults, baseDN, userFilter, null);
635 }
636
637 public static List<SearchResult> getUsers(
638 long ldapServerId, long companyId, LdapContext ctx, int maxResults)
639 throws Exception {
640
641 String postfix = getPropertyPostfix(ldapServerId);
642
643 String baseDN = PrefsPropsUtil.getString(
644 companyId, PropsKeys.LDAP_BASE_DN + postfix);
645 String userFilter = PrefsPropsUtil.getString(
646 companyId, PropsKeys.LDAP_IMPORT_USER_SEARCH_FILTER + postfix);
647
648 return getUsers(companyId, ctx, maxResults, baseDN, userFilter);
649 }
650
651 public static String getUsersDN(long ldapServerId, long companyId)
652 throws Exception {
653
654 String postfix = getPropertyPostfix(ldapServerId);
655
656 return PrefsPropsUtil.getString(companyId,
657 PropsKeys.LDAP_USERS_DN + postfix);
658 }
659
660 public static boolean hasUser(
661 long ldapServerId, long companyId, String screenName)
662 throws Exception {
663
664 if (getUser(ldapServerId, companyId, screenName) != null) {
665 return true;
666 }
667 else {
668 return false;
669 }
670 }
671
672 public static void importFromLDAP() throws Exception {
673 List<Company> companies = CompanyLocalServiceUtil.getCompanies(false);
674
675 for (Company company : companies) {
676 importFromLDAP(company.getCompanyId());
677 }
678 }
679
680 public static void importFromLDAP(long companyId) throws Exception {
681 if (!isImportEnabled(companyId)) {
682 return;
683 }
684
685 long[] ldapServerIds = StringUtil.split(
686 PrefsPropsUtil.getString(companyId, "ldap.server.ids"), 0L);
687
688 for (long ldapServerId : ldapServerIds) {
689 importFromLDAP(ldapServerId, companyId);
690 }
691 }
692
693 public static void importFromLDAP(long ldapServerId, long companyId)
694 throws Exception {
695
696 if (!isImportEnabled(companyId)) {
697 return;
698 }
699
700 LdapContext ctx = getContext(ldapServerId, companyId);
701
702 if (ctx == null) {
703 return;
704 }
705
706 try {
707 String importMethod = PrefsPropsUtil.getString(
708 companyId, PropsKeys.LDAP_IMPORT_METHOD);
709
710 if (importMethod.equals(IMPORT_BY_USER)) {
711 List<SearchResult> results = getUsers(
712 ldapServerId, companyId, ctx, 0);
713
714
716 for (SearchResult result : results) {
717 Attributes attributes = getUserAttributes(
718 ldapServerId, companyId, ctx,
719 getNameInNamespace(ldapServerId, companyId, result));
720
721 importLDAPUser(
722 ldapServerId, companyId, ctx, attributes,
723 StringPool.BLANK, true);
724 }
725 }
726 else if (importMethod.equals(IMPORT_BY_GROUP)) {
727 List<SearchResult> results = getGroups(
728 ldapServerId, companyId, ctx, 0);
729
730
732 for (SearchResult result : results) {
733 Attributes attributes = getGroupAttributes(
734 ldapServerId, companyId, ctx,
735 getNameInNamespace(ldapServerId, companyId, result),
736 true);
737
738 importLDAPGroup(ldapServerId, companyId, ctx, attributes,
739 true);
740 }
741 }
742 }
743 catch (Exception e) {
744 _log.error("Error importing LDAP users and groups", e);
745 }
746 finally {
747 if (ctx != null) {
748 ctx.close();
749 }
750 }
751 }
752
753 public static UserGroup importLDAPGroup(
754 long ldapServerId, long companyId, LdapContext ctx,
755 Attributes attributes, boolean importGroupMembership)
756 throws Exception {
757
758 String postfix = getPropertyPostfix(ldapServerId);
759
760 AttributesTransformer attributesTransformer =
761 AttributesTransformerFactory.getInstance();
762
763 attributes = attributesTransformer.transformGroup(attributes);
764
765 Properties groupMappings = getGroupMappings(ldapServerId, companyId);
766
767 LogUtil.debug(_log, groupMappings);
768
769 String groupName = LDAPUtil.getAttributeValue(
770 attributes, groupMappings.getProperty("groupName")).toLowerCase();
771 String description = LDAPUtil.getAttributeValue(
772 attributes, groupMappings.getProperty("description"));
773
774
776 UserGroup userGroup = null;
777
778 try {
779 userGroup = UserGroupLocalServiceUtil.getUserGroup(
780 companyId, groupName);
781
782 UserGroupLocalServiceUtil.updateUserGroup(
783 companyId, userGroup.getUserGroupId(), groupName, description);
784 }
785 catch (NoSuchUserGroupException nsuge) {
786 if (_log.isDebugEnabled()) {
787 _log.debug("Adding user group to portal " + groupName);
788 }
789
790 long defaultUserId = UserLocalServiceUtil.getDefaultUserId(
791 companyId);
792
793 try {
794 userGroup = UserGroupLocalServiceUtil.addUserGroup(
795 defaultUserId, companyId, groupName, description);
796 }
797 catch (Exception e) {
798 if (_log.isWarnEnabled()) {
799 _log.warn("Could not create user group " + groupName);
800 }
801
802 if (_log.isDebugEnabled()) {
803 _log.debug(e, e);
804 }
805 }
806 }
807
808
810 if (importGroupMembership && (userGroup != null)) {
811 Attribute attribute = attributes.get(
812 groupMappings.getProperty("user"));
813
814 if (attribute != null) {
815 String baseDN = PrefsPropsUtil.getString(
816 companyId, PropsKeys.LDAP_BASE_DN + postfix);
817
818 StringBuilder sb = new StringBuilder();
819
820 sb.append("(&");
821 sb.append(
822 PrefsPropsUtil.getString(
823 companyId,
824 PropsKeys.LDAP_IMPORT_GROUP_SEARCH_FILTER + postfix));
825 sb.append("(");
826 sb.append(groupMappings.getProperty("groupName"));
827 sb.append("=");
828 sb.append(
829 LDAPUtil.getAttributeValue(
830 attributes, groupMappings.getProperty("groupName")));
831 sb.append("))");
832
833 attribute = getMultivaluedAttribute(
834 companyId, ctx, baseDN, sb.toString(), attribute);
835
836 _importUsersAndMembershipFromLDAPGroup(
837 ldapServerId, companyId, ctx, userGroup.getUserGroupId(),
838 attribute);
839 }
840 }
841
842 return userGroup;
843 }
844
845 public static User importLDAPUser(
846 long ldapServerId, long companyId, LdapContext ctx,
847 Attributes attributes, String password,
848 boolean importGroupMembership)
849 throws Exception {
850
851 LDAPUserTransactionThreadLocal.setOriginatesFromLDAP(true);
852
853 try {
854 return _importLDAPUser(
855 ldapServerId, companyId, ctx, attributes, password,
856 importGroupMembership);
857 }
858 finally {
859 LDAPUserTransactionThreadLocal.setOriginatesFromLDAP(false);
860 }
861 }
862
863 public static boolean isAuthEnabled(long companyId) throws SystemException {
864 if (PrefsPropsUtil.getBoolean(
865 companyId, PropsKeys.LDAP_AUTH_ENABLED,
866 PropsValues.LDAP_AUTH_ENABLED)) {
867
868 return true;
869 }
870 else {
871 return false;
872 }
873 }
874
875 public static boolean isExportEnabled(long companyId)
876 throws SystemException {
877
878 if (PrefsPropsUtil.getBoolean(
879 companyId, PropsKeys.LDAP_EXPORT_ENABLED,
880 PropsValues.LDAP_EXPORT_ENABLED)) {
881
882 return true;
883 }
884 else {
885 return false;
886 }
887 }
888
889 public static boolean isImportEnabled(long companyId)
890 throws SystemException {
891
892 if (PrefsPropsUtil.getBoolean(
893 companyId, PropsKeys.LDAP_IMPORT_ENABLED,
894 PropsValues.LDAP_IMPORT_ENABLED)) {
895
896 return true;
897 }
898 else {
899 return false;
900 }
901 }
902
903 public static boolean isImportOnStartup(long companyId)
904 throws SystemException {
905
906 if (PrefsPropsUtil.getBoolean(
907 companyId, PropsKeys.LDAP_IMPORT_ON_STARTUP)) {
908
909 return true;
910 }
911 else {
912 return false;
913 }
914 }
915
916 public static boolean isNtlmEnabled(long companyId)
917 throws SystemException {
918
919 if (!isAuthEnabled(companyId)) {
920 return false;
921 }
922
923 if (PrefsPropsUtil.getBoolean(
924 companyId, PropsKeys.NTLM_AUTH_ENABLED,
925 PropsValues.NTLM_AUTH_ENABLED)) {
926
927 return true;
928 }
929 else {
930 return false;
931 }
932 }
933
934 public static boolean isPasswordPolicyEnabled(long companyId)
935 throws SystemException {
936
937 if (PrefsPropsUtil.getBoolean(
938 companyId, PropsKeys.LDAP_PASSWORD_POLICY_ENABLED,
939 PropsValues.LDAP_PASSWORD_POLICY_ENABLED)) {
940
941 return true;
942 }
943 else {
944 return false;
945 }
946 }
947
948 public static boolean isSiteMinderEnabled(long companyId)
949 throws SystemException {
950
951 if (!isAuthEnabled(companyId)) {
952 return false;
953 }
954
955 if (PrefsPropsUtil.getBoolean(
956 companyId, PropsKeys.SITEMINDER_AUTH_ENABLED,
957 PropsValues.SITEMINDER_AUTH_ENABLED)) {
958
959 return true;
960 }
961 else {
962 return false;
963 }
964 }
965
966 private static Attributes _getAttributes(
967 LdapContext ctx, String fullDistinguishedName,
968 String[] attributeIds)
969 throws Exception {
970
971 Name fullDN = new CompositeName().add(fullDistinguishedName);
972
973 Attributes attributes = null;
974
975 String[] auditAttributeIds = {
976 "creatorsName", "createTimestamp", "modifiersName",
977 "modifyTimestamp"
978 };
979
980 if (attributeIds == null) {
981
982
984 attributes = ctx.getAttributes(fullDN);
985
986 NamingEnumeration<? extends Attribute> enu = ctx.getAttributes(
987 fullDN, auditAttributeIds).getAll();
988
989 while (enu.hasMoreElements()) {
990 attributes.put(enu.nextElement());
991 }
992
993 enu.close();
994 }
995 else {
996
997
999 int attributeCount = attributeIds.length + auditAttributeIds.length;
1000
1001 String[] allAttributeIds = new String[attributeCount];
1002
1003 System.arraycopy(
1004 attributeIds, 0, allAttributeIds, 0, attributeIds.length);
1005 System.arraycopy(
1006 auditAttributeIds, 0, allAttributeIds, attributeIds.length,
1007 auditAttributeIds.length);
1008
1009 attributes = ctx.getAttributes(fullDN, allAttributeIds);
1010 }
1011
1012 return attributes;
1013 }
1014
1015 private static byte[] _getCookie(Control[] controls) {
1016 if (controls == null) {
1017 return null;
1018 }
1019
1020 for (Control control : controls) {
1021 if (control instanceof PagedResultsResponseControl) {
1022 PagedResultsResponseControl pagedResultsResponseControl =
1023 (PagedResultsResponseControl)control;
1024
1025 return pagedResultsResponseControl.getCookie();
1026 }
1027 }
1028
1029 return null;
1030 }
1031
1032 private static void _getDNName(
1033 long ldapServerId, long companyId, User user,
1034 Properties userMappings, Name name)
1035 throws Exception {
1036
1037
1039 StringBuilder sb = new StringBuilder();
1040
1041 sb.append(userMappings.getProperty("screenName"));
1042 sb.append(StringPool.EQUAL);
1043 sb.append(user.getScreenName());
1044 sb.append(StringPool.COMMA);
1045 sb.append(getUsersDN(ldapServerId, companyId));
1046
1047 name.add(sb.toString());
1048 }
1049
1050 private static String _getNextRange(String attributeId) {
1051 String originalAttributeId = null;
1052 int start = 0;
1053 int end = 0;
1054
1055 int x = attributeId.indexOf(StringPool.SEMICOLON);
1056
1057 if (x < 0) {
1058 originalAttributeId = attributeId;
1059 end = PropsValues.LDAP_RANGE_SIZE - 1;
1060 }
1061 else {
1062 int y = attributeId.indexOf(StringPool.EQUAL, x);
1063 int z = attributeId.indexOf(StringPool.DASH, y);
1064
1065 originalAttributeId = attributeId.substring(0, x);
1066 start = GetterUtil.getInteger(attributeId.substring(y + 1, z));
1067 end = GetterUtil.getInteger(attributeId.substring(z + 1));
1068
1069 start += PropsValues.LDAP_RANGE_SIZE;
1070 end += PropsValues.LDAP_RANGE_SIZE;
1071 }
1072
1073 StringBuilder sb = new StringBuilder();
1074
1075 sb.append(originalAttributeId);
1076 sb.append(StringPool.SEMICOLON);
1077 sb.append("range=");
1078 sb.append(start);
1079 sb.append(StringPool.DASH);
1080 sb.append(end);
1081
1082 return sb.toString();
1083 }
1084
1085 private static void _importGroupsAndMembershipFromLDAPUser(
1086 long ldapServerId, long companyId, LdapContext ctx, long userId,
1087 Attribute attr)
1088 throws Exception {
1089
1090 List<Long> newUserGroupIds = new ArrayList<Long>(attr.size());
1091
1092 for (int i = 0; i < attr.size(); i++) {
1093
1094
1096 String fullGroupDN = (String)attr.get(i);
1097
1098 Attributes groupAttributes = null;
1099
1100 try {
1101 groupAttributes = getGroupAttributes(
1102 ldapServerId, companyId, ctx, fullGroupDN);
1103 }
1104 catch (NameNotFoundException nnfe) {
1105 _log.error(
1106 "LDAP group not found with fullGroupDN " + fullGroupDN);
1107
1108 _log.error(nnfe, nnfe);
1109
1110 continue;
1111 }
1112
1113 UserGroup userGroup = importLDAPGroup(
1114 ldapServerId, companyId, ctx, groupAttributes, false);
1115
1116
1118 if (userGroup != null) {
1119 if (_log.isDebugEnabled()) {
1120 _log.debug(
1121 "Adding " + userId + " to group " +
1122 userGroup.getUserGroupId());
1123 }
1124
1125 newUserGroupIds.add(userGroup.getUserGroupId());
1126 }
1127 }
1128
1129 UserGroupLocalServiceUtil.setUserUserGroups(
1130 userId,
1131 ArrayUtil.toArray(
1132 newUserGroupIds.toArray(new Long[newUserGroupIds.size()])));
1133 }
1134
1135 private static User _importLDAPUser(
1136 long ldapServerId, long companyId, LdapContext ctx,
1137 Attributes attributes, String password,
1138 boolean importGroupMembership)
1139 throws Exception {
1140
1141 AttributesTransformer attributesTransformer =
1142 AttributesTransformerFactory.getInstance();
1143
1144 attributes = attributesTransformer.transformUser(attributes);
1145
1146 Properties userMappings = getUserMappings(ldapServerId, companyId);
1147
1148 LogUtil.debug(_log, userMappings);
1149
1150 User defaultUser = UserLocalServiceUtil.getDefaultUser(companyId);
1151
1152 boolean autoPassword = false;
1153 boolean updatePassword = true;
1154
1155 if (password.equals(StringPool.BLANK)) {
1156 autoPassword = true;
1157 updatePassword = false;
1158 }
1159
1160 long creatorUserId = 0;
1161 boolean passwordReset = false;
1162 boolean autoScreenName = false;
1163 String screenName = LDAPUtil.getAttributeValue(
1164 attributes, userMappings.getProperty("screenName")).toLowerCase();
1165 String emailAddress = LDAPUtil.getAttributeValue(
1166 attributes, userMappings.getProperty("emailAddress"));
1167 String openId = StringPool.BLANK;
1168 Locale locale = defaultUser.getLocale();
1169 String firstName = LDAPUtil.getAttributeValue(
1170 attributes, userMappings.getProperty("firstName"));
1171 String middleName = LDAPUtil.getAttributeValue(
1172 attributes, userMappings.getProperty("middleName"));
1173 String lastName = LDAPUtil.getAttributeValue(
1174 attributes, userMappings.getProperty("lastName"));
1175
1176 if (Validator.isNull(firstName) || Validator.isNull(lastName)) {
1177 String fullName = LDAPUtil.getAttributeValue(
1178 attributes, userMappings.getProperty("fullName"));
1179
1180 String[] names = LDAPUtil.splitFullName(fullName);
1181
1182 firstName = names[0];
1183 middleName = names[1];
1184 lastName = names[2];
1185 }
1186
1187 int prefixId = 0;
1188 int suffixId = 0;
1189 boolean male = true;
1190 int birthdayMonth = Calendar.JANUARY;
1191 int birthdayDay = 1;
1192 int birthdayYear = 1970;
1193 String jobTitle = LDAPUtil.getAttributeValue(
1194 attributes, userMappings.getProperty("jobTitle"));
1195 long[] groupIds = null;
1196 long[] organizationIds = null;
1197 long[] roleIds = null;
1198 List<UserGroupRole> userGroupRoles = null;
1199 long[] userGroupIds = null;
1200 boolean sendEmail = false;
1201 ServiceContext serviceContext = new ServiceContext();
1202
1203 if (_log.isDebugEnabled()) {
1204 _log.debug(
1205 "Screen name " + screenName + " and email address " +
1206 emailAddress);
1207 }
1208
1209 if (Validator.isNull(screenName) || Validator.isNull(emailAddress)) {
1210 if (_log.isWarnEnabled()) {
1211 _log.warn(
1212 "Cannot add user because screen name and email address " +
1213 "are required");
1214 }
1215
1216 return null;
1217 }
1218
1219 User user = null;
1220
1221 try {
1222
1223
1225 String authType = PrefsPropsUtil.getString(
1226 companyId, PropsKeys.COMPANY_SECURITY_AUTH_TYPE,
1227 PropsValues.COMPANY_SECURITY_AUTH_TYPE);
1228
1229 if (authType.equals(CompanyConstants.AUTH_TYPE_SN)) {
1230 user = UserLocalServiceUtil.getUserByScreenName(
1231 companyId, screenName);
1232 }
1233 else {
1234 user = UserLocalServiceUtil.getUserByEmailAddress(
1235 companyId, emailAddress);
1236 }
1237
1238
1240 if (user.isDefaultUser()) {
1241 return user;
1242 }
1243
1244
1248 Date ldapUserModifiedDate = null;
1249
1250 String modifiedDate = LDAPUtil.getAttributeValue(
1251 attributes, "modifyTimestamp");
1252
1253 try {
1254 if (Validator.isNull(modifiedDate)) {
1255 if (_log.isInfoEnabled()) {
1256 _log.info(
1257 "LDAP entry never modified, skipping user " +
1258 user.getEmailAddress());
1259 }
1260
1261 return user;
1262 }
1263 else {
1264 DateFormat dateFormat =
1265 DateFormatFactoryUtil.getSimpleDateFormat(
1266 "yyyyMMddHHmmss");
1267
1268 ldapUserModifiedDate = dateFormat.parse(modifiedDate);
1269 }
1270
1271 if (ldapUserModifiedDate.equals(user.getModifiedDate()) &&
1272 autoPassword) {
1273
1274 if (_log.isDebugEnabled()) {
1275 _log.debug(
1276 "User is already syncronized, skipping user " +
1277 user.getEmailAddress());
1278 }
1279
1280 return user;
1281 }
1282 }
1283 catch (ParseException pe) {
1284 if (_log.isDebugEnabled()) {
1285 _log.debug(
1286 "Unable to parse LDAP modify timestamp " +
1287 modifiedDate);
1288 }
1289
1290 _log.debug(pe, pe);
1291 }
1292
1293
1295 if (Validator.isNull(screenName)) {
1296 autoScreenName = true;
1297 }
1298
1299 if (autoScreenName) {
1300 ScreenNameGenerator screenNameGenerator =
1301 (ScreenNameGenerator)InstancePool.get(
1302 PropsValues.USERS_SCREEN_NAME_GENERATOR);
1303
1304 screenName = screenNameGenerator.generate(
1305 companyId, user.getUserId(), emailAddress);
1306 }
1307
1308 Contact contact = user.getContact();
1309
1310 Calendar birthdayCal = CalendarFactoryUtil.getCalendar();
1311
1312 birthdayCal.setTime(contact.getBirthday());
1313
1314 birthdayMonth = birthdayCal.get(Calendar.MONTH);
1315 birthdayDay = birthdayCal.get(Calendar.DATE);
1316 birthdayYear = birthdayCal.get(Calendar.YEAR);
1317
1318
1320 if (updatePassword) {
1321 user = UserLocalServiceUtil.updatePassword(
1322 user.getUserId(), password, password, passwordReset, true);
1323 }
1324
1325 user = UserLocalServiceUtil.updateUser(
1326 user.getUserId(), password, StringPool.BLANK, StringPool.BLANK,
1327 user.isPasswordReset(), user.getReminderQueryQuestion(),
1328 user.getReminderQueryAnswer(), screenName, emailAddress, openId,
1329 user.getLanguageId(), user.getTimeZoneId(), user.getGreeting(),
1330 user.getComments(), firstName, middleName, lastName,
1331 contact.getPrefixId(), contact.getSuffixId(), contact.getMale(),
1332 birthdayMonth, birthdayDay, birthdayYear, contact.getSmsSn(),
1333 contact.getAimSn(), contact.getFacebookSn(), contact.getIcqSn(),
1334 contact.getJabberSn(), contact.getMsnSn(),
1335 contact.getMySpaceSn(), contact.getSkypeSn(),
1336 contact.getTwitterSn(), contact.getYmSn(), jobTitle, groupIds,
1337 organizationIds, roleIds, userGroupRoles, userGroupIds,
1338 serviceContext);
1339
1340 if (ldapUserModifiedDate != null) {
1341 UserLocalServiceUtil.updateModifiedDate(
1342 user.getUserId(), ldapUserModifiedDate);
1343 }
1344 }
1345 catch (NoSuchUserException nsue) {
1346
1347
1349 }
1350 catch (Exception e) {
1351 _log.error(
1352 "Error updating user with screen name " + screenName +
1353 " and email address " + emailAddress,
1354 e);
1355
1356 return null;
1357 }
1358
1359 if (user == null) {
1360 try {
1361 if (_log.isDebugEnabled()) {
1362 _log.debug("Adding user to portal " + emailAddress);
1363 }
1364
1365 user = UserLocalServiceUtil.addUser(
1366 creatorUserId, companyId, autoPassword, password, password,
1367 autoScreenName, screenName, emailAddress, openId, locale,
1368 firstName, middleName, lastName, prefixId, suffixId, male,
1369 birthdayMonth, birthdayDay, birthdayYear, jobTitle,
1370 groupIds, organizationIds, roleIds, userGroupIds, sendEmail,
1371 serviceContext);
1372 }
1373 catch (Exception e) {
1374 _log.error(
1375 "Problem adding user with screen name " + screenName +
1376 " and email address " + emailAddress,
1377 e);
1378 }
1379 }
1380
1381
1383 if (importGroupMembership && (user != null)) {
1384 String userMappingsGroup = userMappings.getProperty("group");
1385
1386 if (userMappingsGroup != null) {
1387 Attribute attribute = attributes.get(userMappingsGroup);
1388
1389 if (attribute != null) {
1390 _importGroupsAndMembershipFromLDAPUser(
1391 ldapServerId, companyId, ctx, user.getUserId(),
1392 attribute);
1393 }
1394 }
1395 }
1396
1397 return user;
1398 }
1399
1400 private static void _importUsersAndMembershipFromLDAPGroup(
1401 long ldapServerId, long companyId, LdapContext ctx,
1402 long userGroupId, Attribute attr)
1403 throws Exception {
1404
1405 List<Long> newUserIds = new ArrayList<Long>(attr.size());
1406
1407 for (int i = 0; i < attr.size(); i++) {
1408
1409
1411 String fullUserDN = (String)attr.get(i);
1412
1413 Attributes userAttributes = null;
1414
1415 try {
1416 userAttributes = getUserAttributes(ldapServerId, companyId, ctx,
1417 fullUserDN);
1418 }
1419 catch (NameNotFoundException nnfe) {
1420 _log.error("LDAP user not found with fullUserDN " + fullUserDN);
1421
1422 _log.error(nnfe, nnfe);
1423
1424 continue;
1425 }
1426
1427 User user = importLDAPUser(
1428 ldapServerId, companyId, ctx, userAttributes, StringPool.BLANK,
1429 false);
1430
1431
1433 if (user != null) {
1434 if (_log.isDebugEnabled()) {
1435 _log.debug(
1436 "Adding " + user.getUserId() + " to group " +
1437 userGroupId);
1438 }
1439
1440 newUserIds.add(user.getUserId());
1441 }
1442 }
1443
1444 UserLocalServiceUtil.setUserGroupUsers(
1445 userGroupId,
1446 ArrayUtil.toArray(newUserIds.toArray(new Long[newUserIds.size()])));
1447 }
1448
1449 private static List<SearchResult> _searchLDAP(
1450 long companyId, LdapContext ctx, int maxResults, String baseDN,
1451 String filter, String[] attributeIds)
1452 throws Exception {
1453
1454 List<SearchResult> results = new ArrayList<SearchResult>();
1455
1456 SearchControls cons = new SearchControls(
1457 SearchControls.SUBTREE_SCOPE, maxResults, 0, attributeIds, false,
1458 false);
1459
1460 try {
1461 byte[] cookie = new byte[0];
1462
1463 while (cookie != null) {
1464 if (cookie.length == 0) {
1465 ctx.setRequestControls(
1466 new Control[] {
1467 new PagedResultsControl(
1468 PropsValues.LDAP_PAGE_SIZE, Control.CRITICAL)
1469 });
1470 }
1471 else {
1472 ctx.setRequestControls(
1473 new Control[] {
1474 new PagedResultsControl(
1475 PropsValues.LDAP_PAGE_SIZE, cookie,
1476 Control.CRITICAL)
1477 });
1478 }
1479
1480 NamingEnumeration<SearchResult> enu = ctx.search(
1481 baseDN, filter, cons);
1482
1483 while (enu.hasMoreElements()) {
1484 results.add(enu.nextElement());
1485 }
1486
1487 enu.close();
1488
1489 cookie = _getCookie(ctx.getResponseControls());
1490 }
1491 }
1492 catch (OperationNotSupportedException onse) {
1493 ctx.setRequestControls(null);
1494
1495 NamingEnumeration<SearchResult> enu = ctx.search(
1496 baseDN, filter, cons);
1497
1498 while (enu.hasMoreElements()) {
1499 results.add(enu.nextElement());
1500 }
1501
1502 enu.close();
1503 }
1504 finally {
1505 ctx.setRequestControls(null);
1506 }
1507
1508 return results;
1509 }
1510
1511 private static Log _log = LogFactoryUtil.getLog(PortalLDAPUtil.class);
1512
1513}