/** * 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.portal.kernel.log.Log; import com.liferay.portal.kernel.log.LogFactoryUtil; import com.liferay.portal.kernel.model.Contact; import com.liferay.portal.kernel.model.User; import com.liferay.portal.kernel.model.UserGroup; import com.liferay.portal.kernel.security.ldap.LDAPSettings; import com.liferay.portal.kernel.service.UserGroupLocalService; import com.liferay.portal.kernel.service.UserLocalService; import com.liferay.portal.kernel.util.Validator; import com.liferay.portal.kernel.workflow.WorkflowConstants; import com.liferay.portal.security.exportimport.UserExporter; 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.authenticator.configuration.LDAPAuthConfiguration; import com.liferay.portal.security.ldap.configuration.ConfigurationProvider; import com.liferay.portal.security.ldap.exportimport.Modifications; import com.liferay.portal.security.ldap.exportimport.PortalToLDAPConverter; import com.liferay.portal.security.ldap.internal.PortalLDAPContext; import com.liferay.portal.security.ldap.util.LDAPUtil; import java.io.Serializable; import java.util.Date; import java.util.List; import java.util.Map; import java.util.Properties; import javax.naming.Binding; import javax.naming.CompositeName; import javax.naming.Name; import javax.naming.NameNotFoundException; import javax.naming.directory.Attribute; import javax.naming.directory.Attributes; import javax.naming.directory.ModificationItem; import javax.naming.directory.SchemaViolationException; import javax.naming.ldap.LdapContext; import org.apache.commons.lang.time.StopWatch; 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 * @author Vilmos Papp */ @Component(immediate = true, service = UserExporter.class) public class LDAPUserExporterImpl implements UserExporter { @Override public void exportUser( Contact contact, Map<String, Serializable> contactExpandoAttributes) throws Exception { long companyId = contact.getCompanyId(); StopWatch stopWatch = new StopWatch(); if (_log.isDebugEnabled()) { stopWatch.start(); _log.debug("Exporting contact " + contact); } if (!_ldapSettings.isExportEnabled(companyId)) { return; } User user = _userLocalService.getUserByContactId( contact.getContactId()); if (user.isDefaultUser() || (user.getStatus() != WorkflowConstants.STATUS_APPROVED)) { return; } long ldapServerId = _portalLDAP.getLdapServerId( companyId, user.getScreenName(), user.getEmailAddress()); LdapContext ldapContext = _portalLDAP.getContext( ldapServerId, companyId); try { if (ldapContext == null) { return; } Properties contactMappings = _ldapSettings.getContactMappings( ldapServerId, companyId); Properties contactExpandoMappings = _ldapSettings.getContactExpandoMappings( ldapServerId, companyId); Binding binding = _portalLDAP.getUser( ldapServerId, contact.getCompanyId(), user.getScreenName(), user.getEmailAddress()); if (binding == null) { Properties userMappings = _ldapSettings.getUserMappings( ldapServerId, companyId); binding = addUser( ldapServerId, ldapContext, user, userMappings); } Name name = new CompositeName(); name.add( _portalLDAP.getNameInNamespace( ldapServerId, companyId, binding)); Modifications modifications = _portalToLDAPConverter.getLDAPContactModifications( contact, contactExpandoAttributes, contactMappings, contactExpandoMappings); if (modifications == null) { return; } ModificationItem[] modificationItems = modifications.getItems(); ldapContext.modifyAttributes(name, modificationItems); } finally { if (ldapContext != null) { ldapContext.close(); } if (_log.isDebugEnabled()) { _log.debug( "Finished exporting contact " + contact + " in " + stopWatch.getTime() + "ms"); } } } @Override public void exportUser( long userId, long userGroupId, UserOperation userOperation) throws Exception { User user = _userLocalService.getUser(userId); long companyId = user.getCompanyId(); StopWatch stopWatch = new StopWatch(); if (_log.isDebugEnabled()) { stopWatch.start(); _log.debug( "Exporting user " + user + " in user group " + userGroupId); } if (!_ldapSettings.isExportEnabled(companyId) || !_ldapSettings.isExportGroupEnabled(companyId)) { return; } long ldapServerId = _portalLDAP.getLdapServerId( companyId, user.getScreenName(), user.getEmailAddress()); LdapContext ldapContext = _portalLDAP.getContext( ldapServerId, companyId); if (ldapContext == null) { return; } UserGroup userGroup = _userGroupLocalService.getUserGroup(userGroupId); Properties groupMappings = _ldapSettings.getGroupMappings( ldapServerId, companyId); Properties userMappings = _ldapSettings.getUserMappings( ldapServerId, companyId); Binding binding = _portalLDAP.getGroup( ldapServerId, companyId, userGroup.getName()); if (binding == null) { if (userOperation == UserOperation.ADD) { addGroup( ldapServerId, ldapContext, userGroup, user, groupMappings, userMappings); } else { if (_log.isWarnEnabled()) { _log.warn( "Unable to get or add LDAP bindings for user group " + userGroup.getName()); } } return; } try { Name name = new CompositeName(); name.add( _portalLDAP.getNameInNamespace( ldapServerId, companyId, binding)); Modifications modifications = _portalToLDAPConverter.getLDAPGroupModifications( ldapServerId, userGroup, user, groupMappings, userMappings, userOperation); ModificationItem[] modificationItems = modifications.getItems(); ldapContext.modifyAttributes(name, modificationItems); } catch (SchemaViolationException sve) { if (_log.isInfoEnabled()) { _log.info( "Unable to update LDAP bindings for user group " + userGroup.getName(), sve); } String fullGroupDN = _portalLDAP.getNameInNamespace( ldapServerId, companyId, binding); Attributes attributes = _portalLDAP.getGroupAttributes( ldapServerId, companyId, ldapContext, fullGroupDN, true); Attribute groupMembers = attributes.get( groupMappings.getProperty(GroupConverterKeys.USER)); if ((groupMembers != null) && (groupMembers.size() == 1)) { ldapContext.unbind(fullGroupDN); } } finally { if (ldapContext != null) { ldapContext.close(); } if (_log.isDebugEnabled()) { _log.debug( "Finished exporting user " + user + " in user group " + userGroupId + " in " + stopWatch.getTime() + "ms"); } } } @Override public void exportUser( User user, Map<String, Serializable> userExpandoAttributes) throws Exception { if (user.isDefaultUser() || (user.getStatus() != WorkflowConstants.STATUS_APPROVED)) { return; } long companyId = user.getCompanyId(); if (!_ldapSettings.isExportEnabled(companyId)) { return; } long ldapServerId = _portalLDAP.getLdapServerId( companyId, user.getScreenName(), user.getEmailAddress()); LdapContext ldapContext = _portalLDAP.getContext( ldapServerId, companyId); try { if (ldapContext == null) { return; } Properties userMappings = _ldapSettings.getUserMappings( ldapServerId, companyId); Properties userExpandoMappings = _ldapSettings.getUserExpandoMappings(ldapServerId, companyId); Binding binding = _portalLDAP.getUser( ldapServerId, user.getCompanyId(), user.getScreenName(), user.getEmailAddress(), true); if (binding == null) { binding = addUser( ldapServerId, ldapContext, user, userMappings); } else { Attributes attributes = _portalLDAP.getUserAttributes( ldapServerId, companyId, ldapContext, _portalLDAP.getNameInNamespace( ldapServerId, companyId, binding)); String modifyTimestamp = LDAPUtil.getAttributeString( attributes, "modifyTimestamp"); if (Validator.isNotNull(modifyTimestamp)) { Date modifiedDate = LDAPUtil.parseDate(modifyTimestamp); if (modifiedDate.equals(user.getModifiedDate())) { if (_log.isDebugEnabled()) { _log.debug( "Skipping user " + user.getEmailAddress() + " because he is already synchronized"); } return; } } } Name name = new CompositeName(); name.add( _portalLDAP.getNameInNamespace( ldapServerId, companyId, binding)); Modifications modifications = _portalToLDAPConverter.getLDAPUserModifications( user, userExpandoAttributes, userMappings, userExpandoMappings); if (modifications == null) { return; } ModificationItem[] modificationItems = modifications.getItems(); ldapContext.modifyAttributes(name, modificationItems); if (!_ldapSettings.isExportGroupEnabled(companyId)) { return; } List<UserGroup> userGroups = _userGroupLocalService.getUserUserGroups(user.getUserId()); for (UserGroup userGroup : userGroups) { exportUser( user.getUserId(), userGroup.getUserGroupId(), UserOperation.ADD); } Modifications groupModifications = _portalToLDAPConverter.getLDAPUserGroupModifications( ldapServerId, userGroups, user, userMappings); ModificationItem[] groupModificationItems = groupModifications.getItems(); if (groupModificationItems.length > 0) { ldapContext.modifyAttributes(name, groupModificationItems); } } catch (NameNotFoundException nnfe) { LDAPAuthConfiguration ldapAuthConfiguration = _ldapAuthConfigurationProvider.getConfiguration(companyId); if (ldapAuthConfiguration.required()) { throw nnfe; } _log.error(nnfe, nnfe); } finally { if (ldapContext != null) { ldapContext.close(); } } } @Reference(policyOption = ReferencePolicyOption.GREEDY, unbind = "-") public void setPortalToLDAPConverter( PortalToLDAPConverter portalToLDAPConverter) { _portalToLDAPConverter = portalToLDAPConverter; } protected Binding addGroup( long ldapServerId, LdapContext ldapContext, UserGroup userGroup, User user, Properties groupMappings, Properties userMappings) throws Exception { Name name = new CompositeName(); name.add( _portalToLDAPConverter.getGroupDNName( ldapServerId, userGroup, groupMappings)); Attributes attributes = _portalToLDAPConverter.getLDAPGroupAttributes( ldapServerId, userGroup, user, groupMappings, userMappings); ldapContext.bind(name, new PortalLDAPContext(attributes)); Binding binding = _portalLDAP.getGroup( ldapServerId, userGroup.getCompanyId(), userGroup.getName()); return binding; } protected Binding addUser( long ldapServerId, LdapContext ldapContext, User user, Properties userMappings) throws Exception { Name name = new CompositeName(); name.add( _portalToLDAPConverter.getUserDNName( ldapServerId, user, userMappings)); Attributes attributes = _portalToLDAPConverter.getLDAPUserAttributes( ldapServerId, user, userMappings); ldapContext.bind(name, new PortalLDAPContext(attributes)); Binding binding = _portalLDAP.getUser( ldapServerId, user.getCompanyId(), user.getScreenName(), user.getEmailAddress()); return binding; } @Reference( target = "(factoryPid=com.liferay.portal.security.ldap.authenticator.configuration.LDAPAuthConfiguration)", unbind = "-" ) protected void setConfigurationProvider( ConfigurationProvider<LDAPAuthConfiguration> ldapAuthConfigurationProvider) { _ldapAuthConfigurationProvider = ldapAuthConfigurationProvider; } @Reference(unbind = "-") protected void setLdapSettings(LDAPSettings ldapSettings) { _ldapSettings = ldapSettings; } @Reference(policyOption = ReferencePolicyOption.GREEDY, unbind = "-") protected void setPortalLDAP(PortalLDAP portalLDAP) { _portalLDAP = portalLDAP; } @Reference(unbind = "-") protected void setUserGroupLocalService( UserGroupLocalService userGroupLocalService) { _userGroupLocalService = userGroupLocalService; } @Reference(unbind = "-") protected void setUserLocalService(UserLocalService userLocalService) { _userLocalService = userLocalService; } private static final Log _log = LogFactoryUtil.getLog( LDAPUserExporterImpl.class); private ConfigurationProvider<LDAPAuthConfiguration> _ldapAuthConfigurationProvider; private LDAPSettings _ldapSettings; private PortalLDAP _portalLDAP; private PortalToLDAPConverter _portalToLDAPConverter; private UserGroupLocalService _userGroupLocalService; private UserLocalService _userLocalService; }