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