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 ((portraitBytes != null) && (portraitBytes.length > 0)) {
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 UserGroupLocalServiceUtil.updateUserGroup(
962 companyId, userGroup.getUserGroupId(), ldapGroup.getGroupName(),
963 ldapGroup.getDescription(), null);
964 }
965 catch (NoSuchUserGroupException nsuge) {
966 if (_log.isDebugEnabled()) {
967 _log.debug(
968 "Adding user group to portal " + ldapGroup.getGroupName());
969 }
970
971 long defaultUserId = UserLocalServiceUtil.getDefaultUserId(
972 companyId);
973
974 LDAPUserGroupTransactionThreadLocal.setOriginatesFromLDAP(true);
975
976 try {
977 userGroup = UserGroupLocalServiceUtil.addUserGroup(
978 defaultUserId, companyId, ldapGroup.getGroupName(),
979 ldapGroup.getDescription(), null);
980 }
981 catch (Exception e) {
982 if (_log.isWarnEnabled()) {
983 _log.warn(
984 "Unable to create user group " +
985 ldapGroup.getGroupName());
986 }
987
988 if (_log.isDebugEnabled()) {
989 _log.debug(e, e);
990 }
991 }
992 finally {
993 LDAPUserGroupTransactionThreadLocal.setOriginatesFromLDAP(
994 false);
995 }
996 }
997
998 addRole(companyId, ldapGroup, userGroup);
999
1000 return userGroup;
1001 }
1002
1003 protected void importUsers(
1004 long ldapServerId, long companyId, LdapContext ldapContext,
1005 Properties userMappings, Properties userExpandoMappings,
1006 Properties contactMappings, Properties contactExpandoMappings,
1007 long userGroupId, Attribute attribute)
1008 throws Exception {
1009
1010 Set<Long> newUserIds = new LinkedHashSet<Long>(attribute.size());
1011
1012 for (int i = 0; i < attribute.size(); i++) {
1013 String fullUserDN = (String)attribute.get(i);
1014
1015 Attributes userAttributes = null;
1016
1017 try {
1018 userAttributes = PortalLDAPUtil.getUserAttributes(
1019 ldapServerId, companyId, ldapContext, fullUserDN);
1020 }
1021 catch (NameNotFoundException nnfe) {
1022 _log.error(
1023 "LDAP user not found with fullUserDN " + fullUserDN, nnfe);
1024
1025 continue;
1026 }
1027
1028 try {
1029 User user = importUser(
1030 ldapServerId, companyId, userAttributes, userMappings,
1031 userExpandoMappings, contactMappings,
1032 contactExpandoMappings, StringPool.BLANK);
1033
1034 if (user != null) {
1035 if (_log.isDebugEnabled()) {
1036 _log.debug(
1037 "Adding " + user.getUserId() + " to group " +
1038 userGroupId);
1039 }
1040
1041 UserLocalServiceUtil.addUserGroupUsers(
1042 userGroupId, new long[] {user.getUserId()});
1043
1044 newUserIds.add(user.getUserId());
1045 }
1046 }
1047 catch (Exception e) {
1048 _log.error("Unable to load user " + userAttributes, e);
1049 }
1050 }
1051
1052 List<User> userGroupUsers = UserLocalServiceUtil.getUserGroupUsers(
1053 userGroupId);
1054
1055 for (User user : userGroupUsers) {
1056 if (!newUserIds.contains(user.getUserId())) {
1057 UserLocalServiceUtil.deleteUserGroupUser(
1058 userGroupId, user.getUserId());
1059 }
1060 }
1061 }
1062
1063 protected void populateExpandoAttributes(
1064 ExpandoBridge expandoBridge, Map<String, String[]> expandoAttributes,
1065 Properties expandoMappings) {
1066
1067 Map<String, Serializable> serializedExpandoAttributes =
1068 new HashMap<String, Serializable>();
1069
1070 for (Map.Entry<String, String[]> expandoAttribute :
1071 expandoAttributes.entrySet()) {
1072
1073 String name = expandoAttribute.getKey();
1074
1075 if (!expandoBridge.hasAttribute(name)) {
1076 continue;
1077 }
1078
1079 if (!expandoMappings.containsKey(name) ||
1080 _ldapUserIgnoreAttributes.contains(name)) {
1081
1082 int type = expandoBridge.getAttributeType(name);
1083
1084 Serializable value =
1085 ExpandoConverterUtil.getAttributeFromStringArray(
1086 type, expandoAttribute.getValue());
1087
1088 serializedExpandoAttributes.put(name, value);
1089 }
1090 }
1091
1092 try {
1093 ExpandoValueLocalServiceUtil.addValues(
1094 expandoBridge.getCompanyId(), expandoBridge.getClassName(),
1095 ExpandoTableConstants.DEFAULT_TABLE_NAME,
1096 expandoBridge.getClassPK(), serializedExpandoAttributes);
1097 }
1098 catch (Exception e) {
1099 if (_log.isWarnEnabled()) {
1100 _log.warn("Unable to populate expando attributes");
1101 }
1102
1103 if (_log.isDebugEnabled()) {
1104 _log.debug(e, e);
1105 }
1106 }
1107 }
1108
1109 protected void setProperty(
1110 Object bean1, Object bean2, String propertyName) {
1111
1112 Object value = BeanPropertiesUtil.getObject(bean2, propertyName);
1113
1114 BeanPropertiesUtil.setProperty(bean1, propertyName, value);
1115 }
1116
1117 protected void updateExpandoAttributes(
1118 User user, LDAPUser ldapUser, Properties userExpandoMappings,
1119 Properties contactExpandoMappings)
1120 throws Exception {
1121
1122 ExpandoBridge userExpandoBridge = user.getExpandoBridge();
1123
1124 populateExpandoAttributes(
1125 userExpandoBridge, ldapUser.getUserExpandoAttributes(),
1126 userExpandoMappings);
1127
1128 Contact contact = user.getContact();
1129
1130 ExpandoBridge contactExpandoBridge = contact.getExpandoBridge();
1131
1132 populateExpandoAttributes(
1133 contactExpandoBridge, ldapUser.getContactExpandoAttributes(),
1134 contactExpandoMappings);
1135 }
1136
1137 protected void updateLDAPUser(
1138 User ldapUser, Contact ldapContact, User user,
1139 Properties userMappings, Properties contactMappings)
1140 throws PortalException, SystemException {
1141
1142 Contact contact = user.getContact();
1143
1144 for (String propertyName : _CONTACT_PROPERTY_NAMES) {
1145 if (!contactMappings.containsKey(propertyName) ||
1146 _ldapUserIgnoreAttributes.contains(propertyName)) {
1147
1148 setProperty(ldapContact, contact, propertyName);
1149 }
1150 }
1151
1152 for (String propertyName : _USER_PROPERTY_NAMES) {
1153 if (!userMappings.containsKey(propertyName) ||
1154 _ldapUserIgnoreAttributes.contains(propertyName) ) {
1155
1156 setProperty(ldapUser, user, propertyName);
1157 }
1158 }
1159 }
1160
1161 protected User updateUser(
1162 long companyId, LDAPUser ldapUser, User user,
1163 Properties userMappings, Properties contactMappings,
1164 String password, String modifiedDate, boolean isNew)
1165 throws Exception {
1166
1167 Date ldapUserModifiedDate = null;
1168
1169 boolean passwordReset = ldapUser.isPasswordReset();
1170
1171 if (PrefsPropsUtil.getBoolean(
1172 companyId, PropsKeys.LDAP_EXPORT_ENABLED,
1173 PropsValues.LDAP_EXPORT_ENABLED)) {
1174
1175 passwordReset = user.isPasswordReset();
1176 }
1177
1178 try {
1179 if (Validator.isNotNull(modifiedDate)) {
1180 ldapUserModifiedDate = LDAPUtil.parseDate(modifiedDate);
1181
1182 if (ldapUserModifiedDate.equals(user.getModifiedDate())) {
1183 if (ldapUser.isAutoPassword()) {
1184 if (_log.isDebugEnabled()) {
1185 _log.debug(
1186 "Skipping user " + user.getEmailAddress() +
1187 " because he is already synchronized");
1188 }
1189
1190 return user;
1191 }
1192
1193 UserLocalServiceUtil.updatePassword(
1194 user.getUserId(), password, password, passwordReset,
1195 true);
1196
1197 if (_log.isDebugEnabled()) {
1198 _log.debug(
1199 "User " + user.getEmailAddress() +
1200 " is already synchronized, but updated " +
1201 "password to avoid a blank value");
1202 }
1203
1204 return user;
1205 }
1206 }
1207 else if (!isNew) {
1208 if (_log.isInfoEnabled()) {
1209 _log.info(
1210 "Skipping user " + user.getEmailAddress() +
1211 " because the LDAP entry was never modified");
1212 }
1213
1214 return user;
1215 }
1216 }
1217 catch (ParseException pe) {
1218 if (_log.isDebugEnabled()) {
1219 _log.debug(
1220 "Unable to parse LDAP modify timestamp " + modifiedDate,
1221 pe);
1222 }
1223 }
1224
1225 if (!PropsValues.LDAP_IMPORT_USER_PASSWORD_ENABLED) {
1226 password = PropsValues.LDAP_IMPORT_USER_PASSWORD_DEFAULT;
1227
1228 if (password.equalsIgnoreCase(_USER_PASSWORD_SCREEN_NAME)) {
1229 password = ldapUser.getScreenName();
1230 }
1231 }
1232
1233 if (Validator.isNull(ldapUser.getScreenName())) {
1234 ldapUser.setAutoScreenName(true);
1235 }
1236
1237 if (ldapUser.isAutoScreenName()) {
1238 ScreenNameGenerator screenNameGenerator =
1239 ScreenNameGeneratorFactory.getInstance();
1240
1241 ldapUser.setScreenName(
1242 screenNameGenerator.generate(
1243 companyId, user.getUserId(), ldapUser.getEmailAddress()));
1244 }
1245
1246 Calendar birthdayCal = CalendarFactoryUtil.getCalendar();
1247
1248 Contact ldapContact = ldapUser.getContact();
1249
1250 birthdayCal.setTime(ldapContact.getBirthday());
1251
1252 int birthdayMonth = birthdayCal.get(Calendar.MONTH);
1253 int birthdayDay = birthdayCal.get(Calendar.DAY_OF_MONTH);
1254 int birthdayYear = birthdayCal.get(Calendar.YEAR);
1255
1256 if (ldapUser.isUpdatePassword()) {
1257 UserLocalServiceUtil.updatePassword(
1258 user.getUserId(), password, password, passwordReset, true);
1259 }
1260
1261 updateLDAPUser(
1262 ldapUser.getUser(), ldapContact, user, userMappings,
1263 contactMappings);
1264
1265 user = UserLocalServiceUtil.updateUser(
1266 user.getUserId(), password, StringPool.BLANK, StringPool.BLANK,
1267 passwordReset, ldapUser.getReminderQueryQuestion(),
1268 ldapUser.getReminderQueryAnswer(), ldapUser.getScreenName(),
1269 ldapUser.getEmailAddress(), ldapUser.getFacebookId(),
1270 ldapUser.getOpenId(), ldapUser.getLanguageId(),
1271 ldapUser.getTimeZoneId(), ldapUser.getGreeting(),
1272 ldapUser.getComments(), ldapUser.getFirstName(),
1273 ldapUser.getMiddleName(), ldapUser.getLastName(),
1274 ldapUser.getPrefixId(), ldapUser.getSuffixId(), ldapUser.isMale(),
1275 birthdayMonth, birthdayDay, birthdayYear, ldapUser.getSmsSn(),
1276 ldapUser.getAimSn(), ldapUser.getFacebookSn(), ldapUser.getIcqSn(),
1277 ldapUser.getJabberSn(), ldapUser.getMsnSn(),
1278 ldapUser.getMySpaceSn(), ldapUser.getSkypeSn(),
1279 ldapUser.getTwitterSn(), ldapUser.getYmSn(), ldapUser.getJobTitle(),
1280 ldapUser.getGroupIds(), ldapUser.getOrganizationIds(),
1281 ldapUser.getRoleIds(), ldapUser.getUserGroupRoles(),
1282 ldapUser.getUserGroupIds(), ldapUser.getServiceContext());
1283
1284 if (ldapUserModifiedDate != null) {
1285 user = UserLocalServiceUtil.updateModifiedDate(
1286 user.getUserId(), ldapUserModifiedDate);
1287 }
1288
1289 if (ldapUser.isUpdatePortrait()) {
1290 byte[] portraitBytes = ldapUser.getPortraitBytes();
1291
1292 if ((portraitBytes != null) && (portraitBytes.length > 0)) {
1293 UserLocalServiceUtil.updatePortrait(
1294 user.getUserId(), portraitBytes);
1295 }
1296 else {
1297 UserLocalServiceUtil.deletePortrait(user.getUserId());
1298 }
1299 }
1300
1301 user = UserLocalServiceUtil.updateStatus(
1302 user.getUserId(), ldapUser.getStatus());
1303
1304 return user;
1305 }
1306
1307 private static final String[] _CONTACT_PROPERTY_NAMES = {
1308 "aimSn", "employeeNumber", "facebookSn", "icqSn", "jabberSn", "male",
1309 "msnSn", "mySpaceSn","prefixId", "skypeSn", "smsSn", "suffixId",
1310 "twitterSn", "ymSn"
1311 };
1312
1313 private static final String _IMPORT_BY_GROUP = "group";
1314
1315 private static final String _IMPORT_BY_USER = "user";
1316
1317 private static final String _USER_PASSWORD_SCREEN_NAME = "screenName";
1318
1319 private static final String[] _USER_PROPERTY_NAMES = {
1320 "comments", "greeting", "jobTitle", "languageId", "middleName",
1321 "openId", "timeZoneId"
1322 };
1323
1324 private static Log _log = LogFactoryUtil.getLog(
1325 PortalLDAPImporterImpl.class);
1326
1327 private LDAPToPortalConverter _ldapToPortalConverter;
1328 private Set<String> _ldapUserIgnoreAttributes = SetUtil.fromArray(
1329 PropsValues.LDAP_USER_IGNORE_ATTRIBUTES);
1330 private PortalCache<String, Long> _portalCache = SingleVMPoolUtil.getCache(
1331 PortalLDAPImporter.class.getName(), false);
1332
1333 }