001    /**
002     * Copyright (c) 2000-2013 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.kernel.ldap.LDAPUtil;
018    import com.liferay.portal.kernel.log.Log;
019    import com.liferay.portal.kernel.log.LogFactoryUtil;
020    import com.liferay.portal.kernel.security.pacl.DoPrivileged;
021    import com.liferay.portal.kernel.util.PropsKeys;
022    import com.liferay.portal.kernel.util.Validator;
023    import com.liferay.portal.kernel.workflow.WorkflowConstants;
024    import com.liferay.portal.model.Contact;
025    import com.liferay.portal.model.User;
026    import com.liferay.portal.model.UserGroup;
027    import com.liferay.portal.security.auth.AuthSettingsUtil;
028    import com.liferay.portal.service.UserGroupLocalServiceUtil;
029    import com.liferay.portal.service.UserLocalServiceUtil;
030    import com.liferay.portal.util.PrefsPropsUtil;
031    
032    import java.io.Serializable;
033    
034    import java.util.Date;
035    import java.util.List;
036    import java.util.Map;
037    import java.util.Properties;
038    
039    import javax.naming.Binding;
040    import javax.naming.CompositeName;
041    import javax.naming.Name;
042    import javax.naming.NameNotFoundException;
043    import javax.naming.directory.Attribute;
044    import javax.naming.directory.Attributes;
045    import javax.naming.directory.ModificationItem;
046    import javax.naming.directory.SchemaViolationException;
047    import javax.naming.ldap.LdapContext;
048    
049    /**
050     * @author Michael C. Han
051     * @author Brian Wing Shun Chan
052     * @author Marcellus Tavares
053     * @author Wesley Gong
054     * @author Vilmos Papp
055     */
056    @DoPrivileged
057    public class PortalLDAPExporterImpl implements PortalLDAPExporter {
058    
059            @Override
060            public void exportToLDAP(
061                            Contact contact, Map<String, Serializable> contactExpandoAttributes)
062                    throws Exception {
063    
064                    long companyId = contact.getCompanyId();
065    
066                    if (!AuthSettingsUtil.isLDAPAuthEnabled(companyId) ||
067                            !LDAPSettingsUtil.isExportEnabled(companyId)) {
068    
069                            return;
070                    }
071    
072                    User user = UserLocalServiceUtil.getUserByContactId(
073                            contact.getContactId());
074    
075                    if (user.isDefaultUser() ||
076                            (user.getStatus() != WorkflowConstants.STATUS_APPROVED)) {
077    
078                            return;
079                    }
080    
081                    long ldapServerId = PortalLDAPUtil.getLdapServerId(
082                            companyId, user.getScreenName(), user.getEmailAddress());
083    
084                    LdapContext ldapContext = PortalLDAPUtil.getContext(
085                            ldapServerId, companyId);
086    
087                    try {
088                            if (ldapContext == null) {
089                                    return;
090                            }
091    
092                            Properties contactMappings = LDAPSettingsUtil.getContactMappings(
093                                    ldapServerId, companyId);
094                            Properties contactExpandoMappings =
095                                    LDAPSettingsUtil.getContactExpandoMappings(
096                                            ldapServerId, companyId);
097    
098                            Binding binding = PortalLDAPUtil.getUser(
099                                    ldapServerId, contact.getCompanyId(), user.getScreenName(),
100                                    user.getEmailAddress());
101    
102                            if (binding == null) {
103                                    Properties userMappings = LDAPSettingsUtil.getUserMappings(
104                                            ldapServerId, companyId);
105    
106                                    binding = addUser(
107                                            ldapServerId, ldapContext, user, userMappings);
108                            }
109    
110                            Name name = new CompositeName();
111    
112                            name.add(
113                                    PortalLDAPUtil.getNameInNamespace(
114                                            ldapServerId, companyId, binding));
115    
116                            Modifications modifications =
117                                    _portalToLDAPConverter.getLDAPContactModifications(
118                                            contact, contactExpandoAttributes, contactMappings,
119                                            contactExpandoMappings);
120    
121                            if (modifications == null) {
122                                    return;
123                            }
124    
125                            ModificationItem[] modificationItems = modifications.getItems();
126    
127                            ldapContext.modifyAttributes(name, modificationItems);
128                    }
129                    finally {
130                            if (ldapContext != null) {
131                                    ldapContext.close();
132                            }
133                    }
134            }
135    
136            @Override
137            public void exportToLDAP(
138                            long userId, long userGroupId, LDAPOperation ldapOperation)
139                    throws Exception {
140    
141                    User user = UserLocalServiceUtil.getUser(userId);
142    
143                    long companyId = user.getCompanyId();
144    
145                    if (!AuthSettingsUtil.isLDAPAuthEnabled(companyId) ||
146                            !LDAPSettingsUtil.isExportEnabled(companyId) ||
147                            !LDAPSettingsUtil.isExportGroupEnabled(companyId)) {
148    
149                            return;
150                    }
151    
152                    long ldapServerId = PortalLDAPUtil.getLdapServerId(
153                            companyId, user.getScreenName(), user.getEmailAddress());
154    
155                    LdapContext ldapContext = PortalLDAPUtil.getContext(
156                            ldapServerId, companyId);
157    
158                    if (ldapContext == null) {
159                            return;
160                    }
161    
162                    UserGroup userGroup = UserGroupLocalServiceUtil.getUserGroup(
163                            userGroupId);
164    
165                    Properties groupMappings = LDAPSettingsUtil.getGroupMappings(
166                            ldapServerId, companyId);
167                    Properties userMappings = LDAPSettingsUtil.getUserMappings(
168                            ldapServerId, companyId);
169    
170                    Binding binding = PortalLDAPUtil.getGroup(
171                            ldapServerId, companyId, userGroup.getName());
172    
173                    if (binding == null) {
174                            if (ldapOperation == LDAPOperation.ADD) {
175                                    addGroup(
176                                            ldapServerId, ldapContext, userGroup, user, groupMappings,
177                                            userMappings);
178                            }
179                            else {
180                                    if (_log.isWarnEnabled()) {
181                                            _log.warn(
182                                                    "Unable to get or add LDAP bindings for user group " +
183                                                            userGroup.getName());
184                                    }
185                            }
186    
187                            return;
188                    }
189    
190                    try {
191                            Name name = new CompositeName();
192    
193                            name.add(
194                                    PortalLDAPUtil.getNameInNamespace(
195                                            ldapServerId, companyId, binding));
196    
197                            Modifications modifications =
198                                    _portalToLDAPConverter.getLDAPGroupModifications(
199                                            ldapServerId, userGroup, user, groupMappings, userMappings,
200                                            ldapOperation);
201    
202                            ModificationItem[] modificationItems = modifications.getItems();
203    
204                            ldapContext.modifyAttributes(name, modificationItems);
205                    }
206                    catch (SchemaViolationException sve) {
207                            if (_log.isInfoEnabled()) {
208                                    _log.info(
209                                            "Unable to update LDAP bindings for user group " +
210                                                    userGroup.getName(),
211                                            sve);
212                            }
213    
214                            String fullGroupDN = PortalLDAPUtil.getNameInNamespace(
215                                    ldapServerId, companyId, binding);
216    
217                            Attributes attributes = PortalLDAPUtil.getGroupAttributes(
218                                    ldapServerId, companyId, ldapContext, fullGroupDN, true);
219    
220                            Attribute groupMembers = attributes.get(
221                                    groupMappings.getProperty(GroupConverterKeys.USER));
222    
223                            if ((groupMembers != null) && (groupMembers.size() == 1)) {
224                                    ldapContext.unbind(fullGroupDN);
225                            }
226                    }
227                    finally {
228                            if (ldapContext != null) {
229                                    ldapContext.close();
230                            }
231                    }
232            }
233    
234            @Override
235            public void exportToLDAP(
236                            User user, Map<String, Serializable> userExpandoAttributes)
237                    throws Exception {
238    
239                    if (user.isDefaultUser() ||
240                            (user.getStatus() != WorkflowConstants.STATUS_APPROVED)) {
241    
242                            return;
243                    }
244    
245                    long companyId = user.getCompanyId();
246    
247                    if (!AuthSettingsUtil.isLDAPAuthEnabled(companyId) ||
248                            !LDAPSettingsUtil.isExportEnabled(companyId)) {
249    
250                            return;
251                    }
252    
253                    long ldapServerId = PortalLDAPUtil.getLdapServerId(
254                            companyId, user.getScreenName(), user.getEmailAddress());
255    
256                    LdapContext ldapContext = PortalLDAPUtil.getContext(
257                            ldapServerId, companyId);
258    
259                    try {
260                            if (ldapContext == null) {
261                                    return;
262                            }
263    
264                            Properties userMappings = LDAPSettingsUtil.getUserMappings(
265                                    ldapServerId, companyId);
266                            Properties userExpandoMappings =
267                                    LDAPSettingsUtil.getUserExpandoMappings(
268                                            ldapServerId, companyId);
269    
270                            Binding binding = PortalLDAPUtil.getUser(
271                                    ldapServerId, user.getCompanyId(), user.getScreenName(),
272                                    user.getEmailAddress(), true);
273    
274                            if (binding == null) {
275                                    binding = addUser(
276                                            ldapServerId, ldapContext, user, userMappings);
277                            }
278                            else {
279                                    Attributes attributes = PortalLDAPUtil.getUserAttributes(
280                                            ldapServerId, companyId, ldapContext,
281                                            PortalLDAPUtil.getNameInNamespace(
282                                                    ldapServerId, companyId, binding));
283    
284                                    String modifyTimestamp = LDAPUtil.getAttributeString(
285                                            attributes, "modifyTimestamp");
286    
287                                    if (Validator.isNotNull(modifyTimestamp)) {
288                                            Date modifiedDate = LDAPUtil.parseDate(modifyTimestamp);
289    
290                                            if (modifiedDate.equals(user.getModifiedDate()) &&
291                                                    !user.getPasswordModified()) {
292    
293                                                    if (_log.isDebugEnabled()) {
294                                                            _log.debug(
295                                                                    "Skipping user " + user.getEmailAddress() +
296                                                                            " because he is already synchronized");
297                                                    }
298    
299                                                    return;
300                                            }
301                                    }
302                            }
303    
304                            Name name = new CompositeName();
305    
306                            name.add(
307                                    PortalLDAPUtil.getNameInNamespace(
308                                            ldapServerId, companyId, binding));
309    
310                            Modifications modifications =
311                                    _portalToLDAPConverter.getLDAPUserModifications(
312                                            user, userExpandoAttributes, userMappings,
313                                            userExpandoMappings);
314    
315                            if (modifications == null) {
316                                    return;
317                            }
318    
319                            ModificationItem[] modificationItems = modifications.getItems();
320    
321                            ldapContext.modifyAttributes(name, modificationItems);
322    
323                            if (!LDAPSettingsUtil.isExportGroupEnabled(companyId)) {
324                                    return;
325                            }
326    
327                            List<UserGroup> userGroups =
328                                    UserGroupLocalServiceUtil.getUserUserGroups(user.getUserId());
329    
330                            for (UserGroup userGroup : userGroups) {
331                                    exportToLDAP(
332                                            user.getUserId(), userGroup.getUserGroupId(),
333                                            LDAPOperation.ADD);
334                            }
335    
336                            Modifications groupModifications =
337                                    _portalToLDAPConverter.getLDAPUserGroupModifications(
338                                            ldapServerId, userGroups, user, userMappings);
339    
340                            ModificationItem[] groupModificationItems =
341                                    groupModifications.getItems();
342    
343                            if (groupModificationItems.length > 0) {
344                                    ldapContext.modifyAttributes(name, groupModificationItems);
345                            }
346                    }
347                    catch (NameNotFoundException nnfe) {
348                            if (PrefsPropsUtil.getBoolean(
349                                            companyId, PropsKeys.LDAP_AUTH_REQUIRED)) {
350    
351                                    throw nnfe;
352                            }
353    
354                            _log.error(nnfe, nnfe);
355                    }
356                    finally {
357                            if (ldapContext != null) {
358                                    ldapContext.close();
359                            }
360                    }
361            }
362    
363            public void setPortalToLDAPConverter(
364                    PortalToLDAPConverter portalToLDAPConverter) {
365    
366                    _portalToLDAPConverter = portalToLDAPConverter;
367            }
368    
369            protected Binding addGroup(
370                            long ldapServerId, LdapContext ldapContext, UserGroup userGroup,
371                            User user, Properties groupMappings, Properties userMappings)
372                    throws Exception {
373    
374                    Name name = new CompositeName();
375    
376                    name.add(
377                            _portalToLDAPConverter.getGroupDNName(
378                                    ldapServerId, userGroup, groupMappings));
379    
380                    Attributes attributes = _portalToLDAPConverter.getLDAPGroupAttributes(
381                            ldapServerId, userGroup, user, groupMappings, userMappings);
382    
383                    ldapContext.bind(name, new PortalLDAPContext(attributes));
384    
385                    Binding binding = PortalLDAPUtil.getGroup(
386                            ldapServerId, userGroup.getCompanyId(), userGroup.getName());
387    
388                    return binding;
389            }
390    
391            protected Binding addUser(
392                            long ldapServerId, LdapContext ldapContext, User user,
393                            Properties userMappings)
394                    throws Exception {
395    
396                    Name name = new CompositeName();
397    
398                    name.add(
399                            _portalToLDAPConverter.getUserDNName(
400                                    ldapServerId, user, userMappings));
401    
402                    Attributes attributes = _portalToLDAPConverter.getLDAPUserAttributes(
403                            ldapServerId, user, userMappings);
404    
405                    ldapContext.bind(name, new PortalLDAPContext(attributes));
406    
407                    Binding binding = PortalLDAPUtil.getUser(
408                            ldapServerId, user.getCompanyId(), user.getScreenName(),
409                            user.getEmailAddress());
410    
411                    return binding;
412            }
413    
414            private static Log _log = LogFactoryUtil.getLog(
415                    PortalLDAPExporterImpl.class);
416    
417            private PortalToLDAPConverter _portalToLDAPConverter;
418    
419    }