1   /**
2    * Copyright (c) 2000-2008 Liferay, Inc. All rights reserved.
3    *
4    * Permission is hereby granted, free of charge, to any person obtaining a copy
5    * of this software and associated documentation files (the "Software"), to deal
6    * in the Software without restriction, including without limitation the rights
7    * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8    * copies of the Software, and to permit persons to whom the Software is
9    * furnished to do so, subject to the following conditions:
10   *
11   * The above copyright notice and this permission notice shall be included in
12   * all copies or substantial portions of the Software.
13   *
14   * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15   * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16   * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17   * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18   * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19   * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20   * SOFTWARE.
21   */
22  
23  package com.liferay.portal.security.ldap;
24  
25  import com.liferay.portal.NoSuchUserException;
26  import com.liferay.portal.NoSuchUserGroupException;
27  import com.liferay.portal.SystemException;
28  import com.liferay.portal.kernel.log.Log;
29  import com.liferay.portal.kernel.log.LogFactoryUtil;
30  import com.liferay.portal.kernel.log.LogUtil;
31  import com.liferay.portal.kernel.util.CalendarFactoryUtil;
32  import com.liferay.portal.kernel.util.PropertiesUtil;
33  import com.liferay.portal.kernel.util.StringPool;
34  import com.liferay.portal.kernel.util.StringUtil;
35  import com.liferay.portal.kernel.util.Validator;
36  import com.liferay.portal.model.Company;
37  import com.liferay.portal.model.CompanyConstants;
38  import com.liferay.portal.model.Contact;
39  import com.liferay.portal.model.User;
40  import com.liferay.portal.model.UserGroup;
41  import com.liferay.portal.service.CompanyLocalServiceUtil;
42  import com.liferay.portal.service.UserGroupLocalServiceUtil;
43  import com.liferay.portal.service.UserLocalServiceUtil;
44  import com.liferay.portal.util.PrefsPropsUtil;
45  import com.liferay.portal.util.PropsKeys;
46  import com.liferay.portal.util.PropsValues;
47  import com.liferay.util.ldap.LDAPUtil;
48  import com.liferay.util.ldap.Modifications;
49  
50  import java.text.DateFormat;
51  import java.text.ParseException;
52  import java.text.SimpleDateFormat;
53  
54  import java.util.Calendar;
55  import java.util.Date;
56  import java.util.List;
57  import java.util.Locale;
58  import java.util.Properties;
59  
60  import javax.naming.Binding;
61  import javax.naming.Context;
62  import javax.naming.NameNotFoundException;
63  import javax.naming.NamingEnumeration;
64  import javax.naming.directory.Attribute;
65  import javax.naming.directory.Attributes;
66  import javax.naming.directory.ModificationItem;
67  import javax.naming.directory.SearchControls;
68  import javax.naming.directory.SearchResult;
69  import javax.naming.ldap.InitialLdapContext;
70  import javax.naming.ldap.LdapContext;
71  
72  /**
73   * <a href="PortalLDAPUtil.java.html"><b><i>View Source</i></b></a>
74   *
75   * @author Michael Young
76   * @author Brian Wing Shun Chan
77   * @author Jerry Niu
78   * @author Scott Lee
79   * @author Hervé Ménage
80   *
81   */
82  public class PortalLDAPUtil {
83  
84      public static final String IMPORT_BY_USER = "user";
85  
86      public static final String IMPORT_BY_GROUP = "group";
87  
88      public static void exportToLDAP(Contact contact) throws Exception {
89          long companyId = contact.getCompanyId();
90  
91          if (!isAuthEnabled(companyId) || !isExportEnabled(companyId)) {
92              return;
93          }
94  
95          LdapContext ctx = getContext(companyId);
96  
97          if (ctx == null) {
98              return;
99          }
100 
101         User user = UserLocalServiceUtil.getUserByContactId(
102             contact.getContactId());
103 
104         Properties userMappings = getUserMappings(companyId);
105         Binding binding = getUser(contact.getCompanyId(), user.getScreenName());
106         String name = StringPool.BLANK;
107 
108         if (binding == null) {
109 
110             // Generate full DN based on user DN
111 
112             StringBuilder sb = new StringBuilder();
113 
114             sb.append(userMappings.getProperty("screenName"));
115             sb.append(StringPool.EQUAL);
116             sb.append(user.getScreenName());
117             sb.append(StringPool.COMMA);
118             sb.append(getUsersDN(companyId));
119 
120             name = sb.toString();
121 
122             // Create new user in LDAP
123 
124             LDAPUser ldapUser = (LDAPUser)Class.forName(
125                 PropsValues.LDAP_USER_IMPL).newInstance();
126 
127             ldapUser.setUser(user);
128 
129             ctx.bind(name, ldapUser);
130         }
131         else {
132 
133             // Modify existing LDAP user record
134 
135             name = getNameInNamespace(companyId, binding);
136 
137             Modifications mods = Modifications.getInstance();
138 
139             mods.addItem(
140                 userMappings.getProperty("firstName"), contact.getFirstName());
141             mods.addItem(
142                 userMappings.getProperty("lastName"), contact.getLastName());
143 
144             String fullNameMapping = userMappings.getProperty("fullName");
145 
146             if (Validator.isNotNull(fullNameMapping)) {
147                 mods.addItem(fullNameMapping, contact.getFullName());
148             }
149 
150             String jobTitleMapping = userMappings.getProperty("jobTitle");
151 
152             if (Validator.isNotNull(jobTitleMapping)) {
153                 mods.addItem(jobTitleMapping, contact.getJobTitle());
154             }
155 
156             ModificationItem[] modItems = mods.getItems();
157 
158             ctx.modifyAttributes(name, modItems);
159         }
160 
161         ctx.close();
162     }
163 
164     public static void exportToLDAP(User user) throws Exception {
165         long companyId = user.getCompanyId();
166 
167         if (!isAuthEnabled(companyId) || !isExportEnabled(companyId)) {
168             return;
169         }
170 
171         LdapContext ctx = getContext(companyId);
172 
173         if (ctx == null) {
174             return;
175         }
176 
177         Properties userMappings = getUserMappings(companyId);
178         Binding binding = getUser(user.getCompanyId(), user.getScreenName());
179         String name = StringPool.BLANK;
180 
181         if (binding == null) {
182 
183             // User is not exported until contact is created
184 
185         }
186         else {
187 
188             // Modify existing LDAP user record
189 
190             name = getNameInNamespace(companyId, binding);
191 
192             Modifications mods = Modifications.getInstance();
193 
194             mods.addItem(
195                 userMappings.getProperty("firstName"), user.getFirstName());
196             mods.addItem(
197                 userMappings.getProperty("lastName"), user.getLastName());
198 
199             String fullNameMapping = userMappings.getProperty("fullName");
200 
201             if (Validator.isNotNull(fullNameMapping)) {
202                 mods.addItem(fullNameMapping, user.getFullName());
203             }
204 
205             if (user.isPasswordModified() &&
206                 Validator.isNotNull(user.getPasswordUnencrypted())) {
207 
208                 mods.addItem(
209                     userMappings.getProperty("password"),
210                     user.getPasswordUnencrypted());
211             }
212 
213             mods.addItem(
214                 userMappings.getProperty("emailAddress"),
215                 user.getEmailAddress());
216 
217             String jobTitleMapping = userMappings.getProperty("jobTitle");
218 
219             if (Validator.isNotNull(jobTitleMapping)) {
220                 mods.addItem(jobTitleMapping, user.getContact().getJobTitle());
221             }
222 
223             ModificationItem[] modItems = mods.getItems();
224 
225             ctx.modifyAttributes(name, modItems);
226         }
227 
228         ctx.close();
229     }
230 
231     public static String getAuthSearchFilter(
232             long companyId, String emailAddress, String screenName,
233             String userId)
234         throws SystemException {
235 
236         String filter = PrefsPropsUtil.getString(
237             companyId, PropsKeys.LDAP_AUTH_SEARCH_FILTER);
238 
239         if (_log.isDebugEnabled()) {
240             _log.debug("Search filter before transformation " + filter);
241         }
242 
243         filter = StringUtil.replace(
244             filter,
245             new String[] {
246                 "@company_id@", "@email_address@", "@screen_name@", "@user_id@"
247             },
248             new String[] {
249                 String.valueOf(companyId), emailAddress, screenName,
250                 userId
251             });
252 
253         if (_log.isDebugEnabled()) {
254             _log.debug("Search filter after transformation " + filter);
255         }
256 
257         return filter;
258     }
259 
260     public static LdapContext getContext(long companyId) throws Exception {
261         String baseProviderURL = PrefsPropsUtil.getString(
262             companyId, PropsKeys.LDAP_BASE_PROVIDER_URL);
263         String pricipal = PrefsPropsUtil.getString(
264             companyId, PropsKeys.LDAP_SECURITY_PRINCIPAL);
265         String credentials = PrefsPropsUtil.getString(
266             companyId, PropsKeys.LDAP_SECURITY_CREDENTIALS);
267 
268         return getContext(companyId, baseProviderURL, pricipal, credentials);
269     }
270 
271     public static LdapContext getContext(
272             long companyId, String providerURL, String pricipal,
273             String credentials)
274         throws Exception {
275 
276         Properties env = new Properties();
277 
278         env.put(
279             Context.INITIAL_CONTEXT_FACTORY,
280             PrefsPropsUtil.getString(
281                 companyId, PropsKeys.LDAP_FACTORY_INITIAL));
282         env.put(Context.PROVIDER_URL, providerURL);
283         env.put(Context.SECURITY_PRINCIPAL, pricipal);
284         env.put(Context.SECURITY_CREDENTIALS, credentials);
285         env.put(
286             Context.REFERRAL,
287             PrefsPropsUtil.getString(companyId, PropsKeys.LDAP_REFERRAL));
288 
289         LogUtil.debug(_log, env);
290 
291         LdapContext ctx = null;
292 
293         try {
294             ctx = new InitialLdapContext(env, null);
295         }
296         catch (Exception e) {
297             if (_log.isWarnEnabled()) {
298                 _log.warn("Failed to bind to the LDAP server");
299             }
300 
301             if (_log.isDebugEnabled()) {
302                 _log.debug(e);
303             }
304         }
305 
306         return ctx;
307     }
308 
309     public static Attributes getGroupAttributes(
310             long companyId, LdapContext ctx, String fullDistinguishedName)
311         throws Exception {
312 
313         Properties groupMappings = getGroupMappings(companyId);
314 
315         String[] mappedGroupAttributeIds = {
316             groupMappings.getProperty("groupName"),
317             groupMappings.getProperty("description")
318         };
319 
320         return _getAttributes(
321             ctx, fullDistinguishedName, mappedGroupAttributeIds);
322     }
323 
324     public static Properties getGroupMappings(long companyId)
325         throws Exception {
326 
327         Properties groupMappings = PropertiesUtil.load(
328             PrefsPropsUtil.getString(companyId, PropsKeys.LDAP_GROUP_MAPPINGS));
329 
330         LogUtil.debug(_log, groupMappings);
331 
332         return groupMappings;
333     }
334 
335     public static NamingEnumeration<SearchResult> getGroups(
336             long companyId, LdapContext ctx, int maxResults)
337         throws Exception {
338 
339         String baseDN = PrefsPropsUtil.getString(
340             companyId, PropsKeys.LDAP_BASE_DN);
341         String groupFilter = PrefsPropsUtil.getString(
342             companyId, PropsKeys.LDAP_IMPORT_GROUP_SEARCH_FILTER);
343 
344         return getGroups(companyId, ctx, maxResults, baseDN, groupFilter);
345     }
346 
347     public static NamingEnumeration<SearchResult> getGroups(
348             long companyId, LdapContext ctx, int maxResults, String baseDN,
349             String groupFilter)
350         throws Exception {
351 
352         SearchControls cons = new SearchControls(
353             SearchControls.SUBTREE_SCOPE, maxResults, 0, null, false, false);
354 
355         return ctx.search(baseDN, groupFilter, cons);
356     }
357 
358     public static String getNameInNamespace(long companyId, Binding binding)
359         throws Exception {
360 
361         String baseDN = PrefsPropsUtil.getString(
362             companyId, PropsKeys.LDAP_BASE_DN);
363 
364         if (Validator.isNull(baseDN)) {
365             return binding.getName();
366         }
367         else {
368             StringBuilder sb = new StringBuilder();
369 
370             sb.append(binding.getName());
371             sb.append(StringPool.COMMA);
372             sb.append(baseDN);
373 
374             return sb.toString();
375         }
376     }
377 
378     public static Binding getUser(long companyId, String screenName)
379         throws Exception {
380 
381         LdapContext ctx = getContext(companyId);
382 
383         if (ctx == null) {
384             return null;
385         }
386 
387         String baseDN = PrefsPropsUtil.getString(
388             companyId, PropsKeys.LDAP_BASE_DN);
389 
390         Properties userMappings = getUserMappings(companyId);
391 
392         StringBuilder filter = new StringBuilder();
393 
394         filter.append(StringPool.OPEN_PARENTHESIS);
395         filter.append(userMappings.getProperty("screenName"));
396         filter.append(StringPool.EQUAL);
397         filter.append(screenName);
398         filter.append(StringPool.CLOSE_PARENTHESIS);
399 
400         SearchControls cons = new SearchControls(
401             SearchControls.SUBTREE_SCOPE, 1, 0, null, false, false);
402 
403         NamingEnumeration<SearchResult> enu = ctx.search(
404             baseDN, filter.toString(), cons);
405 
406         ctx.close();
407 
408         if (enu.hasMoreElements()) {
409             Binding binding = enu.nextElement();
410 
411             return binding;
412         }
413         else {
414             return null;
415         }
416     }
417 
418     public static Attributes getUserAttributes(
419             long companyId, LdapContext ctx, String fullDistinguishedName)
420         throws Exception {
421 
422         Properties userMappings = getUserMappings(companyId);
423 
424         String[] mappedUserAttributeIds = {
425             userMappings.getProperty("screenName"),
426             userMappings.getProperty("emailAddress"),
427             userMappings.getProperty("fullName"),
428             userMappings.getProperty("firstName"),
429             userMappings.getProperty("middleName"),
430             userMappings.getProperty("lastName"),
431             userMappings.getProperty("jobTitle"),
432             userMappings.getProperty("group")
433         };
434 
435         return _getAttributes(
436             ctx, fullDistinguishedName, mappedUserAttributeIds);
437     }
438 
439     public static Properties getUserMappings(long companyId) throws Exception {
440         Properties userMappings = PropertiesUtil.load(
441             PrefsPropsUtil.getString(companyId, PropsKeys.LDAP_USER_MAPPINGS));
442 
443         LogUtil.debug(_log, userMappings);
444 
445         return userMappings;
446     }
447 
448     public static NamingEnumeration<SearchResult> getUsers(
449             long companyId, LdapContext ctx, int maxResults)
450         throws Exception {
451 
452         String baseDN = PrefsPropsUtil.getString(
453             companyId, PropsKeys.LDAP_BASE_DN);
454         String userFilter = PrefsPropsUtil.getString(
455             companyId, PropsKeys.LDAP_IMPORT_USER_SEARCH_FILTER);
456 
457         return getUsers(companyId, ctx, maxResults, baseDN, userFilter);
458     }
459 
460     public static NamingEnumeration<SearchResult> getUsers(
461             long companyId, LdapContext ctx, int maxResults, String baseDN,
462             String userFilter)
463         throws Exception {
464 
465         SearchControls cons = new SearchControls(
466             SearchControls.SUBTREE_SCOPE, maxResults, 0, null, false, false);
467 
468         return ctx.search(baseDN, userFilter, cons);
469     }
470 
471     public static String getUsersDN(long companyId) throws Exception {
472         return PrefsPropsUtil.getString(companyId, PropsKeys.LDAP_USERS_DN);
473     }
474 
475     public static boolean hasUser(long companyId, String screenName)
476         throws Exception {
477 
478         if (getUser(companyId, screenName) != null) {
479             return true;
480         }
481         else {
482             return false;
483         }
484     }
485 
486     public static void importFromLDAP() throws Exception {
487         List<Company> companies = CompanyLocalServiceUtil.getCompanies();
488 
489         for (Company company : companies) {
490             importFromLDAP(company.getCompanyId());
491         }
492     }
493 
494     public static void importFromLDAP(long companyId) throws Exception {
495         if (!isImportEnabled(companyId)) {
496             return;
497         }
498 
499         LdapContext ctx = getContext(companyId);
500 
501         if (ctx == null) {
502             return;
503         }
504 
505         try {
506             String importMethod = PrefsPropsUtil.getString(
507                 companyId, PropsKeys.LDAP_IMPORT_METHOD);
508 
509             if (importMethod.equals(IMPORT_BY_USER)) {
510                 NamingEnumeration<SearchResult> enu = getUsers(
511                     companyId, ctx, 0);
512 
513                 // Loop through all LDAP users
514 
515                 while (enu.hasMoreElements()) {
516                     SearchResult result = enu.nextElement();
517 
518                     Attributes attrs = getUserAttributes(
519                         companyId, ctx, getNameInNamespace(companyId, result));
520 
521                     importLDAPUser(
522                         companyId, ctx, attrs, StringPool.BLANK, true);
523                 }
524             }
525             else if (importMethod.equals(IMPORT_BY_GROUP)) {
526                 NamingEnumeration<SearchResult> enu = getGroups(
527                     companyId, ctx, 0);
528 
529                 // Loop through all LDAP groups
530 
531                 while (enu.hasMoreElements()) {
532                     SearchResult result = enu.nextElement();
533 
534                     Attributes attrs = getGroupAttributes(
535                         companyId, ctx, getNameInNamespace(companyId, result));
536 
537                     importLDAPGroup(companyId, ctx, attrs, true);
538                 }
539             }
540         }
541         catch (Exception e) {
542             _log.error("Error importing LDAP users and groups", e);
543         }
544         finally {
545             if (ctx != null) {
546                 ctx.close();
547             }
548         }
549     }
550 
551     public static UserGroup importLDAPGroup(
552             long companyId, LdapContext ctx, Attributes attrs,
553             boolean importGroupMembership)
554         throws Exception {
555 
556         AttributesTransformer attrsTransformer =
557             AttributesTransformerFactory.getInstance();
558 
559         attrs = attrsTransformer.transformGroup(attrs);
560 
561         Properties groupMappings = getGroupMappings(companyId);
562 
563         LogUtil.debug(_log, groupMappings);
564 
565         String groupName = LDAPUtil.getAttributeValue(
566             attrs, groupMappings.getProperty("groupName")).toLowerCase();
567         String description = LDAPUtil.getAttributeValue(
568             attrs, groupMappings.getProperty("description"));
569 
570         // Get or create user group
571 
572         UserGroup userGroup = null;
573 
574         try {
575             userGroup = UserGroupLocalServiceUtil.getUserGroup(
576                 companyId, groupName);
577 
578             UserGroupLocalServiceUtil.updateUserGroup(
579                 companyId, userGroup.getUserGroupId(), groupName, description);
580         }
581         catch (NoSuchUserGroupException nsuge) {
582             if (_log.isDebugEnabled()) {
583                 _log.debug("Adding user group to portal " + groupName);
584             }
585 
586             long defaultUserId = UserLocalServiceUtil.getDefaultUserId(
587                 companyId);
588 
589             try {
590                 userGroup = UserGroupLocalServiceUtil.addUserGroup(
591                     defaultUserId, companyId, groupName, description);
592             }
593             catch (Exception e) {
594                 if (_log.isWarnEnabled()) {
595                     _log.warn("Could not create user group " + groupName);
596                 }
597 
598                 if (_log.isDebugEnabled()) {
599                     _log.debug(e, e);
600                 }
601             }
602         }
603 
604         // Import users and membership
605 
606         if (importGroupMembership && (userGroup != null)) {
607             Attribute attr = attrs.get(groupMappings.getProperty("user"));
608 
609             if (attr != null) {
610                 _importUsersAndMembershipFromLDAPGroup(
611                     companyId, ctx, userGroup.getUserGroupId(), attr);
612             }
613         }
614 
615         return userGroup;
616     }
617 
618     public static User importLDAPUser(
619             long companyId, LdapContext ctx, Attributes attrs, String password,
620             boolean importGroupMembership)
621         throws Exception {
622 
623         AttributesTransformer attrsTransformer =
624             AttributesTransformerFactory.getInstance();
625 
626         attrs = attrsTransformer.transformUser(attrs);
627 
628         Properties userMappings = getUserMappings(companyId);
629 
630         LogUtil.debug(_log, userMappings);
631 
632         User defaultUser = UserLocalServiceUtil.getDefaultUser(companyId);
633 
634         boolean autoPassword = false;
635         boolean updatePassword = true;
636 
637         if (password.equals(StringPool.BLANK)) {
638             autoPassword = true;
639             updatePassword = false;
640         }
641 
642         long creatorUserId = 0;
643         boolean passwordReset = false;
644         boolean autoScreenName = false;
645         String screenName = LDAPUtil.getAttributeValue(
646             attrs, userMappings.getProperty("screenName")).toLowerCase();
647         String emailAddress = LDAPUtil.getAttributeValue(
648             attrs, userMappings.getProperty("emailAddress"));
649         Locale locale = defaultUser.getLocale();
650         String firstName = LDAPUtil.getAttributeValue(
651             attrs, userMappings.getProperty("firstName"));
652         String middleName = LDAPUtil.getAttributeValue(
653             attrs, userMappings.getProperty("middleName"));
654         String lastName = LDAPUtil.getAttributeValue(
655             attrs, userMappings.getProperty("lastName"));
656 
657         if (Validator.isNull(firstName) || Validator.isNull(lastName)) {
658             String fullName = LDAPUtil.getAttributeValue(
659                 attrs, userMappings.getProperty("fullName"));
660 
661             String[] names = LDAPUtil.splitFullName(fullName);
662 
663             firstName = names[0];
664             middleName = names[1];
665             lastName = names[2];
666         }
667 
668         int prefixId = 0;
669         int suffixId = 0;
670         boolean male = true;
671         int birthdayMonth = Calendar.JANUARY;
672         int birthdayDay = 1;
673         int birthdayYear = 1970;
674         String jobTitle = LDAPUtil.getAttributeValue(
675             attrs, userMappings.getProperty("jobTitle"));
676         long[] organizationIds = new long[0];
677         boolean sendEmail = false;
678 
679         if (_log.isDebugEnabled()) {
680             _log.debug(
681                 "Screen name " + screenName + " and email address " +
682                     emailAddress);
683         }
684 
685         if (Validator.isNull(screenName) || Validator.isNull(emailAddress)) {
686             if (_log.isWarnEnabled()) {
687                 _log.warn(
688                     "Cannot add user because screen name and email address " +
689                         "are required");
690             }
691 
692             return null;
693         }
694 
695         User user = null;
696 
697         try {
698 
699             // Find corresponding portal user
700 
701             String authType = PrefsPropsUtil.getString(
702                 companyId, PropsKeys.COMPANY_SECURITY_AUTH_TYPE,
703                 PropsValues.COMPANY_SECURITY_AUTH_TYPE);
704 
705             if (authType.equals(CompanyConstants.AUTH_TYPE_SN)) {
706                 user = UserLocalServiceUtil.getUserByScreenName(
707                     companyId, screenName);
708             }
709             else {
710                 user = UserLocalServiceUtil.getUserByEmailAddress(
711                     companyId, emailAddress);
712             }
713 
714             // Skip if is default user
715 
716             if (user.isDefaultUser()) {
717                 return user;
718             }
719 
720             // User already exists in the Liferay database. Skip import if user
721             // fields have been already synced, if import is part of a scheduled
722             // import, or if the LDAP entry has never been modified.
723 
724             Date ldapUserModifiedDate = null;
725 
726             String modifiedDate = LDAPUtil.getAttributeValue(
727                 attrs, "modifyTimestamp");
728 
729             try {
730                 if (Validator.isNull(modifiedDate)) {
731                     if (_log.isInfoEnabled()) {
732                         _log.info(
733                             "LDAP entry never modified, skipping user " +
734                                 user.getEmailAddress());
735                     }
736 
737                     return user;
738                 }
739                 else {
740                     DateFormat dateFormat = new SimpleDateFormat(
741                         "yyyyMMddHHmmss");
742 
743                     ldapUserModifiedDate = dateFormat.parse(modifiedDate);
744                 }
745 
746                 if (ldapUserModifiedDate.equals(user.getModifiedDate()) &&
747                     autoPassword) {
748 
749                     if (_log.isDebugEnabled()) {
750                         _log.debug(
751                             "User is already syncronized, skipping user " +
752                                 user.getEmailAddress());
753                     }
754 
755                     return user;
756                 }
757             }
758             catch (ParseException pe) {
759                 if (_log.isDebugEnabled()) {
760                     _log.debug(
761                         "Unable to parse LDAP modify timestamp " +
762                             modifiedDate);
763                 }
764 
765                 _log.debug(pe, pe);
766             }
767 
768             Contact contact = user.getContact();
769 
770             Calendar birthdayCal = CalendarFactoryUtil.getCalendar();
771 
772             birthdayCal.setTime(contact.getBirthday());
773 
774             birthdayMonth = birthdayCal.get(Calendar.MONTH);
775             birthdayDay = birthdayCal.get(Calendar.DATE);
776             birthdayYear = birthdayCal.get(Calendar.YEAR);
777 
778             // User exists so update user information
779 
780             if (updatePassword) {
781                 user = UserLocalServiceUtil.updatePassword(
782                     user.getUserId(), password, password, passwordReset,
783                     true);
784             }
785 
786             user = UserLocalServiceUtil.updateUser(
787                 user.getUserId(), password, user.isPasswordReset(), screenName,
788                 emailAddress, user.getLanguageId(), user.getTimeZoneId(),
789                 user.getGreeting(), user.getComments(), firstName, middleName,
790                 lastName, contact.getPrefixId(), contact.getSuffixId(),
791                 contact.getMale(), birthdayMonth, birthdayDay, birthdayYear,
792                 contact.getSmsSn(), contact.getAimSn(), contact.getFacebookSn(),
793                 contact.getIcqSn(), contact.getJabberSn(), contact.getMsnSn(),
794                 contact.getMySpaceSn(), contact.getSkypeSn(),
795                 contact.getTwitterSn(), contact.getYmSn(), jobTitle,
796                 user.getOrganizationIds());
797 
798             if (ldapUserModifiedDate != null) {
799                 UserLocalServiceUtil.updateModifiedDate(
800                     user.getUserId(), ldapUserModifiedDate);
801             }
802         }
803         catch (NoSuchUserException nsue) {
804 
805             // User does not exist so create
806 
807         }
808 
809         if (user == null) {
810             try {
811                 if (_log.isDebugEnabled()) {
812                     _log.debug("Adding user to portal " + emailAddress);
813                 }
814 
815                 user = UserLocalServiceUtil.addUser(
816                     creatorUserId, companyId, autoPassword, password, password,
817                     autoScreenName, screenName, emailAddress, locale, firstName,
818                     middleName, lastName, prefixId, suffixId, male,
819                     birthdayMonth, birthdayDay, birthdayYear, jobTitle,
820                     organizationIds, sendEmail);
821             }
822             catch (Exception e) {
823                 _log.error(
824                     "Problem adding user with screen name " + screenName +
825                         " and email address " + emailAddress,
826                     e);
827             }
828         }
829 
830         // Import user groups and membership
831 
832         if (importGroupMembership && (user != null)) {
833             String userMappingsGroup = userMappings.getProperty("group");
834 
835             if (userMappingsGroup != null) {
836                 Attribute attr = attrs.get(userMappingsGroup);
837 
838                 if (attr != null) {
839                     _importGroupsAndMembershipFromLDAPUser(
840                         companyId, ctx, user.getUserId(), attr);
841                 }
842             }
843         }
844 
845         return user;
846     }
847 
848     public static boolean isAuthEnabled(long companyId) throws SystemException {
849         if (PrefsPropsUtil.getBoolean(
850                 companyId, PropsKeys.LDAP_AUTH_ENABLED,
851                 PropsValues.LDAP_AUTH_ENABLED)) {
852 
853             return true;
854         }
855         else {
856             return false;
857         }
858     }
859 
860     public static boolean isExportEnabled(long companyId)
861         throws SystemException {
862 
863         if (PrefsPropsUtil.getBoolean(
864                 companyId, PropsKeys.LDAP_EXPORT_ENABLED,
865                 PropsValues.LDAP_EXPORT_ENABLED)) {
866 
867             return true;
868         }
869         else {
870             return false;
871         }
872     }
873 
874     public static boolean isImportEnabled(long companyId)
875         throws SystemException {
876 
877         if (PrefsPropsUtil.getBoolean(
878                 companyId, PropsKeys.LDAP_IMPORT_ENABLED,
879                 PropsValues.LDAP_IMPORT_ENABLED)) {
880 
881             return true;
882         }
883         else {
884             return false;
885         }
886     }
887 
888     public static boolean isImportOnStartup(long companyId)
889         throws SystemException {
890 
891         if (PrefsPropsUtil.getBoolean(
892                 companyId, PropsKeys.LDAP_IMPORT_ON_STARTUP)) {
893 
894             return true;
895         }
896         else {
897             return false;
898         }
899     }
900 
901     public static boolean isNtlmEnabled(long companyId)
902         throws SystemException {
903 
904         if (!isAuthEnabled(companyId)) {
905             return false;
906         }
907 
908         if (PrefsPropsUtil.getBoolean(
909                 companyId, PropsKeys.NTLM_AUTH_ENABLED,
910                 PropsValues.NTLM_AUTH_ENABLED)) {
911 
912             return true;
913         }
914         else {
915             return false;
916         }
917     }
918 
919     public static boolean isPasswordPolicyEnabled(long companyId)
920         throws SystemException {
921 
922         if (PrefsPropsUtil.getBoolean(
923                 companyId, PropsKeys.LDAP_PASSWORD_POLICY_ENABLED,
924                 PropsValues.LDAP_PASSWORD_POLICY_ENABLED)) {
925 
926             return true;
927         }
928         else {
929             return false;
930         }
931     }
932 
933     public static boolean isSiteMinderEnabled(long companyId)
934         throws SystemException {
935 
936         if (!isAuthEnabled(companyId)) {
937             return false;
938         }
939 
940         if (PrefsPropsUtil.getBoolean(
941                 companyId, PropsKeys.SITEMINDER_AUTH_ENABLED,
942                 PropsValues.SITEMINDER_AUTH_ENABLED)) {
943 
944             return true;
945         }
946         else {
947             return false;
948         }
949     }
950 
951     private static Attributes _getAttributes(
952             LdapContext ctx, String fullDistinguishedName,
953             String[] attributeIds)
954         throws Exception {
955 
956         Attributes attrs = null;
957 
958         String[] auditAttributeIds = {
959             "creatorsName", "createTimestamp", "modifiersName",
960             "modifyTimestamp"
961         };
962 
963         if (attributeIds == null) {
964 
965             // Get complete listing of LDAP attributes (slow)
966 
967             attrs = ctx.getAttributes(fullDistinguishedName);
968 
969             NamingEnumeration<? extends Attribute> enu = ctx.getAttributes(
970                 fullDistinguishedName, auditAttributeIds).getAll();
971 
972             while (enu.hasMoreElements()) {
973                 attrs.put(enu.nextElement());
974             }
975         }
976         else {
977 
978             // Get specified LDAP attributes
979 
980             int attributeCount = attributeIds.length + auditAttributeIds.length;
981 
982             String[] allAttributeIds = new String[attributeCount];
983 
984             System.arraycopy(
985                 attributeIds, 0, allAttributeIds, 0, attributeIds.length);
986             System.arraycopy(
987                 auditAttributeIds, 0, allAttributeIds, attributeIds.length,
988                 auditAttributeIds.length);
989 
990             attrs = ctx.getAttributes(fullDistinguishedName, allAttributeIds);
991         }
992 
993         return attrs;
994     }
995 
996     private static void _importGroupsAndMembershipFromLDAPUser(
997             long companyId, LdapContext ctx, long userId, Attribute attr)
998         throws Exception {
999 
1000        // Remove all user group membership from user
1001
1002        UserGroupLocalServiceUtil.clearUserUserGroups(userId);
1003
1004        for (int i = 0; i < attr.size(); i++) {
1005
1006            // Find group in LDAP
1007
1008            String fullGroupDN = (String)attr.get(i);
1009
1010            Attributes groupAttrs = null;
1011
1012            try {
1013                groupAttrs = getGroupAttributes(companyId, ctx, fullGroupDN);
1014            }
1015            catch (NameNotFoundException nnfe) {
1016                _log.error(
1017                    "LDAP group not found with fullGroupDN " + fullGroupDN);
1018
1019                _log.error(nnfe, nnfe);
1020
1021                continue;
1022            }
1023
1024            UserGroup userGroup = importLDAPGroup(
1025                companyId, ctx, groupAttrs, false);
1026
1027            // Add user to user group
1028
1029            if (userGroup != null) {
1030                if (_log.isDebugEnabled()) {
1031                    _log.debug(
1032                        "Adding " + userId + " to group " +
1033                            userGroup.getUserGroupId());
1034                }
1035
1036                UserLocalServiceUtil.addUserGroupUsers(
1037                    userGroup.getUserGroupId(), new long[] {userId});
1038            }
1039        }
1040    }
1041
1042    private static void _importUsersAndMembershipFromLDAPGroup(
1043            long companyId, LdapContext ctx, long userGroupId, Attribute attr)
1044        throws Exception {
1045
1046        // Remove all user membership from user group
1047
1048        UserLocalServiceUtil.clearUserGroupUsers(userGroupId);
1049
1050        for (int i = 0; i < attr.size(); i++) {
1051
1052            // Find user in LDAP
1053
1054            String fullUserDN = (String)attr.get(i);
1055
1056            Attributes userAttrs = null;
1057
1058            try {
1059                userAttrs = getUserAttributes(companyId, ctx, fullUserDN);
1060            }
1061            catch (NameNotFoundException nnfe) {
1062                _log.error(
1063                    "LDAP user not found with fullUserDN " + fullUserDN);
1064
1065                _log.error(nnfe, nnfe);
1066
1067                continue;
1068            }
1069
1070            User user = importLDAPUser(
1071                companyId, ctx, userAttrs, StringPool.BLANK, false);
1072
1073            // Add user to user group
1074
1075            if (user != null) {
1076                if (_log.isDebugEnabled()) {
1077                    _log.debug(
1078                        "Adding " + user.getUserId() + " to group " +
1079                            userGroupId);
1080                }
1081
1082                UserLocalServiceUtil.addUserGroupUsers(
1083                    userGroupId, new long[] {user.getUserId()});
1084            }
1085        }
1086    }
1087
1088    private static Log _log = LogFactoryUtil.getLog(PortalLDAPUtil.class);
1089
1090}