2 * Copyright (c) 2000-2009 Liferay, Inc. All rights reserved.
4 * Permission is hereby granted, free of charge, to any person obtaining a copy
5 * of this software and associated documentation files (the "Software"), to deal
6 * in the Software without restriction, including without limitation the rights
7 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 * copies of the Software, and to permit persons to whom the Software is
9 * furnished to do so, subject to the following conditions:
11 * The above copyright notice and this permission notice shall be included in
12 * all copies or substantial portions of the Software.
14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
23 package com.liferay.portal.security.ldap;
25 import java.text.DateFormat;
26 import java.text.SimpleDateFormat;
27 import java.util.ArrayList;
28 import java.util.List;
29 import java.util.Properties;
31 import javax.naming.Binding;
32 import javax.naming.CompositeName;
33 import javax.naming.Context;
34 import javax.naming.Name;
35 import javax.naming.NamingEnumeration;
36 import javax.naming.NamingException;
37 import javax.naming.directory.Attribute;
38 import javax.naming.directory.Attributes;
39 import javax.naming.directory.SearchControls;
40 import javax.naming.directory.SearchResult;
41 import javax.naming.ldap.InitialLdapContext;
42 import javax.naming.ldap.LdapContext;
44 import com.liferay.portal.kernel.exception.SystemException;
45 import com.liferay.portal.kernel.log.Log;
46 import com.liferay.portal.kernel.log.LogFactoryUtil;
47 import com.liferay.portal.kernel.log.LogUtil;
48 import com.liferay.portal.kernel.util.ArrayUtil;
49 import com.liferay.portal.kernel.util.GetterUtil;
50 import com.liferay.portal.kernel.util.PrefsPropsUtil;
51 import com.liferay.portal.kernel.util.PropertiesUtil;
52 import com.liferay.portal.kernel.util.PropsKeys;
53 import com.liferay.portal.kernel.util.StringPool;
54 import com.liferay.portal.kernel.util.StringUtil;
55 import com.liferay.portal.kernel.util.Validator;
56 import com.liferay.portal.util.PropsValues;
59 * <a href="PortalLDAPUtil.java.html"><b><i>View Source</i></b></a>
61 * @author Michael Young
62 * @author Brian Wing Shun Chan
65 * @author Herv� M�nage
68 public class PortalLDAPUtil {
70 static DateFormat dateFormat = new SimpleDateFormat("yyyyMMddHHmmss");
72 private static Log _log = LogFactoryUtil.getLog(PortalLDAPUtil.class);
75 static LdapContext ctx = null;
79 public static Boolean isEmptyENTLDAPGroup(Properties groupMappings, Attributes attrs) {
80 Attribute attr = attrs.get(groupMappings.getProperty("user"));
82 if (attr.size()==0 || (attr.size()==1 && ((String) attr.get(0)).equals("uid=system_fake_user"))) {
85 } catch (NamingException e) {
92 public static boolean isAuthEnabled(long companyId) throws SystemException {
93 if (PrefsPropsUtil.getBoolean(companyId, PropsKeys.LDAP_AUTH_ENABLED,
94 PropsValues.LDAP_AUTH_ENABLED)) {
102 public static boolean isExportEnabled(long companyId)
103 throws SystemException {
105 if (PrefsPropsUtil.getBoolean(companyId, PropsKeys.LDAP_EXPORT_ENABLED,
106 PropsValues.LDAP_EXPORT_ENABLED)) {
114 public static boolean isImportOnStartup(long companyId)
115 throws SystemException {
117 if (PrefsPropsUtil.getBoolean(companyId,
118 PropsKeys.LDAP_IMPORT_ON_STARTUP)) {
126 public static boolean isNtlmEnabled(long companyId) throws SystemException {
128 if (!isAuthEnabled(companyId)) {
132 if (PrefsPropsUtil.getBoolean(companyId, PropsKeys.NTLM_AUTH_ENABLED,
133 PropsValues.NTLM_AUTH_ENABLED)) {
141 public static boolean isPasswordPolicyEnabled(long companyId)
142 throws SystemException {
144 if (PrefsPropsUtil.getBoolean(companyId,
145 PropsKeys.LDAP_PASSWORD_POLICY_ENABLED,
146 PropsValues.LDAP_PASSWORD_POLICY_ENABLED)) {
154 public static boolean isSiteMinderEnabled(long companyId)
155 throws SystemException {
157 if (!isAuthEnabled(companyId)) {
161 if (PrefsPropsUtil.getBoolean(companyId,
162 PropsKeys.SITEMINDER_AUTH_ENABLED,
163 PropsValues.SITEMINDER_AUTH_ENABLED)) {
171 private static Attributes _getAttributes(String fullDistinguishedName, String[] attributeIds, long companyId)
174 Attributes attrs = null;
175 String[] auditAttributeIds = { "creatorsName", "createTimestamp", "modifiersName", "modifyTimestamp" };
177 if (attributeIds == null) {
179 // Get complete listing of LDAP attributes (slow)
180 attrs = doContextAttributes(companyId, fullDistinguishedName);
181 NamingEnumeration<? extends Attribute> enu = doContextAttributes(companyId, fullDistinguishedName, auditAttributeIds).getAll();
182 while (enu.hasMoreElements()) {
183 attrs.put(enu.nextElement());
188 // Get specified LDAP attributes
189 int attributeCount = attributeIds.length + auditAttributeIds.length;
190 String[] allAttributeIds = new String[attributeCount];
191 System.arraycopy(attributeIds, 0, allAttributeIds, 0, attributeIds.length);
192 System.arraycopy(auditAttributeIds, 0, allAttributeIds, attributeIds.length, auditAttributeIds.length);
193 attrs = doContextAttributes(companyId, fullDistinguishedName, allAttributeIds);
199 public static String[] splitFullName(String fullName) {
200 String firstName = StringPool.BLANK;
201 String lastName = StringPool.BLANK;
202 String middleName = StringPool.BLANK;
204 if (Validator.isNotNull(fullName)) {
205 String[] name = StringUtil.split(fullName, " ");
208 lastName = name[name.length - 1];
209 middleName = StringPool.BLANK;
211 if (name.length > 2) {
212 for (int i = 1; i < name.length - 1; i++) {
213 if (Validator.isNull(name[i].trim())) {
221 middleName += name[i].trim();
226 firstName = GetterUtil.getString(firstName, lastName);
227 lastName = firstName;
230 return new String[] {firstName, middleName, lastName};
234 * Delete a user in LDAP
239 public static void delete(long companyId, String dn) throws Exception {
241 getContext(companyId).unbind(dn);
245 _log.error("Could not delete dn "+dn+" in LDAP.");
252 public static Attributes getGroupAttributes(long companyId, String fullDistinguishedName) throws Exception {
253 return getGroupAttributes(companyId, fullDistinguishedName, false);
256 public static Attributes getGroupAttributes(long companyId,
257 String fullDistinguishedName,
258 boolean includeReferenceAttributes) throws Exception {
260 Properties groupMappings = getGroupMappings(companyId);
262 List<String> mappedGroupAttributeIds = new ArrayList<String>();
264 mappedGroupAttributeIds.add(groupMappings.getProperty("groupName"));
265 mappedGroupAttributeIds.add(groupMappings.getProperty("description"));
267 if (includeReferenceAttributes) {
268 mappedGroupAttributeIds.add(groupMappings.getProperty("user"));
271 return _getAttributes(fullDistinguishedName,
272 mappedGroupAttributeIds.toArray(new String[0]), companyId);
276 public static Properties getGroupMappings(long companyId) throws Exception {
278 Properties groupMappings = PropertiesUtil.load(PrefsPropsUtil.getString(companyId, PropsKeys.LDAP_GROUP_MAPPINGS));
279 return groupMappings;
282 public static NamingEnumeration<SearchResult> getGroups(long companyId, int maxResults) throws Exception {
284 String baseDN = PrefsPropsUtil.getString(companyId, PropsKeys.LDAP_BASE_DN);
285 String groupFilter = PrefsPropsUtil.getString(companyId, PropsKeys.LDAP_IMPORT_GROUP_SEARCH_FILTER);
286 return getGroups(companyId, maxResults, baseDN, groupFilter);
289 public static NamingEnumeration<SearchResult> getGroups(long companyId, int maxResults, String baseDN, String groupFilter)
292 SearchControls cons = new SearchControls(SearchControls.SUBTREE_SCOPE, maxResults, 0, null, false, false);
293 return doContextSearch(companyId, baseDN, groupFilter, cons);
296 public static String getNameInNamespace(long companyId, Binding binding)
299 String baseDN = PrefsPropsUtil.getString(companyId, PropsKeys.LDAP_BASE_DN);
301 if (Validator.isNull(baseDN)) {
302 return binding.getName();
304 StringBuilder sb = new StringBuilder();
306 sb.append(binding.getName());
307 sb.append(StringPool.COMMA);
310 return sb.toString();
314 public static String getNameInNamespace(
315 long ldapServerId, long companyId, Binding binding)
318 String postfix = LDAPSettingsUtil.getPropertyPostfix(ldapServerId);
319 String baseDN = PrefsPropsUtil.getString(companyId, PropsKeys.LDAP_BASE_DN + postfix);
321 String name = binding.getName();
323 if (name.startsWith(StringPool.QUOTE) &&
324 name.endsWith(StringPool.QUOTE)) {
326 name = name.substring(1, name.length() - 1);
329 if (Validator.isNull(baseDN)) {
330 return name.toString();
333 return name.concat(StringPool.COMMA).concat(baseDN);
337 public static Binding getUser(long companyId, String screenName)
340 NamingEnumeration<SearchResult> enu = null;
343 String baseDN = PrefsPropsUtil.getString(companyId, PropsKeys.LDAP_BASE_DN);
345 Properties userMappings = PropertiesUtil.load(PrefsPropsUtil.getString(companyId, PropsKeys.LDAP_USER_MAPPINGS));
347 StringBuilder filter = new StringBuilder();
349 filter.append(StringPool.OPEN_PARENTHESIS);
350 filter.append(userMappings.getProperty("screenName"));
351 filter.append(StringPool.EQUAL);
352 filter.append(screenName);
353 filter.append(StringPool.CLOSE_PARENTHESIS);
355 SearchControls cons = new SearchControls(
356 SearchControls.SUBTREE_SCOPE, 1, 0, null, false, false);
358 enu = doContextSearch(companyId, baseDN, filter.toString(), cons);
360 } catch (Exception e) {
364 if (enu.hasMoreElements()) {
365 Binding binding = enu.nextElement();
375 public static Attributes getUserAttributes(long companyId, String fullDistinguishedName) throws Exception {
377 Properties userMappings = PropertiesUtil.load(PrefsPropsUtil.getString(companyId, PropsKeys.LDAP_USER_MAPPINGS));
379 String[] allAttrs = {
380 userMappings.getProperty(LDAPConstants.LDAP_ATTRIBUTE_SCREENNAME),
381 userMappings.getProperty(LDAPConstants.LDAP_ATTRIBUTE_EMAIL),
382 userMappings.getProperty(LDAPConstants.LDAP_ATTRIBUTE_FULLNAME),
383 userMappings.getProperty(LDAPConstants.LDAP_ATTRIBUTE_FIRSTNAME),
384 userMappings.getProperty(LDAPConstants.LDAP_ATTRIBUTE_MIDDLENAME),
385 userMappings.getProperty(LDAPConstants.LDAP_ATTRIBUTE_LASTNAME),
386 userMappings.getProperty(LDAPConstants.LDAP_ATTRIBUTE_JOBTITLE),
387 userMappings.getProperty(LDAPConstants.LDAP_ATTRIBUTE_GROUP),
388 userMappings.getProperty(LDAPConstants.LDAP_ATTRIBUTE_BIRTHDATE, ""),
389 LDAPConstants.LDAP_ATTRIBUTE_OBJECTCLASS,
390 LDAPConstants.LDAP_ATTRIBUTE_ENTVALIDACCOUNT,
391 LDAPConstants.LDAP_ATTRIBUTE_UID,
392 LDAPConstants.LDAP_ATTRIBUTE_HOMEPHONE,
393 LDAPConstants.LDAP_ATTRIBUTE_TELEPHONENUMBER,
394 LDAPConstants.LDAP_ATTRIBUTE_MAIL,
395 LDAPConstants.LDAP_ATTRIBUTE_MOBILE,
396 LDAPConstants.LDAP_ATTRIBUTE_ENTPERSONMOBILESMS,
397 LDAPConstants.LDAP_ATTRIBUTE_ENTPERSONMAILDIFFUSION,
398 LDAPConstants.LDAP_ATTRIBUTE_ENTPERSONADRESSE,
399 LDAPConstants.LDAP_ATTRIBUTE_ENTPERSONADRESSEDIFFUSION,
400 LDAPConstants.LDAP_ATTRIBUTE_ENTELEVEBOURSIER,
401 LDAPConstants.LDAP_ATTRIBUTE_ENTELEVETRANSPORT,
402 LDAPConstants.LDAP_ATTRIBUTE_ENTELEVEREGIME,
403 LDAPConstants.LDAP_ATTRIBUTE_ENTPERSONJOINTURE,
404 LDAPConstants.LDAP_ATTRIBUTE_ENTPERSONPROFILS,
405 LDAPConstants.LDAP_ATTRIBUTE_ENTAUXENSCATEGODISCIPLINE,
406 LDAPConstants.LDAP_ATTRIBUTE_ENTPERSONSTRUCTRATTACH,
407 LDAPConstants.LDAP_ATTRIBUTE_ENTPERSONFONCTIONS,
408 LDAPConstants.LDAP_ATTRIBUTE_ENTAUXENSMATIEREENSEIGNETAB,
409 LDAPConstants.LDAP_ATTRIBUTE_ENTELEVEAUTORITEPARENTALE,
410 LDAPConstants.LDAP_ATTRIBUTE_ENTAUXENSCLASSESPRINCIPAL,
411 LDAPConstants.LDAP_ATTRIBUTE_ENTELEVEPARENTS,
412 LDAPConstants.LDAP_ATTRIBUTE_ENTELEVEPERSRELELEVE
415 return _getAttributes(fullDistinguishedName, allAttrs, companyId);
418 public static Attributes getUserAttributes(
419 long ldapServerId, long companyId, LdapContext ldapContext,
420 String fullDistinguishedName)
423 Properties userMappings = LDAPSettingsUtil.getUserMappings(ldapServerId, companyId);
424 Properties userExpandoMappings = LDAPSettingsUtil.getUserExpandoMappings(ldapServerId, companyId);
426 PropertiesUtil.merge(userMappings, userExpandoMappings);
428 Properties contactMappings = LDAPSettingsUtil.getContactMappings(ldapServerId, companyId);
429 Properties contactExpandoMappings = LDAPSettingsUtil.getContactExpandoMappings(ldapServerId, companyId);
431 PropertiesUtil.merge(contactMappings, contactExpandoMappings);
433 PropertiesUtil.merge(userMappings, contactMappings);
435 String[] mappedUserAttributeIds = ArrayUtil.toStringArray(
436 userMappings.values().toArray(new Object[userMappings.size()]));
438 return _getAttributes(ldapContext, fullDistinguishedName, mappedUserAttributeIds);
443 private static Attributes _getAttributes(
444 LdapContext ldapContext, String fullDistinguishedName,
445 String[] attributeIds)
448 Name fullDN = new CompositeName().add(fullDistinguishedName);
450 Attributes attributes = null;
452 String[] auditAttributeIds = {
453 LDAPConstants.LDAP_ATTRIBUTE_CREATORSNAME, LDAPConstants.LDAP_ATTRIBUTE_CREATETIMESTAMP, LDAPConstants.LDAP_ATTRIBUTE_MODIFIERSNAME, LDAPConstants.LDAP_ATTRIBUTE_MODIFYTIMESTAMP
456 if (attributeIds == null) {
458 // Get complete listing of LDAP attributes (slow)
460 attributes = ldapContext.getAttributes(fullDN);
461 NamingEnumeration<? extends Attribute> enu = null;
464 enu = ldapContext.getAttributes(fullDN, auditAttributeIds).getAll();
466 while (enu.hasMoreElements()) {
467 attributes.put(enu.nextElement());
478 // Get specified LDAP attributes
480 int attributeCount = attributeIds.length + auditAttributeIds.length;
482 String[] allAttributeIds = new String[attributeCount];
484 System.arraycopy(attributeIds, 0, allAttributeIds, 0, attributeIds.length);
485 System.arraycopy(auditAttributeIds, 0, allAttributeIds, attributeIds.length, auditAttributeIds.length);
487 attributes = ldapContext.getAttributes(fullDN, allAttributeIds);
494 public static Properties getUserMappings(long companyId) throws Exception {
496 Properties userMappings = PropertiesUtil.load(PrefsPropsUtil.getString(companyId, PropsKeys.LDAP_USER_MAPPINGS));
501 public static NamingEnumeration<SearchResult> getUsers(long companyId, int maxResults) throws Exception {
503 return getUsers(companyId, maxResults, null);
506 public static NamingEnumeration<SearchResult> getUsers(long companyId, int maxResults, String[] attrs) throws Exception {
508 String baseDN = PrefsPropsUtil.getString(companyId, PropsKeys.LDAP_BASE_DN);
509 String userFilter = PrefsPropsUtil.getString(companyId, PropsKeys.LDAP_IMPORT_USER_SEARCH_FILTER);
510 return getUsers(companyId, maxResults, baseDN, userFilter, attrs);
513 public static NamingEnumeration<SearchResult> getUsers(long companyId, int maxResults, String baseDN, String userFilter, String[] attrs)
516 SearchControls cons = new SearchControls(SearchControls.SUBTREE_SCOPE, maxResults, 0, attrs, false, false);
518 return doContextSearch(companyId, baseDN, userFilter, cons);
521 public static NamingEnumeration<SearchResult> getAllEtabs(long companyId, String[] attrs) throws Exception {
523 String etabBaseDN = "ou=etablissements,"+PrefsPropsUtil.getString(companyId, PropsKeys.LDAP_BASE_DN);
524 String etabFilter = "(objectClass=*)";
525 SearchControls cons = new SearchControls(SearchControls.ONELEVEL_SCOPE, 0, 0, attrs, false, false);
526 return doContextSearch(companyId, etabBaseDN, etabFilter, cons);
529 public static String getUsersDN(long companyId) throws Exception {
530 return PrefsPropsUtil.getString(companyId, PropsKeys.LDAP_USERS_DN);
533 public static long getLdapServerId(
537 long[] ldapServerIds = StringUtil.split(
538 PrefsPropsUtil.getString(companyId, "ldap.server.ids"), 0L);
540 if(ldapServerIds.length <= 0) {
544 return ldapServerIds[0];
547 public static boolean hasUser(long companyId, String screenName)
550 if (getUser(companyId, screenName) != null) {
557 public static String getAuthSearchFilter(long companyId,
558 String emailAddress, String screenName, String userId)
559 throws SystemException {
561 String filter = PrefsPropsUtil.getString(companyId, PropsKeys.LDAP_AUTH_SEARCH_FILTER);
563 filter = StringUtil.replace(filter, new String[] { "@company_id@",
564 "@email_address@", "@screen_name@", "@user_id@" },
565 new String[] { String.valueOf(companyId), emailAddress,
566 screenName, userId });
571 public static NamingEnumeration<SearchResult> doContextSearch(long companyId, String baseDN, String searchFilter, SearchControls cons) throws Exception {
573 return getContext(companyId).search(baseDN, searchFilter, cons);
575 catch(Exception exc) {
580 return getContext(companyId).search(baseDN, searchFilter, cons);
585 public static Attributes doContextAttributes(long companyId, String search) throws Exception {
587 return getContext(companyId).getAttributes(search);
589 catch(Exception exc) {
594 return getContext(companyId).getAttributes(search);
598 public static Attributes doContextAttributes(long companyId, String search, String[] attributeIds) throws Exception {
600 return getContext(companyId).getAttributes(search, attributeIds);
602 catch(Exception exc) {
607 return getContext(companyId).getAttributes(search, attributeIds);
611 public static LdapContext getContext(long companyId) throws Exception {
612 return getContext(getLdapServerId(companyId), companyId);
615 public static LdapContext getContext(long ldapServerId, long companyId)
618 String postfix = LDAPSettingsUtil.getPropertyPostfix(ldapServerId);
619 String baseProviderURL = PrefsPropsUtil.getString(companyId, PropsKeys.LDAP_BASE_PROVIDER_URL + postfix);
620 if (Validator.isNull(baseProviderURL)){
621 baseProviderURL = PrefsPropsUtil.getString(companyId, PropsKeys.LDAP_BASE_PROVIDER_URL);
623 String pricipal = PrefsPropsUtil.getString(companyId, PropsKeys.LDAP_SECURITY_PRINCIPAL + postfix);
624 if (Validator.isNull(pricipal)){
625 pricipal = PrefsPropsUtil.getString(companyId, PropsKeys.LDAP_SECURITY_PRINCIPAL);
627 String credentials = PrefsPropsUtil.getString(companyId, PropsKeys.LDAP_SECURITY_CREDENTIALS + postfix);
628 if (Validator.isNull(credentials)){
629 credentials = PrefsPropsUtil.getString(companyId, PropsKeys.LDAP_SECURITY_CREDENTIALS);
631 return getContext(companyId, baseProviderURL, pricipal, credentials);
634 public static LdapContext getContext(long companyId, String providerURL,
635 String pricipal, String credentials) throws Exception {
641 Properties env = new Properties();
643 env.put(Context.INITIAL_CONTEXT_FACTORY, PrefsPropsUtil.getString(companyId, PropsKeys.LDAP_FACTORY_INITIAL));
644 env.put(Context.PROVIDER_URL, providerURL);
645 env.put(Context.SECURITY_PRINCIPAL, pricipal);
646 env.put(Context.SECURITY_CREDENTIALS, credentials);
647 env.put(Context.REFERRAL, PrefsPropsUtil.getString(companyId, PropsKeys.LDAP_REFERRAL));
651 env.put("com.sun.jndi.ldap.connect.pool", "true");
652 env.put("com.sun.jndi.ldap.connect.pool.maxsize", "50");
653 env.put("com.sun.jndi.ldap.connect.pool.timeout", "10000");
655 LogUtil.debug(_log, env);
658 ctx = new InitialLdapContext(env, null);
659 } catch (Exception e) {
660 _log.warn("Failed to bind to the LDAP server", e);