1
14
15 package com.liferay.portal.security.ldap;
16
17 import com.liferay.portal.NoSuchUserException;
18 import com.liferay.portal.NoSuchUserGroupException;
19 import com.liferay.portal.kernel.log.Log;
20 import com.liferay.portal.kernel.log.LogFactoryUtil;
21 import com.liferay.portal.kernel.log.LogUtil;
22 import com.liferay.portal.kernel.util.ArrayUtil;
23 import com.liferay.portal.kernel.util.CalendarFactoryUtil;
24 import com.liferay.portal.kernel.util.DateFormatFactoryUtil;
25 import com.liferay.portal.kernel.util.PropsKeys;
26 import com.liferay.portal.kernel.util.StringBundler;
27 import com.liferay.portal.kernel.util.StringPool;
28 import com.liferay.portal.kernel.util.StringUtil;
29 import com.liferay.portal.kernel.util.Validator;
30 import com.liferay.portal.model.Company;
31 import com.liferay.portal.model.CompanyConstants;
32 import com.liferay.portal.model.Contact;
33 import com.liferay.portal.model.User;
34 import com.liferay.portal.model.UserGroup;
35 import com.liferay.portal.security.auth.ScreenNameGenerator;
36 import com.liferay.portal.security.auth.ScreenNameGeneratorFactory;
37 import com.liferay.portal.service.CompanyLocalServiceUtil;
38 import com.liferay.portal.service.UserGroupLocalServiceUtil;
39 import com.liferay.portal.service.UserLocalServiceUtil;
40 import com.liferay.portal.util.PrefsPropsUtil;
41 import com.liferay.portal.util.PropsValues;
42 import com.liferay.portlet.expando.model.ExpandoBridge;
43 import com.liferay.portlet.expando.util.ExpandoConverterUtil;
44 import com.liferay.util.ldap.LDAPUtil;
45
46 import java.io.Serializable;
47
48 import java.text.DateFormat;
49 import java.text.ParseException;
50
51 import java.util.ArrayList;
52 import java.util.Calendar;
53 import java.util.Date;
54 import java.util.List;
55 import java.util.Map;
56 import java.util.Properties;
57
58 import javax.naming.Binding;
59 import javax.naming.NameNotFoundException;
60 import javax.naming.directory.Attribute;
61 import javax.naming.directory.Attributes;
62 import javax.naming.directory.SearchResult;
63 import javax.naming.ldap.LdapContext;
64
65
71 public class PortalLDAPImporterImpl implements PortalLDAPImporter {
72
73 public void importFromLDAP() throws Exception {
74 List<Company> companies = CompanyLocalServiceUtil.getCompanies(false);
75
76 for (Company company : companies) {
77 importFromLDAP(company.getCompanyId());
78 }
79 }
80
81 public void importFromLDAP(long companyId) throws Exception {
82 if (!LDAPSettingsUtil.isImportEnabled(companyId)) {
83 return;
84 }
85
86 long[] ldapServerIds = StringUtil.split(
87 PrefsPropsUtil.getString(companyId, "ldap.server.ids"), 0L);
88
89 for (long ldapServerId : ldapServerIds) {
90 importFromLDAP(ldapServerId, companyId);
91 }
92 }
93
94 public void importFromLDAP(long ldapServerId, long companyId)
95 throws Exception {
96
97 if (!LDAPSettingsUtil.isImportEnabled(companyId)) {
98 return;
99 }
100
101 LdapContext ldapContext = PortalLDAPUtil.getContext(
102 ldapServerId, companyId);
103
104 if (ldapContext == null) {
105 return;
106 }
107
108 try {
109 String importMethod = PrefsPropsUtil.getString(
110 companyId, PropsKeys.LDAP_IMPORT_METHOD);
111
112 if (importMethod.equals(_IMPORT_BY_USER)) {
113 List<SearchResult> searchResults = PortalLDAPUtil.getUsers(
114 ldapServerId, companyId, ldapContext, 0);
115
116
118 for (SearchResult searchResult : searchResults) {
119 Attributes attributes = PortalLDAPUtil.getUserAttributes(
120 ldapServerId, companyId, ldapContext,
121 PortalLDAPUtil.getNameInNamespace(
122 ldapServerId, companyId, searchResult));
123
124 try {
125 importLDAPUser(
126 ldapServerId, companyId, ldapContext, attributes,
127 StringPool.BLANK, true);
128 }
129 catch (Exception e) {
130 _log.error("Unable to import user " + searchResult, e);
131 }
132 }
133 }
134 else if (importMethod.equals(_IMPORT_BY_GROUP)) {
135 List<SearchResult> searchResults = PortalLDAPUtil.getGroups(
136 ldapServerId, companyId, ldapContext, 0);
137
138
140 for (SearchResult searchResult : searchResults) {
141 Attributes attributes = PortalLDAPUtil.getGroupAttributes(
142 ldapServerId, companyId, ldapContext,
143 PortalLDAPUtil.getNameInNamespace(
144 ldapServerId, companyId, searchResult),
145 true);
146
147 importLDAPGroup(
148 ldapServerId, companyId, ldapContext, attributes, true);
149 }
150 }
151 }
152 catch (Exception e) {
153 _log.error("Error importing LDAP users and groups", e);
154 }
155 finally {
156 if (ldapContext != null) {
157 ldapContext.close();
158 }
159 }
160 }
161
162 public User importLDAPUser(
163 long ldapServerId, long companyId, LdapContext ldapContext,
164 Attributes attributes, String password,
165 boolean importGroupMembership)
166 throws Exception {
167
168 LDAPUserTransactionThreadLocal.setOriginatesFromLDAP(true);
169
170 try {
171 return doImportLDAPUser(
172 ldapServerId, companyId, ldapContext, attributes, password,
173 importGroupMembership);
174 }
175 finally {
176 LDAPUserTransactionThreadLocal.setOriginatesFromLDAP(false);
177 }
178 }
179
180 public void setLDAPToPortalConverter(
181 LDAPToPortalConverter ldapToPortalConverter) {
182
183 _ldapToPortalConverter = ldapToPortalConverter;
184 }
185
186 protected User createLiferayUser(
187 long companyId, LDAPUser ldapUser, String password) {
188
189 try {
190 if (_log.isDebugEnabled()) {
191 _log.debug(
192 "Adding user to portal " + ldapUser.getEmailAddress());
193 }
194
195 Calendar birthdayCal = CalendarFactoryUtil.getCalendar();
196
197 birthdayCal.setTime(ldapUser.getBirthday());
198
199 int birthdayMonth = birthdayCal.get(Calendar.MONTH);
200 int birthdayDay = birthdayCal.get(Calendar.DAY_OF_MONTH);
201 int birthdayYear = birthdayCal.get(Calendar.YEAR);
202
203 return UserLocalServiceUtil.addUser(
204 ldapUser.getCreatorUserId(), companyId,
205 ldapUser.isAutoPassword(), password, password,
206 ldapUser.isAutoScreenName(), ldapUser.getScreenName(),
207 ldapUser.getEmailAddress(), ldapUser.getOpenId(),
208 ldapUser.getLocale(), ldapUser.getFirstName(),
209 ldapUser.getMiddleName(), ldapUser.getLastName(),
210 ldapUser.getPrefixId(), ldapUser.getSuffixId(),
211 ldapUser.isMale(), birthdayMonth, birthdayDay, birthdayYear,
212 ldapUser.getJobTitle(), ldapUser.getGroupIds(),
213 ldapUser.getOrganizationIds(), ldapUser.getRoleIds(),
214 ldapUser.getUserGroupIds(), ldapUser.isSendEmail(),
215 ldapUser.getServiceContext());
216
217 }
218 catch (Exception e) {
219 _log.error(
220 "Unable to add user with screen name " +
221 ldapUser.getScreenName() + " and email address " +
222 ldapUser.getEmailAddress(),
223 e);
224
225 return null;
226 }
227 }
228
229 protected User doImportLDAPUser(
230 long ldapServerId, long companyId, LdapContext ldapContext,
231 Attributes attributes, String password,
232 boolean importGroupMembership)
233 throws Exception {
234
235 AttributesTransformer attributesTransformer =
236 AttributesTransformerFactory.getInstance();
237
238 attributes = attributesTransformer.transformUser(attributes);
239
240 Properties userMappings = LDAPSettingsUtil.getUserMappings(
241 ldapServerId, companyId);
242 Properties userExpandoMappings =
243 LDAPSettingsUtil.getUserExpandoMappings(
244 ldapServerId, companyId);
245 Properties contactMappings = LDAPSettingsUtil.getContactMappings(
246 ldapServerId, companyId);
247 Properties contactExpandoMappings =
248 LDAPSettingsUtil.getContactExpandoMappings(ldapServerId, companyId);
249
250 LDAPUser ldapUser = _ldapToPortalConverter.importLDAPUser(
251 companyId, attributes, userMappings, userExpandoMappings,
252 contactMappings, contactExpandoMappings, password);
253
254 User user = findLiferayUser(companyId, ldapUser);
255
256 if ((user != null) && user.isDefaultUser()) {
257 return user;
258 }
259
260 if (user != null) {
261
262
266 String modifiedDate = LDAPUtil.getAttributeValue(
267 attributes, "modifyTimestamp");
268
269 user = updateLiferayUser(
270 companyId, ldapUser, user, password, modifiedDate);
271 }
272 else {
273 user = createLiferayUser(companyId, ldapUser, password);
274 }
275
276 updateExpandoAttributes(user, ldapUser);
277
278 if (!importGroupMembership || (user == null)) {
279 return user;
280 }
281
282 importGroupsAndMembershipFromLDAPUser(
283 ldapServerId, companyId, ldapContext, attributes, ldapUser,
284 user, userMappings);
285
286 return user;
287 }
288
289 protected User findLiferayUser(long companyId, LDAPUser ldapUser)
290 throws Exception {
291
292 User user = null;
293
294 try {
295 String authType = PrefsPropsUtil.getString(
296 companyId, PropsKeys.COMPANY_SECURITY_AUTH_TYPE,
297 PropsValues.COMPANY_SECURITY_AUTH_TYPE);
298
299 if (authType.equals(CompanyConstants.AUTH_TYPE_SN)) {
300 user = UserLocalServiceUtil.getUserByScreenName(
301 companyId, ldapUser.getScreenName());
302 }
303 else {
304 user = UserLocalServiceUtil.getUserByEmailAddress(
305 companyId, ldapUser.getEmailAddress());
306 }
307 }
308 catch (NoSuchUserException nsue) {
309 }
310
311 return user;
312 }
313
314 protected void importGroupsAndMembershipFromLDAPUser(
315 long ldapServerId, long companyId, LdapContext ldapContext,
316 Attributes attributes, LDAPUser ldapUser, User user,
317 Properties userMappings)
318 throws Exception {
319
320 String userMappingsGroup = userMappings.getProperty("group");
321
322 if (Validator.isNull(userMappingsGroup)) {
323 return;
324 }
325
326 Attribute attribute = attributes.get(userMappingsGroup);
327
328 if (attribute == null) {
329 return;
330 }
331
332 attribute.clear();
333
334 Properties groupMappings = LDAPSettingsUtil.getGroupMappings(
335 ldapServerId, companyId);
336
337 String postfix = LDAPSettingsUtil.getPropertyPostfix(ldapServerId);
338
339 String baseDN = PrefsPropsUtil.getString(
340 companyId, PropsKeys.LDAP_BASE_DN + postfix);
341
342 Binding binding = PortalLDAPUtil.getUser(
343 ldapServerId, companyId, ldapUser.getScreenName());
344
345 String fullUserDN = PortalLDAPUtil.getNameInNamespace(
346 ldapServerId, companyId, binding);
347
348 StringBundler sb = new StringBundler(9);
349
350 sb.append(StringPool.OPEN_PARENTHESIS);
351 sb.append(StringPool.AMPERSAND);
352 sb.append(
353 PrefsPropsUtil.getString(
354 companyId,
355 PropsKeys.LDAP_IMPORT_GROUP_SEARCH_FILTER + postfix));
356 sb.append(StringPool.OPEN_PARENTHESIS);
357 sb.append(groupMappings.getProperty("user"));
358 sb.append(StringPool.EQUAL);
359 sb.append(fullUserDN);
360 sb.append(StringPool.CLOSE_PARENTHESIS);
361 sb.append(StringPool.CLOSE_PARENTHESIS);
362
363 List<SearchResult> searchResults = PortalLDAPUtil.searchLDAP(
364 companyId, ldapContext, 0, baseDN, sb.toString(), null);
365
366 for (SearchResult searchResult : searchResults) {
367 String fullGroupDN = PortalLDAPUtil.getNameInNamespace(
368 ldapServerId, companyId, searchResult);
369
370 attribute.add(fullGroupDN);
371 }
372
373 List<Long> newUserGroupIds = new ArrayList<Long>(attribute.size());
374
375 for (int i = 0; i < attribute.size(); i++) {
376 String fullGroupDN = (String) attribute.get(i);
377
378 Attributes groupAttributes = null;
379
380 try {
381 groupAttributes = PortalLDAPUtil.getGroupAttributes(
382 ldapServerId, companyId, ldapContext, fullGroupDN);
383 }
384 catch (NameNotFoundException nnfe) {
385 _log.error(
386 "LDAP group not found with fullGroupDN " + fullGroupDN,
387 nnfe);
388
389 continue;
390 }
391
392 UserGroup userGroup = importLDAPGroup(
393 ldapServerId, companyId, ldapContext, groupAttributes, false);
394
395 if (userGroup != null) {
396 if (_log.isDebugEnabled()) {
397 _log.debug(
398 "Adding " + user.getUserId() + " to group " +
399 userGroup.getUserGroupId());
400 }
401
402 newUserGroupIds.add(userGroup.getUserGroupId());
403 }
404 }
405
406 UserGroupLocalServiceUtil.setUserUserGroups(
407 user.getUserId(),
408 ArrayUtil.toArray(
409 newUserGroupIds.toArray(new Long[newUserGroupIds.size()])));
410 }
411
412 protected UserGroup importLDAPGroup(
413 long ldapServerId, long companyId, LdapContext ldapContext,
414 Attributes attributes, boolean importGroupMembership)
415 throws Exception {
416
417 AttributesTransformer attributesTransformer =
418 AttributesTransformerFactory.getInstance();
419
420 attributes = attributesTransformer.transformGroup(attributes);
421
422 Properties groupMappings = LDAPSettingsUtil.getGroupMappings(
423 ldapServerId, companyId);
424
425 LogUtil.debug(_log, groupMappings);
426
427 LDAPGroup ldapGroup = _ldapToPortalConverter.importLDAPGroup(
428 companyId, attributes, groupMappings);
429
430 UserGroup userGroup = null;
431
432 try {
433 userGroup = UserGroupLocalServiceUtil.getUserGroup(
434 companyId, ldapGroup.getGroupName());
435
436 UserGroupLocalServiceUtil.updateUserGroup(
437 companyId, userGroup.getUserGroupId(), ldapGroup.getGroupName(),
438 ldapGroup.getDescription());
439 }
440 catch (NoSuchUserGroupException nsuge) {
441 if (_log.isDebugEnabled()) {
442 _log.debug(
443 "Adding user group to portal " + ldapGroup.getGroupName());
444 }
445
446 long defaultUserId = UserLocalServiceUtil.getDefaultUserId(
447 companyId);
448
449 try {
450 userGroup = UserGroupLocalServiceUtil.addUserGroup(
451 defaultUserId, companyId, ldapGroup.getGroupName(),
452 ldapGroup.getDescription());
453 }
454 catch (Exception e) {
455 if (_log.isWarnEnabled()) {
456 _log.warn(
457 "Unable to create user group " +
458 ldapGroup.getGroupName());
459 }
460
461 if (_log.isDebugEnabled()) {
462 _log.debug(e, e);
463 }
464 }
465 }
466
467 if (!importGroupMembership || (userGroup == null)) {
468 return userGroup;
469 }
470
471 Attribute attribute = attributes.get(groupMappings.getProperty("user"));
472
473 if (attribute == null) {
474 return userGroup;
475 }
476
477 String postfix = LDAPSettingsUtil.getPropertyPostfix(ldapServerId);
478
479 String baseDN = PrefsPropsUtil.getString(
480 companyId, PropsKeys.LDAP_BASE_DN + postfix);
481
482 StringBundler sb = new StringBundler(7);
483
484 sb.append("(&");
485 sb.append(
486 PrefsPropsUtil.getString(
487 companyId,
488 PropsKeys.LDAP_IMPORT_GROUP_SEARCH_FILTER + postfix));
489 sb.append("(");
490 sb.append(groupMappings.getProperty("groupName"));
491 sb.append("=");
492 sb.append(
493 LDAPUtil.getAttributeValue(
494 attributes, groupMappings.getProperty("groupName")));
495 sb.append("))");
496
497 attribute = PortalLDAPUtil.getMultivaluedAttribute(
498 companyId, ldapContext, baseDN, sb.toString(), attribute);
499
500 importUsersAndMembershipFromLDAPGroup(
501 ldapServerId, companyId, ldapContext, userGroup.getUserGroupId(),
502 attribute);
503
504 return userGroup;
505 }
506
507 protected void importUsersAndMembershipFromLDAPGroup(
508 long ldapServerId, long companyId, LdapContext ldapContext,
509 long userGroupId, Attribute attribute)
510 throws Exception {
511
512 List<Long> newUserIds = new ArrayList<Long>(attribute.size());
513
514 for (int i = 0; i < attribute.size(); i++) {
515 String fullUserDN = (String)attribute.get(i);
516
517 Attributes userAttributes = null;
518
519 try {
520 userAttributes = PortalLDAPUtil.getUserAttributes(
521 ldapServerId, companyId, ldapContext, fullUserDN);
522 }
523 catch (NameNotFoundException nnfe) {
524 _log.error(
525 "LDAP user not found with fullUserDN " + fullUserDN, nnfe);
526
527 continue;
528 }
529
530 try {
531 User user = importLDAPUser(
532 ldapServerId, companyId, ldapContext, userAttributes,
533 StringPool.BLANK, false);
534
535 if (user != null) {
536 if (_log.isDebugEnabled()) {
537 _log.debug(
538 "Adding " + user.getUserId() + " to group " +
539 userGroupId);
540 }
541
542 newUserIds.add(user.getUserId());
543 }
544 }
545 catch (Exception e) {
546 _log.error("Unable to load user " + userAttributes, e);
547 }
548 }
549
550 UserLocalServiceUtil.setUserGroupUsers(
551 userGroupId,
552 ArrayUtil.toArray(newUserIds.toArray(new Long[newUserIds.size()])));
553 }
554
555 protected void populateExpandoAttributes(
556 ExpandoBridge expandoBridge, Map<String, String> expandoAttributes) {
557
558 for (Map.Entry<String, String> expandoAttribute :
559 expandoAttributes.entrySet()) {
560
561 String name = expandoAttribute.getKey();
562
563 if (!expandoBridge.hasAttribute(name)) {
564 continue;
565 }
566
567 int type = expandoBridge.getAttributeType(name);
568
569 Serializable value = ExpandoConverterUtil.getAttributeFromString(
570 type, expandoAttribute.getValue());
571
572 expandoBridge.setAttribute(name, value);
573 }
574 }
575
576 protected void updateExpandoAttributes(User user, LDAPUser ldapUser) {
577 ExpandoBridge userExpandoBridge = user.getExpandoBridge();
578
579 populateExpandoAttributes(
580 userExpandoBridge, ldapUser.getUserExpandoAttributes());
581
582 Contact contact = user.getContact();
583
584 ExpandoBridge contactExpandoBridge = contact.getExpandoBridge();
585
586 populateExpandoAttributes(
587 contactExpandoBridge , ldapUser.getContactExpandoAttributes());
588 }
589
590 protected User updateLiferayUser(
591 long companyId, LDAPUser ldapUser, User user,
592 String password, String modifiedDate)
593 throws Exception {
594
595 Date ldapUserModifiedDate = null;
596
597 try {
598 if (Validator.isNull(modifiedDate)) {
599 if (_log.isInfoEnabled()) {
600 _log.info(
601 "LDAP entry never modified, skipping user " +
602 user.getEmailAddress());
603 }
604
605 return user;
606 }
607 else {
608 DateFormat dateFormat =
609 DateFormatFactoryUtil.getSimpleDateFormat(
610 "yyyyMMddHHmmss");
611
612 ldapUserModifiedDate = dateFormat.parse(modifiedDate);
613 }
614
615 if (ldapUserModifiedDate.equals(user.getModifiedDate()) &&
616 ldapUser.isAutoPassword()) {
617
618 if (_log.isDebugEnabled()) {
619 _log.debug(
620 "User is already synchronized, skipping user " +
621 user.getEmailAddress());
622 }
623
624 return user;
625 }
626 }
627 catch (ParseException pe) {
628 if (_log.isDebugEnabled()) {
629 _log.debug(
630 "Unable to parse LDAP modify timestamp " + modifiedDate,
631 pe);
632 }
633 }
634
635 if (Validator.isNull(ldapUser.getScreenName())) {
636 ldapUser.setAutoScreenName(true);
637 }
638
639 if (ldapUser.isAutoScreenName()) {
640 ScreenNameGenerator screenNameGenerator =
641 ScreenNameGeneratorFactory.getInstance();
642
643 ldapUser.setScreenName(
644 screenNameGenerator.generate(
645 companyId, user.getUserId(), ldapUser.getEmailAddress()));
646 }
647
648 try {
649 Calendar birthdayCal = CalendarFactoryUtil.getCalendar();
650
651 birthdayCal.setTime(user.getContact().getBirthday());
652
653 int birthdayMonth = birthdayCal.get(Calendar.MONTH);
654 int birthdayDay = birthdayCal.get(Calendar.DAY_OF_MONTH);
655 int birthdayYear = birthdayCal.get(Calendar.YEAR);
656
657 if (ldapUser.isUpdatePassword()) {
658 UserLocalServiceUtil.updatePassword(
659 user.getUserId(), password, password,
660 ldapUser.isPasswordReset(), true);
661 }
662
663 user = UserLocalServiceUtil.updateUser(
664 user.getUserId(), password, StringPool.BLANK,
665 StringPool.BLANK, ldapUser.isPasswordReset(),
666 ldapUser.getReminderQueryQuestion(),
667 ldapUser.getReminderQueryAnswer(), ldapUser.getScreenName(),
668 ldapUser.getEmailAddress(), ldapUser.getOpenId(),
669 ldapUser.getLanguageId(), ldapUser.getTimeZoneId(),
670 ldapUser.getGreeting(), ldapUser.getComments(),
671 ldapUser.getFirstName(), ldapUser.getMiddleName(),
672 ldapUser.getLastName(), ldapUser.getPrefixId(),
673 ldapUser.getSuffixId(), ldapUser.isMale(), birthdayMonth,
674 birthdayDay, birthdayYear, ldapUser.getSmsSn(),
675 ldapUser.getAimSn(), ldapUser.getFacebookSn(),
676 ldapUser.getIcqSn(), ldapUser.getJabberSn(),
677 ldapUser.getMsnSn(), ldapUser.getMySpaceSn(),
678 ldapUser.getSkypeSn(), ldapUser.getTwitterSn(),
679 ldapUser.getYmSn(), ldapUser.getJobTitle(),
680 ldapUser.getGroupIds(), ldapUser.getOrganizationIds(),
681 ldapUser.getRoleIds(), ldapUser.getUserGroupRoles(),
682 ldapUser.getUserGroupIds(), ldapUser.getServiceContext());
683
684 if (ldapUserModifiedDate != null) {
685 user = UserLocalServiceUtil.updateModifiedDate(
686 user.getUserId(), ldapUserModifiedDate);
687 }
688
689 return user;
690 }
691 catch (Exception e) {
692 _log.error(
693 "Unable to update user with screen name " +
694 ldapUser.getScreenName() + " and email address " +
695 ldapUser.getEmailAddress(),
696 e);
697
698 return null;
699 }
700 }
701
702 private static final String _IMPORT_BY_GROUP = "group";
703
704 private static final String _IMPORT_BY_USER = "user";
705
706 private static Log _log = LogFactoryUtil.getLog(
707 PortalLDAPImporterImpl.class);
708
709 private LDAPToPortalConverter _ldapToPortalConverter;
710
711 }