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