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