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