This is an automated email from the ASF dual-hosted git repository.
cgivre pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/drill.git
The following commit(s) were added to refs/heads/master by this push:
new 6564098fd3 DRILL-8499: new util for creating random strings (#2918)
6564098fd3 is described below
commit 6564098fd310ee488c14783a70de4e5fc95abaa0
Author: PJ Fanning <[email protected]>
AuthorDate: Wed Jun 26 16:32:04 2024 +0100
DRILL-8499: new util for creating random strings (#2918)
---
LICENSE | 9 +
.../drill/yarn/appMaster/http/WebServer.java | 4 +-
.../rest/ssl/SslContextFactoryConfigurator.java | 4 +-
.../drill/exec/util/SecureRandomStringUtils.java | 216 +++++++++++++++++++++
4 files changed, 229 insertions(+), 4 deletions(-)
diff --git a/LICENSE b/LICENSE
index d4d163861e..86f2a884bd 100644
--- a/LICENSE
+++ b/LICENSE
@@ -201,6 +201,15 @@
See the License for the specific language governing permissions and
limitations under the License.
+---------------------------------------------------------------------------
+This product includes code from Apache Commons Lang3, licensed under the
+Apache License 2.0.
+
+Apache Commons Lang
+Copyright 2001-2024 The Apache Software Foundation
+
+-
exec/java-exec/src/main/java/org/apache/drill/exec/util/SecureRandomStringUtils.java
+
---------------------------------------------------------------------------
This product includes source licensed under the MIT license.
diff --git
a/drill-yarn/src/main/java/org/apache/drill/yarn/appMaster/http/WebServer.java
b/drill-yarn/src/main/java/org/apache/drill/yarn/appMaster/http/WebServer.java
index bc7ae1ec72..74861a7b9a 100644
---
a/drill-yarn/src/main/java/org/apache/drill/yarn/appMaster/http/WebServer.java
+++
b/drill-yarn/src/main/java/org/apache/drill/yarn/appMaster/http/WebServer.java
@@ -37,12 +37,12 @@ import javax.servlet.http.HttpSession;
import javax.servlet.http.HttpSessionEvent;
import javax.servlet.http.HttpSessionListener;
-import org.apache.commons.lang3.RandomStringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.drill.exec.server.rest.CsrfTokenInjectFilter;
import org.apache.drill.exec.server.rest.CsrfTokenValidateFilter;
import com.google.common.collect.ImmutableSet;
+import org.apache.drill.exec.util.SecureRandomStringUtils;
import org.apache.drill.yarn.appMaster.Dispatcher;
import org.apache.drill.yarn.core.DrillOnYarnConfig;
import org.bouncycastle.asn1.x500.X500NameBuilder;
@@ -428,7 +428,7 @@ public class WebServer implements AutoCloseable {
certificate.verify(certificate.getPublicKey());
// Generate a random password for keystore protection
- final String keyStorePasswd = RandomStringUtils.random(20);
+ final String keyStorePasswd = SecureRandomStringUtils.random(20);
final KeyStore keyStore = KeyStore.getInstance("JKS");
keyStore.load(null, null);
keyStore.setKeyEntry("DrillAutoGeneratedCert", keyPair.getPrivate(),
diff --git
a/exec/java-exec/src/main/java/org/apache/drill/exec/server/rest/ssl/SslContextFactoryConfigurator.java
b/exec/java-exec/src/main/java/org/apache/drill/exec/server/rest/ssl/SslContextFactoryConfigurator.java
index 89421c6919..bbd6897a0c 100644
---
a/exec/java-exec/src/main/java/org/apache/drill/exec/server/rest/ssl/SslContextFactoryConfigurator.java
+++
b/exec/java-exec/src/main/java/org/apache/drill/exec/server/rest/ssl/SslContextFactoryConfigurator.java
@@ -17,11 +17,11 @@
*/
package org.apache.drill.exec.server.rest.ssl;
-import org.apache.commons.lang3.RandomStringUtils;
import org.apache.drill.common.config.DrillConfig;
import org.apache.drill.exec.ExecConstants;
import org.apache.drill.exec.ssl.SSLConfig;
import org.apache.drill.exec.ssl.SSLConfigBuilder;
+import org.apache.drill.exec.util.SecureRandomStringUtils;
import org.bouncycastle.asn1.x500.X500NameBuilder;
import org.bouncycastle.asn1.x500.style.BCStyle;
import org.bouncycastle.cert.X509v3CertificateBuilder;
@@ -202,7 +202,7 @@ public class SslContextFactoryConfigurator {
certificate.verify(certificate.getPublicKey());
// Generate a random password for keystore protection
- final String keyStorePasswd = RandomStringUtils.random(20);
+ final String keyStorePasswd = SecureRandomStringUtils.random(20);
final KeyStore keyStore = KeyStore.getInstance("JKS");
keyStore.load(null, null);
keyStore.setKeyEntry("DrillAutoGeneratedCert", keyPair.getPrivate(),
diff --git
a/exec/java-exec/src/main/java/org/apache/drill/exec/util/SecureRandomStringUtils.java
b/exec/java-exec/src/main/java/org/apache/drill/exec/util/SecureRandomStringUtils.java
new file mode 100644
index 0000000000..ea0eebc893
--- /dev/null
+++
b/exec/java-exec/src/main/java/org/apache/drill/exec/util/SecureRandomStringUtils.java
@@ -0,0 +1,216 @@
+/*
+ * 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.apache.drill.exec.util;
+
+import org.apache.commons.lang3.StringUtils;
+
+import java.security.NoSuchAlgorithmException;
+import java.security.SecureRandom;
+
+/**
+ * Based on Commons Lang3 RandomStringUtils, but with a SecureRandom.
+ *
+ * For internal Apache Drill use only.
+ */
+public class SecureRandomStringUtils {
+ // Based on
https://github.com/apache/commons-lang/blob/5e07d873e6b45714d29bf47634adffa3b5aef098/src/main/java/org/apache/commons/lang3/RandomStringUtils.java
+
+ private static SecureRandom RANDOM_INSTANCE;
+
+ private static SecureRandom random() {
+ if (RANDOM_INSTANCE != null) {
+ return RANDOM_INSTANCE;
+ }
+ try {
+ RANDOM_INSTANCE = SecureRandom.getInstanceStrong();
+ return RANDOM_INSTANCE;
+ } catch (NoSuchAlgorithmException e) {
+ throw new IllegalStateException("Cannot create
SecureRandom.getInstanceStrong()", e);
+ }
+ }
+
+ // Random
+ /**
+ * Creates a random string whose length is the number of characters
+ * specified.
+ *
+ * <p>Characters will be chosen from the set of all characters.</p>
+ *
+ * @param count the length of random string to create
+ * @return the random string
+ * @throws IllegalArgumentException if {@code count} < 0.
+ */
+ public static String random(final int count) {
+ return random(count, false, false);
+ }
+
+ /**
+ * Creates a random string whose length is the number of characters
+ * specified.
+ *
+ * <p>Characters will be chosen from the set of alpha-numeric
+ * characters as indicated by the arguments.</p>
+ *
+ * @param count the length of random string to create
+ * @param letters if {@code true}, generated string may include
+ * alphabetic characters
+ * @param numbers if {@code true}, generated string may include
+ * numeric characters
+ * @return the random string
+ * @throws IllegalArgumentException if {@code count} < 0.
+ */
+ private static String random(final int count, final boolean letters, final
boolean numbers) {
+ return random(count, 0, 0, letters, numbers);
+ }
+
+ /**
+ * Creates a random string whose length is the number of characters
+ * specified.
+ *
+ * <p>Characters will be chosen from the set of alpha-numeric
+ * characters as indicated by the arguments.</p>
+ *
+ * @param count the length of random string to create
+ * @param start the position in set of chars to start at
+ * @param end the position in set of chars to end before
+ * @param letters if {@code true}, generated string may include
+ * alphabetic characters
+ * @param numbers if {@code true}, generated string may include
+ * numeric characters
+ * @return the random string
+ * @throws IllegalArgumentException if {@code count} < 0.
+ */
+ private static String random(final int count, final int start, final int
end, final boolean letters, final boolean numbers) {
+ return random(count, start, end, letters, numbers, null, random());
+ }
+
+ /**
+ * Creates a random string based on a variety of options, using
+ * supplied source of randomness.
+ *
+ * <p>If start and end are both {@code 0}, start and end are set
+ * to {@code ' '} and {@code 'z'}, the ASCII printable
+ * characters, will be used, unless letters and numbers are both
+ * {@code false}, in which case, start and end are set to
+ * {@code 0} and {@link Character#MAX_CODE_POINT}.
+ *
+ * <p>If set is not {@code null}, characters between start and
+ * end are chosen.</p>
+ *
+ * <p>This method accepts a user-supplied {@link SecureRandom}
+ * instance to use as a source of randomness. By seeding a single
+ * {@link SecureRandom} instance with a fixed seed and using it for each
call,
+ * the same random sequence of strings can be generated repeatedly
+ * and predictably.</p>
+ *
+ * @param count the length of random string to create
+ * @param start the position in set of chars to start at (inclusive)
+ * @param end the position in set of chars to end before (exclusive)
+ * @param letters if {@code true}, generated string may include
+ * alphabetic characters
+ * @param numbers if {@code true}, generated string may include
+ * numeric characters
+ * @param chars the set of chars to choose randoms from, must not be empty.
+ * If {@code null}, then it will use the set of all chars.
+ * @param random a source of randomness.
+ * @return the random string
+ * @throws ArrayIndexOutOfBoundsException if there are not
+ * {@code (end - start) + 1} characters in the set array.
+ * @throws IllegalArgumentException if {@code count} < 0 or the provided
chars array is empty.
+ */
+ private static String random(int count, int start, int end, final boolean
letters, final boolean numbers,
+ final char[] chars, final SecureRandom random) {
+ if (count == 0) {
+ return StringUtils.EMPTY;
+ }
+ if (count < 0) {
+ throw new IllegalArgumentException("Requested random string length " +
count + " is less than 0.");
+ }
+ if (chars != null && chars.length == 0) {
+ throw new IllegalArgumentException("The chars array must not be empty");
+ }
+
+ if (start == 0 && end == 0) {
+ if (chars != null) {
+ end = chars.length;
+ } else if (!letters && !numbers) {
+ end = Character.MAX_CODE_POINT;
+ } else {
+ end = 'z' + 1;
+ start = ' ';
+ }
+ } else if (end <= start) {
+ throw new IllegalArgumentException("Parameter end (" + end + ") must be
greater than start (" + start + ")");
+ }
+
+ final int zeroDigitAscii = 48;
+ final int firstLetterAscii = 65;
+
+ if (chars == null && (numbers && end <= zeroDigitAscii
+ || letters && end <= firstLetterAscii)) {
+ throw new IllegalArgumentException("Parameter end (" + end + ") must be
greater then (" + zeroDigitAscii + ") for generating digits " +
+ "or greater then (" + firstLetterAscii + ") for generating
letters.");
+ }
+
+ final StringBuilder builder = new StringBuilder(count);
+ final int gap = end - start;
+
+ while (count-- != 0) {
+ final int codePoint;
+ if (chars == null) {
+ codePoint = random.nextInt(gap) + start;
+
+ switch (Character.getType(codePoint)) {
+ case Character.UNASSIGNED:
+ case Character.PRIVATE_USE:
+ case Character.SURROGATE:
+ count++;
+ continue;
+ }
+
+ } else {
+ codePoint = chars[random.nextInt(gap) + start];
+ }
+
+ final int numberOfChars = Character.charCount(codePoint);
+ if (count == 0 && numberOfChars > 1) {
+ count++;
+ continue;
+ }
+
+ if (letters && Character.isLetter(codePoint)
+ || numbers && Character.isDigit(codePoint)
+ || !letters && !numbers) {
+ builder.appendCodePoint(codePoint);
+
+ if (numberOfChars == 2) {
+ count--;
+ }
+
+ } else {
+ count++;
+ }
+ }
+ return builder.toString();
+ }
+
+ private SecureRandomStringUtils() {
+ // empty
+ }
+
+}