001
014
015 package com.liferay.portal.security.ldap;
016
017 import com.liferay.portal.NoSuchRoleException;
018 import com.liferay.portal.NoSuchUserGroupException;
019 import com.liferay.portal.kernel.bean.BeanPropertiesUtil;
020 import com.liferay.portal.kernel.cache.PortalCache;
021 import com.liferay.portal.kernel.cache.SingleVMPoolUtil;
022 import com.liferay.portal.kernel.exception.PortalException;
023 import com.liferay.portal.kernel.exception.SystemException;
024 import com.liferay.portal.kernel.ldap.LDAPUtil;
025 import com.liferay.portal.kernel.log.Log;
026 import com.liferay.portal.kernel.log.LogFactoryUtil;
027 import com.liferay.portal.kernel.security.pacl.DoPrivileged;
028 import com.liferay.portal.kernel.util.ArrayUtil;
029 import com.liferay.portal.kernel.util.CalendarFactoryUtil;
030 import com.liferay.portal.kernel.util.GetterUtil;
031 import com.liferay.portal.kernel.util.LocaleUtil;
032 import com.liferay.portal.kernel.util.PropsKeys;
033 import com.liferay.portal.kernel.util.SetUtil;
034 import com.liferay.portal.kernel.util.StringBundler;
035 import com.liferay.portal.kernel.util.StringPool;
036 import com.liferay.portal.kernel.util.StringUtil;
037 import com.liferay.portal.kernel.util.Validator;
038 import com.liferay.portal.model.Company;
039 import com.liferay.portal.model.CompanyConstants;
040 import com.liferay.portal.model.Contact;
041 import com.liferay.portal.model.Group;
042 import com.liferay.portal.model.Role;
043 import com.liferay.portal.model.RoleConstants;
044 import com.liferay.portal.model.User;
045 import com.liferay.portal.model.UserGroup;
046 import com.liferay.portal.security.auth.CompanyThreadLocal;
047 import com.liferay.portal.security.auth.ScreenNameGenerator;
048 import com.liferay.portal.security.auth.ScreenNameGeneratorFactory;
049 import com.liferay.portal.service.CompanyLocalServiceUtil;
050 import com.liferay.portal.service.GroupLocalServiceUtil;
051 import com.liferay.portal.service.LockLocalServiceUtil;
052 import com.liferay.portal.service.RoleLocalServiceUtil;
053 import com.liferay.portal.service.ServiceContext;
054 import com.liferay.portal.service.UserGroupLocalServiceUtil;
055 import com.liferay.portal.service.UserLocalServiceUtil;
056 import com.liferay.portal.util.PrefsPropsUtil;
057 import com.liferay.portal.util.PropsValues;
058 import com.liferay.portlet.expando.model.ExpandoBridge;
059 import com.liferay.portlet.expando.model.ExpandoTableConstants;
060 import com.liferay.portlet.expando.service.ExpandoValueLocalServiceUtil;
061 import com.liferay.portlet.expando.util.ExpandoConverterUtil;
062
063 import java.io.Serializable;
064
065 import java.text.ParseException;
066
067 import java.util.ArrayList;
068 import java.util.Calendar;
069 import java.util.Date;
070 import java.util.HashMap;
071 import java.util.LinkedHashSet;
072 import java.util.List;
073 import java.util.Locale;
074 import java.util.Map;
075 import java.util.Properties;
076 import java.util.Set;
077
078 import javax.naming.Binding;
079 import javax.naming.NameNotFoundException;
080 import javax.naming.NamingEnumeration;
081 import javax.naming.directory.Attribute;
082 import javax.naming.directory.Attributes;
083 import javax.naming.directory.SearchControls;
084 import javax.naming.directory.SearchResult;
085 import javax.naming.ldap.LdapContext;
086
087
093 @DoPrivileged
094 public class PortalLDAPImporterImpl implements PortalLDAPImporter {
095
096 @Override
097 public void importFromLDAP() throws Exception {
098 List<Company> companies = CompanyLocalServiceUtil.getCompanies(false);
099
100 for (Company company : companies) {
101 importFromLDAP(company.getCompanyId());
102 }
103 }
104
105 @Override
106 public void importFromLDAP(long companyId) throws Exception {
107 if (!LDAPSettingsUtil.isImportEnabled(companyId)) {
108 return;
109 }
110
111 long defaultUserId = UserLocalServiceUtil.getDefaultUserId(companyId);
112
113 if (LockLocalServiceUtil.hasLock(
114 defaultUserId, PortalLDAPImporterUtil.class.getName(),
115 companyId)) {
116
117 if (_log.isDebugEnabled()) {
118 _log.debug(
119 "Skipping LDAP import for company " + companyId +
120 "because another LDAP import is in process");
121 }
122
123 return;
124 }
125
126 LockLocalServiceUtil.lock(
127 defaultUserId, PortalLDAPImporterUtil.class.getName(), companyId,
128 PortalLDAPImporterImpl.class.getName(), false,
129 PropsValues.LDAP_IMPORT_LOCK_EXPIRATION_TIME);
130
131 long threadLocalCompanyId = CompanyThreadLocal.getCompanyId();
132
133 try {
134 if (threadLocalCompanyId == CompanyConstants.SYSTEM) {
135 CompanyThreadLocal.setCompanyId(companyId);
136 }
137
138 long[] ldapServerIds = StringUtil.split(
139 PrefsPropsUtil.getString(companyId, "ldap.server.ids"), 0L);
140
141 for (long ldapServerId : ldapServerIds) {
142 importFromLDAP(ldapServerId, companyId);
143 }
144
145 for (int ldapServerId = 0;; ldapServerId++) {
146 String postfix = LDAPSettingsUtil.getPropertyPostfix(
147 ldapServerId);
148
149 String providerUrl = PrefsPropsUtil.getString(
150 companyId, PropsKeys.LDAP_BASE_PROVIDER_URL + postfix);
151
152 if (Validator.isNull(providerUrl)) {
153 break;
154 }
155
156 importFromLDAP(ldapServerId, companyId);
157 }
158 }
159 finally {
160 LockLocalServiceUtil.unlock(
161 PortalLDAPImporterUtil.class.getName(), companyId);
162
163 CompanyThreadLocal.setCompanyId(threadLocalCompanyId);
164 }
165 }
166
167 @Override
168 public void importFromLDAP(long ldapServerId, long companyId)
169 throws Exception {
170
171 if (!LDAPSettingsUtil.isImportEnabled(companyId)) {
172 return;
173 }
174
175 LdapContext ldapContext = PortalLDAPUtil.getContext(
176 ldapServerId, companyId);
177
178 if (ldapContext == null) {
179 return;
180 }
181
182 try {
183 Properties userMappings = LDAPSettingsUtil.getUserMappings(
184 ldapServerId, companyId);
185 Properties userExpandoMappings =
186 LDAPSettingsUtil.getUserExpandoMappings(
187 ldapServerId, companyId);
188 Properties contactMappings = LDAPSettingsUtil.getContactMappings(
189 ldapServerId, companyId);
190 Properties contactExpandoMappings =
191 LDAPSettingsUtil.getContactExpandoMappings(
192 ldapServerId, companyId);
193 Properties groupMappings = LDAPSettingsUtil.getGroupMappings(
194 ldapServerId, companyId);
195
196 String importMethod = PrefsPropsUtil.getString(
197 companyId, PropsKeys.LDAP_IMPORT_METHOD);
198
199 if (importMethod.equals(_IMPORT_BY_GROUP)) {
200 importFromLDAPByGroup(
201 ldapServerId, companyId, ldapContext, userMappings,
202 userExpandoMappings, contactMappings,
203 contactExpandoMappings, groupMappings);
204 }
205 else if (importMethod.equals(_IMPORT_BY_USER)) {
206 importFromLDAPByUser(
207 ldapServerId, companyId, ldapContext, userMappings,
208 userExpandoMappings, contactMappings,
209 contactExpandoMappings, groupMappings);
210 }
211 }
212 catch (Exception e) {
213 _log.error("Error importing LDAP users and groups", e);
214 }
215 finally {
216 if (ldapContext != null) {
217 ldapContext.close();
218 }
219 }
220 }
221
222 @Override
223 public User importLDAPUser(
224 long ldapServerId, long companyId, LdapContext ldapContext,
225 Attributes attributes, String password)
226 throws Exception {
227
228 Properties userMappings = LDAPSettingsUtil.getUserMappings(
229 ldapServerId, companyId);
230 Properties userExpandoMappings =
231 LDAPSettingsUtil.getUserExpandoMappings(ldapServerId, companyId);
232 Properties contactMappings = LDAPSettingsUtil.getContactMappings(
233 ldapServerId, companyId);
234 Properties contactExpandoMappings =
235 LDAPSettingsUtil.getContactExpandoMappings(ldapServerId, companyId);
236
237 User user = importUser(
238 ldapServerId, companyId, attributes, userMappings,
239 userExpandoMappings, contactMappings, contactExpandoMappings,
240 password);
241
242 Properties groupMappings = LDAPSettingsUtil.getGroupMappings(
243 ldapServerId, companyId);
244
245 importGroups(
246 ldapServerId, companyId, ldapContext, attributes, user,
247 userMappings, groupMappings);
248
249 return user;
250 }
251
252 @Override
253 public User importLDAPUser(
254 long ldapServerId, long companyId, String emailAddress,
255 String screenName)
256 throws Exception {
257
258 LdapContext ldapContext = null;
259
260 NamingEnumeration<SearchResult> enu = null;
261
262 try {
263 String postfix = LDAPSettingsUtil.getPropertyPostfix(ldapServerId);
264
265 String baseDN = PrefsPropsUtil.getString(
266 companyId, PropsKeys.LDAP_BASE_DN + postfix);
267
268 ldapContext = PortalLDAPUtil.getContext(ldapServerId, companyId);
269
270 if (ldapContext == null) {
271 _log.error("Unable to bind to the LDAP server");
272
273 return null;
274 }
275
276 String filter = PrefsPropsUtil.getString(
277 companyId, PropsKeys.LDAP_AUTH_SEARCH_FILTER + postfix);
278
279 if (_log.isDebugEnabled()) {
280 _log.debug("Search filter before transformation " + filter);
281 }
282
283 filter = StringUtil.replace(
284 filter,
285 new String[] {
286 "@company_id@", "@email_address@", "@screen_name@"
287 },
288 new String[] {
289 String.valueOf(companyId), emailAddress, screenName
290 });
291
292 LDAPUtil.validateFilter(filter);
293
294 if (_log.isDebugEnabled()) {
295 _log.debug("Search filter after transformation " + filter);
296 }
297
298 Properties userMappings = LDAPSettingsUtil.getUserMappings(
299 ldapServerId, companyId);
300
301 String userMappingsScreenName = GetterUtil.getString(
302 userMappings.getProperty("screenName"));
303
304 userMappingsScreenName = StringUtil.toLowerCase(
305 userMappingsScreenName);
306
307 SearchControls searchControls = new SearchControls(
308 SearchControls.SUBTREE_SCOPE, 1, 0,
309 new String[] {userMappingsScreenName}, false, false);
310
311 enu = ldapContext.search(baseDN, filter, searchControls);
312
313 if (enu.hasMoreElements()) {
314 if (_log.isDebugEnabled()) {
315 _log.debug("Search filter returned at least one result");
316 }
317
318 Binding binding = enu.nextElement();
319
320 Attributes attributes = PortalLDAPUtil.getUserAttributes(
321 ldapServerId, companyId, ldapContext,
322 PortalLDAPUtil.getNameInNamespace(
323 ldapServerId, companyId, binding));
324
325 return importLDAPUser(
326 ldapServerId, companyId, ldapContext, attributes,
327 StringPool.BLANK);
328 }
329 else {
330 return null;
331 }
332 }
333 catch (Exception e) {
334 if (_log.isWarnEnabled()) {
335 _log.warn("Problem accessing LDAP server " + e.getMessage());
336 }
337
338 if (_log.isDebugEnabled()) {
339 _log.debug(e, e);
340 }
341
342 throw new SystemException(
343 "Problem accessing LDAP server " + e.getMessage());
344 }
345 finally {
346 if (enu != null) {
347 enu.close();
348 }
349
350 if (ldapContext != null) {
351 ldapContext.close();
352 }
353 }
354 }
355
356 @Override
357 public User importLDAPUser(
358 long companyId, String emailAddress, String screenName)
359 throws Exception {
360
361 long[] ldapServerIds = StringUtil.split(
362 PrefsPropsUtil.getString(companyId, "ldap.server.ids"), 0L);
363
364 for (long ldapServerId : ldapServerIds) {
365 User user = importLDAPUser(
366 ldapServerId, companyId, emailAddress, screenName);
367
368 if (user != null) {
369 return user;
370 }
371 }
372
373 for (int ldapServerId = 0;; ldapServerId++) {
374 String postfix = LDAPSettingsUtil.getPropertyPostfix(ldapServerId);
375
376 String providerUrl = PrefsPropsUtil.getString(
377 companyId, PropsKeys.LDAP_BASE_PROVIDER_URL + postfix);
378
379 if (Validator.isNull(providerUrl)) {
380 break;
381 }
382
383 User user = importLDAPUser(
384 ldapServerId, companyId, emailAddress, screenName);
385
386 if (user != null) {
387 return user;
388 }
389 }
390
391 if (_log.isDebugEnabled()) {
392 if (Validator.isNotNull(emailAddress)) {
393 _log.debug(
394 "User with the email address " + emailAddress +
395 " was not found in any LDAP servers");
396 }
397 else {
398 _log.debug(
399 "User with the screen name " + screenName +
400 " was not found in any LDAP servers");
401 }
402 }
403
404 return null;
405 }
406
407 @Override
408 public User importLDAPUserByScreenName(long companyId, String screenName)
409 throws Exception {
410
411 long ldapServerId = PortalLDAPUtil.getLdapServerId(
412 companyId, screenName, StringPool.BLANK);
413
414 SearchResult result = (SearchResult)PortalLDAPUtil.getUser(
415 ldapServerId, companyId, screenName, StringPool.BLANK);
416
417 if (result == null) {
418 if (_log.isWarnEnabled()) {
419 _log.warn(
420 "No user was found in LDAP with screenName " + screenName);
421 }
422
423 return null;
424 }
425
426 LdapContext ldapContext = PortalLDAPUtil.getContext(
427 ldapServerId, companyId);
428
429 String fullUserDN = PortalLDAPUtil.getNameInNamespace(
430 ldapServerId, companyId, result);
431
432 Attributes attributes = PortalLDAPUtil.getUserAttributes(
433 ldapServerId, companyId, ldapContext, fullUserDN);
434
435 User user = importLDAPUser(
436 ldapServerId, companyId, ldapContext, attributes, StringPool.BLANK);
437
438 ldapContext.close();
439
440 return user;
441 }
442
443 public void setLDAPToPortalConverter(
444 LDAPToPortalConverter ldapToPortalConverter) {
445
446 _ldapToPortalConverter = ldapToPortalConverter;
447 }
448
449 protected void addRole(
450 long companyId, LDAPGroup ldapGroup, UserGroup userGroup)
451 throws Exception {
452
453 if (!PropsValues.LDAP_IMPORT_CREATE_ROLE_PER_GROUP) {
454 return;
455 }
456
457 Role role = null;
458
459 try {
460 role = RoleLocalServiceUtil.getRole(
461 companyId, ldapGroup.getGroupName());
462 }
463 catch (NoSuchRoleException nsre) {
464 User defaultUser = UserLocalServiceUtil.getDefaultUser(companyId);
465
466 Map<Locale, String> descriptionMap = new HashMap<Locale, String>();
467
468 descriptionMap.put(
469 LocaleUtil.getDefault(), "Autogenerated role from LDAP import");
470
471 role = RoleLocalServiceUtil.addRole(
472 defaultUser.getUserId(), null, 0, ldapGroup.getGroupName(),
473 null, descriptionMap, RoleConstants.TYPE_REGULAR, null, null);
474 }
475
476 Group group = userGroup.getGroup();
477
478 if (GroupLocalServiceUtil.hasRoleGroup(
479 role.getRoleId(), group.getGroupId())) {
480
481 return;
482 }
483
484 GroupLocalServiceUtil.addRoleGroups(
485 role.getRoleId(), new long[] {group.getGroupId()});
486 }
487
488 protected User addUser(long companyId, LDAPUser ldapUser, String password)
489 throws Exception {
490
491 if (_log.isDebugEnabled()) {
492 _log.debug("Adding user " + ldapUser.getEmailAddress());
493 }
494
495 boolean autoPassword = ldapUser.isAutoPassword();
496
497 if (!PropsValues.LDAP_IMPORT_USER_PASSWORD_ENABLED) {
498 autoPassword =
499 PropsValues.LDAP_IMPORT_USER_PASSWORD_AUTOGENERATED &&
500 !PropsValues.AUTH_PIPELINE_ENABLE_LIFERAY_CHECK;
501
502 if (!autoPassword) {
503 String defaultPassword =
504 PropsValues.LDAP_IMPORT_USER_PASSWORD_DEFAULT;
505
506 if (StringUtil.equalsIgnoreCase(
507 defaultPassword, _USER_PASSWORD_SCREEN_NAME)) {
508
509 defaultPassword = ldapUser.getScreenName();
510 }
511
512 password = defaultPassword;
513 }
514 }
515
516 Calendar birthdayCal = CalendarFactoryUtil.getCalendar();
517
518 birthdayCal.setTime(ldapUser.getBirthday());
519
520 int birthdayMonth = birthdayCal.get(Calendar.MONTH);
521 int birthdayDay = birthdayCal.get(Calendar.DAY_OF_MONTH);
522 int birthdayYear = birthdayCal.get(Calendar.YEAR);
523
524 User user = UserLocalServiceUtil.addUser(
525 ldapUser.getCreatorUserId(), companyId, autoPassword, password,
526 password, ldapUser.isAutoScreenName(), ldapUser.getScreenName(),
527 ldapUser.getEmailAddress(), 0, StringPool.BLANK,
528 ldapUser.getLocale(), ldapUser.getFirstName(),
529 ldapUser.getMiddleName(), ldapUser.getLastName(), 0, 0,
530 ldapUser.isMale(), birthdayMonth, birthdayDay, birthdayYear,
531 StringPool.BLANK, ldapUser.getGroupIds(),
532 ldapUser.getOrganizationIds(), ldapUser.getRoleIds(),
533 ldapUser.getUserGroupIds(), ldapUser.isSendEmail(),
534 ldapUser.getServiceContext());
535
536 if (ldapUser.isUpdatePortrait()) {
537 byte[] portraitBytes = ldapUser.getPortraitBytes();
538
539 if (ArrayUtil.isNotEmpty(portraitBytes)) {
540 user = UserLocalServiceUtil.updatePortrait(
541 user.getUserId(), portraitBytes);
542 }
543 }
544
545 return user;
546 }
547
548 protected void addUserGroupsNotAddedByLDAPImport(
549 long userId, Set<Long> userGroupIds)
550 throws Exception {
551
552 List<UserGroup> userGroups =
553 UserGroupLocalServiceUtil.getUserUserGroups(userId);
554
555 for (UserGroup userGroup : userGroups) {
556 if (!userGroup.isAddedByLDAPImport()) {
557 userGroupIds.add(userGroup.getUserGroupId());
558 }
559 }
560 }
561
562 protected String escapeValue(String value) {
563 return StringUtil.replace(value, "\\,", "\\\\,");
564 }
565
566 protected User getUser(long companyId, LDAPUser ldapUser) throws Exception {
567 User user = null;
568
569 String authType = PrefsPropsUtil.getString(
570 companyId, PropsKeys.COMPANY_SECURITY_AUTH_TYPE,
571 PropsValues.COMPANY_SECURITY_AUTH_TYPE);
572
573 if (authType.equals(CompanyConstants.AUTH_TYPE_SN) &&
574 !ldapUser.isAutoScreenName()) {
575
576 user = UserLocalServiceUtil.fetchUserByScreenName(
577 companyId, ldapUser.getScreenName());
578 }
579 else {
580 user = UserLocalServiceUtil.fetchUserByEmailAddress(
581 companyId, ldapUser.getEmailAddress());
582 }
583
584 return user;
585 }
586
587 protected Attribute getUsers(
588 long ldapServerId, long companyId, LdapContext ldapContext,
589 Attributes attributes, UserGroup userGroup,
590 Properties groupMappings)
591 throws Exception {
592
593 Attribute attribute = attributes.get(groupMappings.getProperty("user"));
594
595 if (attribute == null) {
596 return null;
597 }
598
599 String postfix = LDAPSettingsUtil.getPropertyPostfix(ldapServerId);
600
601 String baseDN = PrefsPropsUtil.getString(
602 companyId, PropsKeys.LDAP_BASE_DN + postfix);
603
604 StringBundler sb = new StringBundler(7);
605
606 sb.append("(&");
607 sb.append(
608 PrefsPropsUtil.getString(
609 companyId,
610 PropsKeys.LDAP_IMPORT_GROUP_SEARCH_FILTER + postfix));
611 sb.append(StringPool.OPEN_PARENTHESIS);
612 sb.append(groupMappings.getProperty("groupName"));
613 sb.append("=");
614 sb.append(escapeValue(userGroup.getName()));
615 sb.append("))");
616
617 return PortalLDAPUtil.getMultivaluedAttribute(
618 companyId, ldapContext, baseDN, sb.toString(), attribute);
619 }
620
621 protected void importFromLDAPByGroup(
622 long ldapServerId, long companyId, LdapContext ldapContext,
623 Properties userMappings, Properties userExpandoMappings,
624 Properties contactMappings, Properties contactExpandoMappings,
625 Properties groupMappings)
626 throws Exception {
627
628 byte[] cookie = new byte[0];
629
630 while (cookie != null) {
631 List<SearchResult> searchResults = new ArrayList<SearchResult>();
632
633 String groupMappingsGroupName = GetterUtil.getString(
634 groupMappings.getProperty("groupName"));
635
636 groupMappingsGroupName = StringUtil.toLowerCase(
637 groupMappingsGroupName);
638
639 cookie = PortalLDAPUtil.getGroups(
640 ldapServerId, companyId, ldapContext, cookie, 0,
641 new String[] {groupMappingsGroupName}, searchResults);
642
643 for (SearchResult searchResult : searchResults) {
644 try {
645 Attributes attributes = PortalLDAPUtil.getGroupAttributes(
646 ldapServerId, companyId, ldapContext,
647 PortalLDAPUtil.getNameInNamespace(
648 ldapServerId, companyId, searchResult),
649 true);
650
651 UserGroup userGroup = importUserGroup(
652 companyId, attributes, groupMappings);
653
654 Attribute usersAttribute = getUsers(
655 ldapServerId, companyId, ldapContext, attributes,
656 userGroup, groupMappings);
657
658 if (usersAttribute == null) {
659 if (_log.isInfoEnabled()) {
660 _log.info(
661 "No users found in " + userGroup.getName());
662 }
663
664 continue;
665 }
666
667 importUsers(
668 ldapServerId, companyId, ldapContext, userMappings,
669 userExpandoMappings, contactMappings,
670 contactExpandoMappings, userGroup.getUserGroupId(),
671 usersAttribute);
672 }
673 catch (Exception e) {
674 _log.error("Unable to import group " + searchResult, e);
675 }
676 }
677 }
678 }
679
680 protected void importFromLDAPByUser(
681 long ldapServerId, long companyId, LdapContext ldapContext,
682 Properties userMappings, Properties userExpandoMappings,
683 Properties contactMappings, Properties contactExpandoMappings,
684 Properties groupMappings)
685 throws Exception {
686
687 byte[] cookie = new byte[0];
688
689 while (cookie != null) {
690 List<SearchResult> searchResults = new ArrayList<SearchResult>();
691
692 String userMappingsScreenName = GetterUtil.getString(
693 userMappings.getProperty("screenName"));
694
695 userMappingsScreenName = StringUtil.toLowerCase(
696 userMappingsScreenName);
697
698 cookie = PortalLDAPUtil.getUsers(
699 ldapServerId, companyId, ldapContext, cookie, 0,
700 new String[] {userMappingsScreenName}, searchResults);
701
702 for (SearchResult searchResult : searchResults) {
703 try {
704 Attributes userAttributes =
705 PortalLDAPUtil.getUserAttributes(
706 ldapServerId, companyId, ldapContext,
707 PortalLDAPUtil.getNameInNamespace(
708 ldapServerId, companyId, searchResult));
709
710 User user = importUser(
711 ldapServerId, companyId, userAttributes, userMappings,
712 userExpandoMappings, contactMappings,
713 contactExpandoMappings, StringPool.BLANK);
714
715 importGroups(
716 ldapServerId, companyId, ldapContext, userAttributes,
717 user, userMappings, groupMappings);
718 }
719 catch (Exception e) {
720 _log.error("Unable to import user " + searchResult, e);
721 }
722 }
723 }
724 }
725
726 protected Set<Long> importGroup(
727 long ldapServerId, long companyId, LdapContext ldapContext,
728 String fullGroupDN, User user, Properties groupMappings,
729 Set<Long> newUserGroupIds)
730 throws Exception {
731
732 String userGroupIdKey = null;
733
734 Long userGroupId = null;
735
736 if (PropsValues.LDAP_IMPORT_GROUP_CACHE_ENABLED) {
737 StringBundler sb = new StringBundler(5);
738
739 sb.append(ldapServerId);
740 sb.append(StringPool.UNDERLINE);
741 sb.append(companyId);
742 sb.append(StringPool.UNDERLINE);
743 sb.append(fullGroupDN);
744
745 userGroupIdKey = sb.toString();
746
747 userGroupId = _portalCache.get(userGroupIdKey);
748 }
749
750 if (userGroupId != null) {
751 if (_log.isDebugEnabled()) {
752 _log.debug("Skipping reimport of full group DN " + fullGroupDN);
753 }
754 }
755 else {
756 if (_log.isDebugEnabled()) {
757 _log.debug("Importing full group DN " + fullGroupDN);
758 }
759
760 Attributes groupAttributes = null;
761
762 try {
763 groupAttributes = PortalLDAPUtil.getGroupAttributes(
764 ldapServerId, companyId, ldapContext, fullGroupDN);
765 }
766 catch (NameNotFoundException nnfe) {
767 _log.error(
768 "LDAP group not found with full group DN " + fullGroupDN,
769 nnfe);
770 }
771
772 UserGroup userGroup = importUserGroup(
773 companyId, groupAttributes, groupMappings);
774
775 if (userGroup == null) {
776 return newUserGroupIds;
777 }
778
779 userGroupId = userGroup.getUserGroupId();
780
781 if (PropsValues.LDAP_IMPORT_GROUP_CACHE_ENABLED) {
782 _portalCache.put(userGroupIdKey, userGroupId);
783 }
784 }
785
786 if (_log.isDebugEnabled()) {
787 _log.debug(
788 "Adding " + user.getUserId() + " to group " + userGroupId);
789 }
790
791 newUserGroupIds.add(userGroupId);
792
793 return newUserGroupIds;
794 }
795
796 protected void importGroups(
797 long ldapServerId, long companyId, LdapContext ldapContext,
798 Attributes attributes, User user, Properties userMappings,
799 Properties groupMappings)
800 throws Exception {
801
802 Set<Long> newUserGroupIds = new LinkedHashSet<Long>();
803
804 if (PrefsPropsUtil.getBoolean(
805 companyId, PropsKeys.LDAP_IMPORT_GROUP_SEARCH_FILTER_ENABLED)) {
806
807 String postfix = LDAPSettingsUtil.getPropertyPostfix(ldapServerId);
808
809 String baseDN = PrefsPropsUtil.getString(
810 companyId, PropsKeys.LDAP_BASE_DN + postfix);
811
812 Binding binding = PortalLDAPUtil.getUser(
813 ldapServerId, companyId, user.getScreenName(),
814 user.getEmailAddress());
815
816 String fullUserDN = PortalLDAPUtil.getNameInNamespace(
817 ldapServerId, companyId, binding);
818
819 StringBundler sb = new StringBundler(9);
820
821 sb.append(StringPool.OPEN_PARENTHESIS);
822 sb.append(StringPool.AMPERSAND);
823 sb.append(
824 PrefsPropsUtil.getString(
825 companyId,
826 PropsKeys.LDAP_IMPORT_GROUP_SEARCH_FILTER + postfix));
827 sb.append(StringPool.OPEN_PARENTHESIS);
828 sb.append(groupMappings.getProperty("user"));
829 sb.append(StringPool.EQUAL);
830 sb.append(escapeValue(fullUserDN));
831 sb.append(StringPool.CLOSE_PARENTHESIS);
832 sb.append(StringPool.CLOSE_PARENTHESIS);
833
834 byte[] cookie = new byte[0];
835
836 while (cookie != null) {
837 List<SearchResult> searchResults =
838 new ArrayList<SearchResult>();
839
840 String groupMappingsGroupName = GetterUtil.getString(
841 groupMappings.getProperty("groupName"));
842
843 groupMappingsGroupName = StringUtil.toLowerCase(
844 groupMappingsGroupName);
845
846 cookie = PortalLDAPUtil.searchLDAP(
847 companyId, ldapContext, cookie, 0, baseDN, sb.toString(),
848 new String[] {groupMappingsGroupName}, searchResults);
849
850 for (SearchResult searchResult : searchResults) {
851 String fullGroupDN = PortalLDAPUtil.getNameInNamespace(
852 ldapServerId, companyId, searchResult);
853
854 newUserGroupIds = importGroup(
855 ldapServerId, companyId, ldapContext, fullGroupDN, user,
856 groupMappings, newUserGroupIds);
857 }
858 }
859 }
860 else {
861 String userMappingsGroup = userMappings.getProperty("group");
862
863 if (Validator.isNull(userMappingsGroup)) {
864 return;
865 }
866
867 Attribute userGroupAttribute = attributes.get(userMappingsGroup);
868
869 if (userGroupAttribute == null) {
870 return;
871 }
872
873 for (int i = 0; i < userGroupAttribute.size(); i++) {
874 String fullGroupDN = (String)userGroupAttribute.get(i);
875
876 newUserGroupIds = importGroup(
877 ldapServerId, companyId, ldapContext, fullGroupDN, user,
878 groupMappings, newUserGroupIds);
879 }
880 }
881
882 addUserGroupsNotAddedByLDAPImport(user.getUserId(), newUserGroupIds);
883
884 Set<Long> oldUserGroupIds = new LinkedHashSet<Long>();
885
886 List<UserGroup> oldUserGroups =
887 UserGroupLocalServiceUtil.getUserUserGroups(user.getUserId());
888
889 for (UserGroup oldUserGroup : oldUserGroups) {
890 oldUserGroupIds.add(oldUserGroup.getUserGroupId());
891 }
892
893 if (!oldUserGroupIds.equals(newUserGroupIds)) {
894 long[] userGroupIds = ArrayUtil.toLongArray(newUserGroupIds);
895
896 UserGroupLocalServiceUtil.setUserUserGroups(
897 user.getUserId(), userGroupIds);
898 }
899 }
900
901 protected User importUser(
902 long ldapServerId, long companyId, Attributes attributes,
903 Properties userMappings, Properties userExpandoMappings,
904 Properties contactMappings, Properties contactExpandoMappings,
905 String password)
906 throws Exception {
907
908 LDAPUserTransactionThreadLocal.setOriginatesFromLDAP(true);
909
910 try {
911 AttributesTransformer attributesTransformer =
912 AttributesTransformerFactory.getInstance();
913
914 attributes = attributesTransformer.transformUser(attributes);
915
916 LDAPUser ldapUser = _ldapToPortalConverter.importLDAPUser(
917 companyId, attributes, userMappings, userExpandoMappings,
918 contactMappings, contactExpandoMappings, password);
919
920 User user = getUser(companyId, ldapUser);
921
922 if ((user != null) && user.isDefaultUser()) {
923 return user;
924 }
925
926 ServiceContext serviceContext = ldapUser.getServiceContext();
927
928 serviceContext.setAttribute("ldapServerId", ldapServerId);
929
930 boolean isNew = false;
931
932 if (user == null) {
933 user = addUser(companyId, ldapUser, password);
934
935 isNew = true;
936 }
937
938 String modifiedDate = LDAPUtil.getAttributeString(
939 attributes, "modifyTimestamp");
940
941 user = updateUser(
942 companyId, ldapUser, user, userMappings, contactMappings,
943 password, modifiedDate, isNew);
944
945 updateExpandoAttributes(
946 user, ldapUser, userExpandoMappings, contactExpandoMappings);
947
948 return user;
949 }
950 finally {
951 LDAPUserTransactionThreadLocal.setOriginatesFromLDAP(false);
952 }
953 }
954
955 protected UserGroup importUserGroup(
956 long companyId, Attributes attributes, Properties groupMappings)
957 throws Exception {
958
959 AttributesTransformer attributesTransformer =
960 AttributesTransformerFactory.getInstance();
961
962 attributes = attributesTransformer.transformGroup(attributes);
963
964 LDAPGroup ldapGroup = _ldapToPortalConverter.importLDAPGroup(
965 companyId, attributes, groupMappings);
966
967 UserGroup userGroup = null;
968
969 try {
970 userGroup = UserGroupLocalServiceUtil.getUserGroup(
971 companyId, ldapGroup.getGroupName());
972
973 if (!Validator.equals(
974 userGroup.getDescription(), ldapGroup.getDescription())) {
975
976 UserGroupLocalServiceUtil.updateUserGroup(
977 companyId, userGroup.getUserGroupId(),
978 ldapGroup.getGroupName(), ldapGroup.getDescription(), null);
979 }
980 }
981 catch (NoSuchUserGroupException nsuge) {
982 if (_log.isDebugEnabled()) {
983 _log.debug(
984 "Adding user group to portal " + ldapGroup.getGroupName());
985 }
986
987 long defaultUserId = UserLocalServiceUtil.getDefaultUserId(
988 companyId);
989
990 LDAPUserGroupTransactionThreadLocal.setOriginatesFromLDAP(true);
991
992 try {
993 userGroup = UserGroupLocalServiceUtil.addUserGroup(
994 defaultUserId, companyId, ldapGroup.getGroupName(),
995 ldapGroup.getDescription(), null);
996 }
997 catch (Exception e) {
998 if (_log.isWarnEnabled()) {
999 _log.warn(
1000 "Unable to create user group " +
1001 ldapGroup.getGroupName());
1002 }
1003
1004 if (_log.isDebugEnabled()) {
1005 _log.debug(e, e);
1006 }
1007 }
1008 finally {
1009 LDAPUserGroupTransactionThreadLocal.setOriginatesFromLDAP(
1010 false);
1011 }
1012 }
1013
1014 addRole(companyId, ldapGroup, userGroup);
1015
1016 return userGroup;
1017 }
1018
1019 protected void importUsers(
1020 long ldapServerId, long companyId, LdapContext ldapContext,
1021 Properties userMappings, Properties userExpandoMappings,
1022 Properties contactMappings, Properties contactExpandoMappings,
1023 long userGroupId, Attribute attribute)
1024 throws Exception {
1025
1026 Set<Long> newUserIds = new LinkedHashSet<Long>(attribute.size());
1027
1028 for (int i = 0; i < attribute.size(); i++) {
1029 String fullUserDN = (String)attribute.get(i);
1030
1031 Attributes userAttributes = null;
1032
1033 try {
1034 userAttributes = PortalLDAPUtil.getUserAttributes(
1035 ldapServerId, companyId, ldapContext, fullUserDN);
1036 }
1037 catch (NameNotFoundException nnfe) {
1038 _log.error(
1039 "LDAP user not found with fullUserDN " + fullUserDN, nnfe);
1040
1041 continue;
1042 }
1043
1044 try {
1045 User user = importUser(
1046 ldapServerId, companyId, userAttributes, userMappings,
1047 userExpandoMappings, contactMappings,
1048 contactExpandoMappings, StringPool.BLANK);
1049
1050 if (user != null) {
1051 if (_log.isDebugEnabled()) {
1052 _log.debug(
1053 "Adding " + user.getUserId() + " to group " +
1054 userGroupId);
1055 }
1056
1057 UserLocalServiceUtil.addUserGroupUsers(
1058 userGroupId, new long[] {user.getUserId()});
1059
1060 newUserIds.add(user.getUserId());
1061 }
1062 }
1063 catch (Exception e) {
1064 _log.error("Unable to load user " + userAttributes, e);
1065 }
1066 }
1067
1068 List<User> userGroupUsers = UserLocalServiceUtil.getUserGroupUsers(
1069 userGroupId);
1070
1071 for (User user : userGroupUsers) {
1072 if (!newUserIds.contains(user.getUserId())) {
1073 UserLocalServiceUtil.deleteUserGroupUser(
1074 userGroupId, user.getUserId());
1075 }
1076 }
1077 }
1078
1079 protected void populateExpandoAttributes(
1080 ExpandoBridge expandoBridge, Map<String, String[]> expandoAttributes,
1081 Properties expandoMappings) {
1082
1083 Map<String, Serializable> serializedExpandoAttributes =
1084 new HashMap<String, Serializable>();
1085
1086 for (Map.Entry<String, String[]> expandoAttribute :
1087 expandoAttributes.entrySet()) {
1088
1089 String name = expandoAttribute.getKey();
1090
1091 if (!expandoBridge.hasAttribute(name)) {
1092 continue;
1093 }
1094
1095 if (!expandoMappings.containsKey(name) ||
1096 _ldapUserIgnoreAttributes.contains(name)) {
1097
1098 int type = expandoBridge.getAttributeType(name);
1099
1100 Serializable value =
1101 ExpandoConverterUtil.getAttributeFromStringArray(
1102 type, expandoAttribute.getValue());
1103
1104 serializedExpandoAttributes.put(name, value);
1105 }
1106 }
1107
1108 try {
1109 ExpandoValueLocalServiceUtil.addValues(
1110 expandoBridge.getCompanyId(), expandoBridge.getClassName(),
1111 ExpandoTableConstants.DEFAULT_TABLE_NAME,
1112 expandoBridge.getClassPK(), serializedExpandoAttributes);
1113 }
1114 catch (Exception e) {
1115 if (_log.isWarnEnabled()) {
1116 _log.warn("Unable to populate expando attributes");
1117 }
1118
1119 if (_log.isDebugEnabled()) {
1120 _log.debug(e, e);
1121 }
1122 }
1123 }
1124
1125 protected void setProperty(
1126 Object bean1, Object bean2, String propertyName) {
1127
1128 Object value = BeanPropertiesUtil.getObject(bean2, propertyName);
1129
1130 BeanPropertiesUtil.setProperty(bean1, propertyName, value);
1131 }
1132
1133 protected void updateExpandoAttributes(
1134 User user, LDAPUser ldapUser, Properties userExpandoMappings,
1135 Properties contactExpandoMappings)
1136 throws Exception {
1137
1138 ExpandoBridge userExpandoBridge = user.getExpandoBridge();
1139
1140 populateExpandoAttributes(
1141 userExpandoBridge, ldapUser.getUserExpandoAttributes(),
1142 userExpandoMappings);
1143
1144 Contact contact = user.getContact();
1145
1146 ExpandoBridge contactExpandoBridge = contact.getExpandoBridge();
1147
1148 populateExpandoAttributes(
1149 contactExpandoBridge, ldapUser.getContactExpandoAttributes(),
1150 contactExpandoMappings);
1151 }
1152
1153 protected void updateLDAPUser(
1154 User ldapUser, Contact ldapContact, User user,
1155 Properties userMappings, Properties contactMappings)
1156 throws PortalException, SystemException {
1157
1158 Contact contact = user.getContact();
1159
1160 for (String propertyName : _CONTACT_PROPERTY_NAMES) {
1161 if (!contactMappings.containsKey(propertyName) ||
1162 _ldapUserIgnoreAttributes.contains(propertyName)) {
1163
1164 setProperty(ldapContact, contact, propertyName);
1165 }
1166 }
1167
1168 for (String propertyName : _USER_PROPERTY_NAMES) {
1169 if (!userMappings.containsKey(propertyName) ||
1170 _ldapUserIgnoreAttributes.contains(propertyName) ) {
1171
1172 setProperty(ldapUser, user, propertyName);
1173 }
1174 }
1175 }
1176
1177 protected User updateUser(
1178 long companyId, LDAPUser ldapUser, User user,
1179 Properties userMappings, Properties contactMappings,
1180 String password, String modifiedDate, boolean isNew)
1181 throws Exception {
1182
1183 Date ldapUserModifiedDate = null;
1184
1185 boolean passwordReset = ldapUser.isPasswordReset();
1186
1187 if (PrefsPropsUtil.getBoolean(
1188 companyId, PropsKeys.LDAP_EXPORT_ENABLED,
1189 PropsValues.LDAP_EXPORT_ENABLED)) {
1190
1191 passwordReset = user.isPasswordReset();
1192 }
1193
1194 try {
1195 if (Validator.isNotNull(modifiedDate)) {
1196 ldapUserModifiedDate = LDAPUtil.parseDate(modifiedDate);
1197
1198 if (ldapUserModifiedDate.equals(user.getModifiedDate())) {
1199 if (ldapUser.isAutoPassword()) {
1200 if (_log.isDebugEnabled()) {
1201 _log.debug(
1202 "Skipping user " + user.getEmailAddress() +
1203 " because he is already synchronized");
1204 }
1205
1206 return user;
1207 }
1208
1209 UserLocalServiceUtil.updatePassword(
1210 user.getUserId(), password, password, passwordReset,
1211 true);
1212
1213 if (_log.isDebugEnabled()) {
1214 _log.debug(
1215 "User " + user.getEmailAddress() +
1216 " is already synchronized, but updated " +
1217 "password to avoid a blank value");
1218 }
1219
1220 return user;
1221 }
1222 }
1223 else if (!isNew) {
1224 if (_log.isInfoEnabled()) {
1225 _log.info(
1226 "Skipping user " + user.getEmailAddress() +
1227 " because the LDAP entry was never modified");
1228 }
1229
1230 return user;
1231 }
1232 }
1233 catch (ParseException pe) {
1234 if (_log.isDebugEnabled()) {
1235 _log.debug(
1236 "Unable to parse LDAP modify timestamp " + modifiedDate,
1237 pe);
1238 }
1239 }
1240
1241 if (!PropsValues.LDAP_IMPORT_USER_PASSWORD_ENABLED) {
1242 password = PropsValues.LDAP_IMPORT_USER_PASSWORD_DEFAULT;
1243
1244 if (StringUtil.equalsIgnoreCase(
1245 password, _USER_PASSWORD_SCREEN_NAME)) {
1246
1247 password = ldapUser.getScreenName();
1248 }
1249 }
1250
1251 if (Validator.isNull(ldapUser.getScreenName())) {
1252 ldapUser.setAutoScreenName(true);
1253 }
1254
1255 if (ldapUser.isAutoScreenName()) {
1256 ScreenNameGenerator screenNameGenerator =
1257 ScreenNameGeneratorFactory.getInstance();
1258
1259 ldapUser.setScreenName(
1260 screenNameGenerator.generate(
1261 companyId, user.getUserId(), ldapUser.getEmailAddress()));
1262 }
1263
1264 Calendar birthdayCal = CalendarFactoryUtil.getCalendar();
1265
1266 Contact ldapContact = ldapUser.getContact();
1267
1268 birthdayCal.setTime(ldapContact.getBirthday());
1269
1270 int birthdayMonth = birthdayCal.get(Calendar.MONTH);
1271 int birthdayDay = birthdayCal.get(Calendar.DAY_OF_MONTH);
1272 int birthdayYear = birthdayCal.get(Calendar.YEAR);
1273
1274 if (ldapUser.isUpdatePassword()) {
1275 UserLocalServiceUtil.updatePassword(
1276 user.getUserId(), password, password, passwordReset, true);
1277 }
1278
1279 updateLDAPUser(
1280 ldapUser.getUser(), ldapContact, user, userMappings,
1281 contactMappings);
1282
1283 user = UserLocalServiceUtil.updateUser(
1284 user.getUserId(), password, StringPool.BLANK, StringPool.BLANK,
1285 passwordReset, ldapUser.getReminderQueryQuestion(),
1286 ldapUser.getReminderQueryAnswer(), ldapUser.getScreenName(),
1287 ldapUser.getEmailAddress(), ldapUser.getFacebookId(),
1288 ldapUser.getOpenId(), ldapUser.getLanguageId(),
1289 ldapUser.getTimeZoneId(), ldapUser.getGreeting(),
1290 ldapUser.getComments(), ldapUser.getFirstName(),
1291 ldapUser.getMiddleName(), ldapUser.getLastName(),
1292 ldapUser.getPrefixId(), ldapUser.getSuffixId(), ldapUser.isMale(),
1293 birthdayMonth, birthdayDay, birthdayYear, ldapUser.getSmsSn(),
1294 ldapUser.getAimSn(), ldapUser.getFacebookSn(), ldapUser.getIcqSn(),
1295 ldapUser.getJabberSn(), ldapUser.getMsnSn(),
1296 ldapUser.getMySpaceSn(), ldapUser.getSkypeSn(),
1297 ldapUser.getTwitterSn(), ldapUser.getYmSn(), ldapUser.getJobTitle(),
1298 ldapUser.getGroupIds(), ldapUser.getOrganizationIds(),
1299 ldapUser.getRoleIds(), ldapUser.getUserGroupRoles(),
1300 ldapUser.getUserGroupIds(), ldapUser.getServiceContext());
1301
1302 if (ldapUserModifiedDate != null) {
1303 user = UserLocalServiceUtil.updateModifiedDate(
1304 user.getUserId(), ldapUserModifiedDate);
1305 }
1306
1307 if (ldapUser.isUpdatePortrait()) {
1308 byte[] portraitBytes = ldapUser.getPortraitBytes();
1309
1310 if (ArrayUtil.isNotEmpty(portraitBytes)) {
1311 UserLocalServiceUtil.updatePortrait(
1312 user.getUserId(), portraitBytes);
1313 }
1314 else {
1315 UserLocalServiceUtil.deletePortrait(user.getUserId());
1316 }
1317 }
1318
1319 user = UserLocalServiceUtil.updateStatus(
1320 user.getUserId(), ldapUser.getStatus());
1321
1322 return user;
1323 }
1324
1325 private static final String[] _CONTACT_PROPERTY_NAMES = {
1326 "aimSn", "employeeNumber", "facebookSn", "icqSn", "jabberSn", "male",
1327 "msnSn", "mySpaceSn","prefixId", "skypeSn", "smsSn", "suffixId",
1328 "twitterSn", "ymSn"
1329 };
1330
1331 private static final String _IMPORT_BY_GROUP = "group";
1332
1333 private static final String _IMPORT_BY_USER = "user";
1334
1335 private static final String _USER_PASSWORD_SCREEN_NAME = "screenName";
1336
1337 private static final String[] _USER_PROPERTY_NAMES = {
1338 "comments", "greeting", "jobTitle", "languageId", "middleName",
1339 "openId", "timeZoneId"
1340 };
1341
1342 private static Log _log = LogFactoryUtil.getLog(
1343 PortalLDAPImporterImpl.class);
1344
1345 private LDAPToPortalConverter _ldapToPortalConverter;
1346 private Set<String> _ldapUserIgnoreAttributes = SetUtil.fromArray(
1347 PropsValues.LDAP_USER_IGNORE_ATTRIBUTES);
1348 private PortalCache<String, Long> _portalCache = SingleVMPoolUtil.getCache(
1349 PortalLDAPImporter.class.getName(), false);
1350
1351 }