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