This is an automated email from the ASF dual-hosted git repository. nmalin pushed a commit to branch release18.12 in repository https://gitbox.apache.org/repos/asf/ofbiz-framework.git
commit 7a55ea89066238ec82329c9fc2f6de98af616810 Author: Nicolas Malin <nicolas.ma...@nereide.fr> AuthorDate: Wed Jul 28 11:59:03 2021 +0200 Fixed: UserLoginHistory failed the store operation with large password (OFBIZ-12287) Backport 2aa68dc4de8892e8a7cbb38c10a3a3dd65d233e5 from trunk When you have a user with long password (greater than 256 characters) present in OFBiz and you try to log with, OFBiz return a long error message with sensitive information due to exceeding value size to store on the field UserLoginHistory.passwordUsed. To solve this we don't return any information on the genericValue that failed and analyze the field passwordUsed to escape the case where the password set to login is create than the database field capacity. Thanks to Daniel Elkabes <daniel.elka...@whitesourcesoftware.com> and Hagai Wechsler <hagai.wechs...@whitesourcesoftware.com> from white source software to raise the problem. --- .../apache/ofbiz/common/login/LoginServices.java | 38 +++++++++++++++++++--- 1 file changed, 33 insertions(+), 5 deletions(-) diff --git a/framework/common/src/main/java/org/apache/ofbiz/common/login/LoginServices.java b/framework/common/src/main/java/org/apache/ofbiz/common/login/LoginServices.java index 5d032fb..74ac8ff 100644 --- a/framework/common/src/main/java/org/apache/ofbiz/common/login/LoginServices.java +++ b/framework/common/src/main/java/org/apache/ofbiz/common/login/LoginServices.java @@ -51,6 +51,7 @@ import org.apache.ofbiz.entity.condition.EntityCondition; import org.apache.ofbiz.entity.condition.EntityFunction; import org.apache.ofbiz.entity.condition.EntityOperator; import org.apache.ofbiz.entity.model.ModelEntity; +import org.apache.ofbiz.entity.model.ModelField; import org.apache.ofbiz.entity.transaction.GenericTransactionException; import org.apache.ofbiz.entity.transaction.TransactionUtil; import org.apache.ofbiz.entity.util.EntityListIterator; @@ -351,8 +352,12 @@ public class LoginServices { } // ONLY save the password if it was incorrect - if ("N".equals(successfulLogin) && !"false".equals(EntityUtilProperties.getPropertyValue("security", "store.login.history.incorrect.password", delegator))) { - ulhCreateMap.put("passwordUsed", password); + // we will check in the hash size isn't too huge for the store other wise store a fix string + if ("N".equals(successfulLogin) && !"false".equals(EntityUtilProperties.getPropertyValue("security", + "store.login.history.incorrect.password", delegator))) { + ulhCreateMap.put("passwordUsed", isGivenPasswordCanBeStored(delegator, password) + ? " TOO LONG FOR STORAGE " + : password); } delegator.create("UserLoginHistory", ulhCreateMap); @@ -363,7 +368,6 @@ public class LoginServices { if (doStore) { geeErrMsg += " and updating login status to reset hasLoggedOut, unsuccessful login count, etc."; } - geeErrMsg += ": " + e.toString(); try { TransactionUtil.rollback(beganTransaction, geeErrMsg, e); } catch (GenericTransactionException e2) { @@ -453,6 +457,30 @@ public class LoginServices { } /** + * To escape an exception when the password store due to limitation size for passwordUsed field, we analyse if it's possible. + * @param delegator + * @param password + * @return + * @throws GenericEntityException + */ + private static boolean isGivenPasswordCanBeStored(Delegator delegator, String password) + throws GenericEntityException { + ModelEntity modelEntityUserLoginHistory = delegator.getModelEntity("UserLoginHistory"); + ModelField passwordUsedField = modelEntityUserLoginHistory.getField("passwordUsed"); + int maxPasswordSize = delegator.getEntityFieldType( + modelEntityUserLoginHistory, + passwordUsedField.getType()).stringLength(); + int passwordUsedCurrentSize = password.length(); + + // if the field is encrypted, we check the size of the hashed result + ModelField.EncryptMethod encryptMethod = passwordUsedField.getEncryptMethod(); + if (encryptMethod.isEncrypted()) { + passwordUsedCurrentSize = delegator.encryptFieldValue("UserLoginHistory", encryptMethod, password).toString().length(); + } + return passwordUsedCurrentSize > maxPasswordSize; + } + + /** * Login service to authenticate a username without password, storing history * * @return Map of results including (userLogin) GenericValue object @@ -593,7 +621,7 @@ public class LoginServices { .orderBy("-fromDate") .cursorScrollInsensitive(); Timestamp nowTimestamp = UtilDateTime.nowTimestamp(); - + try (EntityListIterator eli = eq.queryIterator()) { GenericValue pwdHist; if ((pwdHist = eli.next()) != null) { @@ -645,7 +673,7 @@ public class LoginServices { String questionEnumId = (String) context.get("securityQuestion"); String securityAnswer = (String) context.get("securityAnswer"); - + // security: don't create a user login if the specified partyId (if not empty) already exists // unless the logged in user has permission to do so (same partyId or PARTYMGR_CREATE) if (UtilValidate.isNotEmpty(partyId)) {