001    /**
002     * Copyright (c) 2000-present 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.PwdEncryptorException;
018    import com.liferay.portal.kernel.exception.SystemException;
019    import com.liferay.portal.kernel.log.Log;
020    import com.liferay.portal.kernel.log.LogFactoryUtil;
021    import com.liferay.portal.kernel.util.GetterUtil;
022    import com.liferay.portal.kernel.util.PropsKeys;
023    import com.liferay.portal.kernel.util.StringBundler;
024    import com.liferay.portal.kernel.util.StringPool;
025    import com.liferay.portal.kernel.util.Validator;
026    import com.liferay.portal.model.Contact;
027    import com.liferay.portal.model.Image;
028    import com.liferay.portal.model.User;
029    import com.liferay.portal.model.UserGroup;
030    import com.liferay.portal.security.exportimport.UserOperation;
031    import com.liferay.portal.security.pwd.PasswordEncryptorUtil;
032    import com.liferay.portal.service.ImageLocalServiceUtil;
033    import com.liferay.portal.util.PrefsPropsUtil;
034    import com.liferay.portlet.expando.model.ExpandoBridge;
035    import com.liferay.portlet.expando.util.ExpandoConverterUtil;
036    
037    import java.io.Serializable;
038    
039    import java.util.HashMap;
040    import java.util.List;
041    import java.util.Map;
042    import java.util.Properties;
043    
044    import javax.naming.Binding;
045    import javax.naming.directory.Attribute;
046    import javax.naming.directory.Attributes;
047    import javax.naming.directory.BasicAttribute;
048    import javax.naming.directory.BasicAttributes;
049    import javax.naming.directory.DirContext;
050    
051    import org.apache.commons.beanutils.PropertyUtils;
052    
053    /**
054     * @author Michael C. Han
055     * @author Brian Wing Shun Chan
056     * @author Marcellus Tavares
057     * @author Wesley Gong
058     */
059    public class DefaultPortalToLDAPConverter implements PortalToLDAPConverter {
060    
061            public DefaultPortalToLDAPConverter() {
062                    _reservedUserFieldNames.put(
063                            UserConverterKeys.GROUP, UserConverterKeys.GROUP);
064                    _reservedUserFieldNames.put(
065                            UserConverterKeys.PASSWORD, UserConverterKeys.PASSWORD);
066                    _reservedUserFieldNames.put(
067                            UserConverterKeys.PORTRAIT, UserConverterKeys.PORTRAIT);
068                    _reservedUserFieldNames.put(
069                            UserConverterKeys.SCREEN_NAME, UserConverterKeys.SCREEN_NAME);
070            }
071    
072            @Override
073            public String getGroupDNName(
074                            long ldapServerId, UserGroup userGroup, Properties groupMappings)
075                    throws Exception {
076    
077                    Binding groupBinding = PortalLDAPUtil.getGroup(
078                            ldapServerId, userGroup.getCompanyId(), userGroup.getName());
079    
080                    if (groupBinding != null) {
081                            return PortalLDAPUtil.getNameInNamespace(
082                                    ldapServerId, userGroup.getCompanyId(), groupBinding);
083                    }
084    
085                    StringBundler sb = new StringBundler(5);
086    
087                    sb.append(
088                            GetterUtil.getString(
089                                    groupMappings.getProperty(_groupDNFieldName), _DEFAULT_DN));
090                    sb.append(StringPool.EQUAL);
091                    sb.append(userGroup.getName());
092                    sb.append(StringPool.COMMA);
093                    sb.append(
094                            PortalLDAPUtil.getGroupsDN(ldapServerId, userGroup.getCompanyId()));
095    
096                    return sb.toString();
097            }
098    
099            @Override
100            public Modifications getLDAPContactModifications(
101                            Contact contact, Map<String, Serializable> contactExpandoAttributes,
102                            Properties contactMappings, Properties contactExpandoMappings)
103                    throws Exception {
104    
105                    if (contactMappings.isEmpty() && contactExpandoMappings.isEmpty()) {
106                            return null;
107                    }
108    
109                    Modifications modifications = getModifications(
110                            contact, contactMappings, _reservedContactFieldNames);
111    
112                    populateCustomAttributeModifications(
113                            contact, contact.getExpandoBridge(), contactExpandoAttributes,
114                            contactExpandoMappings, modifications);
115    
116                    return modifications;
117            }
118    
119            @Override
120            public Attributes getLDAPGroupAttributes(
121                            long ldapServerId, UserGroup userGroup, User user,
122                            Properties groupMappings, Properties userMappings)
123                    throws Exception {
124    
125                    Attributes attributes = new BasicAttributes(true);
126    
127                    Attribute objectClass = new BasicAttribute(_OBJECT_CLASS);
128    
129                    String postfix = LDAPSettingsUtil.getPropertyPostfix(ldapServerId);
130    
131                    String[] defaultObjectClasses = PrefsPropsUtil.getStringArray(
132                            userGroup.getCompanyId(),
133                            PropsKeys.LDAP_GROUP_DEFAULT_OBJECT_CLASSES + postfix,
134                            StringPool.COMMA);
135    
136                    for (int i = 0; i < defaultObjectClasses.length; i++) {
137                            objectClass.add(defaultObjectClasses[i]);
138                    }
139    
140                    attributes.put(objectClass);
141    
142                    addAttributeMapping(
143                            groupMappings.getProperty(GroupConverterKeys.GROUP_NAME),
144                            userGroup.getName(), attributes);
145                    addAttributeMapping(
146                            groupMappings.getProperty(GroupConverterKeys.DESCRIPTION),
147                            userGroup.getDescription(), attributes);
148                    addAttributeMapping(
149                            groupMappings.getProperty(GroupConverterKeys.USER),
150                            getUserDNName(ldapServerId, user, userMappings), attributes);
151    
152                    return attributes;
153            }
154    
155            @Override
156            public Modifications getLDAPGroupModifications(
157                            long ldapServerId, UserGroup userGroup, User user,
158                            Properties groupMappings, Properties userMappings,
159                            UserOperation userOperation)
160                    throws Exception {
161    
162                    Modifications modifications = Modifications.getInstance();
163    
164                    String groupDN = getGroupDNName(ldapServerId, userGroup, groupMappings);
165                    String userDN = getUserDNName(ldapServerId, user, userMappings);
166    
167                    if (PortalLDAPUtil.isGroupMember(
168                                    ldapServerId, user.getCompanyId(), groupDN, userDN)) {
169    
170                            if (userOperation == UserOperation.REMOVE) {
171                                    modifications.addItem(
172                                            DirContext.REMOVE_ATTRIBUTE,
173                                            groupMappings.getProperty(GroupConverterKeys.USER), userDN);
174                            }
175                    }
176                    else {
177                            if (userOperation == UserOperation.ADD) {
178                                    modifications.addItem(
179                                            DirContext.ADD_ATTRIBUTE,
180                                            groupMappings.getProperty(GroupConverterKeys.USER), userDN);
181                            }
182                    }
183    
184                    return modifications;
185            }
186    
187            @Override
188            public Attributes getLDAPUserAttributes(
189                    long ldapServerId, User user, Properties userMappings) {
190    
191                    Attributes attributes = new BasicAttributes(true);
192    
193                    Attribute objectClass = new BasicAttribute(_OBJECT_CLASS);
194    
195                    String postfix = LDAPSettingsUtil.getPropertyPostfix(ldapServerId);
196    
197                    String[] defaultObjectClasses = PrefsPropsUtil.getStringArray(
198                            user.getCompanyId(),
199                            PropsKeys.LDAP_USER_DEFAULT_OBJECT_CLASSES + postfix,
200                            StringPool.COMMA);
201    
202                    for (int i = 0; i < defaultObjectClasses.length; i++) {
203                            objectClass.add(defaultObjectClasses[i]);
204                    }
205    
206                    attributes.put(objectClass);
207    
208                    addAttributeMapping(
209                            userMappings.getProperty(UserConverterKeys.UUID), user.getUuid(),
210                            attributes);
211                    addAttributeMapping(
212                            userMappings.getProperty(UserConverterKeys.SCREEN_NAME),
213                            user.getScreenName(), attributes);
214                    addAttributeMapping(
215                            userMappings.getProperty(UserConverterKeys.PASSWORD),
216                            getEncryptedPasswordForLDAP(user), attributes);
217                    addAttributeMapping(
218                            userMappings.getProperty(UserConverterKeys.EMAIL_ADDRESS),
219                            user.getEmailAddress(), attributes);
220                    addAttributeMapping(
221                            userMappings.getProperty(UserConverterKeys.FULL_NAME),
222                            user.getFullName(), attributes);
223                    addAttributeMapping(
224                            userMappings.getProperty(UserConverterKeys.FIRST_NAME),
225                            user.getFirstName(), attributes);
226                    addAttributeMapping(
227                            userMappings.getProperty(UserConverterKeys.MIDDLE_NAME),
228                            user.getMiddleName(), attributes);
229                    addAttributeMapping(
230                            userMappings.getProperty(UserConverterKeys.LAST_NAME),
231                            user.getLastName(), attributes);
232                    addAttributeMapping(
233                            userMappings.getProperty(UserConverterKeys.JOB_TITLE),
234                            user.getJobTitle(), attributes);
235                    addAttributeMapping(
236                            userMappings.getProperty(UserConverterKeys.PORTRAIT),
237                            getUserPortrait(user), attributes);
238                    addAttributeMapping(
239                            userMappings.getProperty(UserConverterKeys.STATUS),
240                            String.valueOf(user.getStatus()), attributes);
241    
242                    return attributes;
243            }
244    
245            @Override
246            public Modifications getLDAPUserGroupModifications(
247                            long ldapServerId, List<UserGroup> userGroups, User user,
248                            Properties userMappings)
249                    throws Exception {
250    
251                    Modifications modifications = Modifications.getInstance();
252    
253                    String groupMappingAttributeName = userMappings.getProperty(
254                            UserConverterKeys.GROUP);
255    
256                    if (Validator.isNull(groupMappingAttributeName)) {
257                            return modifications;
258                    }
259    
260                    Properties groupMappings = LDAPSettingsUtil.getGroupMappings(
261                            ldapServerId, user.getCompanyId());
262    
263                    String userDN = getUserDNName(ldapServerId, user, userMappings);
264    
265                    for (UserGroup userGroup : userGroups) {
266                            String groupDN = getGroupDNName(
267                                    ldapServerId, userGroup, groupMappings);
268    
269                            if (PortalLDAPUtil.isUserGroupMember(
270                                            ldapServerId, user.getCompanyId(), groupDN, userDN)) {
271    
272                                    continue;
273                            }
274    
275                            modifications.addItem(
276                                    DirContext.ADD_ATTRIBUTE, groupMappingAttributeName, groupDN);
277                    }
278    
279                    return modifications;
280            }
281    
282            @Override
283            public Modifications getLDAPUserModifications(
284                            User user, Map<String, Serializable> userExpandoAttributes,
285                            Properties userMappings, Properties userExpandoMappings)
286                    throws Exception {
287    
288                    Modifications modifications = getModifications(
289                            user, userMappings, _reservedUserFieldNames);
290    
291                    if (user.isPasswordModified() &&
292                            Validator.isNotNull(user.getPasswordUnencrypted())) {
293    
294                            String newPassword = getEncryptedPasswordForLDAP(user);
295    
296                            String passwordKey = userMappings.getProperty(
297                                    UserConverterKeys.PASSWORD);
298    
299                            if (passwordKey.equals("unicodePwd")) {
300                                    String newQuotedPassword = StringPool.QUOTE.concat(
301                                            newPassword).concat(StringPool.QUOTE);
302    
303                                    byte[] newUnicodePassword = newQuotedPassword.getBytes(
304                                            "UTF-16LE");
305    
306                                    addModificationItem(
307                                            new BasicAttribute(passwordKey, newUnicodePassword),
308                                            modifications);
309                            }
310                            else {
311                                    addModificationItem(passwordKey, newPassword, modifications);
312                            }
313                    }
314    
315                    String portraitKey = userMappings.getProperty(
316                            UserConverterKeys.PORTRAIT);
317    
318                    if (Validator.isNotNull(portraitKey)) {
319                            addModificationItem(
320                                    new BasicAttribute(portraitKey, getUserPortrait(user)),
321                                    modifications);
322                    }
323    
324                    populateCustomAttributeModifications(
325                            user, user.getExpandoBridge(), userExpandoAttributes,
326                            userExpandoMappings, modifications);
327    
328                    return modifications;
329            }
330    
331            @Override
332            public String getUserDNName(
333                            long ldapServerId, User user, Properties userMappings)
334                    throws Exception {
335    
336                    Binding userBinding = PortalLDAPUtil.getUser(
337                            ldapServerId, user.getCompanyId(), user.getScreenName(),
338                            user.getEmailAddress());
339    
340                    if (userBinding != null) {
341                            return PortalLDAPUtil.getNameInNamespace(
342                                    ldapServerId, user.getCompanyId(), userBinding);
343                    }
344    
345                    StringBundler sb = new StringBundler(5);
346    
347                    sb.append(
348                            GetterUtil.getString(
349                                    userMappings.getProperty(_userDNFieldName), _DEFAULT_DN));
350                    sb.append(StringPool.EQUAL);
351                    sb.append(PropertyUtils.getProperty(user, _userDNFieldName));
352                    sb.append(StringPool.COMMA);
353                    sb.append(PortalLDAPUtil.getUsersDN(ldapServerId, user.getCompanyId()));
354    
355                    return sb.toString();
356            }
357    
358            public void setContactReservedFieldNames(
359                    List<String> reservedContactFieldNames) {
360    
361                    for (String reservedContactFieldName : reservedContactFieldNames) {
362                            _reservedContactFieldNames.put(
363                                    reservedContactFieldName, reservedContactFieldName);
364                    }
365            }
366    
367            public void setUserDNFieldName(String userDNFieldName) {
368                    _userDNFieldName = userDNFieldName;
369            }
370    
371            public void setUserReservedFieldNames(List<String> reservedUserFieldNames) {
372                    for (String reservedUserFieldName : reservedUserFieldNames) {
373                            _reservedUserFieldNames.put(
374                                    reservedUserFieldName, reservedUserFieldName);
375                    }
376            }
377    
378            protected void addAttributeMapping(
379                    String attributeName, Object attributeValue, Attributes attributes) {
380    
381                    if (Validator.isNotNull(attributeName) && (attributeValue != null)) {
382                            attributes.put(attributeName, attributeValue);
383                    }
384            }
385    
386            protected void addAttributeMapping(
387                    String attributeName, String attributeValue, Attributes attributes) {
388    
389                    if (Validator.isNotNull(attributeName) &&
390                            Validator.isNotNull(attributeValue)) {
391    
392                            attributes.put(attributeName, attributeValue);
393                    }
394            }
395    
396            protected void addModificationItem(
397                    BasicAttribute basicAttribute, Modifications modifications) {
398    
399                    if (basicAttribute != null) {
400                            modifications.addItem(basicAttribute);
401                    }
402            }
403    
404            protected void addModificationItem(
405                    String attributeName, String attributeValue,
406                    Modifications modifications) {
407    
408                    if (Validator.isNotNull(attributeName)) {
409                            modifications.addItem(attributeName, attributeValue);
410                    }
411            }
412    
413            protected String getEncryptedPasswordForLDAP(User user) {
414                    String password = user.getPasswordUnencrypted();
415    
416                    if (Validator.isNull(password)) {
417                            return password;
418                    }
419    
420                    String algorithm = PrefsPropsUtil.getString(
421                            user.getCompanyId(),
422                            PropsKeys.LDAP_AUTH_PASSWORD_ENCRYPTION_ALGORITHM);
423    
424                    if (Validator.isNull(algorithm)) {
425                            return password;
426                    }
427    
428                    try {
429                            StringBundler sb = new StringBundler(4);
430    
431                            if (!algorithm.equals(PasswordEncryptorUtil.TYPE_NONE)) {
432                                    sb.append(StringPool.OPEN_CURLY_BRACE);
433                                    sb.append(algorithm);
434                                    sb.append(StringPool.CLOSE_CURLY_BRACE);
435                            }
436    
437                            sb.append(PasswordEncryptorUtil.encrypt(algorithm, password, null));
438    
439                            return sb.toString();
440                    }
441                    catch (PwdEncryptorException pee) {
442                            throw new SystemException(pee);
443                    }
444            }
445    
446            protected Modifications getModifications(
447                    Object object, Properties objectMappings,
448                    Map<String, String> reservedFieldNames) {
449    
450                    Modifications modifications = Modifications.getInstance();
451    
452                    for (Map.Entry<Object, Object> entry : objectMappings.entrySet()) {
453                            String fieldName = (String)entry.getKey();
454    
455                            if (reservedFieldNames.containsKey(fieldName)) {
456                                    continue;
457                            }
458    
459                            String ldapAttributeName = (String)entry.getValue();
460    
461                            try {
462                                    Object attributeValue = PropertyUtils.getProperty(
463                                            object, fieldName);
464    
465                                    if (attributeValue != null) {
466                                            addModificationItem(
467                                                    ldapAttributeName, attributeValue.toString(),
468                                                    modifications);
469                                    }
470                            }
471                            catch (Exception e) {
472                                    if (_log.isWarnEnabled()) {
473                                            _log.warn(
474                                                    "Unable to map field " + fieldName + " to class " +
475                                                            object.getClass(),
476                                                    e);
477                                    }
478                            }
479                    }
480    
481                    return modifications;
482            }
483    
484            protected byte[] getUserPortrait(User user) {
485                    byte[] bytes = null;
486    
487                    if (user.getPortraitId() == 0) {
488                            return bytes;
489                    }
490    
491                    Image image = null;
492    
493                    try {
494                            image = ImageLocalServiceUtil.getImage(user.getPortraitId());
495    
496                            if (image != null) {
497                                    bytes = image.getTextObj();
498                            }
499                    }
500                    catch (Exception e) {
501                            if (_log.isWarnEnabled()) {
502                                    _log.warn(
503                                            "Unable to get the portrait for user " + user.getUserId(),
504                                            e);
505                            }
506                    }
507    
508                    return bytes;
509            }
510    
511            protected void populateCustomAttributeModifications(
512                    Object object, ExpandoBridge expandoBridge,
513                    Map<String, Serializable> expandoAttributes, Properties expandoMappings,
514                    Modifications modifications) {
515    
516                    if ((expandoAttributes == null) || expandoAttributes.isEmpty()) {
517                            return;
518                    }
519    
520                    for (Map.Entry<Object, Object> entry : expandoMappings.entrySet()) {
521                            String fieldName = (String)entry.getKey();
522                            String ldapAttributeName = (String)entry.getValue();
523    
524                            Serializable fieldValue = expandoAttributes.get(fieldName);
525    
526                            if (fieldValue == null) {
527                                    continue;
528                            }
529    
530                            try {
531                                    int type = expandoBridge.getAttributeType(fieldName);
532    
533                                    String value = ExpandoConverterUtil.getStringFromAttribute(
534                                            type, fieldValue);
535    
536                                    addModificationItem(ldapAttributeName, value, modifications);
537                            }
538                            catch (Exception e) {
539                                    if (_log.isWarnEnabled()) {
540                                            _log.warn(
541                                                    "Unable to map field " + fieldName + " to class " +
542                                                            object.getClass(),
543                                                    e);
544                                    }
545                            }
546                    }
547            }
548    
549            private static final String _DEFAULT_DN = "cn";
550    
551            private static final String _OBJECT_CLASS = "objectclass";
552    
553            private static Log _log = LogFactoryUtil.getLog(
554                    DefaultPortalToLDAPConverter.class);
555    
556            private String _groupDNFieldName = GroupConverterKeys.GROUP_NAME;
557            private Map<String, String> _reservedContactFieldNames =
558                    new HashMap<String, String>();
559            private Map<String, String> _reservedUserFieldNames =
560                    new HashMap<String, String>();
561            private String _userDNFieldName = UserConverterKeys.SCREEN_NAME;
562    
563    }