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