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