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