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