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