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