You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@jmeter.apache.org by fs...@apache.org on 2020/12/06 10:36:48 UTC

[jmeter] 03/04: Keystore password not reset on reload

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

fschumacher pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/jmeter.git

commit 6701514938f743d864956e4564db13776f7a1f02
Author: Felix Schumacher <fe...@internetallee.de>
AuthorDate: Sun Dec 6 11:29:43 2020 +0100

    Keystore password not reset on reload
    
    Bugzilla Id: 64955
---
 .../java/org/apache/jmeter/util/SSLManager.java    | 94 ++++++++++++++--------
 xdocs/changes.xml                                  |  1 +
 2 files changed, 61 insertions(+), 34 deletions(-)

diff --git a/src/core/src/main/java/org/apache/jmeter/util/SSLManager.java b/src/core/src/main/java/org/apache/jmeter/util/SSLManager.java
index 067ef5c..6b491eb 100644
--- a/src/core/src/main/java/org/apache/jmeter/util/SSLManager.java
+++ b/src/core/src/main/java/org/apache/jmeter/util/SSLManager.java
@@ -17,18 +17,24 @@
 
 package org.apache.jmeter.util;
 
-import java.io.BufferedInputStream;
 import java.io.File;
 import java.io.FileInputStream;
+import java.io.IOException;
 import java.io.InputStream;
 import java.net.HttpURLConnection;
 import java.security.KeyStore;
+import java.security.KeyStoreException;
+import java.security.NoSuchAlgorithmException;
 import java.security.Provider;
 import java.security.Security;
+import java.security.UnrecoverableKeyException;
+import java.security.cert.CertificateException;
 import java.util.Arrays;
 import java.util.Locale;
 
+import javax.swing.JLabel;
 import javax.swing.JOptionPane;
+import javax.swing.JPanel;
 import javax.swing.JPasswordField;
 
 import org.apache.commons.lang3.Validate;
@@ -37,6 +43,8 @@ import org.apache.jmeter.util.keystore.JmeterKeyStore;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+import net.miginfocom.swing.MigLayout;
+
 /**
  * The SSLManager handles the KeyStore information for JMeter. Basically, it
  * handles all the logic for loading and initializing all the JSSE parameters
@@ -75,7 +83,7 @@ public abstract class SSLManager {
     private volatile boolean truststoreLoaded=false;
 
     /** Have the password available */
-    protected String defaultpw = System.getProperty(KEY_STORE_PASSWORD);
+    protected volatile String defaultpw = System.getProperty(KEY_STORE_PASSWORD);
 
     private int keystoreAliasStartIndex;
 
@@ -130,20 +138,16 @@ public abstract class SSLManager {
               // The string 'NONE' is used for the keystore location when using PKCS11
               // https://docs.oracle.com/javase/8/docs/technotes/guides/security/p11guide.html#JSSE
               if ("NONE".equalsIgnoreCase(fileName)) {
-                 this.keyStore.load(null, Validate.notNull(getPassword(), "Password should not be null"));
+                 retryLoadKeys(null, false);
                  log.info("Total of {} aliases loaded OK from PKCS11", keyStore.getAliasCount());
               } else {
                  File initStore = new File(fileName);
                  if (fileName.length() > 0 && initStore.exists()) {
-                    try (InputStream fis = new FileInputStream(initStore);
-                            InputStream fileInputStream = new BufferedInputStream(fis)) {
-                        this.keyStore.load(fileInputStream, getPassword());
-                        if (log.isInfoEnabled()) {
-                            log.info(
-                                    "Total of {} aliases loaded OK from keystore",
-                                    keyStore.getAliasCount());
-                        }
-                    }
+                     retryLoadKeys(initStore, true);
+                     if (log.isInfoEnabled()) {
+                         log.info("Total of {} aliases loaded OK from keystore {}",
+                                 keyStore.getAliasCount(), fileName);
+                     }
                  } else {
                     log.warn("Keystore file not found, loading empty keystore");
                     this.defaultpw = ""; // Ensure not null
@@ -162,6 +166,29 @@ public abstract class SSLManager {
         return this.keyStore;
     }
 
+    private void retryLoadKeys(File initStore, boolean allowEmptyPassword) throws NoSuchAlgorithmException, CertificateException, IOException, KeyStoreException,
+            UnrecoverableKeyException {
+        for (int i=0; i<3; i++) {
+            String password = getPassword();
+            if (!allowEmptyPassword) {
+                Validate.notNull(password, "Password for keystore must not be null");
+            }
+            try {
+                if (initStore == null) {
+                    this.keyStore.load(null, password);
+                } else {
+                    try (InputStream fis = new FileInputStream(initStore)) {
+                        this.keyStore.load(fis, password);
+                    }
+                }
+                return;
+            } catch (IOException e) {
+                log.debug("Could not load keystore. Wrong password for keystore?", e);
+            }
+            this.defaultpw = null;
+        }
+    }
+
     /*
      * The password can be defined as a property; this dialogue is provided to allow it
      * to be entered at run-time.
@@ -171,26 +198,26 @@ public abstract class SSLManager {
         if (null == password) {
             final GuiPackage guiInstance = GuiPackage.getInstance();
             if (guiInstance != null) {
-                synchronized (this) { // TODO is sync really needed?
-                  JPasswordField pwf = new JPasswordField(64);
-                  pwf.setEchoChar('*');
-                  int choice = JOptionPane.showConfirmDialog(
-                          guiInstance.getMainFrame(),
-                          pwf,
-                          JMeterUtils.getResString("ssl_pass_prompt"),
-                          JOptionPane.OK_CANCEL_OPTION,
-                          JOptionPane.PLAIN_MESSAGE);
-                  if (choice == JOptionPane.OK_OPTION) {
-                     char[] pwchars = pwf.getPassword();
-                     this.defaultpw = new String(pwchars);
-                     Arrays.fill(pwchars, '*');
-                  }
-                  System.setProperty(KEY_STORE_PASSWORD, this.defaultpw);
-                  password = this.defaultpw;
-               }
-            } else {
-               log.warn("No password provided, and no GUI present so cannot prompt");
+                JPanel panel = new JPanel(new MigLayout("fillx, wrap 2", "[][fill, grow]"));
+                JLabel passwordLabel = new JLabel("Password: ");
+                JPasswordField pwf = new JPasswordField(64);
+                pwf.setEchoChar('*');
+                passwordLabel.setLabelFor(pwf);
+                panel.add(passwordLabel);
+                panel.add(pwf);
+                int choice = JOptionPane.showConfirmDialog(guiInstance.getMainFrame(), panel,
+                        JMeterUtils.getResString("ssl_pass_prompt"), JOptionPane.OK_CANCEL_OPTION,
+                        JOptionPane.PLAIN_MESSAGE);
+                if (choice == JOptionPane.OK_OPTION) {
+                    char[] pwchars = pwf.getPassword();
+                    this.defaultpw = new String(pwchars);
+                    Arrays.fill(pwchars, '*');
+                }
+                System.setProperty(KEY_STORE_PASSWORD, this.defaultpw);
+                password = this.defaultpw;
             }
+        } else {
+            log.warn("No password provided, and no GUI present so cannot prompt");
         }
         return password;
     }
@@ -239,9 +266,8 @@ public abstract class SSLManager {
                 File initStore = new File(fileName);
 
                 if (initStore.exists()) {
-                    try (InputStream fis = new FileInputStream(initStore);
-                            InputStream fileInputStream = new BufferedInputStream(fis)) {
-                        this.trustStore.load(fileInputStream, null);
+                    try (InputStream fis = new FileInputStream(initStore)) {
+                        this.trustStore.load(fis, null);
                         log.info("Truststore loaded OK from file");
                     }
                 } else {
diff --git a/xdocs/changes.xml b/xdocs/changes.xml
index 0b6ee08..13e7d06 100644
--- a/xdocs/changes.xml
+++ b/xdocs/changes.xml
@@ -122,6 +122,7 @@ Summary
 
 <h3>HTTP Samplers and Test Script Recorder</h3>
 <ul>
+  <li><bug>64955</bug>Keystore password not reset on reload</li>
 </ul>
 
 <h3>Other Samplers</h3>