/**
* Copyright (c) 2000-present Liferay, Inc. All rights reserved.
*
* This library is free software; you can redistribute it and/or modify it under
* the terms of the GNU Lesser General Public License as published by the Free
* Software Foundation; either version 2.1 of the License, or (at your option)
* any later version.
*
* This library is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
* details.
*/
package com.liferay.portal.security.ldap.internal.exportimport;
import com.liferay.expando.kernel.model.ExpandoBridge;
import com.liferay.expando.kernel.util.ExpandoConverterUtil;
import com.liferay.portal.kernel.bean.BeanPropertiesUtil;
import com.liferay.portal.kernel.exception.SystemException;
import com.liferay.portal.kernel.log.Log;
import com.liferay.portal.kernel.log.LogFactoryUtil;
import com.liferay.portal.kernel.model.Contact;
import com.liferay.portal.kernel.model.Image;
import com.liferay.portal.kernel.model.User;
import com.liferay.portal.kernel.model.UserGroup;
import com.liferay.portal.kernel.security.auth.PasswordModificationThreadLocal;
import com.liferay.portal.kernel.security.ldap.LDAPSettings;
import com.liferay.portal.kernel.security.pwd.PasswordEncryptor;
import com.liferay.portal.kernel.security.pwd.PasswordEncryptorUtil;
import com.liferay.portal.kernel.service.ImageLocalService;
import com.liferay.portal.kernel.util.GetterUtil;
import com.liferay.portal.kernel.util.Props;
import com.liferay.portal.kernel.util.PropsKeys;
import com.liferay.portal.kernel.util.StringBundler;
import com.liferay.portal.kernel.util.StringPool;
import com.liferay.portal.kernel.util.Validator;
import com.liferay.portal.security.exportimport.UserOperation;
import com.liferay.portal.security.ldap.GroupConverterKeys;
import com.liferay.portal.security.ldap.PortalLDAP;
import com.liferay.portal.security.ldap.UserConverterKeys;
import com.liferay.portal.security.ldap.authenticator.configuration.LDAPAuthConfiguration;
import com.liferay.portal.security.ldap.configuration.ConfigurationProvider;
import com.liferay.portal.security.ldap.configuration.LDAPServerConfiguration;
import com.liferay.portal.security.ldap.exportimport.Modifications;
import com.liferay.portal.security.ldap.exportimport.PortalToLDAPConverter;
import java.io.Serializable;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import javax.naming.Binding;
import javax.naming.directory.Attribute;
import javax.naming.directory.Attributes;
import javax.naming.directory.BasicAttribute;
import javax.naming.directory.BasicAttributes;
import javax.naming.directory.DirContext;
import org.osgi.service.component.annotations.Component;
import org.osgi.service.component.annotations.Reference;
import org.osgi.service.component.annotations.ReferencePolicyOption;
/**
* @author Michael C. Han
* @author Brian Wing Shun Chan
* @author Marcellus Tavares
* @author Wesley Gong
*/
@Component(immediate = true, service = PortalToLDAPConverter.class)
public class DefaultPortalToLDAPConverter implements PortalToLDAPConverter {
public DefaultPortalToLDAPConverter() {
_reservedUserFieldNames.put(
UserConverterKeys.GROUP, UserConverterKeys.GROUP);
_reservedUserFieldNames.put(
UserConverterKeys.PASSWORD, UserConverterKeys.PASSWORD);
_reservedUserFieldNames.put(
UserConverterKeys.PORTRAIT, UserConverterKeys.PORTRAIT);
_reservedUserFieldNames.put(
UserConverterKeys.SCREEN_NAME, UserConverterKeys.SCREEN_NAME);
}
@Override
public String getGroupDNName(
long ldapServerId, UserGroup userGroup, Properties groupMappings)
throws Exception {
Binding groupBinding = _portalLDAP.getGroup(
ldapServerId, userGroup.getCompanyId(), userGroup.getName());
if (groupBinding != null) {
return _portalLDAP.getNameInNamespace(
ldapServerId, userGroup.getCompanyId(), groupBinding);
}
StringBundler sb = new StringBundler(5);
sb.append(
GetterUtil.getString(
groupMappings.getProperty(GroupConverterKeys.GROUP_NAME),
_DEFAULT_DN));
sb.append(StringPool.EQUAL);
sb.append(userGroup.getName());
sb.append(StringPool.COMMA);
sb.append(
_portalLDAP.getGroupsDN(ldapServerId, userGroup.getCompanyId()));
return sb.toString();
}
@Override
public Modifications getLDAPContactModifications(
Contact contact, Map<String, Serializable> contactExpandoAttributes,
Properties contactMappings, Properties contactExpandoMappings)
throws Exception {
if (contactMappings.isEmpty() && contactExpandoMappings.isEmpty()) {
return null;
}
Modifications modifications = getModifications(
contact, contactMappings, _reservedContactFieldNames);
populateCustomAttributeModifications(
contact, contact.getExpandoBridge(), contactExpandoAttributes,
contactExpandoMappings, modifications);
return modifications;
}
@Override
public Attributes getLDAPGroupAttributes(
long ldapServerId, UserGroup userGroup, User user,
Properties groupMappings, Properties userMappings)
throws Exception {
Attributes attributes = new BasicAttributes(true);
Attribute objectClassAttribute = new BasicAttribute(_OBJECT_CLASS);
LDAPServerConfiguration ldapServerConfiguration =
_ldapServerConfigurationProvider.getConfiguration(
userGroup.getCompanyId(), ldapServerId);
String[] defaultObjectClassNames =
ldapServerConfiguration.groupDefaultObjectClasses();
for (String defaultObjectClassName : defaultObjectClassNames) {
objectClassAttribute.add(defaultObjectClassName);
}
attributes.put(objectClassAttribute);
addAttributeMapping(
groupMappings.getProperty(GroupConverterKeys.GROUP_NAME),
userGroup.getName(), attributes);
addAttributeMapping(
groupMappings.getProperty(GroupConverterKeys.DESCRIPTION),
userGroup.getDescription(), attributes);
addAttributeMapping(
groupMappings.getProperty(GroupConverterKeys.USER),
getUserDNName(ldapServerId, user, userMappings), attributes);
return attributes;
}
@Override
public Modifications getLDAPGroupModifications(
long ldapServerId, UserGroup userGroup, User user,
Properties groupMappings, Properties userMappings,
UserOperation userOperation)
throws Exception {
Modifications modifications = Modifications.getInstance();
String groupDN = getGroupDNName(ldapServerId, userGroup, groupMappings);
String userDN = getUserDNName(ldapServerId, user, userMappings);
if (_portalLDAP.isGroupMember(
ldapServerId, user.getCompanyId(), groupDN, userDN)) {
if (userOperation == UserOperation.REMOVE) {
modifications.addItem(
DirContext.REMOVE_ATTRIBUTE,
groupMappings.getProperty(GroupConverterKeys.USER), userDN);
}
}
else {
if (userOperation == UserOperation.ADD) {
modifications.addItem(
DirContext.ADD_ATTRIBUTE,
groupMappings.getProperty(GroupConverterKeys.USER), userDN);
}
}
return modifications;
}
@Override
public Attributes getLDAPUserAttributes(
long ldapServerId, User user, Properties userMappings) {
Attributes attributes = new BasicAttributes(true);
Attribute objectClassAttribute = new BasicAttribute(_OBJECT_CLASS);
LDAPServerConfiguration ldapServerConfiguration =
_ldapServerConfigurationProvider.getConfiguration(
user.getCompanyId(), ldapServerId);
String[] defaultObjectClassNames =
ldapServerConfiguration.userDefaultObjectClasses();
for (String defaultObjectClassName : defaultObjectClassNames) {
objectClassAttribute.add(defaultObjectClassName);
}
attributes.put(objectClassAttribute);
addAttributeMapping(
userMappings.getProperty(UserConverterKeys.UUID), user.getUuid(),
attributes);
addAttributeMapping(
userMappings.getProperty(UserConverterKeys.SCREEN_NAME),
user.getScreenName(), attributes);
addAttributeMapping(
userMappings.getProperty(UserConverterKeys.PASSWORD),
getEncryptedPasswordForLDAP(user, userMappings), attributes);
addAttributeMapping(
userMappings.getProperty(UserConverterKeys.EMAIL_ADDRESS),
user.getEmailAddress(), attributes);
addAttributeMapping(
userMappings.getProperty(UserConverterKeys.FULL_NAME),
user.getFullName(), attributes);
addAttributeMapping(
userMappings.getProperty(UserConverterKeys.FIRST_NAME),
user.getFirstName(), attributes);
addAttributeMapping(
userMappings.getProperty(UserConverterKeys.MIDDLE_NAME),
user.getMiddleName(), attributes);
addAttributeMapping(
userMappings.getProperty(UserConverterKeys.LAST_NAME),
user.getLastName(), attributes);
addAttributeMapping(
userMappings.getProperty(UserConverterKeys.JOB_TITLE),
user.getJobTitle(), attributes);
addAttributeMapping(
userMappings.getProperty(UserConverterKeys.PORTRAIT),
getUserPortrait(user), attributes);
addAttributeMapping(
userMappings.getProperty(UserConverterKeys.STATUS),
String.valueOf(user.getStatus()), attributes);
return attributes;
}
@Override
public Modifications getLDAPUserGroupModifications(
long ldapServerId, List<UserGroup> userGroups, User user,
Properties userMappings)
throws Exception {
Modifications modifications = Modifications.getInstance();
String groupMappingAttributeName = userMappings.getProperty(
UserConverterKeys.GROUP);
if (Validator.isNull(groupMappingAttributeName)) {
return modifications;
}
Properties groupMappings = _ldapSettings.getGroupMappings(
ldapServerId, user.getCompanyId());
String userDN = getUserDNName(ldapServerId, user, userMappings);
for (UserGroup userGroup : userGroups) {
String groupDN = getGroupDNName(
ldapServerId, userGroup, groupMappings);
if (_portalLDAP.isUserGroupMember(
ldapServerId, user.getCompanyId(), groupDN, userDN)) {
continue;
}
modifications.addItem(
DirContext.ADD_ATTRIBUTE, groupMappingAttributeName, groupDN);
}
return modifications;
}
@Override
public Modifications getLDAPUserModifications(
User user, Map<String, Serializable> userExpandoAttributes,
Properties userMappings, Properties userExpandoMappings)
throws Exception {
Modifications modifications = getModifications(
user, userMappings, _reservedUserFieldNames);
if (PasswordModificationThreadLocal.isPasswordModified() &&
Validator.isNotNull(
PasswordModificationThreadLocal.getPasswordUnencrypted())) {
String newPassword = getEncryptedPasswordForLDAP(
user, userMappings);
String passwordKey = userMappings.getProperty(
UserConverterKeys.PASSWORD);
addModificationItem(passwordKey, newPassword, modifications);
}
String portraitKey = userMappings.getProperty(
UserConverterKeys.PORTRAIT);
if (Validator.isNotNull(portraitKey)) {
addModificationItem(
new BasicAttribute(portraitKey, getUserPortrait(user)),
modifications);
}
populateCustomAttributeModifications(
user, user.getExpandoBridge(), userExpandoAttributes,
userExpandoMappings, modifications);
return modifications;
}
@Override
public String getUserDNName(
long ldapServerId, User user, Properties userMappings)
throws Exception {
Binding userBinding = _portalLDAP.getUser(
ldapServerId, user.getCompanyId(), user.getScreenName(),
user.getEmailAddress());
if (userBinding != null) {
return _portalLDAP.getNameInNamespace(
ldapServerId, user.getCompanyId(), userBinding);
}
StringBundler sb = new StringBundler(5);
sb.append(
GetterUtil.getString(
userMappings.getProperty(_userDNFieldName), _DEFAULT_DN));
sb.append(StringPool.EQUAL);
sb.append(BeanPropertiesUtil.getStringSilent(user, _userDNFieldName));
sb.append(StringPool.COMMA);
sb.append(_portalLDAP.getUsersDN(ldapServerId, user.getCompanyId()));
return sb.toString();
}
public void setContactReservedFieldNames(
List<String> reservedContactFieldNames) {
for (String reservedContactFieldName : reservedContactFieldNames) {
_reservedContactFieldNames.put(
reservedContactFieldName, reservedContactFieldName);
}
}
public void setUserDNFieldName(String userDNFieldName) {
_userDNFieldName = userDNFieldName;
}
public void setUserReservedFieldNames(List<String> reservedUserFieldNames) {
for (String reservedUserFieldName : reservedUserFieldNames) {
_reservedUserFieldNames.put(
reservedUserFieldName, reservedUserFieldName);
}
}
protected void addAttributeMapping(
String attributeName, Object attributeValue, Attributes attributes) {
if (Validator.isNotNull(attributeName) && (attributeValue != null)) {
attributes.put(attributeName, attributeValue);
}
}
protected void addAttributeMapping(
String attributeName, String attributeValue, Attributes attributes) {
if (Validator.isNotNull(attributeName) &&
Validator.isNotNull(attributeValue)) {
attributes.put(attributeName, attributeValue);
}
}
protected void addModificationItem(
BasicAttribute basicAttribute, Modifications modifications) {
if (basicAttribute != null) {
modifications.addItem(basicAttribute);
}
}
protected void addModificationItem(
String attributeName, String attributeValue,
Modifications modifications) {
if (Validator.isNotNull(attributeName)) {
modifications.addItem(attributeName, attributeValue);
}
}
protected String getEncryptedPasswordForLDAP(
User user, Properties userMappings) {
String password =
PasswordModificationThreadLocal.getPasswordUnencrypted();
if (Validator.isNull(password)) {
return password;
}
LDAPAuthConfiguration ldapAuthConfiguration =
_ldapAuthConfigurationProvider.getConfiguration(
user.getCompanyId());
String algorithm = ldapAuthConfiguration.passwordEncryptionAlgorithm();
if (Validator.isNull(algorithm)) {
return password;
}
try {
StringBundler sb = new StringBundler(4);
if (!algorithm.equals(PasswordEncryptorUtil.TYPE_NONE) &&
!hasLegacyPasswordEncryptionAlgorithm()) {
sb.append(StringPool.OPEN_CURLY_BRACE);
sb.append(algorithm);
sb.append(StringPool.CLOSE_CURLY_BRACE);
}
sb.append(_passwordEncryptor.encrypt(algorithm, password, null));
String passwordKey = userMappings.getProperty(
UserConverterKeys.PASSWORD);
if (passwordKey.equals("unicodePwd")) {
String quotedPassword = StringPool.QUOTE.concat(
sb.toString()).concat(StringPool.QUOTE);
byte[] unicodePassword = quotedPassword.getBytes("UTF-16LE");
return new String(unicodePassword);
}
return sb.toString();
}
catch (Exception e) {
throw new SystemException(e);
}
}
protected Modifications getModifications(
Object object, Properties objectMappings,
Map<String, String> reservedFieldNames) {
Modifications modifications = Modifications.getInstance();
for (Map.Entry<Object, Object> entry : objectMappings.entrySet()) {
String fieldName = (String)entry.getKey();
if (reservedFieldNames.containsKey(fieldName)) {
continue;
}
String ldapAttributeName = (String)entry.getValue();
try {
Object attributeValue = BeanPropertiesUtil.getObjectSilent(
object, fieldName);
if (attributeValue != null) {
addModificationItem(
ldapAttributeName, attributeValue.toString(),
modifications);
}
}
catch (Exception e) {
if (_log.isWarnEnabled()) {
_log.warn(
"Unable to map field " + fieldName + " to class " +
object.getClass(),
e);
}
}
}
return modifications;
}
protected byte[] getUserPortrait(User user) {
byte[] bytes = null;
if (user.getPortraitId() == 0) {
return bytes;
}
Image image = null;
try {
image = _imageLocalService.getImage(user.getPortraitId());
if (image != null) {
bytes = image.getTextObj();
}
}
catch (Exception e) {
if (_log.isWarnEnabled()) {
_log.warn(
"Unable to get the portrait for user " + user.getUserId(),
e);
}
}
return bytes;
}
protected boolean hasLegacyPasswordEncryptionAlgorithm() {
if (Validator.isNotNull(
GetterUtil.getString(
_props.get(
PropsKeys.PASSWORDS_ENCRYPTION_ALGORITHM_LEGACY)))) {
return true;
}
return false;
}
protected void populateCustomAttributeModifications(
Object object, ExpandoBridge expandoBridge,
Map<String, Serializable> expandoAttributes, Properties expandoMappings,
Modifications modifications) {
if ((expandoAttributes == null) || expandoAttributes.isEmpty()) {
return;
}
for (Map.Entry<Object, Object> entry : expandoMappings.entrySet()) {
String fieldName = (String)entry.getKey();
String ldapAttributeName = (String)entry.getValue();
Serializable fieldValue = expandoAttributes.get(fieldName);
if (fieldValue == null) {
continue;
}
try {
int type = expandoBridge.getAttributeType(fieldName);
String value = ExpandoConverterUtil.getStringFromAttribute(
type, fieldValue);
addModificationItem(ldapAttributeName, value, modifications);
}
catch (Exception e) {
if (_log.isWarnEnabled()) {
_log.warn(
"Unable to map field " + fieldName + " to class " +
object.getClass(),
e);
}
}
}
}
@Reference(unbind = "-")
protected void setImageLocalService(ImageLocalService imageLocalService) {
_imageLocalService = imageLocalService;
}
@Reference(
target = "(factoryPid=com.liferay.portal.security.ldap.authenticator.configuration.LDAPAuthConfiguration)",
unbind = "-"
)
protected void setLDAPAuthConfigurationProvider(
ConfigurationProvider<LDAPAuthConfiguration>
ldapAuthConfigurationProvider) {
_ldapAuthConfigurationProvider = ldapAuthConfigurationProvider;
}
@Reference(
target = "(factoryPid=com.liferay.portal.security.ldap.configuration.LDAPServerConfiguration)",
unbind = "-"
)
protected void setLDAPServerConfigurationProvider(
ConfigurationProvider<LDAPServerConfiguration>
ldapServerConfigurationProvider) {
_ldapServerConfigurationProvider = ldapServerConfigurationProvider;
}
@Reference(unbind = "-")
protected void setLdapSettings(LDAPSettings ldapSettings) {
_ldapSettings = ldapSettings;
}
@Reference(unbind = "-")
protected void setPasswordEncryptor(PasswordEncryptor passwordEncryptor) {
_passwordEncryptor = passwordEncryptor;
}
@Reference(policyOption = ReferencePolicyOption.GREEDY, unbind = "-")
protected void setPortalLDAP(PortalLDAP portalLDAP) {
_portalLDAP = portalLDAP;
}
private static final String _DEFAULT_DN = "cn";
private static final String _OBJECT_CLASS = "objectclass";
private static final Log _log = LogFactoryUtil.getLog(
DefaultPortalToLDAPConverter.class);
private ImageLocalService _imageLocalService;
private ConfigurationProvider<LDAPAuthConfiguration>
_ldapAuthConfigurationProvider;
private ConfigurationProvider<LDAPServerConfiguration>
_ldapServerConfigurationProvider;
private LDAPSettings _ldapSettings;
private PasswordEncryptor _passwordEncryptor;
private PortalLDAP _portalLDAP;
@Reference
private Props _props;
private final Map<String, String> _reservedContactFieldNames =
new HashMap<>();
private final Map<String, String> _reservedUserFieldNames = new HashMap<>();
private String _userDNFieldName = UserConverterKeys.SCREEN_NAME;
}