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.dao.shard.ShardUtil;
023 import com.liferay.portal.kernel.exception.PortalException;
024 import com.liferay.portal.kernel.exception.SystemException;
025 import com.liferay.portal.kernel.ldap.LDAPUtil;
026 import com.liferay.portal.kernel.log.Log;
027 import com.liferay.portal.kernel.log.LogFactoryUtil;
028 import com.liferay.portal.kernel.security.pacl.DoPrivileged;
029 import com.liferay.portal.kernel.util.ArrayUtil;
030 import com.liferay.portal.kernel.util.CalendarFactoryUtil;
031 import com.liferay.portal.kernel.util.GetterUtil;
032 import com.liferay.portal.kernel.util.LocaleUtil;
033 import com.liferay.portal.kernel.util.PropsKeys;
034 import com.liferay.portal.kernel.util.SetUtil;
035 import com.liferay.portal.kernel.util.StringBundler;
036 import com.liferay.portal.kernel.util.StringPool;
037 import com.liferay.portal.kernel.util.StringUtil;
038 import com.liferay.portal.kernel.util.Validator;
039 import com.liferay.portal.model.Company;
040 import com.liferay.portal.model.CompanyConstants;
041 import com.liferay.portal.model.Contact;
042 import com.liferay.portal.model.Group;
043 import com.liferay.portal.model.Role;
044 import com.liferay.portal.model.RoleConstants;
045 import com.liferay.portal.model.User;
046 import com.liferay.portal.model.UserGroup;
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 import com.liferay.util.PwdGenerator;
063
064 import java.io.Serializable;
065
066 import java.text.ParseException;
067
068 import java.util.ArrayList;
069 import java.util.Calendar;
070 import java.util.Date;
071 import java.util.HashMap;
072 import java.util.LinkedHashSet;
073 import java.util.List;
074 import java.util.Locale;
075 import java.util.Map;
076 import java.util.Properties;
077 import java.util.Set;
078
079 import javax.naming.Binding;
080 import javax.naming.NameNotFoundException;
081 import javax.naming.NamingEnumeration;
082 import javax.naming.directory.Attribute;
083 import javax.naming.directory.Attributes;
084 import javax.naming.directory.SearchControls;
085 import javax.naming.directory.SearchResult;
086 import javax.naming.ldap.LdapContext;
087
088
094 @DoPrivileged
095 public class PortalLDAPImporterImpl implements PortalLDAPImporter {
096
097 @Override
098 public void importFromLDAP() throws Exception {
099 List<Company> companies = CompanyLocalServiceUtil.getCompanies(false);
100
101 for (Company company : companies) {
102 importFromLDAP(company.getCompanyId());
103 }
104 }
105
106 @Override
107 public void importFromLDAP(long companyId) throws Exception {
108 if (!LDAPSettingsUtil.isImportEnabled(companyId)) {
109 return;
110 }
111
112 try {
113 ShardUtil.pushCompanyService(companyId);
114
115 long defaultUserId = UserLocalServiceUtil.getDefaultUserId(
116 companyId);
117
118 if (LockLocalServiceUtil.hasLock(
119 defaultUserId, PortalLDAPImporterUtil.class.getName(),
120 companyId)) {
121
122 if (_log.isDebugEnabled()) {
123 _log.debug(
124 "Skipping LDAP import for company " + companyId +
125 " because another LDAP import is in process");
126 }
127
128 return;
129 }
130
131 LockLocalServiceUtil.lock(
132 defaultUserId, PortalLDAPImporterUtil.class.getName(),
133 companyId, PortalLDAPImporterImpl.class.getName(), false,
134 PropsValues.LDAP_IMPORT_LOCK_EXPIRATION_TIME);
135
136 long[] ldapServerIds = StringUtil.split(
137 PrefsPropsUtil.getString(companyId, "ldap.server.ids"), 0L);
138
139 for (long ldapServerId : ldapServerIds) {
140 importFromLDAP(ldapServerId, companyId);
141 }
142
143 for (int ldapServerId = 0;; ldapServerId++) {
144 String postfix = LDAPSettingsUtil.getPropertyPostfix(
145 ldapServerId);
146
147 String providerUrl = PrefsPropsUtil.getString(
148 companyId, PropsKeys.LDAP_BASE_PROVIDER_URL + postfix);
149
150 if (Validator.isNull(providerUrl)) {
151 break;
152 }
153
154 importFromLDAP(ldapServerId, companyId);
155 }
156 }
157 finally {
158 LockLocalServiceUtil.unlock(
159 PortalLDAPImporterUtil.class.getName(), companyId);
160
161 ShardUtil.popCompanyService();
162 }
163 }
164
165 @Override
166 public void importFromLDAP(long ldapServerId, long companyId)
167 throws Exception {
168
169 if (!LDAPSettingsUtil.isImportEnabled(companyId)) {
170 return;
171 }
172
173 LdapContext ldapContext = PortalLDAPUtil.getContext(
174 ldapServerId, companyId);
175
176 if (ldapContext == null) {
177 return;
178 }
179
180 try {
181 Properties userMappings = LDAPSettingsUtil.getUserMappings(
182 ldapServerId, companyId);
183 Properties userExpandoMappings =
184 LDAPSettingsUtil.getUserExpandoMappings(
185 ldapServerId, companyId);
186 Properties contactMappings = LDAPSettingsUtil.getContactMappings(
187 ldapServerId, companyId);
188 Properties contactExpandoMappings =
189 LDAPSettingsUtil.getContactExpandoMappings(
190 ldapServerId, companyId);
191 Properties groupMappings = LDAPSettingsUtil.getGroupMappings(
192 ldapServerId, companyId);
193
194 String importMethod = PrefsPropsUtil.getString(
195 companyId, PropsKeys.LDAP_IMPORT_METHOD);
196
197 if (importMethod.equals(_IMPORT_BY_GROUP)) {
198 importFromLDAPByGroup(
199 ldapServerId, companyId, ldapContext, userMappings,
200 userExpandoMappings, contactMappings,
201 contactExpandoMappings, groupMappings);
202 }
203 else if (importMethod.equals(_IMPORT_BY_USER)) {
204 importFromLDAPByUser(
205 ldapServerId, companyId, ldapContext, userMappings,
206 userExpandoMappings, contactMappings,
207 contactExpandoMappings, groupMappings);
208 }
209 }
210 catch (Exception e) {
211 _log.error("Error importing LDAP users and groups", e);
212 }
213 finally {
214 if (ldapContext != null) {
215 ldapContext.close();
216 }
217 }
218 }
219
220 @Override
221 public User importLDAPUser(
222 long ldapServerId, long companyId, LdapContext ldapContext,
223 Attributes attributes, String password)
224 throws Exception {
225
226 Properties userMappings = LDAPSettingsUtil.getUserMappings(
227 ldapServerId, companyId);
228 Properties userExpandoMappings =
229 LDAPSettingsUtil.getUserExpandoMappings(ldapServerId, companyId);
230 Properties contactMappings = LDAPSettingsUtil.getContactMappings(
231 ldapServerId, companyId);
232 Properties contactExpandoMappings =
233 LDAPSettingsUtil.getContactExpandoMappings(ldapServerId, companyId);
234
235 User user = importUser(
236 ldapServerId, companyId, attributes, userMappings,
237 userExpandoMappings, contactMappings, contactExpandoMappings,
238 password);
239
240 Properties groupMappings = LDAPSettingsUtil.getGroupMappings(
241 ldapServerId, companyId);
242
243 importGroups(
244 ldapServerId, companyId, ldapContext, attributes, user,
245 userMappings, groupMappings);
246
247 return user;
248 }
249
250 @Override
251 public User importLDAPUser(
252 long ldapServerId, long companyId, String emailAddress,
253 String screenName)
254 throws Exception {
255
256 LdapContext ldapContext = null;
257
258 NamingEnumeration<SearchResult> enu = null;
259
260 try {
261 String postfix = LDAPSettingsUtil.getPropertyPostfix(ldapServerId);
262
263 String baseDN = PrefsPropsUtil.getString(
264 companyId, PropsKeys.LDAP_BASE_DN + postfix);
265
266 ldapContext = PortalLDAPUtil.getContext(ldapServerId, companyId);
267
268 if (ldapContext == null) {
269 _log.error("Unable to bind to the LDAP server");
270
271 return null;
272 }
273
274 String filter = PrefsPropsUtil.getString(
275 companyId, PropsKeys.LDAP_AUTH_SEARCH_FILTER + postfix);
276
277 if (_log.isDebugEnabled()) {
278 _log.debug("Search filter before transformation " + filter);
279 }
280
281 filter = StringUtil.replace(
282 filter,
283 new String[] {
284 "@company_id@", "@email_address@", "@screen_name@"
285 },
286 new String[] {
287 String.valueOf(companyId), emailAddress, screenName
288 });
289
290 LDAPUtil.validateFilter(filter);
291
292 if (_log.isDebugEnabled()) {
293 _log.debug("Search filter after transformation " + filter);
294 }
295
296 Properties userMappings = LDAPSettingsUtil.getUserMappings(
297 ldapServerId, companyId);
298
299 String userMappingsScreenName = GetterUtil.getString(
300 userMappings.getProperty("screenName"));
301
302 userMappingsScreenName = StringUtil.toLowerCase(
303 userMappingsScreenName);
304
305 SearchControls searchControls = new SearchControls(
306 SearchControls.SUBTREE_SCOPE, 1, 0,
307 new String[] {userMappingsScreenName}, false, false);
308
309 enu = ldapContext.search(baseDN, filter, searchControls);
310
311 if (enu.hasMoreElements()) {
312 if (_log.isDebugEnabled()) {
313 _log.debug("Search filter returned at least one result");
314 }
315
316 Binding binding = enu.nextElement();
317
318 Attributes attributes = PortalLDAPUtil.getUserAttributes(
319 ldapServerId, companyId, ldapContext,
320 PortalLDAPUtil.getNameInNamespace(
321 ldapServerId, companyId, binding));
322
323 return importLDAPUser(
324 ldapServerId, companyId, ldapContext, attributes,
325 StringPool.BLANK);
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, StringPool.BLANK);
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.getUuid(), 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, StringPool.BLANK);
715
716 importGroups(
717 ldapServerId, companyId, ldapContext, userAttributes,
718 user, userMappings, groupMappings);
719 }
720 catch (Exception e) {
721 _log.error("Unable to import user " + searchResult, e);
722 }
723 }
724 }
725 }
726
727 protected Set<Long> importGroup(
728 long ldapServerId, long companyId, LdapContext ldapContext,
729 String fullGroupDN, User user, Properties groupMappings,
730 Set<Long> newUserGroupIds)
731 throws Exception {
732
733 String userGroupIdKey = null;
734
735 Long userGroupId = null;
736
737 if (PropsValues.LDAP_IMPORT_GROUP_CACHE_ENABLED) {
738 StringBundler sb = new StringBundler(5);
739
740 sb.append(ldapServerId);
741 sb.append(StringPool.UNDERLINE);
742 sb.append(companyId);
743 sb.append(StringPool.UNDERLINE);
744 sb.append(fullGroupDN);
745
746 userGroupIdKey = sb.toString();
747
748 userGroupId = _portalCache.get(userGroupIdKey);
749 }
750
751 if (userGroupId != null) {
752 if (_log.isDebugEnabled()) {
753 _log.debug("Skipping reimport of full group DN " + fullGroupDN);
754 }
755 }
756 else {
757 if (_log.isDebugEnabled()) {
758 _log.debug("Importing full group DN " + fullGroupDN);
759 }
760
761 Attributes groupAttributes = null;
762
763 try {
764 groupAttributes = PortalLDAPUtil.getGroupAttributes(
765 ldapServerId, companyId, ldapContext, fullGroupDN);
766 }
767 catch (NameNotFoundException nnfe) {
768 _log.error(
769 "LDAP group not found with full group DN " + fullGroupDN,
770 nnfe);
771 }
772
773 UserGroup userGroup = importUserGroup(
774 companyId, groupAttributes, groupMappings);
775
776 if (userGroup == null) {
777 return newUserGroupIds;
778 }
779
780 userGroupId = userGroup.getUserGroupId();
781
782 if (PropsValues.LDAP_IMPORT_GROUP_CACHE_ENABLED) {
783 _portalCache.put(userGroupIdKey, userGroupId);
784 }
785 }
786
787 if (_log.isDebugEnabled()) {
788 _log.debug(
789 "Adding " + user.getUserId() + " to group " + userGroupId);
790 }
791
792 newUserGroupIds.add(userGroupId);
793
794 return newUserGroupIds;
795 }
796
797 protected void importGroups(
798 long ldapServerId, long companyId, LdapContext ldapContext,
799 Attributes attributes, User user, Properties userMappings,
800 Properties groupMappings)
801 throws Exception {
802
803 Set<Long> newUserGroupIds = new LinkedHashSet<Long>();
804
805 if (PrefsPropsUtil.getBoolean(
806 companyId, PropsKeys.LDAP_IMPORT_GROUP_SEARCH_FILTER_ENABLED)) {
807
808 String postfix = LDAPSettingsUtil.getPropertyPostfix(ldapServerId);
809
810 String baseDN = PrefsPropsUtil.getString(
811 companyId, PropsKeys.LDAP_BASE_DN + postfix);
812
813 Binding binding = PortalLDAPUtil.getUser(
814 ldapServerId, companyId, user.getScreenName(),
815 user.getEmailAddress());
816
817 String fullUserDN = PortalLDAPUtil.getNameInNamespace(
818 ldapServerId, companyId, binding);
819
820 StringBundler sb = new StringBundler(9);
821
822 sb.append(StringPool.OPEN_PARENTHESIS);
823 sb.append(StringPool.AMPERSAND);
824 sb.append(
825 PrefsPropsUtil.getString(
826 companyId,
827 PropsKeys.LDAP_IMPORT_GROUP_SEARCH_FILTER + postfix));
828 sb.append(StringPool.OPEN_PARENTHESIS);
829 sb.append(groupMappings.getProperty("user"));
830 sb.append(StringPool.EQUAL);
831 sb.append(escapeValue(fullUserDN));
832 sb.append(StringPool.CLOSE_PARENTHESIS);
833 sb.append(StringPool.CLOSE_PARENTHESIS);
834
835 byte[] cookie = new byte[0];
836
837 while (cookie != null) {
838 List<SearchResult> searchResults =
839 new ArrayList<SearchResult>();
840
841 String groupMappingsGroupName = GetterUtil.getString(
842 groupMappings.getProperty("groupName"));
843
844 groupMappingsGroupName = StringUtil.toLowerCase(
845 groupMappingsGroupName);
846
847 cookie = PortalLDAPUtil.searchLDAP(
848 companyId, ldapContext, cookie, 0, baseDN, sb.toString(),
849 new String[] {groupMappingsGroupName}, searchResults);
850
851 for (SearchResult searchResult : searchResults) {
852 String fullGroupDN = PortalLDAPUtil.getNameInNamespace(
853 ldapServerId, companyId, searchResult);
854
855 newUserGroupIds = importGroup(
856 ldapServerId, companyId, ldapContext, fullGroupDN, user,
857 groupMappings, newUserGroupIds);
858 }
859 }
860 }
861 else {
862 String userMappingsGroup = userMappings.getProperty("group");
863
864 if (Validator.isNull(userMappingsGroup)) {
865 return;
866 }
867
868 Attribute userGroupAttribute = attributes.get(userMappingsGroup);
869
870 if (userGroupAttribute == null) {
871 return;
872 }
873
874 for (int i = 0; i < userGroupAttribute.size(); i++) {
875 String fullGroupDN = (String)userGroupAttribute.get(i);
876
877 newUserGroupIds = importGroup(
878 ldapServerId, companyId, ldapContext, fullGroupDN, user,
879 groupMappings, newUserGroupIds);
880 }
881 }
882
883 addUserGroupsNotAddedByLDAPImport(user.getUserId(), newUserGroupIds);
884
885 Set<Long> oldUserGroupIds = new LinkedHashSet<Long>();
886
887 List<UserGroup> oldUserGroups =
888 UserGroupLocalServiceUtil.getUserUserGroups(user.getUserId());
889
890 for (UserGroup oldUserGroup : oldUserGroups) {
891 oldUserGroupIds.add(oldUserGroup.getUserGroupId());
892 }
893
894 if (!oldUserGroupIds.equals(newUserGroupIds)) {
895 long[] userGroupIds = ArrayUtil.toLongArray(newUserGroupIds);
896
897 UserGroupLocalServiceUtil.setUserUserGroups(
898 user.getUserId(), userGroupIds);
899 }
900 }
901
902 protected User importUser(
903 long ldapServerId, long companyId, Attributes attributes,
904 Properties userMappings, Properties userExpandoMappings,
905 Properties contactMappings, Properties contactExpandoMappings,
906 String password)
907 throws Exception {
908
909 LDAPUserTransactionThreadLocal.setOriginatesFromLDAP(true);
910
911 try {
912 AttributesTransformer attributesTransformer =
913 AttributesTransformerFactory.getInstance();
914
915 attributes = attributesTransformer.transformUser(attributes);
916
917 LDAPUser ldapUser = _ldapToPortalConverter.importLDAPUser(
918 companyId, attributes, userMappings, userExpandoMappings,
919 contactMappings, contactExpandoMappings, password);
920
921 User user = getUser(companyId, ldapUser);
922
923 if ((user != null) && user.isDefaultUser()) {
924 return user;
925 }
926
927 ServiceContext serviceContext = ldapUser.getServiceContext();
928
929 serviceContext.setAttribute("ldapServerId", ldapServerId);
930
931 boolean isNew = false;
932
933 if (user == null) {
934 user = addUser(companyId, ldapUser, password);
935
936 isNew = true;
937 }
938
939 String modifyTimestamp = LDAPUtil.getAttributeString(
940 attributes, "modifyTimestamp");
941
942 user = updateUser(
943 companyId, ldapUser, user, userMappings, contactMappings,
944 password, modifyTimestamp, isNew);
945
946 updateExpandoAttributes(
947 user, ldapUser, userExpandoMappings, contactExpandoMappings);
948
949 return user;
950 }
951 finally {
952 LDAPUserTransactionThreadLocal.setOriginatesFromLDAP(false);
953 }
954 }
955
956 protected UserGroup importUserGroup(
957 long companyId, Attributes attributes, Properties groupMappings)
958 throws Exception {
959
960 AttributesTransformer attributesTransformer =
961 AttributesTransformerFactory.getInstance();
962
963 attributes = attributesTransformer.transformGroup(attributes);
964
965 LDAPGroup ldapGroup = _ldapToPortalConverter.importLDAPGroup(
966 companyId, attributes, groupMappings);
967
968 UserGroup userGroup = null;
969
970 try {
971 userGroup = UserGroupLocalServiceUtil.getUserGroup(
972 companyId, ldapGroup.getGroupName());
973
974 if (!Validator.equals(
975 userGroup.getDescription(), ldapGroup.getDescription())) {
976
977 UserGroupLocalServiceUtil.updateUserGroup(
978 companyId, userGroup.getUserGroupId(),
979 ldapGroup.getGroupName(), ldapGroup.getDescription(), null);
980 }
981 }
982 catch (NoSuchUserGroupException nsuge) {
983 if (_log.isDebugEnabled()) {
984 _log.debug(
985 "Adding user group to portal " + ldapGroup.getGroupName());
986 }
987
988 long defaultUserId = UserLocalServiceUtil.getDefaultUserId(
989 companyId);
990
991 LDAPUserGroupTransactionThreadLocal.setOriginatesFromLDAP(true);
992
993 try {
994 userGroup = UserGroupLocalServiceUtil.addUserGroup(
995 defaultUserId, companyId, ldapGroup.getGroupName(),
996 ldapGroup.getDescription(), null);
997 }
998 catch (Exception e) {
999 if (_log.isWarnEnabled()) {
1000 _log.warn(
1001 "Unable to create user group " +
1002 ldapGroup.getGroupName());
1003 }
1004
1005 if (_log.isDebugEnabled()) {
1006 _log.debug(e, e);
1007 }
1008 }
1009 finally {
1010 LDAPUserGroupTransactionThreadLocal.setOriginatesFromLDAP(
1011 false);
1012 }
1013 }
1014
1015 addRole(companyId, ldapGroup, userGroup);
1016
1017 return userGroup;
1018 }
1019
1020 protected void importUsers(
1021 long ldapServerId, long companyId, LdapContext ldapContext,
1022 Properties userMappings, Properties userExpandoMappings,
1023 Properties contactMappings, Properties contactExpandoMappings,
1024 long userGroupId, Attribute attribute)
1025 throws Exception {
1026
1027 Set<Long> newUserIds = new LinkedHashSet<Long>(attribute.size());
1028
1029 for (int i = 0; i < attribute.size(); i++) {
1030 String fullUserDN = (String)attribute.get(i);
1031
1032 Attributes userAttributes = null;
1033
1034 try {
1035 userAttributes = PortalLDAPUtil.getUserAttributes(
1036 ldapServerId, companyId, ldapContext, fullUserDN);
1037 }
1038 catch (NameNotFoundException nnfe) {
1039 _log.error(
1040 "LDAP user not found with fullUserDN " + fullUserDN, nnfe);
1041
1042 continue;
1043 }
1044
1045 try {
1046 User user = importUser(
1047 ldapServerId, companyId, userAttributes, userMappings,
1048 userExpandoMappings, contactMappings,
1049 contactExpandoMappings, StringPool.BLANK);
1050
1051 if (user != null) {
1052 if (_log.isDebugEnabled()) {
1053 _log.debug(
1054 "Adding " + user.getUserId() + " to group " +
1055 userGroupId);
1056 }
1057
1058 UserLocalServiceUtil.addUserGroupUsers(
1059 userGroupId, new long[] {user.getUserId()});
1060
1061 newUserIds.add(user.getUserId());
1062 }
1063 }
1064 catch (Exception e) {
1065 _log.error("Unable to load user " + userAttributes, e);
1066 }
1067 }
1068
1069 List<User> userGroupUsers = UserLocalServiceUtil.getUserGroupUsers(
1070 userGroupId);
1071
1072 for (User user : userGroupUsers) {
1073 if ((ldapServerId == user.getLdapServerId()) &&
1074 !newUserIds.contains(user.getUserId())) {
1075
1076 UserLocalServiceUtil.deleteUserGroupUser(
1077 userGroupId, user.getUserId());
1078 }
1079 }
1080 }
1081
1082 protected void populateExpandoAttributes(
1083 ExpandoBridge expandoBridge, Map<String, String[]> expandoAttributes,
1084 Properties expandoMappings) {
1085
1086 Map<String, Serializable> serializedExpandoAttributes =
1087 new HashMap<String, Serializable>();
1088
1089 for (Map.Entry<String, String[]> expandoAttribute :
1090 expandoAttributes.entrySet()) {
1091
1092 String name = expandoAttribute.getKey();
1093
1094 if (!expandoBridge.hasAttribute(name)) {
1095 continue;
1096 }
1097
1098 if (expandoMappings.containsKey(name) &&
1099 !_ldapUserIgnoreAttributes.contains(name)) {
1100
1101 int type = expandoBridge.getAttributeType(name);
1102
1103 Serializable value =
1104 ExpandoConverterUtil.getAttributeFromStringArray(
1105 type, expandoAttribute.getValue());
1106
1107 serializedExpandoAttributes.put(name, value);
1108 }
1109 }
1110
1111 if (serializedExpandoAttributes.isEmpty()) {
1112 return;
1113 }
1114
1115 try {
1116 ExpandoValueLocalServiceUtil.addValues(
1117 expandoBridge.getCompanyId(), expandoBridge.getClassName(),
1118 ExpandoTableConstants.DEFAULT_TABLE_NAME,
1119 expandoBridge.getClassPK(), serializedExpandoAttributes);
1120 }
1121 catch (Exception e) {
1122 if (_log.isWarnEnabled()) {
1123 _log.warn("Unable to populate expando attributes");
1124 }
1125
1126 if (_log.isDebugEnabled()) {
1127 _log.debug(e, e);
1128 }
1129 }
1130 }
1131
1132 protected void setProperty(
1133 Object bean1, Object bean2, String propertyName) {
1134
1135 Object value = BeanPropertiesUtil.getObject(bean2, propertyName);
1136
1137 BeanPropertiesUtil.setProperty(bean1, propertyName, value);
1138 }
1139
1140 protected void updateExpandoAttributes(
1141 User user, LDAPUser ldapUser, Properties userExpandoMappings,
1142 Properties contactExpandoMappings)
1143 throws Exception {
1144
1145 ExpandoBridge userExpandoBridge = user.getExpandoBridge();
1146
1147 populateExpandoAttributes(
1148 userExpandoBridge, ldapUser.getUserExpandoAttributes(),
1149 userExpandoMappings);
1150
1151 Contact contact = user.getContact();
1152
1153 ExpandoBridge contactExpandoBridge = contact.getExpandoBridge();
1154
1155 populateExpandoAttributes(
1156 contactExpandoBridge, ldapUser.getContactExpandoAttributes(),
1157 contactExpandoMappings);
1158 }
1159
1160 protected void updateLDAPUser(
1161 User ldapUser, Contact ldapContact, User user,
1162 Properties userMappings, Properties contactMappings)
1163 throws PortalException, SystemException {
1164
1165 Contact contact = user.getContact();
1166
1167 for (String propertyName : _CONTACT_PROPERTY_NAMES) {
1168 if (!contactMappings.containsKey(propertyName) ||
1169 _ldapUserIgnoreAttributes.contains(propertyName)) {
1170
1171 setProperty(ldapContact, contact, propertyName);
1172 }
1173 }
1174
1175 for (String propertyName : _USER_PROPERTY_NAMES) {
1176 if (!userMappings.containsKey(propertyName) ||
1177 _ldapUserIgnoreAttributes.contains(propertyName) ) {
1178
1179 setProperty(ldapUser, user, propertyName);
1180 }
1181 }
1182 }
1183
1184 protected User updateUser(
1185 long companyId, LDAPUser ldapUser, User user,
1186 Properties userMappings, Properties contactMappings,
1187 String password, String modifyTimestamp, boolean isNew)
1188 throws Exception {
1189
1190 Date modifiedDate = null;
1191
1192 boolean passwordReset = ldapUser.isPasswordReset();
1193
1194 if (PrefsPropsUtil.getBoolean(
1195 companyId, PropsKeys.LDAP_EXPORT_ENABLED,
1196 PropsValues.LDAP_EXPORT_ENABLED)) {
1197
1198 passwordReset = user.isPasswordReset();
1199 }
1200
1201 try {
1202 if (Validator.isNotNull(modifyTimestamp)) {
1203 modifiedDate = LDAPUtil.parseDate(modifyTimestamp);
1204
1205 if (modifiedDate.equals(user.getModifiedDate())) {
1206 updateUserPassword(
1207 user.getUserId(), ldapUser.getScreenName(), password,
1208 passwordReset);
1209
1210 if (_log.isDebugEnabled()) {
1211 _log.debug(
1212 "User " + user.getEmailAddress() +
1213 " is already synchronized, but updated " +
1214 "password to avoid a blank value");
1215 }
1216
1217 return user;
1218 }
1219 }
1220 else if (!isNew) {
1221 if (_log.isInfoEnabled()) {
1222 _log.info(
1223 "Skipping user " + user.getEmailAddress() +
1224 " because the LDAP entry was never modified");
1225 }
1226
1227 return user;
1228 }
1229 }
1230 catch (ParseException pe) {
1231 if (_log.isDebugEnabled()) {
1232 _log.debug(
1233 "Unable to parse LDAP modify timestamp " + modifyTimestamp,
1234 pe);
1235 }
1236 }
1237
1238 if (Validator.isNull(ldapUser.getScreenName()) ||
1239 ldapUser.isAutoScreenName()) {
1240
1241 ldapUser.setScreenName(user.getScreenName());
1242 }
1243
1244 if (ldapUser.isUpdatePassword()) {
1245 password = updateUserPassword(
1246 user.getUserId(), ldapUser.getScreenName(), password,
1247 passwordReset);
1248 }
1249
1250 Contact ldapContact = ldapUser.getContact();
1251
1252 updateLDAPUser(
1253 ldapUser.getUser(), ldapContact, user, userMappings,
1254 contactMappings);
1255
1256 Calendar birthdayCal = CalendarFactoryUtil.getCalendar();
1257
1258 birthdayCal.setTime(ldapContact.getBirthday());
1259
1260 int birthdayMonth = birthdayCal.get(Calendar.MONTH);
1261 int birthdayDay = birthdayCal.get(Calendar.DAY_OF_MONTH);
1262 int birthdayYear = birthdayCal.get(Calendar.YEAR);
1263
1264 user = UserLocalServiceUtil.updateUser(
1265 user.getUserId(), password, StringPool.BLANK, StringPool.BLANK,
1266 passwordReset, ldapUser.getReminderQueryQuestion(),
1267 ldapUser.getReminderQueryAnswer(), ldapUser.getScreenName(),
1268 ldapUser.getEmailAddress(), ldapUser.getFacebookId(),
1269 ldapUser.getOpenId(), ldapUser.getLanguageId(),
1270 ldapUser.getTimeZoneId(), ldapUser.getGreeting(),
1271 ldapUser.getComments(), ldapUser.getFirstName(),
1272 ldapUser.getMiddleName(), ldapUser.getLastName(),
1273 ldapUser.getPrefixId(), ldapUser.getSuffixId(), ldapUser.isMale(),
1274 birthdayMonth, birthdayDay, birthdayYear, ldapUser.getSmsSn(),
1275 ldapUser.getAimSn(), ldapUser.getFacebookSn(), ldapUser.getIcqSn(),
1276 ldapUser.getJabberSn(), ldapUser.getMsnSn(),
1277 ldapUser.getMySpaceSn(), ldapUser.getSkypeSn(),
1278 ldapUser.getTwitterSn(), ldapUser.getYmSn(), ldapUser.getJobTitle(),
1279 ldapUser.getGroupIds(), ldapUser.getOrganizationIds(),
1280 ldapUser.getRoleIds(), ldapUser.getUserGroupRoles(),
1281 ldapUser.getUserGroupIds(), ldapUser.getServiceContext());
1282
1283 if (modifiedDate != null) {
1284 user = UserLocalServiceUtil.updateModifiedDate(
1285 user.getUserId(), modifiedDate);
1286 }
1287
1288 if (ldapUser.isUpdatePortrait()) {
1289 byte[] portraitBytes = ldapUser.getPortraitBytes();
1290
1291 if (ArrayUtil.isNotEmpty(portraitBytes)) {
1292 UserLocalServiceUtil.updatePortrait(
1293 user.getUserId(), portraitBytes);
1294 }
1295 else {
1296 UserLocalServiceUtil.deletePortrait(user.getUserId());
1297 }
1298 }
1299
1300 user = UserLocalServiceUtil.updateStatus(
1301 user.getUserId(), ldapUser.getStatus());
1302
1303 return user;
1304 }
1305
1306 protected String updateUserPassword(
1307 long userId, String screenName, String password,
1308 boolean passwordReset)
1309 throws PortalException, SystemException {
1310
1311 if (!PropsValues.LDAP_IMPORT_USER_PASSWORD_ENABLED) {
1312 if (PropsValues.LDAP_IMPORT_USER_PASSWORD_AUTOGENERATED) {
1313 password = PwdGenerator.getPassword();
1314 }
1315 else {
1316 password = PropsValues.LDAP_IMPORT_USER_PASSWORD_DEFAULT;
1317
1318 if (StringUtil.equalsIgnoreCase(
1319 password, _USER_PASSWORD_SCREEN_NAME)) {
1320
1321 password = screenName;
1322 }
1323 }
1324 }
1325
1326 UserLocalServiceUtil.updatePassword(
1327 userId, password, password, passwordReset, true);
1328
1329 return password;
1330 }
1331
1332 private static final String[] _CONTACT_PROPERTY_NAMES = {
1333 "aimSn", "birthday", "employeeNumber", "facebookSn", "icqSn",
1334 "jabberSn", "male", "msnSn", "mySpaceSn","prefixId", "skypeSn", "smsSn",
1335 "suffixId", "twitterSn", "ymSn"
1336 };
1337
1338 private static final String _IMPORT_BY_GROUP = "group";
1339
1340 private static final String _IMPORT_BY_USER = "user";
1341
1342 private static final String _USER_PASSWORD_SCREEN_NAME = "screenName";
1343
1344 private static final String[] _USER_PROPERTY_NAMES = {
1345 "comments", "emailAddress", "firstName", "greeting", "jobTitle",
1346 "languageId", "lastName", "middleName", "openId", "portraitId",
1347 "timeZoneId"
1348 };
1349
1350 private static final String _USER_SYNC_STRATEGY_UUID = "uuid";
1351
1352 private static Log _log = LogFactoryUtil.getLog(
1353 PortalLDAPImporterImpl.class);
1354
1355 private LDAPToPortalConverter _ldapToPortalConverter;
1356 private Set<String> _ldapUserIgnoreAttributes = SetUtil.fromArray(
1357 PropsValues.LDAP_USER_IGNORE_ATTRIBUTES);
1358 private PortalCache<String, Long> _portalCache = SingleVMPoolUtil.getCache(
1359 PortalLDAPImporter.class.getName(), false);
1360
1361 }