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