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