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