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