Author: adrianc
Date: Fri Jun 20 10:09:19 2008
New Revision: 669994
URL: http://svn.apache.org/viewvc?rev=669994&view=rev
Log:
Added LDAP user authentication, based on work contributed by Mohamed Amine Azzi and Torsten
Schlabach - https://issues.apache.org/jira/browse/OFBIZ-811.
Internationalization note: this commit contains new UI labels.
Added:
ofbiz/trunk/framework/common/src/org/ofbiz/common/login/LdapAuthenticationServices.java
(with props)
ofbiz/trunk/framework/security/config/jndiLdap.properties (with props)
Modified:
ofbiz/trunk/applications/party/config/PartyUiLabels.xml
ofbiz/trunk/applications/party/webapp/partymgr/party/PartyForms.xml
ofbiz/trunk/framework/common/config/SecurityextUiLabels.xml
ofbiz/trunk/framework/common/servicedef/services.xml
ofbiz/trunk/framework/common/src/org/ofbiz/common/login/LoginServices.java
ofbiz/trunk/framework/security/config/security.properties
ofbiz/trunk/framework/security/entitydef/entitymodel.xml
Modified: ofbiz/trunk/applications/party/config/PartyUiLabels.xml
URL: http://svn.apache.org/viewvc/ofbiz/trunk/applications/party/config/PartyUiLabels.xml?rev=669994&r1=669993&r2=669994&view=diff
==============================================================================
--- ofbiz/trunk/applications/party/config/PartyUiLabels.xml (original)
+++ ofbiz/trunk/applications/party/config/PartyUiLabels.xml Fri Jun 20 10:09:19 2008
@@ -1043,6 +1043,9 @@
<value xml:lang="th">à¸à¸¥à¸£à¸§à¸¡à¸à¸à¸à¸à¸µà¸à¸µà¹à¸¡à¸µà¸à¸£à¸°à¸ªà¸à¸à¸²à¸£à¸à¹à¸à¸²à¸£à¸à¸³à¸à¸²à¸</value>
<value xml:lang="zh">å·¥ä½ç»åå¹´æ°å计</value>
</property>
+ <property key="FormFieldTitle_userLdapDn">
+ <value xml:lang="en">LDAP Distinguished Name</value>
+ </property>
<property key="FormFieldTitle_userLoginId">
<value xml:lang="en">User Login Id</value>
<value xml:lang="fr">Utilisateur de connexion</value>
Modified: ofbiz/trunk/applications/party/webapp/partymgr/party/PartyForms.xml
URL: http://svn.apache.org/viewvc/ofbiz/trunk/applications/party/webapp/partymgr/party/PartyForms.xml?rev=669994&r1=669993&r2=669994&view=diff
==============================================================================
--- ofbiz/trunk/applications/party/webapp/partymgr/party/PartyForms.xml (original)
+++ ofbiz/trunk/applications/party/webapp/partymgr/party/PartyForms.xml Fri Jun 20 10:09:19
2008
@@ -162,9 +162,13 @@
<form name="updateUserLoginSecurity" type="single" target="updateUserLoginSecurity"
default-map-name="editUserLogin"
header-row-style="header-row" default-table-style="basic-table">
+ <actions>
+ <property-to-field field="ldapEnabled" resource="security" property="security.ldap.enable"/>
+ </actions>
<auto-fields-service service-name="updateUserLoginSecurity"/>
<field name="partyId"><hidden/></field>
<field name="userLoginId"><hidden/></field>
+ <field name="userLdapDn" use-when=""true".equals(ldapEnabled)"><text/></field>
<field name="submitButton" title="${uiLabelMap.CommonSave}" widget-style="smallSubmit"><submit
button-type="text-link"/></field>
<field name="cancelLink" title="${uiLabelMap.CommonEmptyHeader}" widget-style="smallSubmit"><hyperlink
target="${donePage}?partyId=${partyId}" also-hidden="false" description="${uiLabelMap.CommonCancelDone}"/></field>
</form>
Modified: ofbiz/trunk/framework/common/config/SecurityextUiLabels.xml
URL: http://svn.apache.org/viewvc/ofbiz/trunk/framework/common/config/SecurityextUiLabels.xml?rev=669994&r1=669993&r2=669994&view=diff
==============================================================================
--- ofbiz/trunk/framework/common/config/SecurityextUiLabels.xml (original)
+++ ofbiz/trunk/framework/common/config/SecurityextUiLabels.xml Fri Jun 20 10:09:19 2008
@@ -611,4 +611,7 @@
<value xml:lang="th">มัà¸à¸à¸°à¹à¸¡à¹à¸ªà¸²à¸¡à¸²à¸£à¸à¹à¸à¹à¹à¸à¹à¸à¸µà¸à¸à¸£à¸±à¹à¸
${reEnableTime}.</value>
<value xml:lang="zh">å°éæ°å¯ç¨ ${reEnableTime}ã</value>
</property>
+ <property key="loginservices.ldap_authentication_failed">
+ <value xml:lang="en">LDAP authentication failed.</value>
+ </property>
</resource>
Modified: ofbiz/trunk/framework/common/servicedef/services.xml
URL: http://svn.apache.org/viewvc/ofbiz/trunk/framework/common/servicedef/services.xml?rev=669994&r1=669993&r2=669994&view=diff
==============================================================================
--- ofbiz/trunk/framework/common/servicedef/services.xml (original)
+++ ofbiz/trunk/framework/common/servicedef/services.xml Fri Jun 20 10:09:19 2008
@@ -398,6 +398,7 @@
<attribute name="enabled" type="String" mode="IN" optional="false"/>
<attribute name="disabledDateTime" type="java.sql.Timestamp" mode="IN" optional="true"/>
<attribute name="successiveFailedLogins" type="Long" mode="IN" optional="true"/>
+ <attribute name="userLdapDn" type="String" mode="IN" optional="true"/>
</service>
<!-- common permission services -->
Added: ofbiz/trunk/framework/common/src/org/ofbiz/common/login/LdapAuthenticationServices.java
URL: http://svn.apache.org/viewvc/ofbiz/trunk/framework/common/src/org/ofbiz/common/login/LdapAuthenticationServices.java?rev=669994&view=auto
==============================================================================
--- ofbiz/trunk/framework/common/src/org/ofbiz/common/login/LdapAuthenticationServices.java
(added)
+++ ofbiz/trunk/framework/common/src/org/ofbiz/common/login/LdapAuthenticationServices.java
Fri Jun 20 10:09:19 2008
@@ -0,0 +1,155 @@
+/*******************************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *******************************************************************************/
+
+package org.ofbiz.common.login;
+
+import java.util.Map;
+import java.util.Properties;
+
+import javax.naming.Context;
+import javax.naming.NamingException;
+import javax.naming.directory.DirContext;
+import javax.naming.directory.InitialDirContext;
+import javax.transaction.Transaction;
+
+import org.ofbiz.base.crypto.HashCrypt;
+import org.ofbiz.base.util.Debug;
+import org.ofbiz.base.util.UtilProperties;
+import org.ofbiz.base.util.UtilValidate;
+import org.ofbiz.entity.GenericDelegator;
+import org.ofbiz.entity.GenericEntityException;
+import org.ofbiz.entity.GenericValue;
+import org.ofbiz.entity.transaction.GenericTransactionException;
+import org.ofbiz.entity.transaction.TransactionUtil;
+import org.ofbiz.service.DispatchContext;
+
+/** LDAP Authentication Services.
+ */
+public class LdapAuthenticationServices {
+
+ public static final String module = LdapAuthenticationServices.class.getName();
+
+ public static boolean userLogin(DispatchContext ctx, Map<String, Object> context)
{
+ Debug.logVerbose("Starting LDAP authentication", module);
+ Properties env = UtilProperties.getProperties("jndiLdap");
+ String username = (String) context.get("login.username");
+ if (username == null) {
+ username = (String) context.get("username");
+ }
+ String password = (String) context.get("login.password");
+ if (password == null) {
+ password = (String) context.get("password");
+ }
+ String dn = null;
+ GenericDelegator delegator = ctx.getDelegator();
+ boolean isServiceAuth = context.get("isServiceAuth") != null && ((Boolean)
context.get("isServiceAuth")).booleanValue();
+ GenericValue userLogin = null;
+ try {
+ userLogin = delegator.findOne("UserLogin", isServiceAuth, "userLoginId", username);
+ } catch (GenericEntityException e) {
+ Debug.logWarning(e, "", module);
+ }
+ if (userLogin != null) {
+ dn = userLogin.getString("userLdapDn");
+ }
+ if (UtilValidate.isEmpty(dn)) {
+ String dnTemplate = (String) env.get("ldap.dn.template");
+ if (dnTemplate != null) {
+ dn = dnTemplate.replace("%u", username);
+ }
+ Debug.logVerbose("Using DN template: " + dn, module);
+ } else {
+ Debug.logVerbose("Using UserLogin.userLdapDn: " + dn, module);
+ }
+ env.put(Context.SECURITY_PRINCIPAL, dn);
+ env.put(Context.SECURITY_CREDENTIALS, password);
+ try {
+ // Create initial context
+ DirContext ldapCtx = new InitialDirContext(env);
+ ldapCtx.close();
+ } catch (NamingException e) {
+ Debug.logVerbose("LDAP authentication failed: " + e.getMessage(), module);
+ return false;
+ }
+ Debug.logVerbose("LDAP authentication succeeded", module);
+ if (!"true".equals(env.get("ldap.synchronize.passwords"))) {
+ return true;
+ }
+ // Synchronize user's OFBiz password with user's LDAP password
+ if (userLogin != null) {
+ boolean useEncryption = "true".equals(UtilProperties.getPropertyValue("security.properties",
"password.encrypt"));
+ String encodedPassword = useEncryption ? HashCrypt.getDigestHash(password, LoginServices.getHashType())
: password;
+ String encodedPasswordOldFunnyHexEncode = useEncryption ? HashCrypt.getDigestHashOldFunnyHexEncode(password,
LoginServices.getHashType()) : password;
+ String encodedPasswordUsingDbHashType = encodedPassword;
+ String currentPassword = userLogin.getString("currentPassword");
+ if (useEncryption && currentPassword != null && currentPassword.startsWith("{"))
{
+ String dbHashType = HashCrypt.getHashTypeFromPrefix(currentPassword);
+ if (dbHashType != null) {
+ encodedPasswordUsingDbHashType = HashCrypt.getDigestHash(password, dbHashType);
+ }
+ }
+ boolean samePassword = currentPassword != null &&
+ (HashCrypt.removeHashTypePrefix(encodedPassword).equals(HashCrypt.removeHashTypePrefix(currentPassword))
||
+ HashCrypt.removeHashTypePrefix(encodedPasswordOldFunnyHexEncode).equals(HashCrypt.removeHashTypePrefix(currentPassword))
||
+ HashCrypt.removeHashTypePrefix(encodedPasswordUsingDbHashType).equals(HashCrypt.removeHashTypePrefix(currentPassword))
||
+ ("true".equals(UtilProperties.getPropertyValue("security.properties",
"password.accept.encrypted.and.plain")) && password.equals(currentPassword)));
+ if (!samePassword) {
+ Debug.logVerbose("Starting password synchronization", module);
+ userLogin.set("currentPassword", useEncryption ? HashCrypt.getDigestHash(password,
LoginServices.getHashType()) : password, false);
+ Transaction parentTx = null;
+ boolean beganTransaction = false;
+ try {
+ try {
+ parentTx = TransactionUtil.suspend();
+ } catch (GenericTransactionException e) {
+ Debug.logError(e, "Could not suspend transaction: " + e.getMessage(),
module);
+ }
+ try {
+ beganTransaction = TransactionUtil.begin();
+ userLogin.store();
+ } catch (GenericEntityException e) {
+ Debug.logError(e, "Error saving UserLogin", module);
+ try {
+ TransactionUtil.rollback(beganTransaction, "Error saving UserLogin",
e);
+ } catch (GenericTransactionException e2) {
+ Debug.logError(e2, "Could not rollback nested transaction: "
+ e2.getMessage(), module);
+ }
+ } finally {
+ try {
+ TransactionUtil.commit(beganTransaction);
+ Debug.logVerbose("Password synchronized", module);
+ } catch (GenericTransactionException e) {
+ Debug.logError(e, "Could not commit nested transaction: " + e.getMessage(),
module);
+ }
+ }
+ } finally {
+ if (parentTx != null) {
+ try {
+ TransactionUtil.resume(parentTx);
+ Debug.logVerbose("Resumed the parent transaction.", module);
+ } catch (GenericTransactionException e) {
+ Debug.logError(e, "Could not resume parent nested transaction:
" + e.getMessage(), module);
+ }
+ }
+ }
+ }
+ }
+ return true;
+ }
+}
Propchange: ofbiz/trunk/framework/common/src/org/ofbiz/common/login/LdapAuthenticationServices.java
------------------------------------------------------------------------------
svn:eol-style = native
Modified: ofbiz/trunk/framework/common/src/org/ofbiz/common/login/LoginServices.java
URL: http://svn.apache.org/viewvc/ofbiz/trunk/framework/common/src/org/ofbiz/common/login/LoginServices.java?rev=669994&r1=669993&r2=669994&view=diff
==============================================================================
--- ofbiz/trunk/framework/common/src/org/ofbiz/common/login/LoginServices.java (original)
+++ ofbiz/trunk/framework/common/src/org/ofbiz/common/login/LoginServices.java Fri Jun 20
10:09:19 2008
@@ -64,10 +64,22 @@
* @return Map of results including (userLogin) GenericValue object
*/
public static Map userLogin(DispatchContext ctx, Map context) {
- Map result = FastMap.newInstance();
- GenericDelegator delegator = ctx.getDelegator();
Locale locale = (Locale) context.get("locale");
+ // Authenticate to LDAP if configured to do so
+ if ("true".equals(UtilProperties.getPropertyValue("security", "security.ldap.enable")))
{
+ if (!LdapAuthenticationServices.userLogin(ctx, context)) {
+ String errMsg = UtilProperties.getMessage(resource, "loginservices.ldap_authentication_failed",
locale);
+ if ("true".equals(UtilProperties.getPropertyValue("security", "security.ldap.fail.login")))
{
+ return ServiceUtil.returnError(errMsg);
+ } else {
+ Debug.logInfo(errMsg, module);
+ }
+ }
+ }
+
+ Map result = FastMap.newInstance();
+ GenericDelegator delegator = ctx.getDelegator();
boolean useEncryption = "true".equals(UtilProperties.getPropertyValue("security.properties",
"password.encrypt"));
// if isServiceAuth is not specified, default to not a service auth
@@ -744,6 +756,9 @@
if (context.containsKey("successiveFailedLogins")) {
userLoginToUpdate.set("successiveFailedLogins", context.get("successiveFailedLogins"),
true);
}
+ if (context.containsKey("userLdapDn")) {
+ userLoginToUpdate.set("userLdapDn", context.get("userLdapDn"), true);
+ }
// if was disabled and we are enabling it, clear disabledDateTime
if (!wasEnabled && "Y".equals(context.get("enabled"))) {
Added: ofbiz/trunk/framework/security/config/jndiLdap.properties
URL: http://svn.apache.org/viewvc/ofbiz/trunk/framework/security/config/jndiLdap.properties?rev=669994&view=auto
==============================================================================
--- ofbiz/trunk/framework/security/config/jndiLdap.properties (added)
+++ ofbiz/trunk/framework/security/config/jndiLdap.properties Fri Jun 20 10:09:19 2008
@@ -0,0 +1,38 @@
+###############################################################################
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+###############################################################################
+####
+# OFBiz LDAP Authentication Settings
+####
+
+# JNDI LDAP settings. Change the following line to
+# point to your LDAP server.
+java.naming.provider.url=ldap://localhost:389
+java.naming.factory.initial=com.sun.jndi.ldap.LdapCtxFactory
+java.naming.security.authentication=simple
+com.sun.jndi.ldap.connect.timeout=5000
+
+# Distinguished Name template. This is used as a default if
+# UserLogin.userLdapDn is empty.
+# The %u placeholder will be replaced by the user's login name,
+# then the resulting string will be used to authenticate the user.
+ldap.dn.template=cn=%u,ou=system
+
+# The following property controls whether the user's OFBiz password
+# is synchronized with the user's LDAP password.
+ldap.synchronize.passwords=true
Propchange: ofbiz/trunk/framework/security/config/jndiLdap.properties
------------------------------------------------------------------------------
svn:eol-style = native
Modified: ofbiz/trunk/framework/security/config/security.properties
URL: http://svn.apache.org/viewvc/ofbiz/trunk/framework/security/config/security.properties?rev=669994&r1=669993&r2=669994&view=diff
==============================================================================
--- ofbiz/trunk/framework/security/config/security.properties (original)
+++ ofbiz/trunk/framework/security/config/security.properties Fri Jun 20 10:09:19 2008
@@ -60,6 +60,12 @@
username.lowercase=false
password.lowercase=false
+# -- Use LDAP for user authentication? --
+security.ldap.enable=false
+
+# -- Fail login if LDAP authentication fails? --
+security.ldap.fail.login=false
+
# -- should we allow x509 certificate login
security.login.cert.allow=true
@@ -70,4 +76,4 @@
security.login.cert.pattern=^(\\w*\\s?\\w*)\\W*.*$
# -- Hours after which EmailAdressVerification should expire
-email_verification.expire.hours=48
\ No newline at end of file
+email_verification.expire.hours=48
Modified: ofbiz/trunk/framework/security/entitydef/entitymodel.xml
URL: http://svn.apache.org/viewvc/ofbiz/trunk/framework/security/entitydef/entitymodel.xml?rev=669994&r1=669993&r2=669994&view=diff
==============================================================================
--- ofbiz/trunk/framework/security/entitydef/entitymodel.xml (original)
+++ ofbiz/trunk/framework/security/entitydef/entitymodel.xml Fri Jun 20 10:09:19 2008
@@ -75,6 +75,9 @@
<field name="lastTimeZone" type="id-long"></field>
<field name="disabledDateTime" type="date-time"></field>
<field name="successiveFailedLogins" type="numeric"></field>
+ <field name="userLdapDn" type="id-vlong-ne">
+ <description>The user's LDAP Distinguished Name - used for LDAP authentication</description>
+ </field>
<prim-key field="userLoginId"/>
</entity>
<entity entity-name="UserLoginPasswordHistory"
|