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.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(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,
851                            String password)
852                    throws Exception {
853    
854                    LDAPUserTransactionThreadLocal.setOriginatesFromLDAP(true);
855    
856                    try {
857                            AttributesTransformer attributesTransformer =
858                                    AttributesTransformerFactory.getInstance();
859    
860                            attributes = attributesTransformer.transformUser(attributes);
861    
862                            LDAPUser ldapUser = _ldapToPortalConverter.importLDAPUser(
863                                    companyId, attributes, userMappings, userExpandoMappings,
864                                    contactMappings, contactExpandoMappings, password);
865    
866                            User user = getUser(companyId, ldapUser);
867    
868                            if ((user != null) && user.isDefaultUser()) {
869                                    return user;
870                            }
871    
872                            if (user == null) {
873                                    user = addUser(companyId, ldapUser, password);
874                            }
875    
876                            String modifiedDate = LDAPUtil.getAttributeString(
877                                    attributes, "modifyTimestamp");
878    
879                            user = updateUser(
880                                    companyId, ldapUser, user, password, modifiedDate);
881    
882                            updateExpandoAttributes(user, ldapUser);
883    
884                            return user;
885                    }
886                    finally {
887                            LDAPUserTransactionThreadLocal.setOriginatesFromLDAP(false);
888                    }
889            }
890    
891            protected UserGroup importUserGroup(
892                            long companyId, Attributes attributes, Properties groupMappings)
893                    throws Exception {
894    
895                    AttributesTransformer attributesTransformer =
896                            AttributesTransformerFactory.getInstance();
897    
898                    attributes = attributesTransformer.transformGroup(attributes);
899    
900                    LDAPGroup ldapGroup = _ldapToPortalConverter.importLDAPGroup(
901                            companyId, attributes, groupMappings);
902    
903                    UserGroup userGroup = null;
904    
905                    try {
906                            userGroup = UserGroupLocalServiceUtil.getUserGroup(
907                                    companyId, ldapGroup.getGroupName());
908    
909                            UserGroupLocalServiceUtil.updateUserGroup(
910                                    companyId, userGroup.getUserGroupId(), ldapGroup.getGroupName(),
911                                    ldapGroup.getDescription());
912                    }
913                    catch (NoSuchUserGroupException nsuge) {
914                            if (_log.isDebugEnabled()) {
915                                    _log.debug(
916                                            "Adding user group to portal " + ldapGroup.getGroupName());
917                            }
918    
919                            long defaultUserId = UserLocalServiceUtil.getDefaultUserId(
920                                    companyId);
921    
922                            LDAPUserGroupTransactionThreadLocal.setOriginatesFromLDAP(true);
923    
924                            try {
925                                    userGroup = UserGroupLocalServiceUtil.addUserGroup(
926                                            defaultUserId, companyId, ldapGroup.getGroupName(),
927                                            ldapGroup.getDescription());
928                            }
929                            catch (Exception e) {
930                                    if (_log.isWarnEnabled()) {
931                                            _log.warn(
932                                                    "Unable to create user group " +
933                                                            ldapGroup.getGroupName());
934                                    }
935    
936                                    if (_log.isDebugEnabled()) {
937                                            _log.debug(e, e);
938                                    }
939                            }
940                            finally {
941                                    LDAPUserGroupTransactionThreadLocal.setOriginatesFromLDAP(
942                                            false);
943                            }
944                    }
945    
946                    addRole(companyId, ldapGroup, userGroup);
947    
948                    return userGroup;
949            }
950    
951            protected void importUsers(
952                            long ldapServerId, long companyId, LdapContext ldapContext,
953                            Properties userMappings, Properties userExpandoMappings,
954                            Properties contactMappings, Properties contactExpandoMappings,
955                            long userGroupId, Attribute attribute)
956                    throws Exception {
957    
958                    List<Long> newUserIds = new ArrayList<Long>(attribute.size());
959    
960                    for (int i = 0; i < attribute.size(); i++) {
961                            String fullUserDN = (String)attribute.get(i);
962    
963                            Attributes userAttributes = null;
964    
965                            try {
966                                    userAttributes = PortalLDAPUtil.getUserAttributes(
967                                            ldapServerId, companyId, ldapContext, fullUserDN);
968                            }
969                            catch (NameNotFoundException nnfe) {
970                                    _log.error(
971                                            "LDAP user not found with fullUserDN " + fullUserDN, nnfe);
972    
973                                    continue;
974                            }
975    
976                            try {
977                                    User user = importUser(
978                                            companyId, userAttributes, userMappings,
979                                            userExpandoMappings, contactMappings,
980                                            contactExpandoMappings, StringPool.BLANK);
981    
982                                    if (user != null) {
983                                            if (_log.isDebugEnabled()) {
984                                                    _log.debug(
985                                                            "Adding " + user.getUserId() + " to group " +
986                                                                    userGroupId);
987                                            }
988    
989                                            UserLocalServiceUtil.addUserGroupUsers(
990                                                    userGroupId, new long[] {user.getUserId()});
991    
992                                            newUserIds.add(user.getUserId());
993                                    }
994                            }
995                            catch (Exception e) {
996                                    _log.error("Unable to load user " + userAttributes, e);
997                            }
998                    }
999    
1000                    List<User> userGroupUsers = UserLocalServiceUtil.getUserGroupUsers(
1001                            userGroupId);
1002    
1003                    for (User user : userGroupUsers) {
1004                            if (!newUserIds.contains(user.getUserId())) {
1005                                    UserLocalServiceUtil.deleteUserGroupUser(
1006                                            userGroupId, user.getUserId());
1007                            }
1008                    }
1009            }
1010    
1011            protected void populateExpandoAttributes(
1012                    ExpandoBridge expandoBridge, Map<String, String> expandoAttributes) {
1013    
1014                    for (Map.Entry<String, String> expandoAttribute :
1015                                    expandoAttributes.entrySet()) {
1016    
1017                            String name = expandoAttribute.getKey();
1018    
1019                            if (!expandoBridge.hasAttribute(name)) {
1020                                    continue;
1021                            }
1022    
1023                            int type = expandoBridge.getAttributeType(name);
1024    
1025                            Serializable value = ExpandoConverterUtil.getAttributeFromString(
1026                                    type, expandoAttribute.getValue());
1027    
1028                            try {
1029                                    ExpandoValueLocalServiceUtil.addValue(
1030                                            expandoBridge.getCompanyId(), expandoBridge.getClassName(),
1031                                            ExpandoTableConstants.DEFAULT_TABLE_NAME, name,
1032                                            expandoBridge.getClassPK(), value);
1033                            }
1034                            catch (Exception e) {
1035                                    _log.error(e, e);
1036                            }
1037                    }
1038            }
1039    
1040            protected void updateExpandoAttributes(User user, LDAPUser ldapUser)
1041                    throws Exception {
1042    
1043                    ExpandoBridge userExpandoBridge = user.getExpandoBridge();
1044    
1045                    populateExpandoAttributes(
1046                            userExpandoBridge, ldapUser.getUserExpandoAttributes());
1047    
1048                    Contact contact = user.getContact();
1049    
1050                    ExpandoBridge contactExpandoBridge = contact.getExpandoBridge();
1051    
1052                    populateExpandoAttributes(
1053                            contactExpandoBridge, ldapUser.getContactExpandoAttributes());
1054            }
1055    
1056            protected User updateUser(
1057                            long companyId, LDAPUser ldapUser, User user, String password,
1058                            String modifiedDate)
1059                    throws Exception {
1060    
1061                    Date ldapUserModifiedDate = null;
1062    
1063                    try {
1064                            if (Validator.isNull(modifiedDate)) {
1065                                    if (_log.isInfoEnabled()) {
1066                                            _log.info(
1067                                                    "LDAP entry never modified, skipping user " +
1068                                                            user.getEmailAddress());
1069                                    }
1070    
1071                                    return user;
1072                            }
1073                            else {
1074                                    ldapUserModifiedDate = LDAPUtil.parseDate(modifiedDate);
1075                            }
1076    
1077                            if (ldapUserModifiedDate.equals(user.getModifiedDate()) &&
1078                                    ldapUser.isAutoPassword()) {
1079    
1080                                    if (_log.isDebugEnabled()) {
1081                                            _log.debug(
1082                                                    "User is already synchronized, skipping user " +
1083                                                            user.getEmailAddress());
1084                                    }
1085    
1086                                    return user;
1087                            }
1088                    }
1089                    catch (ParseException pe) {
1090                            if (_log.isDebugEnabled()) {
1091                                    _log.debug(
1092                                            "Unable to parse LDAP modify timestamp " + modifiedDate,
1093                                            pe);
1094                            }
1095                    }
1096    
1097                    boolean passwordReset = ldapUser.isPasswordReset();
1098    
1099                    if (PrefsPropsUtil.getBoolean(
1100                                    companyId, PropsKeys.LDAP_EXPORT_ENABLED,
1101                                    PropsValues.LDAP_EXPORT_ENABLED)) {
1102    
1103                            passwordReset = user.isPasswordReset();
1104                    }
1105    
1106                    if (Validator.isNull(ldapUser.getScreenName())) {
1107                            ldapUser.setAutoScreenName(true);
1108                    }
1109    
1110                    if (ldapUser.isAutoScreenName()) {
1111                            ScreenNameGenerator screenNameGenerator =
1112                                    ScreenNameGeneratorFactory.getInstance();
1113    
1114                            ldapUser.setScreenName(
1115                                    screenNameGenerator.generate(
1116                                            companyId, user.getUserId(), ldapUser.getEmailAddress()));
1117                    }
1118    
1119                    Calendar birthdayCal = CalendarFactoryUtil.getCalendar();
1120    
1121                    birthdayCal.setTime(user.getContact().getBirthday());
1122    
1123                    int birthdayMonth = birthdayCal.get(Calendar.MONTH);
1124                    int birthdayDay = birthdayCal.get(Calendar.DAY_OF_MONTH);
1125                    int birthdayYear = birthdayCal.get(Calendar.YEAR);
1126    
1127                    if (PropsValues.LDAP_IMPORT_USER_PASSWORD_ENABLED) {
1128                            UserLocalServiceUtil.updatePassword(
1129                                    user.getUserId(), password, password, passwordReset, true);
1130                    }
1131    
1132                    Contact contact = user.getContact();
1133    
1134                    Set<String> ldapIgnoreAttributes = SetUtil.fromArray(
1135                            PropsValues.LDAP_USER_IGNORE_ATTRIBUTES);
1136    
1137                    for (String attribute : ldapIgnoreAttributes) {
1138                            Object value = BeanPropertiesUtil.getObjectSilent(user, attribute);
1139    
1140                            if (value == null) {
1141                                    value = BeanPropertiesUtil.getObjectSilent(contact, attribute);
1142                            }
1143    
1144                            if (value != null) {
1145                                    BeanPropertiesUtil.setProperty(ldapUser, attribute, value);
1146                            }
1147                    }
1148    
1149                    user = UserLocalServiceUtil.updateUser(
1150                            user.getUserId(), password, StringPool.BLANK, StringPool.BLANK,
1151                            passwordReset, ldapUser.getReminderQueryQuestion(),
1152                            ldapUser.getReminderQueryAnswer(), ldapUser.getScreenName(),
1153                            ldapUser.getEmailAddress(), ldapUser.getFacebookId(),
1154                            ldapUser.getOpenId(), ldapUser.getLanguageId(),
1155                            ldapUser.getTimeZoneId(), ldapUser.getGreeting(),
1156                            ldapUser.getComments(), ldapUser.getFirstName(),
1157                            ldapUser.getMiddleName(), ldapUser.getLastName(),
1158                            ldapUser.getPrefixId(), ldapUser.getSuffixId(), ldapUser.isMale(),
1159                            birthdayMonth, birthdayDay, birthdayYear, ldapUser.getSmsSn(),
1160                            ldapUser.getAimSn(), ldapUser.getFacebookSn(), ldapUser.getIcqSn(),
1161                            ldapUser.getJabberSn(), ldapUser.getMsnSn(),
1162                            ldapUser.getMySpaceSn(), ldapUser.getSkypeSn(),
1163                            ldapUser.getTwitterSn(), ldapUser.getYmSn(), ldapUser.getJobTitle(),
1164                            ldapUser.getGroupIds(), ldapUser.getOrganizationIds(),
1165                            ldapUser.getRoleIds(), ldapUser.getUserGroupRoles(),
1166                            ldapUser.getUserGroupIds(), ldapUser.getServiceContext());
1167    
1168                    if (ldapUserModifiedDate != null) {
1169                            user = UserLocalServiceUtil.updateModifiedDate(
1170                                    user.getUserId(), ldapUserModifiedDate);
1171                    }
1172    
1173                    if (ldapUser.isUpdatePortrait()) {
1174                            byte[] portraitBytes = ldapUser.getPortraitBytes();
1175    
1176                            if ((portraitBytes != null) && (portraitBytes.length > 0)) {
1177                                    UserLocalServiceUtil.updatePortrait(
1178                                            user.getUserId(), portraitBytes);
1179                            }
1180                            else {
1181                                    UserLocalServiceUtil.deletePortrait(user.getUserId());
1182                            }
1183                    }
1184    
1185                    return user;
1186            }
1187    
1188            private static final String _IMPORT_BY_GROUP = "group";
1189    
1190            private static final String _IMPORT_BY_USER = "user";
1191    
1192            private static final String _USER_PASSWORD_SCREEN_NAME = "screenName";
1193    
1194            private static Log _log = LogFactoryUtil.getLog(
1195                    PortalLDAPImporterImpl.class);
1196    
1197            private LDAPToPortalConverter _ldapToPortalConverter;
1198            private PortalCache _portalCache = SingleVMPoolUtil.getCache(
1199                    PortalLDAPImporter.class.getName(), false);
1200    
1201    }