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