--- /dev/null
+/**\r
+ * Copyright (c) 2000-2012 Liferay, Inc. All rights reserved.\r
+ *\r
+ * This library is free software; you can redistribute it and/or modify it under\r
+ * the terms of the GNU Lesser General Public License as published by the Free\r
+ * Software Foundation; either version 2.1 of the License, or (at your option)\r
+ * any later version.\r
+ *\r
+ * This library is distributed in the hope that it will be useful, but WITHOUT\r
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS\r
+ * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more\r
+ * details.\r
+ */\r
+\r
+package com.liferay.portal.security.auth;\r
+\r
+import java.util.Hashtable;\r
+import java.util.Map;\r
+import java.util.Properties;\r
+\r
+import javax.naming.Context;\r
+import javax.naming.NamingEnumeration;\r
+import javax.naming.directory.Attribute;\r
+import javax.naming.directory.Attributes;\r
+import javax.naming.directory.SearchControls;\r
+import javax.naming.directory.SearchResult;\r
+import javax.naming.ldap.Control;\r
+import javax.naming.ldap.InitialLdapContext;\r
+import javax.naming.ldap.LdapContext;\r
+\r
+import com.liferay.portal.NoSuchUserException;\r
+import com.liferay.portal.PasswordExpiredException;\r
+import com.liferay.portal.UserLockoutException;\r
+import com.liferay.portal.kernel.log.Log;\r
+import com.liferay.portal.kernel.log.LogFactoryUtil;\r
+import com.liferay.portal.kernel.util.GetterUtil;\r
+import com.liferay.portal.kernel.util.PropsKeys;\r
+import com.liferay.portal.kernel.util.StringBundler;\r
+import com.liferay.portal.kernel.util.StringPool;\r
+import com.liferay.portal.kernel.util.StringUtil;\r
+import com.liferay.portal.kernel.util.Validator;\r
+import com.liferay.portal.model.User;\r
+import com.liferay.portal.security.ldap.LDAPSettingsUtil;\r
+import com.liferay.portal.security.ldap.PortalLDAPUtil;\r
+import com.liferay.portal.security.pwd.PwdEncryptor;\r
+import com.liferay.portal.service.UserLocalServiceUtil;\r
+import com.liferay.portal.util.PrefsPropsUtil;\r
+import com.liferay.portal.util.PropsValues;\r
+import com.liferay.portlet.admin.util.OmniadminUtil;\r
+import com.pentila.entSavoie.synchroLdap.impl.SynchronizationManager;\r
+\r
+/**\r
+ * @author Brian Wing Shun Chan\r
+ * @author Scott Lee\r
+ */\r
+public class LDAPAuth implements Authenticator {\r
+\r
+ public static final String AUTH_METHOD_BIND = "bind";\r
+\r
+ public static final String AUTH_METHOD_PASSWORD_COMPARE =\r
+ "password-compare";\r
+\r
+ public static final String RESULT_PASSWORD_EXP_WARNING =\r
+ "2.16.840.1.113730.3.4.5";\r
+\r
+ public static final String RESULT_PASSWORD_RESET =\r
+ "2.16.840.1.113730.3.4.4";\r
+\r
+ public int authenticateByEmailAddress(\r
+ long companyId, String emailAddress, String password,\r
+ Map<String, String[]> headerMap, Map<String, String[]> parameterMap)\r
+ throws AuthException {\r
+\r
+ try {\r
+ return authenticate(\r
+ companyId, emailAddress, StringPool.BLANK, 0, password);\r
+ }\r
+ catch (Exception e) {\r
+ _log.error(e, e);\r
+\r
+ throw new AuthException(e);\r
+ }\r
+ }\r
+\r
+ public int authenticateByScreenName(\r
+ long companyId, String screenName, String password,\r
+ Map<String, String[]> headerMap, Map<String, String[]> parameterMap)\r
+ throws AuthException {\r
+\r
+ try {\r
+ return authenticate(\r
+ companyId, StringPool.BLANK, screenName, 0, password);\r
+ }\r
+ catch (Exception e) {\r
+ _log.error(e, e);\r
+\r
+ throw new AuthException(e);\r
+ }\r
+ }\r
+\r
+ public int authenticateByUserId(\r
+ long companyId, long userId, String password,\r
+ Map<String, String[]> headerMap, Map<String, String[]> parameterMap)\r
+ throws AuthException {\r
+\r
+ try {\r
+ return authenticate(\r
+ companyId, StringPool.BLANK, StringPool.BLANK, userId,\r
+ password);\r
+ }\r
+ catch (Exception e) {\r
+ _log.error(e, e);\r
+\r
+ throw new AuthException(e);\r
+ }\r
+ }\r
+\r
+ protected LDAPAuthResult authenticate(\r
+ LdapContext ctx, long companyId, Attributes attributes,\r
+ String userDN, String password)\r
+ throws Exception {\r
+\r
+ LDAPAuthResult ldapAuthResult = new LDAPAuthResult();\r
+\r
+ // Check passwords by either doing a comparison between the passwords or\r
+ // by binding to the LDAP server. If using LDAP password policies, bind\r
+ // auth method must be used in order to get the result control codes.\r
+\r
+ String authMethod = PrefsPropsUtil.getString(\r
+ companyId, PropsKeys.LDAP_AUTH_METHOD);\r
+ InitialLdapContext innerCtx = null;\r
+\r
+ if (authMethod.equals(AUTH_METHOD_BIND)) {\r
+ try {\r
+\r
+ //Hashtable<String, Object> env =\r
+ // (Hashtable<String, Object>)ctx.getEnvironment();\r
+\r
+ // Begin fix for webdav\r
+ \r
+ Properties env = new Properties();\r
+\r
+ env.put(Context.INITIAL_CONTEXT_FACTORY, PrefsPropsUtil.getString(companyId, PropsKeys.LDAP_FACTORY_INITIAL));\r
+ env.put(Context.PROVIDER_URL, PrefsPropsUtil.getString(companyId, PropsKeys.LDAP_BASE_PROVIDER_URL));\r
+\r
+ env.put("com.sun.jndi.ldap.connect.pool", "true");\r
+ env.put("com.sun.jndi.ldap.connect.pool.maxsize", "50");\r
+ env.put("com.sun.jndi.ldap.connect.pool.timeout", "100000");\r
+\r
+ // End fix for webdav\r
+\r
+\r
+ env.put(Context.SECURITY_PRINCIPAL, userDN);\r
+ env.put(Context.SECURITY_CREDENTIALS, password);\r
+ env.put(\r
+ Context.REFERRAL,\r
+ PrefsPropsUtil.getString(\r
+ companyId, PropsKeys.LDAP_REFERRAL));\r
+\r
+ // Do not use pooling because principal changes\r
+\r
+ env.put("com.sun.jndi.ldap.connect.pool", "false");\r
+\r
+ innerCtx = new InitialLdapContext(env, null);\r
+\r
+ // Get LDAP bind results\r
+\r
+ Control[] responseControls = innerCtx.getResponseControls();\r
+\r
+ ldapAuthResult.setAuthenticated(true);\r
+ ldapAuthResult.setResponseControl(responseControls);\r
+ }\r
+ catch (Exception e) {\r
+ if (_log.isDebugEnabled()) {\r
+ _log.debug(\r
+ "Failed to bind to the LDAP server with userDN "\r
+ + userDN + " and password " + password);\r
+ }\r
+\r
+ _log.error("Failed to bind to the LDAP server", e);\r
+\r
+ ldapAuthResult.setAuthenticated(false);\r
+ ldapAuthResult.setErrorMessage(e.getMessage());\r
+ }\r
+ finally {\r
+ if (innerCtx != null) {\r
+ innerCtx.close();\r
+ }\r
+ }\r
+ }\r
+ else if (authMethod.equals(AUTH_METHOD_PASSWORD_COMPARE)) {\r
+ Attribute userPassword = attributes.get("userPassword");\r
+\r
+ if (userPassword != null) {\r
+ String ldapPassword = new String((byte[])userPassword.get());\r
+\r
+ String encryptedPassword = password;\r
+\r
+ String algorithm = PrefsPropsUtil.getString(\r
+ companyId,\r
+ PropsKeys.LDAP_AUTH_PASSWORD_ENCRYPTION_ALGORITHM);\r
+\r
+ if (Validator.isNotNull(algorithm)) {\r
+ StringBundler sb = new StringBundler(4);\r
+\r
+ sb.append(StringPool.OPEN_CURLY_BRACE);\r
+ sb.append(algorithm);\r
+ sb.append(StringPool.CLOSE_CURLY_BRACE);\r
+ sb.append(\r
+ PwdEncryptor.encrypt(\r
+ algorithm, password, ldapPassword));\r
+\r
+ encryptedPassword = sb.toString();\r
+ }\r
+\r
+ if (ldapPassword.equals(encryptedPassword)) {\r
+ ldapAuthResult.setAuthenticated(true);\r
+ }\r
+ else {\r
+ ldapAuthResult.setAuthenticated(false);\r
+\r
+ if (_log.isWarnEnabled()) {\r
+ _log.warn(\r
+ "Passwords do not match for userDN " + userDN);\r
+ }\r
+ }\r
+ }\r
+ }\r
+\r
+ return ldapAuthResult;\r
+ }\r
+\r
+ protected int authenticate(\r
+ long companyId, long ldapServerId, String emailAddress,\r
+ String screenName, long userId, String password)\r
+ throws Exception {\r
+\r
+ String postfix = LDAPSettingsUtil.getPropertyPostfix(ldapServerId);\r
+\r
+ LdapContext ldapContext = PortalLDAPUtil.getContext(companyId);\r
+\r
+\r
+ if (ldapContext == null) {\r
+ return FAILURE;\r
+ }\r
+\r
+ NamingEnumeration<SearchResult> enu = null;\r
+\r
+ try {\r
+ String baseDN = PrefsPropsUtil.getString(\r
+ companyId, PropsKeys.LDAP_BASE_DN + postfix);\r
+\r
+ // Process LDAP auth search filter\r
+\r
+ String filter = LDAPSettingsUtil.getAuthSearchFilter(\r
+ ldapServerId, companyId, emailAddress, screenName,\r
+ String.valueOf(userId));\r
+\r
+ Properties userMappings = LDAPSettingsUtil.getUserMappings(\r
+ ldapServerId, companyId);\r
+\r
+ String userMappingsScreenName = GetterUtil.getString(\r
+ userMappings.getProperty("screenName")).toLowerCase();\r
+\r
+ SearchControls searchControls = new SearchControls(\r
+ SearchControls.SUBTREE_SCOPE, 1, 0,\r
+ new String[] {userMappingsScreenName}, false, false);\r
+\r
+\r
+ SearchControls cons = new SearchControls(\r
+ SearchControls.SUBTREE_SCOPE, 1, 0, null, false, false);\r
+ \r
+ enu = PortalLDAPUtil.doContextSearch(\r
+ companyId, baseDN, filter, cons);\r
+\r
+ if (enu.hasMoreElements()) {\r
+ if (_log.isDebugEnabled()) {\r
+ _log.debug("Search filter returned at least one result");\r
+ }\r
+\r
+ SearchResult result = enu.nextElement();\r
+\r
+ String fullUserDN = PortalLDAPUtil.getNameInNamespace(\r
+ companyId, result);\r
+\r
+ Attributes attributes = PortalLDAPUtil.getUserAttributes(\r
+ companyId, fullUserDN);\r
+\r
+ LDAPAuthResult ldapAuthResult = authenticate(\r
+ ldapContext, companyId, attributes, fullUserDN, password);\r
+\r
+ // Process LDAP failure codes\r
+\r
+ String errorMessage = ldapAuthResult.getErrorMessage();\r
+\r
+ if (errorMessage != null) {\r
+ int pos = errorMessage.indexOf(\r
+ PrefsPropsUtil.getString(\r
+ companyId, PropsKeys.LDAP_ERROR_USER_LOCKOUT));\r
+\r
+ if (pos != -1) {\r
+ throw new UserLockoutException();\r
+ }\r
+\r
+ pos = errorMessage.indexOf(\r
+ PrefsPropsUtil.getString(\r
+ companyId, PropsKeys.LDAP_ERROR_PASSWORD_EXPIRED));\r
+\r
+ if (pos != -1) {\r
+ throw new PasswordExpiredException();\r
+ }\r
+ }\r
+\r
+ if (!ldapAuthResult.isAuthenticated()) {\r
+ return FAILURE;\r
+ }\r
+\r
+ // Get user or create from LDAP\r
+\r
+ /**************************\r
+ * MIGRATION MODIFICATION *\r
+ **************************/\r
+ //User user = PortalLDAPImporterUtil.importLDAPUser(\r
+ // ldapServerId, companyId, ldapContext, attributes, password);\r
+\r
+ //User user = SynchronizationManager.synchronizeUser(companyId, attributes, password, false);\r
+\r
+ // Process LDAP success codes\r
+\r
+ String resultCode = ldapAuthResult.getResponseControl();\r
+\r
+// if (resultCode.equals(LDAPAuth.RESULT_PASSWORD_RESET)) {\r
+// UserLocalServiceUtil.updatePasswordReset(\r
+// user.getUserId(), true);\r
+// }\r
+ }\r
+ else {\r
+ if (_log.isDebugEnabled()) {\r
+ _log.debug("Search filter did not return any results");\r
+ }\r
+\r
+ return DNE;\r
+ }\r
+ }\r
+ catch (Exception e) {\r
+ if (e instanceof PasswordExpiredException ||\r
+ e instanceof UserLockoutException) {\r
+\r
+ throw e;\r
+ }\r
+\r
+ _log.error("Problem accessing LDAP server", e);\r
+\r
+ return FAILURE;\r
+ }\r
+ finally {\r
+ if (enu != null) {\r
+ enu.close();\r
+ }\r
+\r
+ if (ldapContext != null) {\r
+ ldapContext.close();\r
+ }\r
+ }\r
+\r
+ return SUCCESS;\r
+ }\r
+\r
+ protected int authenticate(\r
+ long companyId, String emailAddress, String screenName, long userId,\r
+ String password)\r
+ throws Exception {\r
+\r
+ if (!AuthSettingsUtil.isLDAPAuthEnabled(companyId)) {\r
+ if (_log.isDebugEnabled()) {\r
+ _log.debug("Authenticator is not enabled");\r
+ }\r
+\r
+ return SUCCESS;\r
+ }\r
+\r
+ if (_log.isDebugEnabled()) {\r
+ _log.debug("Authenticator is enabled");\r
+ }\r
+\r
+ long[] ldapServerIds = StringUtil.split(\r
+ PrefsPropsUtil.getString(companyId, "ldap.server.ids"), 0L);\r
+\r
+ for (long ldapServerId : ldapServerIds) {\r
+ int result = authenticate(\r
+ companyId, ldapServerId, emailAddress, screenName, userId,\r
+ password);\r
+\r
+ if (result == SUCCESS) {\r
+ return result;\r
+ }\r
+ }\r
+\r
+ for (int ldapServerId = 0;; ldapServerId++) {\r
+ String postfix = LDAPSettingsUtil.getPropertyPostfix(ldapServerId);\r
+\r
+ String providerUrl = PrefsPropsUtil.getString(\r
+ companyId, PropsKeys.LDAP_BASE_PROVIDER_URL + postfix);\r
+\r
+ if (Validator.isNull(providerUrl)) {\r
+ break;\r
+ }\r
+\r
+ int result = authenticate(\r
+ companyId, ldapServerId, emailAddress, screenName, userId,\r
+ password);\r
+\r
+ if (result == SUCCESS) {\r
+ return result;\r
+ }\r
+ }\r
+\r
+ return authenticateRequired(\r
+ companyId, userId, emailAddress, screenName, true, FAILURE);\r
+ }\r
+\r
+ protected int authenticateOmniadmin(\r
+ long companyId, String emailAddress, String screenName, long userId)\r
+ throws Exception {\r
+\r
+ // Only allow omniadmin if Liferay password checking is enabled\r
+\r
+ if (PropsValues.AUTH_PIPELINE_ENABLE_LIFERAY_CHECK) {\r
+ if (userId > 0) {\r
+ if (OmniadminUtil.isOmniadmin(userId)) {\r
+ return SUCCESS;\r
+ }\r
+ }\r
+ else if (Validator.isNotNull(emailAddress)) {\r
+ try {\r
+ User user = UserLocalServiceUtil.getUserByEmailAddress(\r
+ companyId, emailAddress);\r
+\r
+ if (OmniadminUtil.isOmniadmin(user.getUserId())) {\r
+ return SUCCESS;\r
+ }\r
+ }\r
+ catch (NoSuchUserException nsue) {\r
+ }\r
+ }\r
+ else if (Validator.isNotNull(screenName)) {\r
+ try {\r
+ User user = UserLocalServiceUtil.getUserByScreenName(\r
+ companyId, screenName);\r
+\r
+ if (OmniadminUtil.isOmniadmin(user.getUserId())) {\r
+ return SUCCESS;\r
+ }\r
+ }\r
+ catch (NoSuchUserException nsue) {\r
+ }\r
+ }\r
+ }\r
+\r
+ return FAILURE;\r
+ }\r
+\r
+ protected int authenticateRequired(\r
+ long companyId, long userId, String emailAddress, String screenName,\r
+ boolean allowOmniadmin, int failureCode)\r
+ throws Exception {\r
+\r
+ // Make exceptions for omniadmins so that if they break the LDAP\r
+ // configuration, they can still login to fix the problem\r
+\r
+ if (allowOmniadmin &&\r
+ (authenticateOmniadmin(\r
+ companyId, emailAddress, screenName, userId) == SUCCESS)) {\r
+\r
+ return SUCCESS;\r
+ }\r
+\r
+ if (PrefsPropsUtil.getBoolean(\r
+ companyId, PropsKeys.LDAP_AUTH_REQUIRED)) {\r
+\r
+ return failureCode;\r
+ }\r
+ else {\r
+ return SUCCESS;\r
+ }\r
+ }\r
+\r
+ private static Log _log = LogFactoryUtil.getLog(LDAPAuth.class);\r
+\r
+}
\ No newline at end of file