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