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