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 DefaultPortalToLDAPConverter implements PortalToLDAPConverter {
057    
058            public DefaultPortalToLDAPConverter() {
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.UUID), user.getUuid(),
193                            attributes);
194                    addAttributeMapping(
195                            userMappings.getProperty(UserConverterKeys.SCREEN_NAME),
196                            user.getScreenName(), attributes);
197                    addAttributeMapping(
198                            userMappings.getProperty(UserConverterKeys.PASSWORD),
199                            user.getPasswordUnencrypted(), attributes);
200                    addAttributeMapping(
201                            userMappings.getProperty(UserConverterKeys.EMAIL_ADDRESS),
202                            user.getEmailAddress(), attributes);
203                    addAttributeMapping(
204                            userMappings.getProperty(UserConverterKeys.FULL_NAME),
205                            user.getFullName(), attributes);
206                    addAttributeMapping(
207                            userMappings.getProperty(UserConverterKeys.FIRST_NAME),
208                            user.getFirstName(), attributes);
209                    addAttributeMapping(
210                            userMappings.getProperty(UserConverterKeys.MIDDLE_NAME),
211                            user.getMiddleName(), attributes);
212                    addAttributeMapping(
213                            userMappings.getProperty(UserConverterKeys.LAST_NAME),
214                            user.getLastName(), attributes);
215                    addAttributeMapping(
216                            userMappings.getProperty(UserConverterKeys.JOB_TITLE),
217                            user.getJobTitle(), attributes);
218                    addAttributeMapping(
219                            userMappings.getProperty(UserConverterKeys.PORTRAIT),
220                            getUserPortrait(user), attributes);
221    
222                    return attributes;
223            }
224    
225            public Modifications getLDAPUserGroupModifications(
226                            long ldapServerId, List<UserGroup> userGroups, User user,
227                            Properties userMappings)
228                    throws Exception {
229    
230                    Modifications modifications = Modifications.getInstance();
231    
232                    Properties groupMappings = LDAPSettingsUtil.getGroupMappings(
233                            ldapServerId, user.getCompanyId());
234    
235                    String userDN = getUserDNName(ldapServerId, user, userMappings);
236    
237                    for (UserGroup userGroup : userGroups) {
238                            String groupDN = getGroupDNName(
239                                    ldapServerId, userGroup, groupMappings);
240    
241                            if (PortalLDAPUtil.isUserGroupMember(
242                                            ldapServerId, user.getCompanyId(), groupDN, userDN)) {
243    
244                                    continue;
245                            }
246    
247                            modifications.addItem(
248                                    DirContext.ADD_ATTRIBUTE,
249                                    userMappings.getProperty(UserConverterKeys.GROUP), groupDN);
250                    }
251    
252                    return modifications;
253            }
254    
255            public Modifications getLDAPUserModifications(
256                            User user, Map<String, Serializable> userExpandoAttributes,
257                            Properties userMappings, Properties userExpandoMappings)
258                    throws Exception {
259    
260                    Modifications modifications = getModifications(
261                            user, userMappings, _reservedUserFieldNames);
262    
263                    if (user.isPasswordModified() &&
264                            Validator.isNotNull(user.getPasswordUnencrypted())) {
265    
266                            String newPassword = user.getPasswordUnencrypted();
267    
268                            String passwordKey = userMappings.getProperty(
269                                    UserConverterKeys.PASSWORD);
270    
271                            if (passwordKey.equals("unicodePwd")) {
272                                    String newQuotedPassword = StringPool.QUOTE.concat(
273                                            newPassword).concat(StringPool.QUOTE);
274    
275                                    byte[] newUnicodePassword = newQuotedPassword.getBytes(
276                                            "UTF-16LE");
277    
278                                    addModificationItem(
279                                            new BasicAttribute(passwordKey, newUnicodePassword),
280                                            modifications);
281                            }
282                            else {
283                                    addModificationItem(passwordKey, newPassword, modifications);
284                            }
285                    }
286    
287                    String portraitKey = userMappings.getProperty(
288                            UserConverterKeys.PORTRAIT);
289    
290                    if (Validator.isNotNull(portraitKey)) {
291                            addModificationItem(
292                                    new BasicAttribute(portraitKey, getUserPortrait(user)),
293                                    modifications);
294                    }
295    
296                    populateCustomAttributeModifications(
297                            user, user.getExpandoBridge(), userExpandoAttributes,
298                            userExpandoMappings, modifications);
299    
300                    return modifications;
301            }
302    
303            public String getUserDNName(
304                            long ldapServerId, User user, Properties userMappings)
305                    throws Exception {
306    
307                    Binding userBinding = PortalLDAPUtil.getUser(
308                            ldapServerId, user.getCompanyId(), user.getScreenName(),
309                            user.getEmailAddress());
310    
311                    if (userBinding != null) {
312                            return PortalLDAPUtil.getNameInNamespace(
313                                    ldapServerId, user.getCompanyId(), userBinding);
314                    }
315    
316                    StringBundler sb = new StringBundler(5);
317    
318                    sb.append(
319                            GetterUtil.getString(
320                                    userMappings.getProperty(_userDNFieldName), _DEFAULT_DN));
321                    sb.append(StringPool.EQUAL);
322                    sb.append(PropertyUtils.getProperty(user, _userDNFieldName));
323                    sb.append(StringPool.COMMA);
324                    sb.append(PortalLDAPUtil.getUsersDN(ldapServerId, user.getCompanyId()));
325    
326                    return sb.toString();
327            }
328    
329            public void setContactReservedFieldNames(
330                    List<String> reservedContactFieldNames) {
331    
332                    for (String reservedContactFieldName : reservedContactFieldNames) {
333                            _reservedContactFieldNames.put(
334                                    reservedContactFieldName, reservedContactFieldName);
335                    }
336            }
337    
338            public void setUserDNFieldName(String userDNFieldName) {
339                    _userDNFieldName = userDNFieldName;
340            }
341    
342            public void setUserReservedFieldNames(List<String> reservedUserFieldNames) {
343                    for (String reservedUserFieldName : reservedUserFieldNames) {
344                            _reservedUserFieldNames.put(
345                                    reservedUserFieldName, reservedUserFieldName);
346                    }
347            }
348    
349            protected void addAttributeMapping(
350                    String attributeName, Object attributeValue, Attributes attributes) {
351    
352                    if (Validator.isNotNull(attributeName) && (attributeValue != null)) {
353                            attributes.put(attributeName, attributeValue);
354                    }
355            }
356    
357            protected void addAttributeMapping(
358                    String attributeName, String attributeValue, Attributes attributes) {
359    
360                    if (Validator.isNotNull(attributeName) &&
361                            Validator.isNotNull(attributeValue)) {
362    
363                            attributes.put(attributeName, attributeValue);
364                    }
365            }
366    
367            protected void addModificationItem(
368                    BasicAttribute basicAttribute, Modifications modifications) {
369    
370                    if (Validator.isNotNull(basicAttribute)) {
371                            modifications.addItem(basicAttribute);
372                    }
373            }
374    
375            protected void addModificationItem(
376                    String attributeName, String attributeValue,
377                    Modifications modifications) {
378    
379                    if (Validator.isNotNull(attributeName) &&
380                            Validator.isNotNull(attributeValue)) {
381    
382                            modifications.addItem(attributeName, attributeValue);
383                    }
384            }
385    
386            protected Modifications getModifications(
387                    Object object, Properties objectMappings,
388                    Map<String, String> reservedFieldNames) {
389    
390                    Modifications modifications = Modifications.getInstance();
391    
392                    for (Map.Entry<Object, Object> entry : objectMappings.entrySet()) {
393                            String fieldName = (String)entry.getKey();
394    
395                            if (reservedFieldNames.containsKey(fieldName)) {
396                                    continue;
397                            }
398    
399                            String ldapAttributeName = (String)entry.getValue();
400    
401                            try {
402                                    Object attributeValue = PropertyUtils.getProperty(
403                                            object, fieldName);
404    
405                                    if (attributeValue != null) {
406                                            addModificationItem(
407                                                    ldapAttributeName, attributeValue.toString(),
408                                                    modifications);
409                                    }
410                            }
411                            catch (Exception e) {
412                                    if (_log.isWarnEnabled()) {
413                                            _log.warn(
414                                                    "Unable to map field " + fieldName + " to class " +
415                                                            object.getClass(),
416                                                    e);
417                                    }
418                            }
419                    }
420    
421                    return modifications;
422            }
423    
424            protected byte[] getUserPortrait(User user) {
425                    byte[] bytes = null;
426    
427                    if (user.getPortraitId() == 0) {
428                            return bytes;
429                    }
430    
431                    Image image = null;
432    
433                    try {
434                            image = ImageLocalServiceUtil.getImage(user.getPortraitId());
435    
436                            if (image != null) {
437                                    bytes = image.getTextObj();
438                            }
439                    }
440                    catch (Exception e) {
441                            if (_log.isWarnEnabled()) {
442                                    _log.warn(
443                                            "Unable to get the portrait for user " + user.getUserId(),
444                                            e);
445                            }
446                    }
447    
448                    return bytes;
449            }
450    
451            protected void populateCustomAttributeModifications(
452                    Object object, ExpandoBridge expandoBridge,
453                    Map<String, Serializable> expandoAttributes, Properties expandoMappings,
454                    Modifications modifications) {
455    
456                    if ((expandoAttributes == null) || expandoAttributes.isEmpty()) {
457                            return;
458                    }
459    
460                    for (Map.Entry<Object, Object> entry : expandoMappings.entrySet()) {
461                            String fieldName = (String)entry.getKey();
462                            String ldapAttributeName = (String)entry.getValue();
463    
464                            Serializable fieldValue = expandoAttributes.get(fieldName);
465    
466                            if (fieldValue == null) {
467                                    continue;
468                            }
469    
470                            try {
471                                    int type = expandoBridge.getAttributeType(fieldName);
472    
473                                    String value = ExpandoConverterUtil.getStringFromAttribute(
474                                            type, fieldValue);
475    
476                                    addModificationItem(ldapAttributeName, value, modifications);
477                            }
478                            catch (Exception e) {
479                                    if (_log.isWarnEnabled()) {
480                                            _log.warn(
481                                                    "Unable to map field " + fieldName + " to class " +
482                                                            object.getClass(),
483                                                    e);
484                                    }
485                            }
486                    }
487            }
488    
489            private static final String _DEFAULT_DN = "cn";
490    
491            private static final String _OBJECT_CLASS = "objectclass";
492    
493            private static Log _log = LogFactoryUtil.getLog(
494                    DefaultPortalToLDAPConverter.class);
495    
496            private String _groupDNFieldName = GroupConverterKeys.GROUP_NAME;
497            private Map<String, String> _reservedContactFieldNames =
498                    new HashMap<String, String>();
499            private Map<String, String> _reservedUserFieldNames =
500                    new HashMap<String, String>();
501            private String _userDNFieldName = UserConverterKeys.SCREEN_NAME;
502    
503    }