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" |
Free forum by Nabble | Edit this page |