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