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