Skip to content
Permalink
Browse files Browse the repository at this point in the history
Fixed: UserLoginHistory failed the store operation with large passwor…
…d (OFBIZ-12287)

Backport 2aa68dc 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.elkabes@whitesourcesoftware.com> and Hagai Wechsler <hagai.wechsler@whitesourcesoftware.com> from white source software to raise the problem.
  • Loading branch information
nmalin committed Jul 28, 2021
1 parent 326e0f1 commit 2f5b8d3
Showing 1 changed file with 31 additions and 3 deletions.
Expand Up @@ -47,6 +47,7 @@
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;
Expand Down Expand Up @@ -334,8 +335,12 @@ public static Map<String, Object> userLogin(DispatchContext ctx, Map<String, ?>
}

// 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);
Expand All @@ -346,7 +351,6 @@ public static Map<String, Object> userLogin(DispatchContext ctx, Map<String, ?>
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) {
Expand Down Expand Up @@ -435,6 +439,30 @@ public static Map<String, Object> userLogin(DispatchContext ctx, Map<String, ?>
return result;
}

/**
* 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;
}

public static void createUserLoginPasswordHistory(GenericValue userLogin) throws GenericEntityException{
int passwordChangeHistoryLimit = 0;
Delegator delegator = userLogin.getDelegator();
Expand Down

0 comments on commit 2f5b8d3

Please sign in to comment.