This is an automated email from the ASF dual-hosted git repository.

mridulpathak pushed a commit to branch trunk
in repository https://gitbox.apache.org/repos/asf/ofbiz-framework.git


The following commit(s) were added to refs/heads/trunk by this push:
     new 6e857db582 Improved: Use SecureRandom to generate promo codes, captcha 
codes and generated IDs (OFBIZ-13636)
6e857db582 is described below

commit 6e857db582b875e0f8f7a0ea2ec65afcca0afd57
Author: Mridul Pathak <[email protected]>
AuthorDate: Sat Oct 3 13:54:33 2026 +0530

    Improved: Use SecureRandom to generate promo codes, captcha codes and 
generated IDs (OFBIZ-13636)
    
    Promo codes, captcha codes, the parameter map IDs stored in the session and 
the shortened paths were generated with the commons-lang RandomStringUtils, 
which is backed by java.util.Random and so produces values that can be 
predicted from earlier ones.
    
    StringUtil now provides randomString(int, String), which picks each 
character with SecureRandom, together with the ALPHABETIC_CHARS and 
ALPHANUMERIC_CHARS constants, and these four places use it instead. The 
character sets and lengths are unchanged.
    
    Thanks: Jacopo Cappellato (jacopoc) for suggesting the fix.
---
 .../apache/ofbiz/product/promo/PromoServices.java  |  9 +++----
 .../org/apache/ofbiz/base/util/StringUtil.java     | 29 ++++++++++++++++++++++
 .../java/org/apache/ofbiz/base/util/UtilHttp.java  |  3 +--
 .../java/org/apache/ofbiz/common/CommonEvents.java |  8 +++---
 .../apache/ofbiz/webapp/OfbizPathShortener.java    |  4 +--
 5 files changed, 40 insertions(+), 13 deletions(-)

diff --git 
a/applications/product/src/main/java/org/apache/ofbiz/product/promo/PromoServices.java
 
b/applications/product/src/main/java/org/apache/ofbiz/product/promo/PromoServices.java
index 884d33a4b5..f5cea59ce0 100644
--- 
a/applications/product/src/main/java/org/apache/ofbiz/product/promo/PromoServices.java
+++ 
b/applications/product/src/main/java/org/apache/ofbiz/product/promo/PromoServices.java
@@ -31,8 +31,8 @@ import java.util.List;
 import java.util.Locale;
 import java.util.Map;
 
-import org.apache.commons.lang.RandomStringUtils;
 import org.apache.ofbiz.base.util.Debug;
+import org.apache.ofbiz.base.util.StringUtil;
 import org.apache.ofbiz.base.util.UtilDateTime;
 import org.apache.ofbiz.base.util.UtilMisc;
 import org.apache.ofbiz.base.util.UtilProperties;
@@ -57,8 +57,7 @@ public class PromoServices {
 
     private static final String MODULE = PromoServices.class.getName();
     private static final String RESOURCE = "ProductUiLabels";
-    private static final char[] SMART_CHARS = {'A', 'B', 'C', 'D', 'E', 'F', 
'G', 'H', 'K', 'L', 'M', 'N', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W',
-            'X', 'Y', 'Z', '2', '3', '4', '5', '6', '7', '8', '9' };
+    private static final String SMART_CHARS = 
"ABCDEFGHKLMNPQRSTUVWXYZ23456789";
 
     public static Map<String, Object> 
createProductPromoCodeSet(DispatchContext dctx, Map<String, ? extends Object> 
context) {
         Locale locale = (Locale) context.get("locale");
@@ -87,9 +86,9 @@ public class PromoServices {
 
             while (!foundUniqueNewCode) {
                 if (useSmartLayout) {
-                    newPromoCodeId = RandomStringUtils.random(codeLength, 
SMART_CHARS);
+                    newPromoCodeId = StringUtil.randomString(codeLength, 
SMART_CHARS);
                 } else if (useNormalLayout) {
-                    newPromoCodeId = 
RandomStringUtils.randomAlphanumeric(codeLength);
+                    newPromoCodeId = StringUtil.randomString(codeLength, 
StringUtil.ALPHANUMERIC_CHARS);
                 }
                 GenericValue existingPromoCode = null;
                 try {
diff --git 
a/framework/base/src/main/java/org/apache/ofbiz/base/util/StringUtil.java 
b/framework/base/src/main/java/org/apache/ofbiz/base/util/StringUtil.java
index 1652e684ea..d43e156e58 100644
--- a/framework/base/src/main/java/org/apache/ofbiz/base/util/StringUtil.java
+++ b/framework/base/src/main/java/org/apache/ofbiz/base/util/StringUtil.java
@@ -21,6 +21,7 @@ package org.apache.ofbiz.base.util;
 import java.io.UnsupportedEncodingException;
 import java.net.URLDecoder;
 import java.net.URLEncoder;
+import java.security.SecureRandom;
 import java.util.Arrays;
 import java.util.Collection;
 import java.util.Collections;
@@ -52,6 +53,12 @@ public final class StringUtil {
     private static final String MODULE = StringUtil.class.getName();
     private static final Map<String, Pattern> SUBSTITUTION_PATTERN_MAP = 
createSubstitutionPatternMap();
     private static final Pattern SPECIAL_CHAR = 
Pattern.compile("\\&[\\#\\S&&[^\\&]]+\\;");
+    private static final SecureRandom SECURE_RANDOM = new SecureRandom();
+
+    /** The upper and lower case letters, to be used with {@link 
#randomString(int, String)} */
+    public static final String ALPHABETIC_CHARS = 
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
+    /** The upper and lower case letters and the digits, to be used with 
{@link #randomString(int, String)} */
+    public static final String ALPHANUMERIC_CHARS = ALPHABETIC_CHARS + 
"0123456789";
 
     private static Map<String, Pattern> createSubstitutionPatternMap() {
         Map<String, Pattern> substitutionPatternMap = new LinkedHashMap<>();  
// Preserve insertion order
@@ -71,6 +78,28 @@ public final class StringUtil {
         return value != null ? value.intern() : null;
     }
 
+    /**
+     * Generates a random string, using a cryptographically strong random 
number generator, so that the result
+     * cannot be predicted. Use this for codes and identifiers that have to be 
hard to guess.
+     * @param length the length of the string to generate
+     * @param chars the characters the string is made of, each one has the 
same probability to be picked
+     * @return a random string of the given length
+     * @throws IllegalArgumentException if the length is negative or there are 
no characters to choose from
+     */
+    public static String randomString(int length, String chars) {
+        if (length < 0) {
+            throw new IllegalArgumentException("The length must not be 
negative: " + length);
+        }
+        if (chars == null || chars.isEmpty()) {
+            throw new IllegalArgumentException("There must be characters to 
choose from");
+        }
+        StringBuilder sb = new StringBuilder(length);
+        for (int i = 0; i < length; i++) {
+            sb.append(chars.charAt(SECURE_RANDOM.nextInt(chars.length())));
+        }
+        return sb.toString();
+    }
+
     /**
      * Replaces all occurrences of oldString in mainString with newString
      * @param mainString The original string
diff --git 
a/framework/base/src/main/java/org/apache/ofbiz/base/util/UtilHttp.java 
b/framework/base/src/main/java/org/apache/ofbiz/base/util/UtilHttp.java
index b8495d060a..6720f4d8bc 100644
--- a/framework/base/src/main/java/org/apache/ofbiz/base/util/UtilHttp.java
+++ b/framework/base/src/main/java/org/apache/ofbiz/base/util/UtilHttp.java
@@ -69,7 +69,6 @@ import 
org.apache.commons.fileupload2.core.DiskFileItemFactory;
 import org.apache.commons.fileupload2.core.FileItem;
 import org.apache.commons.fileupload2.core.FileUploadException;
 import org.apache.commons.fileupload2.jakarta.JakartaServletFileUpload;
-import org.apache.commons.lang.RandomStringUtils;
 import org.apache.http.NameValuePair;
 import org.apache.http.client.utils.URLEncodedUtils;
 import org.apache.ofbiz.entity.Delegator;
@@ -1706,7 +1705,7 @@ public final class UtilHttp {
             session.setAttribute("_PARAM_MAP_STORE_", paramMapStore);
         }
         Map<String, Object> parameters = getParameterMap(request);
-        String paramMapId = RandomStringUtils.randomAlphanumeric(10);
+        String paramMapId = StringUtil.randomString(10, 
StringUtil.ALPHANUMERIC_CHARS);
         paramMapStore.put(paramMapId, parameters);
         return paramMapId;
     }
diff --git 
a/framework/common/src/main/java/org/apache/ofbiz/common/CommonEvents.java 
b/framework/common/src/main/java/org/apache/ofbiz/common/CommonEvents.java
index a057615754..d8e9ad0f5a 100644
--- a/framework/common/src/main/java/org/apache/ofbiz/common/CommonEvents.java
+++ b/framework/common/src/main/java/org/apache/ofbiz/common/CommonEvents.java
@@ -42,12 +42,12 @@ import jakarta.servlet.http.HttpServletRequest;
 import jakarta.servlet.http.HttpServletResponse;
 import jakarta.servlet.http.HttpSession;
 
-import org.apache.commons.lang.RandomStringUtils;
 import org.apache.commons.lang.StringUtils;
 import org.apache.ofbiz.base.lang.JSON;
 import org.apache.ofbiz.base.location.ComponentLocationResolver;
 import org.apache.ofbiz.base.util.Debug;
 import org.apache.ofbiz.base.util.GeneralException;
+import org.apache.ofbiz.base.util.StringUtil;
 import org.apache.ofbiz.base.util.UtilGenerics;
 import org.apache.ofbiz.base.util.UtilHttp;
 import org.apache.ofbiz.base.util.UtilProperties;
@@ -285,8 +285,8 @@ public class CommonEvents {
             final int height = Integer.parseInt(captchaSizeConfigs[1]);
             final int width = Integer.parseInt(captchaSizeConfigs[2]);
             final int charsToPrint = 
UtilProperties.getPropertyAsInteger("captcha", "captcha.code_length", 6);
-            final char[] availableChars = EntityUtilProperties
-                    .getPropertyValue("captcha", "captcha.characters", 
delegator).toCharArray();
+            final String availableChars = EntityUtilProperties
+                    .getPropertyValue("captcha", "captcha.characters", 
delegator);
 
             // It is possible to pass the font size, image width and height 
with the request as well
             Color backgroundColor = Color.gray;
@@ -319,7 +319,7 @@ public class CommonEvents {
             int maxAdvance = fontMetrics.getMaxAdvance();
             int fontHeight = fontMetrics.getHeight();
 
-            String captchaCode = RandomStringUtils.random(6, availableChars);
+            String captchaCode = StringUtil.randomString(6, availableChars);
 
             float spaceForLetters = -horizMargin * 2 + width;
             float spacePerChar = spaceForLetters / (charsToPrint - 1.0f);
diff --git 
a/framework/webapp/src/main/java/org/apache/ofbiz/webapp/OfbizPathShortener.java
 
b/framework/webapp/src/main/java/org/apache/ofbiz/webapp/OfbizPathShortener.java
index dbe84a6242..e33daf6775 100644
--- 
a/framework/webapp/src/main/java/org/apache/ofbiz/webapp/OfbizPathShortener.java
+++ 
b/framework/webapp/src/main/java/org/apache/ofbiz/webapp/OfbizPathShortener.java
@@ -20,8 +20,8 @@ package org.apache.ofbiz.webapp;
 
 import java.util.Map;
 import javax.transaction.Transaction;
-import org.apache.commons.lang.RandomStringUtils;
 import org.apache.ofbiz.base.crypto.HashCrypt;
+import org.apache.ofbiz.base.util.StringUtil;
 import org.apache.ofbiz.base.util.UtilDateTime;
 import org.apache.ofbiz.base.util.UtilProperties;
 import org.apache.ofbiz.entity.Delegator;
@@ -112,7 +112,7 @@ public class OfbizPathShortener {
      */
     private static String generate() {
         int shortenerSize = UtilProperties.getPropertyAsInteger("security", 
"path.shortener.size", 10);
-        return RandomStringUtils.randomAlphabetic(shortenerSize);
+        return StringUtil.randomString(shortenerSize, 
StringUtil.ALPHABETIC_CHARS);
     }
 
     /**

Reply via email to