This is an automated email from the ASF dual-hosted git repository. schultz pushed a commit to branch 9.0.x in repository https://gitbox.apache.org/repos/asf/tomcat.git
The following commit(s) were added to refs/heads/9.0.x by this push: new b7b89e16a9 Allow digest.sh to accept password from a file or from stdin b7b89e16a9 is described below commit b7b89e16a90d1dd9b9c867fed36ef4cfb868832b Author: Christopher Schultz <ch...@christopherschultz.net> AuthorDate: Mon Mar 11 10:42:57 2024 -0400 Allow digest.sh to accept password from a file or from stdin This fixes https://bz.apache.org/bugzilla/show_bug.cgi?id=57130 --- java/org/apache/catalina/realm/RealmBase.java | 73 ++++++++++++++++++++++++--- webapps/docs/changelog.xml | 4 ++ webapps/docs/realm-howto.xml | 5 +- 3 files changed, 74 insertions(+), 8 deletions(-) diff --git a/java/org/apache/catalina/realm/RealmBase.java b/java/org/apache/catalina/realm/RealmBase.java index afc60b25a9..a81bd63e7a 100644 --- a/java/org/apache/catalina/realm/RealmBase.java +++ b/java/org/apache/catalina/realm/RealmBase.java @@ -29,6 +29,10 @@ import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.Locale; +import java.io.File; +import java.io.BufferedReader; +import java.io.FileReader; +import java.io.InputStreamReader; import javax.servlet.annotation.ServletSecurity.TransportGuarantee; import javax.servlet.http.HttpServletResponse; @@ -1317,6 +1321,9 @@ public abstract class RealmBase extends LifecycleMBeanBase implements Realm { * specified, the default for the CredentialHandler will be used.</li> * <li><b>-h</b> - The fully qualified class name of the CredentialHandler to use. If not specified, the built-in * handlers will be tested in turn and the first one to accept the specified algorithm will be used.</li> + * <li><b>-f</b> - The name of the file that contains passwords to encode. Each + * line in the file should contain only one password. Using this + * option ignores other password input.</li> * </ul> * <p> * This generation process currently supports the following CredentialHandlers, the correct one being selected based @@ -1329,7 +1336,7 @@ public abstract class RealmBase extends LifecycleMBeanBase implements Realm { * * @param args The parameters passed on the command line */ - public static void main(String args[]) { + public static void main(String args[]) throws IOException { // Use negative values since null is not an option to indicate 'not set' int saltLength = -1; @@ -1341,6 +1348,8 @@ public abstract class RealmBase extends LifecycleMBeanBase implements Realm { // the command line String algorithm = null; String handlerClassName = null; + // File name to read password(s) from + String passwordFile = null; if (args.length == 0) { usage(); @@ -1348,8 +1357,12 @@ public abstract class RealmBase extends LifecycleMBeanBase implements Realm { } int argIndex = 0; + // Boolean to check and see if we've reached the -- option + boolean endOfList = false; - while (args.length > argIndex + 2 && args[argIndex].length() == 2 && args[argIndex].charAt(0) == '-') { + // Note: Reducing args.length requirement to argIndex+1 so that -f works and ignores + // trailing words + while (args.length > argIndex + 1 && args[argIndex].length() == 2 && args[argIndex].charAt(0) == '-' && !endOfList) { switch (args[argIndex].charAt(1)) { case 'a': { algorithm = args[argIndex + 1]; @@ -1375,6 +1388,18 @@ public abstract class RealmBase extends LifecycleMBeanBase implements Realm { handlerClassName = args[argIndex + 1]; break; } + case 'f': { + passwordFile = args[argIndex + 1]; + break; + } + case '-': { + // When encountering -- option don't parse anything else as an option + endOfList = true; + // The -- opt doesn't take an argument, decrement the argIndex so that it parses + // all remaining args + argIndex--; + break; + } default: { usage(); return; @@ -1434,18 +1459,52 @@ public abstract class RealmBase extends LifecycleMBeanBase implements Realm { if (keyLength > 0) { IntrospectionUtils.setProperty(handler, "keyLength", Integer.toString(keyLength)); } + if (passwordFile != null) { + // If the file name is used, then don't parse the trailing arguments + argIndex = args.length; + + try { + BufferedReader br; + // Special case, allow for - filename to refer to stdin + if (passwordFile.equals("-")) { + br = new BufferedReader(new InputStreamReader(System.in)); + } else { + br = new BufferedReader(new FileReader(passwordFile)); + } + String line; + while ((line = br.readLine()) != null) { + // Mutate each line in the file, or stdin + mutateCredential(line, handler); + } + } catch (Exception e) { + // A FileNotFound is the likely exception here and self-explanatory. Softly + // reporting it and exit 1 so that you can tell it failed from the command line. + if (e instanceof java.io.FileNotFoundException) { + System.err.println("cannot stat '" + passwordFile + + "': No such file or directory"); + // Not sure if using an exit here is OK, but I wanted to return a code that + // showed failure. + System.exit(1); + } else { + throw e; + } + } + } for (; argIndex < args.length; argIndex++) { - String credential = args[argIndex]; - System.out.print(credential + ":"); - System.out.println(handler.mutate(credential)); + mutateCredential(args[argIndex], handler); } } + private static void mutateCredential(String credential, CredentialHandler handler) { + System.out.print(credential + ":"); + System.out.println(handler.mutate(credential)); + } private static void usage() { - System.out.println("Usage: RealmBase [-a <algorithm>] [-e <encoding>] " + - "[-i <iterations>] [-s <salt-length>] [-k <key-length>] " + "[-h <handler-class-name>] <credentials>"); + System.out.println("Usage: RealmBase [-a <algorithm>] [-e <encoding>]" + + " [-i <iterations>] [-s <salt-length>] [-k <key-length>]" + + " [-h <handler-class-name>] | <XX credentials>"); } diff --git a/webapps/docs/changelog.xml b/webapps/docs/changelog.xml index d8842e1476..f4c5e63ea5 100644 --- a/webapps/docs/changelog.xml +++ b/webapps/docs/changelog.xml @@ -193,6 +193,10 @@ <add> Improvements to Japanese translations by tak7iji. (markt) </add> + <fix> + <bug>57130</bug>: Allow digest.(sh|bat) to accept password from a file + or stdin. (csutherl/schultz) + </fix> </changelog> </subsection> </section> diff --git a/webapps/docs/realm-howto.xml b/webapps/docs/realm-howto.xml index 11c9960349..04d91d5897 100644 --- a/webapps/docs/realm-howto.xml +++ b/webapps/docs/realm-howto.xml @@ -226,7 +226,7 @@ simplified to <code>{digest}</code>.</p> <p>The full syntax of <code>CATALINA_HOME/bin/digest.[bat|sh]</code> is:</p> <source>CATALINA_HOME/bin/digest.[bat|sh] [-a <algorithm>] [-e <encoding>] [-i <iterations>] [-s <salt-length>] [-k <key-length>] - [-h <handler-class-name>] <credentials> + [-h <handler-class-name>] [-f <password-file> | <credentials>] </source> <ul> <li><b>-a</b> - The algorithm to use to generate the stored @@ -251,6 +251,9 @@ simplified to <code>{digest}</code>.</p> tested in turn (MessageDigestCredentialHandler then SecretKeyCredentialHandler) and the first one to accept the specified algorithm will be used.</li> +<li><b>-f</b> - The name of the file that contains passwords to encode. Each + line in the file should contain only one password. Using this + option ignores other password input.</li> </ul> </subsection> --------------------------------------------------------------------- To unsubscribe, e-mail: dev-unsubscr...@tomcat.apache.org For additional commands, e-mail: dev-h...@tomcat.apache.org