001    /**
002     * Copyright (c) 2000-2012 Liferay, Inc. All rights reserved.
003     *
004     * This library is free software; you can redistribute it and/or modify it under
005     * the terms of the GNU Lesser General Public License as published by the Free
006     * Software Foundation; either version 2.1 of the License, or (at your option)
007     * any later version.
008     *
009     * This library is distributed in the hope that it will be useful, but WITHOUT
010     * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
011     * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
012     * details.
013     */
014    
015    package com.liferay.portal.security.ldap;
016    
017    import com.liferay.portal.NoSuchRoleException;
018    import com.liferay.portal.NoSuchUserException;
019    import com.liferay.portal.NoSuchUserGroupException;
020    import com.liferay.portal.kernel.bean.BeanPropertiesUtil;
021    import com.liferay.portal.kernel.cache.PortalCache;
022    import com.liferay.portal.kernel.cache.SingleVMPoolUtil;
023    import com.liferay.portal.kernel.exception.SystemException;
024    import com.liferay.portal.kernel.ldap.LDAPUtil;
025    import com.liferay.portal.kernel.log.Log;
026    import com.liferay.portal.kernel.log.LogFactoryUtil;
027    import com.liferay.portal.kernel.util.CalendarFactoryUtil;
028    import com.liferay.portal.kernel.util.GetterUtil;
029    import com.liferay.portal.kernel.util.LocaleUtil;
030    import com.liferay.portal.kernel.util.PropsKeys;
031    import com.liferay.portal.kernel.util.SetUtil;
032    import com.liferay.portal.kernel.util.StringBundler;
033    import com.liferay.portal.kernel.util.StringPool;
034    import com.liferay.portal.kernel.util.StringUtil;
035    import com.liferay.portal.kernel.util.Time;
036    import com.liferay.portal.kernel.util.Validator;
037    import com.liferay.portal.model.Company;
038    import com.liferay.portal.model.CompanyConstants;
039    import com.liferay.portal.model.Contact;
040    import com.liferay.portal.model.Group;
041    import com.liferay.portal.model.Role;
042    import com.liferay.portal.model.RoleConstants;
043    import com.liferay.portal.model.User;
044    import com.liferay.portal.model.UserGroup;
045    import com.liferay.portal.security.auth.ScreenNameGenerator;
046    import com.liferay.portal.security.auth.ScreenNameGeneratorFactory;
047    import com.liferay.portal.service.CompanyLocalServiceUtil;
048    import com.liferay.portal.service.GroupLocalServiceUtil;
049    import com.liferay.portal.service.LockLocalServiceUtil;
050    import com.liferay.portal.service.RoleLocalServiceUtil;
051    import com.liferay.portal.service.UserGroupLocalServiceUtil;
052    import com.liferay.portal.service.UserLocalServiceUtil;
053    import com.liferay.portal.util.PrefsPropsUtil;
054    import com.liferay.portal.util.PropsValues;
055    import com.liferay.portlet.expando.model.ExpandoBridge;
056    import com.liferay.portlet.expando.model.ExpandoTableConstants;
057    import com.liferay.portlet.expando.service.ExpandoValueLocalServiceUtil;
058    import com.liferay.portlet.expando.util.ExpandoConverterUtil;
059    
060    import java.io.Serializable;
061    
062    import java.text.ParseException;
063    
064    import java.util.ArrayList;
065    import java.util.Calendar;
066    import java.util.Date;
067    import java.util.HashMap;
068    import java.util.List;
069    import java.util.Locale;
070    import java.util.Map;
071    import java.util.Properties;
072    import java.util.Set;
073    
074    import javax.naming.Binding;
075    import javax.naming.NameNotFoundException;
076    import javax.naming.NamingEnumeration;
077    import javax.naming.directory.Attribute;
078    import javax.naming.directory.Attributes;
079    import javax.naming.directory.SearchControls;
080    import javax.naming.directory.SearchResult;
081    import javax.naming.ldap.LdapContext;
082    
083    /**
084     * @author Michael C. Han
085     * @author Brian Wing Shun Chan
086     * @author Wesley Gong
087     * @author Hugo Huijser
088     */
089    public class PortalLDAPImporterImpl implements PortalLDAPImporter {
090    
091            public void importFromLDAP() throws Exception {
092                    List<Company> companies = CompanyLocalServiceUtil.getCompanies(false);
093    
094                    for (Company company : companies) {
095                            importFromLDAP(company.getCompanyId());
096                    }
097            }
098    
099            public void importFromLDAP(long companyId) throws Exception {
100                    if (!LDAPSettingsUtil.isImportEnabled(companyId)) {
101                            return;
102                    }
103    
104                    long defaultUserId = UserLocalServiceUtil.getDefaultUserId(companyId);
105    
106                    if (LockLocalServiceUtil.hasLock(
107                                    defaultUserId, PortalLDAPImporterUtil.class.getName(),
108                                    companyId)) {
109    
110                            if (_log.isDebugEnabled()) {
111                                    _log.debug(
112                                            "Skipping LDAP import for company " + companyId +
113                                                    "because another LDAP import is in process");
114                            }
115    
116                            return;
117                    }
118    
119                    LockLocalServiceUtil.lock(
120                            defaultUserId, PortalLDAPImporterUtil.class.getName(), companyId,
121                            PortalLDAPImporterImpl.class.getName(), false, Time.DAY);
122    
123                    try {
124                            long[] ldapServerIds = StringUtil.split(
125                                    PrefsPropsUtil.getString(companyId, "ldap.server.ids"), 0L);
126    
127                            for (long ldapServerId : ldapServerIds) {
128                                    importFromLDAP(ldapServerId, companyId);
129                            }
130    
131                            for (int ldapServerId = 0;; ldapServerId++) {
132                                    String postfix = LDAPSettingsUtil.getPropertyPostfix(
133                                            ldapServerId);
134    
135                                    String providerUrl = PrefsPropsUtil.getString(
136                                            companyId, PropsKeys.LDAP_BASE_PROVIDER_URL + postfix);
137    
138                                    if (Validator.isNull(providerUrl)) {
139                                            break;
140                                    }
141    
142                                    importFromLDAP(ldapServerId, companyId);
143                            }
144                    }
145                    finally {
146                            LockLocalServiceUtil.unlock(
147                                    PortalLDAPImporterUtil.class.getName(), companyId);
148                    }
149            }
150    
151            public void importFromLDAP(long ldapServerId, long companyId)
152                    throws Exception {
153    
154                    if (!LDAPSettingsUtil.isImportEnabled(companyId)) {
155                            return;
156                    }
157    
158                    LdapContext ldapContext = PortalLDAPUtil.getContext(
159                            ldapServerId, companyId);
160    
161                    if (ldapContext == null) {
162                            return;
163                    }
164    
165                    try {
166                            Properties userMappings = LDAPSettingsUtil.getUserMappings(
167                                    ldapServerId, companyId);
168                            Properties userExpandoMappings =
169                                    LDAPSettingsUtil.getUserExpandoMappings(
170                                            ldapServerId, companyId);
171                            Properties contactMappings = LDAPSettingsUtil.getContactMappings(
172                                    ldapServerId, companyId);
173                            Properties contactExpandoMappings =
174                                    LDAPSettingsUtil.getContactExpandoMappings(
175                                            ldapServerId, companyId);
176                            Properties groupMappings = LDAPSettingsUtil.getGroupMappings(
177                                    ldapServerId, companyId);
178    
179                            String importMethod = PrefsPropsUtil.getString(
180                                    companyId, PropsKeys.LDAP_IMPORT_METHOD);
181    
182                            if (importMethod.equals(_IMPORT_BY_GROUP)) {
183                                    importFromLDAPByGroup(
184                                            ldapServerId, companyId, ldapContext, userMappings,
185                                            userExpandoMappings, contactMappings,
186                                            contactExpandoMappings, groupMappings);
187                            }
188                            else if (importMethod.equals(_IMPORT_BY_USER)) {
189                                    importFromLDAPByUser(
190                                            ldapServerId, companyId, ldapContext, userMappings,
191                                            userExpandoMappings, contactMappings,
192                                            contactExpandoMappings, groupMappings);
193                            }
194                    }
195                    catch (Exception e) {
196                            _log.error("Error importing LDAP users and groups", e);
197                    }
198                    finally {
199                            if (ldapContext != null) {
200                                    ldapContext.close();
201                            }
202                    }
203            }
204    
205            public User importLDAPUser(
206                            long ldapServerId, long companyId, LdapContext ldapContext,
207                            Attributes attributes, String password)
208                    throws Exception {
209    
210                    Properties userMappings = LDAPSettingsUtil.getUserMappings(
211                            ldapServerId, companyId);
212                    Properties userExpandoMappings =
213                            LDAPSettingsUtil.getUserExpandoMappings(ldapServerId, companyId);
214                    Properties contactMappings = LDAPSettingsUtil.getContactMappings(
215                            ldapServerId, companyId);
216                    Properties contactExpandoMappings =
217                            LDAPSettingsUtil.getContactExpandoMappings(ldapServerId, companyId);
218    
219                    User user = importUser(
220                            companyId, attributes, userMappings, userExpandoMappings,
221                            contactMappings, contactExpandoMappings, password);
222    
223                    Properties groupMappings = LDAPSettingsUtil.getGroupMappings(
224                            ldapServerId, companyId);
225    
226                    importGroups(
227                            ldapServerId, companyId, ldapContext, attributes, user,
228                            userMappings, groupMappings);
229    
230                    return user;
231            }
232    
233            public User importLDAPUser(
234                            long ldapServerId, long companyId, String emailAddress,
235                            String screenName)
236                    throws Exception {
237    
238                    LdapContext ldapContext = null;
239    
240                    try {
241                            String postfix = LDAPSettingsUtil.getPropertyPostfix(ldapServerId);
242    
243                            String baseDN = PrefsPropsUtil.getString(
244                                    companyId, PropsKeys.LDAP_BASE_DN + postfix);
245    
246                            ldapContext = PortalLDAPUtil.getContext(ldapServerId, companyId);
247    
248                            if (ldapContext == null) {
249                                    throw new SystemException("Failed to bind to the LDAP server");
250                            }
251    
252                            String filter = PrefsPropsUtil.getString(
253                                    companyId, PropsKeys.LDAP_AUTH_SEARCH_FILTER + postfix);
254    
255                            if (_log.isDebugEnabled()) {
256                                    _log.debug("Search filter before transformation " + filter);
257                            }
258    
259                            filter = StringUtil.replace(
260                                    filter,
261                                    new String[] {
262                                            "@company_id@", "@email_address@", "@screen_name@"
263                                    },
264                                    new String[] {
265                                            String.valueOf(companyId), emailAddress, screenName
266                                    });
267    
268                            if (_log.isDebugEnabled()) {
269                                    _log.debug("Search filter after transformation " + filter);
270                            }
271    
272                            Properties userMappings = LDAPSettingsUtil.getUserMappings(
273                                    ldapServerId, companyId);
274    
275                            String userMappingsScreenName = GetterUtil.getString(
276                                    userMappings.getProperty("screenName")).toLowerCase();
277    
278                            SearchControls searchControls = new SearchControls(
279                                    SearchControls.SUBTREE_SCOPE, 1, 0,
280                                    new String[] {userMappingsScreenName}, false, false);
281    
282                            NamingEnumeration<SearchResult> enu = ldapContext.search(
283                                    baseDN, filter, searchControls);
284    
285                            if (enu.hasMoreElements()) {
286                                    if (_log.isDebugEnabled()) {
287                                            _log.debug("Search filter returned at least one result");
288                                    }
289    
290                                    Binding binding = enu.nextElement();
291    
292                                    Attributes attributes = PortalLDAPUtil.getUserAttributes(
293                                            ldapServerId, companyId, ldapContext,
294                                            PortalLDAPUtil.getNameInNamespace(
295                                                    ldapServerId, companyId, binding));
296    
297                                    return importLDAPUser(
298                                            ldapServerId, companyId, ldapContext, attributes,
299                                            StringPool.BLANK);
300                            }
301                            else {
302                                    return null;
303                            }
304                    }
305                    catch (Exception e) {
306                            if (_log.isWarnEnabled()) {
307                                    _log.warn("Problem accessing LDAP server " + e.getMessage());
308                            }
309    
310                            if (_log.isDebugEnabled()) {
311                                    _log.debug(e, e);
312                            }
313    
314                            throw new SystemException(
315                                    "Problem accessing LDAP server " + e.getMessage());
316                    }
317                    finally {
318                            if (ldapContext != null) {
319                                    ldapContext.close();
320                            }
321                    }
322            }
323    
324            public User importLDAPUser(
325                            long companyId, String emailAddress, String screenName)
326                    throws Exception {
327    
328                    long[] ldapServerIds = StringUtil.split(
329                            PrefsPropsUtil.getString(companyId, "ldap.server.ids"), 0L);
330    
331                    if (ldapServerIds.length <= 0) {
332                            ldapServerIds = new long[] {0};
333                    }
334    
335                    for (long ldapServerId : ldapServerIds) {
336                            User user = importLDAPUser(
337                                    ldapServerId, companyId, emailAddress, screenName);
338    
339                            if (user != null) {
340                                    return user;
341                            }
342                    }
343    
344                    if (_log.isDebugEnabled()) {
345                            if (Validator.isNotNull(emailAddress)) {
346                                    _log.debug(
347                                            "User with the email address " + emailAddress +
348                                    " was not found in any LDAP servers");
349                            }
350                            else {
351                                    _log.debug(
352                                            "User with the screen name " + screenName +
353                                    " was not found in any LDAP servers");
354                            }
355                    }
356    
357                    return null;
358            }
359    
360            public User importLDAPUserByScreenName(long companyId, String screenName)
361                    throws Exception {
362    
363                    long ldapServerId = PortalLDAPUtil.getLdapServerId(
364                            companyId, screenName, StringPool.BLANK);
365    
366                    SearchResult result = (SearchResult)PortalLDAPUtil.getUser(
367                            ldapServerId, companyId, screenName, StringPool.BLANK);
368    
369                    if (result == null) {
370                            if (_log.isWarnEnabled()) {
371                                    _log.warn(
372                                            "No user was found in LDAP with screenName " + screenName);
373                            }
374    
375                            return null;
376                    }
377    
378                    LdapContext ldapContext = PortalLDAPUtil.getContext(
379                            ldapServerId, companyId);
380    
381                    String fullUserDN = PortalLDAPUtil.getNameInNamespace(
382                            ldapServerId, companyId, result);
383    
384                    Attributes attributes = PortalLDAPUtil.getUserAttributes(
385                            ldapServerId, companyId, ldapContext, fullUserDN);
386    
387                    User user = importLDAPUser(
388                            ldapServerId, companyId, ldapContext, attributes, StringPool.BLANK);
389    
390                    ldapContext.close();
391    
392                    return user;
393            }
394    
395            public void setLDAPToPortalConverter(
396                    LDAPToPortalConverter ldapToPortalConverter) {
397    
398                    _ldapToPortalConverter = ldapToPortalConverter;
399            }
400    
401            protected void addRole(
402                            long companyId, LDAPGroup ldapGroup, UserGroup userGroup)
403                    throws Exception {
404    
405                    if (!PropsValues.LDAP_IMPORT_CREATE_ROLE_PER_GROUP) {
406                            return;
407                    }
408    
409                    Role role = null;
410    
411                    try {
412                            role = RoleLocalServiceUtil.getRole(
413                                    companyId, ldapGroup.getGroupName());
414                    }
415                    catch (NoSuchRoleException nsre) {
416                            User defaultUser = UserLocalServiceUtil.getDefaultUser(companyId);
417    
418                            Map<Locale, String> descriptionMap = new HashMap<Locale, String>();
419    
420                            descriptionMap.put(
421                                    LocaleUtil.getDefault(), "Autogenerated role from LDAP import");
422    
423                            role = RoleLocalServiceUtil.addRole(
424                                    defaultUser.getUserId(), companyId, ldapGroup.getGroupName(),
425                                    null, descriptionMap, RoleConstants.TYPE_REGULAR);
426                    }
427    
428                    Group group = userGroup.getGroup();
429    
430                    if (GroupLocalServiceUtil.hasRoleGroup(
431                                    role.getRoleId(), group.getGroupId())) {
432    
433                            return;
434                    }
435    
436                    GroupLocalServiceUtil.addRoleGroups(
437                            role.getRoleId(), new long[] {group.getGroupId()});
438            }
439    
440            protected User addUser(long companyId, LDAPUser ldapUser, String password)
441                    throws Exception {
442    
443                    if (_log.isDebugEnabled()) {
444                            _log.debug("Adding user " + ldapUser.getEmailAddress());
445                    }
446    
447                    boolean autoPassword = ldapUser.isAutoPassword();
448    
449                    if (!PropsValues.LDAP_IMPORT_USER_PASSWORD_ENABLED) {
450                            autoPassword = PropsValues.LDAP_IMPORT_USER_PASSWORD_AUTOGENERATED;
451    
452                            if (!autoPassword) {
453                                    String defaultPassword =
454                                            PropsValues.LDAP_IMPORT_USER_PASSWORD_DEFAULT;
455    
456                                    if (defaultPassword.equalsIgnoreCase(
457                                                    _USER_PASSWORD_SCREEN_NAME)) {
458    
459                                            defaultPassword = ldapUser.getScreenName();
460                                    }
461    
462                                    password = defaultPassword;
463                            }
464                    }
465    
466                    Calendar birthdayCal = CalendarFactoryUtil.getCalendar();
467    
468                    birthdayCal.setTime(ldapUser.getBirthday());
469    
470                    int birthdayMonth = birthdayCal.get(Calendar.MONTH);
471                    int birthdayDay = birthdayCal.get(Calendar.DAY_OF_MONTH);
472                    int birthdayYear = birthdayCal.get(Calendar.YEAR);
473    
474                    User user = UserLocalServiceUtil.addUser(
475                            ldapUser.getCreatorUserId(), companyId, autoPassword, password,
476                            password, ldapUser.isAutoScreenName(), ldapUser.getScreenName(),
477                            ldapUser.getEmailAddress(), 0, StringPool.BLANK,
478                            ldapUser.getLocale(), ldapUser.getFirstName(),
479                            ldapUser.getMiddleName(), ldapUser.getLastName(), 0, 0,
480                            ldapUser.isMale(), birthdayMonth, birthdayDay, birthdayYear,
481                            StringPool.BLANK, ldapUser.getGroupIds(),
482                            ldapUser.getOrganizationIds(), ldapUser.getRoleIds(),
483                            ldapUser.getUserGroupIds(), ldapUser.isSendEmail(),
484                            ldapUser.getServiceContext());
485    
486                    if (ldapUser.isUpdatePortrait()) {
487                            byte[] portraitBytes = ldapUser.getPortraitBytes();
488    
489                            if ((portraitBytes != null) && (portraitBytes.length > 0)) {
490                                    user = UserLocalServiceUtil.updatePortrait(
491                                            user.getUserId(), portraitBytes);
492                            }
493                    }
494    
495                    return user;
496            }
497    
498            protected void addUserGroupsNotAddedByLDAPImport(
499                            long userId, List<Long> userGroupIds)
500                    throws Exception {
501    
502                    List<UserGroup> userGroups =
503                            UserGroupLocalServiceUtil.getUserUserGroups(userId);
504    
505                    for (UserGroup userGroup : userGroups) {
506                            if (!userGroupIds.contains(userGroup.getUserGroupId()) &&
507                                    !userGroup.isAddedByLDAPImport()) {
508    
509                                    userGroupIds.add(userGroup.getUserGroupId());
510                            }
511                    }
512            }
513    
514            protected String escapeValue(String value) {
515                    return StringUtil.replace(value, "\\,", "\\\\,");
516            }
517    
518            protected User getUser(long companyId, LDAPUser ldapUser)
519                    throws Exception {
520    
521                    User user = null;
522    
523                    try {
524                            String authType = PrefsPropsUtil.getString(
525                                    companyId, PropsKeys.COMPANY_SECURITY_AUTH_TYPE,
526                                    PropsValues.COMPANY_SECURITY_AUTH_TYPE);
527    
528                            if (authType.equals(CompanyConstants.AUTH_TYPE_SN) &&
529                                    !ldapUser.isAutoScreenName()) {
530    
531                                    user = UserLocalServiceUtil.getUserByScreenName(
532                                            companyId, ldapUser.getScreenName());
533                            }
534                            else {
535                                    user = UserLocalServiceUtil.getUserByEmailAddress(
536                                            companyId, ldapUser.getEmailAddress());
537                            }
538                    }
539                    catch (NoSuchUserException nsue) {
540                    }
541    
542                    return user;
543            }
544    
545            protected Attribute getUsers(
546                            long ldapServerId, long companyId, LdapContext ldapContext,
547                            Attributes attributes, UserGroup userGroup,
548                            Properties groupMappings)
549                    throws Exception {
550    
551                    Attribute attribute = attributes.get(groupMappings.getProperty("user"));
552    
553                    if (attribute == null) {
554                            return null;
555                    }
556    
557                    String postfix = LDAPSettingsUtil.getPropertyPostfix(ldapServerId);
558    
559                    String baseDN = PrefsPropsUtil.getString(
560                            companyId, PropsKeys.LDAP_BASE_DN + postfix);
561    
562                    StringBundler sb = new StringBundler(7);
563    
564                    sb.append("(&");
565                    sb.append(
566                            PrefsPropsUtil.getString(
567                                    companyId,
568                                    PropsKeys.LDAP_IMPORT_GROUP_SEARCH_FILTER + postfix));
569                    sb.append("(");
570                    sb.append(groupMappings.getProperty("groupName"));
571                    sb.append("=");
572                    sb.append(escapeValue(userGroup.getName()));
573                    sb.append("))");
574    
575                    return PortalLDAPUtil.getMultivaluedAttribute(
576                            companyId, ldapContext, baseDN, sb.toString(), attribute);
577            }
578    
579            protected void importFromLDAPByGroup(
580                            long ldapServerId, long companyId, LdapContext ldapContext,
581                            Properties userMappings, Properties userExpandoMappings,
582                            Properties contactMappings, Properties contactExpandoMappings,
583                            Properties groupMappings)
584                    throws Exception {
585    
586                    byte[] cookie = new byte[0];
587    
588                    while (cookie != null) {
589                            List<SearchResult> searchResults = new ArrayList<SearchResult>();
590    
591                            String groupMappingsGroupName = GetterUtil.getString(
592                                    groupMappings.getProperty("groupName")).toLowerCase();
593    
594                            cookie = PortalLDAPUtil.getGroups(
595                                    ldapServerId, companyId, ldapContext, cookie, 0,
596                                    new String[] {groupMappingsGroupName}, searchResults);
597    
598                            for (SearchResult searchResult : searchResults) {
599                                    try {
600                                            Attributes attributes = PortalLDAPUtil.getGroupAttributes(
601                                                    ldapServerId, companyId, ldapContext,
602                                                    PortalLDAPUtil.getNameInNamespace(
603                                                            ldapServerId, companyId, searchResult),
604                                                    true);
605    
606                                            UserGroup userGroup = importUserGroup(
607                                                    companyId, attributes, groupMappings);
608    
609                                            Attribute usersAttribute = getUsers(
610                                                    ldapServerId, companyId, ldapContext, attributes,
611                                                    userGroup, groupMappings);
612    
613                                            if (usersAttribute == null) {
614                                                    if (_log.isInfoEnabled()) {
615                                                            _log.info(
616                                                                    "No users found in " + userGroup.getName());
617                                                    }
618    
619                                                    continue;
620                                            }
621    
622                                            importUsers(
623                                                    ldapServerId, companyId, ldapContext, userMappings,
624                                                    userExpandoMappings, contactMappings,
625                                                    contactExpandoMappings, userGroup.getUserGroupId(),
626                                                    usersAttribute);
627                                    }
628                                    catch (Exception e) {
629                                            _log.error("Unable to import group " + searchResult, e);
630                                    }
631                            }
632                    }
633            }
634    
635            protected void importFromLDAPByUser(
636                            long ldapServerId, long companyId, LdapContext ldapContext,
637                            Properties userMappings, Properties userExpandoMappings,
638                            Properties contactMappings, Properties contactExpandoMappings,
639                            Properties groupMappings)
640                    throws Exception {
641    
642                    byte[] cookie = new byte[0];
643    
644                    while (cookie != null) {
645                            List<SearchResult> searchResults = new ArrayList<SearchResult>();
646    
647                            String userMappingsScreenName = GetterUtil.getString(
648                                    userMappings.getProperty("screenName")).toLowerCase();
649    
650                            cookie = PortalLDAPUtil.getUsers(
651                                    ldapServerId, companyId, ldapContext, cookie, 0,
652                                    new String[] {userMappingsScreenName}, searchResults);
653    
654                            for (SearchResult searchResult : searchResults) {
655                                    try {
656                                            Attributes userAttributes =
657                                                    PortalLDAPUtil.getUserAttributes(
658                                                            ldapServerId, companyId, ldapContext,
659                                                            PortalLDAPUtil.getNameInNamespace(
660                                                                    ldapServerId, companyId, searchResult));
661    
662                                            User user = importUser(
663                                                    companyId, userAttributes, userMappings,
664                                                    userExpandoMappings, contactMappings,
665                                                    contactExpandoMappings, StringPool.BLANK);
666    
667                                            importGroups(
668                                                    ldapServerId, companyId, ldapContext, userAttributes,
669                                                    user, userMappings, groupMappings);
670                                    }
671                                    catch (Exception e) {
672                                            _log.error("Unable to import user " + searchResult, e);
673                                    }
674                            }
675                    }
676            }
677    
678            protected List<Long> importGroup(
679                            long ldapServerId, long companyId, LdapContext ldapContext,
680                            String fullGroupDN, User user, Properties groupMappings,
681                            List<Long> newUserGroupIds)
682                    throws Exception {
683    
684                    String userGroupIdKey = null;
685    
686                    Long userGroupId = null;
687    
688                    if (PropsValues.LDAP_IMPORT_GROUP_CACHE_ENABLED) {
689                            StringBundler sb = new StringBundler(5);
690    
691                            sb.append(ldapServerId);
692                            sb.append(StringPool.UNDERLINE);
693                            sb.append(companyId);
694                            sb.append(StringPool.UNDERLINE);
695                            sb.append(fullGroupDN);
696    
697                            userGroupIdKey = sb.toString();
698    
699                            userGroupId = (Long)_portalCache.get(userGroupIdKey);
700                    }
701    
702                    if (userGroupId != null) {
703                            if (_log.isDebugEnabled()) {
704                                    _log.debug("Skipping reimport of full group DN " + fullGroupDN);
705                            }
706                    }
707                    else {
708                            if (_log.isDebugEnabled()) {
709                                    _log.debug("Importing full group DN " + fullGroupDN);
710                            }
711    
712                            Attributes groupAttributes = null;
713    
714                            try {
715                                    groupAttributes = PortalLDAPUtil.getGroupAttributes(
716                                            ldapServerId, companyId, ldapContext, fullGroupDN);
717                            }
718                            catch (NameNotFoundException nnfe) {
719                                    _log.error(
720                                            "LDAP group not found with full group DN " + fullGroupDN,
721                                            nnfe);
722                            }
723    
724                            UserGroup userGroup = importUserGroup(
725                                    companyId, groupAttributes, groupMappings);
726    
727                            userGroupId = userGroup.getUserGroupId();
728    
729                            if (PropsValues.LDAP_IMPORT_GROUP_CACHE_ENABLED) {
730                                    _portalCache.put(userGroupIdKey, userGroupId);
731                            }
732                    }
733    
734                    if (userGroupId != null) {
735                            if (_log.isDebugEnabled()) {
736                                    _log.debug(
737                                            "Adding " + user.getUserId() + " to group " + userGroupId);
738                            }
739    
740                            newUserGroupIds.add(userGroupId);
741                    }
742    
743                    return newUserGroupIds;
744            }
745    
746            protected void importGroups(
747                            long ldapServerId, long companyId, LdapContext ldapContext,
748                            Attributes attributes, User user, Properties userMappings,
749                            Properties groupMappings)
750                    throws Exception {
751    
752                    List<Long> newUserGroupIds = new ArrayList<Long>();
753    
754                    if (PrefsPropsUtil.getBoolean(
755                                    companyId, PropsKeys.LDAP_IMPORT_GROUP_SEARCH_FILTER_ENABLED)) {
756    
757                            String postfix = LDAPSettingsUtil.getPropertyPostfix(ldapServerId);
758    
759                            String baseDN = PrefsPropsUtil.getString(
760                                    companyId, PropsKeys.LDAP_BASE_DN + postfix);
761    
762                            Binding binding = PortalLDAPUtil.getUser(
763                                    ldapServerId, companyId, user.getScreenName(),
764                                    user.getEmailAddress());
765    
766                            String fullUserDN = PortalLDAPUtil.getNameInNamespace(
767                                    ldapServerId, companyId, binding);
768    
769                            StringBundler sb = new StringBundler(9);
770    
771                            sb.append(StringPool.OPEN_PARENTHESIS);
772                            sb.append(StringPool.AMPERSAND);
773                            sb.append(
774                                    PrefsPropsUtil.getString(
775                                            companyId,
776                                            PropsKeys.LDAP_IMPORT_GROUP_SEARCH_FILTER + postfix));
777                            sb.append(StringPool.OPEN_PARENTHESIS);
778                            sb.append(groupMappings.getProperty("user"));
779                            sb.append(StringPool.EQUAL);
780                            sb.append(escapeValue(fullUserDN));
781                            sb.append(StringPool.CLOSE_PARENTHESIS);
782                            sb.append(StringPool.CLOSE_PARENTHESIS);
783    
784                            byte[] cookie = new byte[0];
785    
786                            while (cookie != null) {
787                                    List<SearchResult> searchResults =
788                                            new ArrayList<SearchResult>();
789    
790                                    String groupMappingsGroupName = GetterUtil.getString(
791                                            groupMappings.getProperty("groupName")).toLowerCase();
792    
793                                    cookie = PortalLDAPUtil.searchLDAP(
794                                            companyId, ldapContext, cookie, 0, baseDN, sb.toString(),
795                                            new String[] {groupMappingsGroupName}, searchResults);
796    
797                                    for (SearchResult searchResult : searchResults) {
798                                            String fullGroupDN = PortalLDAPUtil.getNameInNamespace(
799                                                    ldapServerId, companyId, searchResult);
800    
801                                            newUserGroupIds = importGroup(
802                                                    ldapServerId, companyId, ldapContext, fullGroupDN, user,
803                                                    groupMappings, newUserGroupIds);
804                                    }
805                            }
806                    }
807                    else {
808                            String userMappingsGroup = userMappings.getProperty("group");
809    
810                            if (Validator.isNull(userMappingsGroup)) {
811                                    return;
812                            }
813    
814                            Attribute userGroupAttribute = attributes.get(userMappingsGroup);
815    
816                            if (userGroupAttribute == null) {
817                                    return;
818                            }
819    
820                            for (int i = 0; i < userGroupAttribute.size(); i++) {
821                                    String fullGroupDN = (String)userGroupAttribute.get(i);
822    
823                                    newUserGroupIds = importGroup(
824                                            ldapServerId, companyId, ldapContext, fullGroupDN, user,
825                                            groupMappings, newUserGroupIds);
826                            }
827                    }
828    
829                    addUserGroupsNotAddedByLDAPImport(user.getUserId(), newUserGroupIds);
830    
831                    for (long newUserGroupId : newUserGroupIds) {
832                            UserLocalServiceUtil.addUserGroupUsers(
833                                    newUserGroupId, new long[] {user.getUserId()});
834                    }
835    
836                    List<UserGroup> userUserGroups =
837                            UserGroupLocalServiceUtil.getUserUserGroups(user.getUserId());
838    
839                    for (UserGroup userGroup : userUserGroups) {
840                            if (!newUserGroupIds.contains(userGroup.getUserGroupId())) {
841                                    UserLocalServiceUtil.deleteUserGroupUser(
842                                            userGroup.getUserGroupId(), user.getUserId());
843                            }
844                    }
845            }
846    
847            protected User importUser(
848                            long companyId, Attributes attributes, Properties userMappings,
849                            Properties userExpandoMappings, Properties contactMappings,
850                            Properties contactExpandoMappings, String password)
851                    throws Exception {
852    
853                    LDAPUserTransactionThreadLocal.setOriginatesFromLDAP(true);
854    
855                    try {
856                            AttributesTransformer attributesTransformer =
857                                    AttributesTransformerFactory.getInstance();
858    
859                            attributes = attributesTransformer.transformUser(attributes);
860    
861                            LDAPUser ldapUser = _ldapToPortalConverter.importLDAPUser(
862                                    companyId, attributes, userMappings, userExpandoMappings,
863                                    contactMappings, contactExpandoMappings, password);
864    
865                            User user = getUser(companyId, ldapUser);
866    
867                            if ((user != null) && user.isDefaultUser()) {
868                                    return user;
869                            }
870    
871                            if (user == null) {
872                                    user = addUser(companyId, ldapUser, password);
873                            }
874    
875                            String modifiedDate = LDAPUtil.getAttributeString(
876                                    attributes, "modifyTimestamp");
877    
878                            user = updateUser(
879                                    companyId, ldapUser, user, password, modifiedDate);
880    
881                            updateExpandoAttributes(user, ldapUser);
882    
883                            return user;
884                    }
885                    finally {
886                            LDAPUserTransactionThreadLocal.setOriginatesFromLDAP(false);
887                    }
888            }
889    
890            protected UserGroup importUserGroup(
891                            long companyId, Attributes attributes, Properties groupMappings)
892                    throws Exception {
893    
894                    AttributesTransformer attributesTransformer =
895                            AttributesTransformerFactory.getInstance();
896    
897                    attributes = attributesTransformer.transformGroup(attributes);
898    
899                    LDAPGroup ldapGroup = _ldapToPortalConverter.importLDAPGroup(
900                            companyId, attributes, groupMappings);
901    
902                    UserGroup userGroup = null;
903    
904                    try {
905                            userGroup = UserGroupLocalServiceUtil.getUserGroup(
906                                    companyId, ldapGroup.getGroupName());
907    
908                            UserGroupLocalServiceUtil.updateUserGroup(
909                                    companyId, userGroup.getUserGroupId(), ldapGroup.getGroupName(),
910                                    ldapGroup.getDescription());
911                    }
912                    catch (NoSuchUserGroupException nsuge) {
913                            if (_log.isDebugEnabled()) {
914                                    _log.debug(
915                                            "Adding user group to portal " + ldapGroup.getGroupName());
916                            }
917    
918                            long defaultUserId = UserLocalServiceUtil.getDefaultUserId(
919                                    companyId);
920    
921                            LDAPUserGroupTransactionThreadLocal.setOriginatesFromLDAP(true);
922    
923                            try {
924                                    userGroup = UserGroupLocalServiceUtil.addUserGroup(
925                                            defaultUserId, companyId, ldapGroup.getGroupName(),
926                                            ldapGroup.getDescription());
927                            }
928                            catch (Exception e) {
929                                    if (_log.isWarnEnabled()) {
930                                            _log.warn(
931                                                    "Unable to create user group " +
932                                                            ldapGroup.getGroupName());
933                                    }
934    
935                                    if (_log.isDebugEnabled()) {
936                                            _log.debug(e, e);
937                                    }
938                            }
939                            finally {
940                                    LDAPUserGroupTransactionThreadLocal.setOriginatesFromLDAP(
941                                            false);
942                            }
943                    }
944    
945                    addRole(companyId, ldapGroup, userGroup);
946    
947                    return userGroup;
948            }
949    
950            protected void importUsers(
951                            long ldapServerId, long companyId, LdapContext ldapContext,
952                            Properties userMappings, Properties userExpandoMappings,
953                            Properties contactMappings, Properties contactExpandoMappings,
954                            long userGroupId, Attribute attribute)
955                    throws Exception {
956    
957                    List<Long> newUserIds = new ArrayList<Long>(attribute.size());
958    
959                    for (int i = 0; i < attribute.size(); i++) {
960                            String fullUserDN = (String)attribute.get(i);
961    
962                            Attributes userAttributes = null;
963    
964                            try {
965                                    userAttributes = PortalLDAPUtil.getUserAttributes(
966                                            ldapServerId, companyId, ldapContext, fullUserDN);
967                            }
968                            catch (NameNotFoundException nnfe) {
969                                    _log.error(
970                                            "LDAP user not found with fullUserDN " + fullUserDN, nnfe);
971    
972                                    continue;
973                            }
974    
975                            try {
976                                    User user = importUser(
977                                            companyId, userAttributes, userMappings,
978                                            userExpandoMappings, contactMappings,
979                                            contactExpandoMappings, StringPool.BLANK);
980    
981                                    if (user != null) {
982                                            if (_log.isDebugEnabled()) {
983                                                    _log.debug(
984                                                            "Adding " + user.getUserId() + " to group " +
985                                                                    userGroupId);
986                                            }
987    
988                                            UserLocalServiceUtil.addUserGroupUsers(
989                                                    userGroupId, new long[] {user.getUserId()});
990    
991                                            newUserIds.add(user.getUserId());
992                                    }
993                            }
994                            catch (Exception e) {
995                                    _log.error("Unable to load user " + userAttributes, e);
996                            }
997                    }
998    
999                    List<User> userGroupUsers = UserLocalServiceUtil.getUserGroupUsers(
1000                            userGroupId);
1001    
1002                    for (User user : userGroupUsers) {
1003                            if (!newUserIds.contains(user.getUserId())) {
1004                                    UserLocalServiceUtil.deleteUserGroupUser(
1005                                            userGroupId, user.getUserId());
1006                            }
1007                    }
1008            }
1009    
1010            protected void populateExpandoAttributes(
1011                    ExpandoBridge expandoBridge, Map<String, String> expandoAttributes) {
1012    
1013                    for (Map.Entry<String, String> expandoAttribute :
1014                                    expandoAttributes.entrySet()) {
1015    
1016                            String name = expandoAttribute.getKey();
1017    
1018                            if (!expandoBridge.hasAttribute(name)) {
1019                                    continue;
1020                            }
1021    
1022                            int type = expandoBridge.getAttributeType(name);
1023    
1024                            Serializable value = ExpandoConverterUtil.getAttributeFromString(
1025                                    type, expandoAttribute.getValue());
1026    
1027                            try {
1028                                    ExpandoValueLocalServiceUtil.addValue(
1029                                            expandoBridge.getCompanyId(), expandoBridge.getClassName(),
1030                                            ExpandoTableConstants.DEFAULT_TABLE_NAME, name,
1031                                            expandoBridge.getClassPK(), value);
1032                            }
1033                            catch (Exception e) {
1034                                    _log.error(e, e);
1035                            }
1036                    }
1037            }
1038    
1039            protected void updateExpandoAttributes(User user, LDAPUser ldapUser)
1040                    throws Exception {
1041    
1042                    ExpandoBridge userExpandoBridge = user.getExpandoBridge();
1043    
1044                    populateExpandoAttributes(
1045                            userExpandoBridge, ldapUser.getUserExpandoAttributes());
1046    
1047                    Contact contact = user.getContact();
1048    
1049                    ExpandoBridge contactExpandoBridge = contact.getExpandoBridge();
1050    
1051                    populateExpandoAttributes(
1052                            contactExpandoBridge, ldapUser.getContactExpandoAttributes());
1053            }
1054    
1055            protected User updateUser(
1056                            long companyId, LDAPUser ldapUser, User user, String password,
1057                            String modifiedDate)
1058                    throws Exception {
1059    
1060                    Date ldapUserModifiedDate = null;
1061    
1062                    try {
1063                            if (Validator.isNull(modifiedDate)) {
1064                                    if (_log.isInfoEnabled()) {
1065                                            _log.info(
1066                                                    "LDAP entry never modified, skipping user " +
1067                                                            user.getEmailAddress());
1068                                    }
1069    
1070                                    return user;
1071                            }
1072                            else {
1073                                    ldapUserModifiedDate = LDAPUtil.parseDate(modifiedDate);
1074                            }
1075    
1076                            if (ldapUserModifiedDate.equals(user.getModifiedDate()) &&
1077                                    ldapUser.isAutoPassword()) {
1078    
1079                                    if (_log.isDebugEnabled()) {
1080                                            _log.debug(
1081                                                    "User is already synchronized, skipping user " +
1082                                                            user.getEmailAddress());
1083                                    }
1084    
1085                                    return user;
1086                            }
1087                    }
1088                    catch (ParseException pe) {
1089                            if (_log.isDebugEnabled()) {
1090                                    _log.debug(
1091                                            "Unable to parse LDAP modify timestamp " + modifiedDate,
1092                                            pe);
1093                            }
1094                    }
1095    
1096                    boolean passwordReset = ldapUser.isPasswordReset();
1097    
1098                    if (PrefsPropsUtil.getBoolean(
1099                                    companyId, PropsKeys.LDAP_EXPORT_ENABLED,
1100                                    PropsValues.LDAP_EXPORT_ENABLED)) {
1101    
1102                            passwordReset = user.isPasswordReset();
1103                    }
1104    
1105                    if (!PropsValues.LDAP_IMPORT_USER_PASSWORD_ENABLED) {
1106                            password = PropsValues.LDAP_IMPORT_USER_PASSWORD_DEFAULT;
1107    
1108                            if (password.equalsIgnoreCase(_USER_PASSWORD_SCREEN_NAME)) {
1109                                    password = ldapUser.getScreenName();
1110                            }
1111                    }
1112    
1113                    if (Validator.isNull(ldapUser.getScreenName())) {
1114                            ldapUser.setAutoScreenName(true);
1115                    }
1116    
1117                    if (ldapUser.isAutoScreenName()) {
1118                            ScreenNameGenerator screenNameGenerator =
1119                                    ScreenNameGeneratorFactory.getInstance();
1120    
1121                            ldapUser.setScreenName(
1122                                    screenNameGenerator.generate(
1123                                            companyId, user.getUserId(), ldapUser.getEmailAddress()));
1124                    }
1125    
1126                    Calendar birthdayCal = CalendarFactoryUtil.getCalendar();
1127    
1128                    birthdayCal.setTime(user.getContact().getBirthday());
1129    
1130                    int birthdayMonth = birthdayCal.get(Calendar.MONTH);
1131                    int birthdayDay = birthdayCal.get(Calendar.DAY_OF_MONTH);
1132                    int birthdayYear = birthdayCal.get(Calendar.YEAR);
1133    
1134                    if (ldapUser.isUpdatePassword()) {
1135                            UserLocalServiceUtil.updatePassword(
1136                                    user.getUserId(), password, password, passwordReset, true);
1137                    }
1138    
1139                    Contact contact = user.getContact();
1140    
1141                    Set<String> ldapIgnoreAttributes = SetUtil.fromArray(
1142                            PropsValues.LDAP_USER_IGNORE_ATTRIBUTES);
1143    
1144                    for (String attribute : ldapIgnoreAttributes) {
1145                            Object value = BeanPropertiesUtil.getObjectSilent(user, attribute);
1146    
1147                            if (value == null) {
1148                                    value = BeanPropertiesUtil.getObjectSilent(contact, attribute);
1149                            }
1150    
1151                            if (value != null) {
1152                                    BeanPropertiesUtil.setProperty(ldapUser, attribute, value);
1153                            }
1154                    }
1155    
1156                    user = UserLocalServiceUtil.updateUser(
1157                            user.getUserId(), password, StringPool.BLANK, StringPool.BLANK,
1158                            passwordReset, ldapUser.getReminderQueryQuestion(),
1159                            ldapUser.getReminderQueryAnswer(), ldapUser.getScreenName(),
1160                            ldapUser.getEmailAddress(), ldapUser.getFacebookId(),
1161                            ldapUser.getOpenId(), ldapUser.getLanguageId(),
1162                            ldapUser.getTimeZoneId(), ldapUser.getGreeting(),
1163                            ldapUser.getComments(), ldapUser.getFirstName(),
1164                            ldapUser.getMiddleName(), ldapUser.getLastName(),
1165                            ldapUser.getPrefixId(), ldapUser.getSuffixId(), ldapUser.isMale(),
1166                            birthdayMonth, birthdayDay, birthdayYear, ldapUser.getSmsSn(),
1167                            ldapUser.getAimSn(), ldapUser.getFacebookSn(), ldapUser.getIcqSn(),
1168                            ldapUser.getJabberSn(), ldapUser.getMsnSn(),
1169                            ldapUser.getMySpaceSn(), ldapUser.getSkypeSn(),
1170                            ldapUser.getTwitterSn(), ldapUser.getYmSn(), ldapUser.getJobTitle(),
1171                            ldapUser.getGroupIds(), ldapUser.getOrganizationIds(),
1172                            ldapUser.getRoleIds(), ldapUser.getUserGroupRoles(),
1173                            ldapUser.getUserGroupIds(), ldapUser.getServiceContext());
1174    
1175                    if (ldapUserModifiedDate != null) {
1176                            user = UserLocalServiceUtil.updateModifiedDate(
1177                                    user.getUserId(), ldapUserModifiedDate);
1178                    }
1179    
1180                    if (ldapUser.isUpdatePortrait()) {
1181                            byte[] portraitBytes = ldapUser.getPortraitBytes();
1182    
1183                            if ((portraitBytes != null) && (portraitBytes.length > 0)) {
1184                                    UserLocalServiceUtil.updatePortrait(
1185                                            user.getUserId(), portraitBytes);
1186                            }
1187                            else {
1188                                    UserLocalServiceUtil.deletePortrait(user.getUserId());
1189                            }
1190                    }
1191    
1192                    return user;
1193            }
1194    
1195            private static final String _IMPORT_BY_GROUP = "group";
1196    
1197            private static final String _IMPORT_BY_USER = "user";
1198    
1199            private static final String _USER_PASSWORD_SCREEN_NAME = "screenName";
1200    
1201            private static Log _log = LogFactoryUtil.getLog(
1202                    PortalLDAPImporterImpl.class);
1203    
1204            private LDAPToPortalConverter _ldapToPortalConverter;
1205            private PortalCache _portalCache = SingleVMPoolUtil.getCache(
1206                    PortalLDAPImporter.class.getName(), false);
1207    
1208    }