diff --git a/api-test/backend/src/main/java/io/metersphere/api/dto/definition/request/ElementUtil.java b/api-test/backend/src/main/java/io/metersphere/api/dto/definition/request/ElementUtil.java index 4d9e4e4ddf..8d4b315e3e 100644 --- a/api-test/backend/src/main/java/io/metersphere/api/dto/definition/request/ElementUtil.java +++ b/api-test/backend/src/main/java/io/metersphere/api/dto/definition/request/ElementUtil.java @@ -620,9 +620,11 @@ public class ElementUtil { return processor; } - public static void setBaseParams(TestElement sampler, MsTestElement parent, ParameterConfig config, String id, String indexPath) { + public static String setBaseParams(TestElement sampler, MsTestElement parent, ParameterConfig config, String id, String indexPath) { sampler.setProperty("MS-ID", id); - sampler.setProperty("MS-RESOURCE-ID", ElementUtil.getResourceId(id, config, parent, indexPath)); + String resourceId = ElementUtil.getResourceId(id, config, parent, indexPath); + sampler.setProperty("MS-RESOURCE-ID", resourceId); + return resourceId; } private static final List preOperates = new ArrayList() {{ diff --git a/api-test/backend/src/main/java/io/metersphere/api/dto/definition/request/sampler/MsHTTPSamplerProxy.java b/api-test/backend/src/main/java/io/metersphere/api/dto/definition/request/sampler/MsHTTPSamplerProxy.java index 5d96e8fb0d..8259bb6f2a 100644 --- a/api-test/backend/src/main/java/io/metersphere/api/dto/definition/request/sampler/MsHTTPSamplerProxy.java +++ b/api-test/backend/src/main/java/io/metersphere/api/dto/definition/request/sampler/MsHTTPSamplerProxy.java @@ -129,7 +129,8 @@ public class MsHTTPSamplerProxy extends MsTestElement { } sampler.setProperty(TestElement.TEST_CLASS, HTTPSamplerProxy.class.getName()); sampler.setProperty(TestElement.GUI_CLASS, SaveService.aliasToClass("HttpTestSampleGui")); - ElementUtil.setBaseParams(sampler, this.getParent(), config, this.getId(), this.getIndex()); + String resourceId = ElementUtil.setBaseParams(sampler, this.getParent(), config, this.getId(), this.getIndex()); + sampler.setMethod(this.getMethod()); sampler.setContentEncoding(StandardCharsets.UTF_8.name()); sampler.setFollowRedirects(this.isFollowRedirects()); @@ -227,7 +228,7 @@ public class MsHTTPSamplerProxy extends MsTestElement { if (this.authManager != null && MsAuthManager.mechanismMap.containsKey(this.authManager.getVerification())) { this.authManager.setAuth(httpSamplerTree, this.authManager, sampler); } - addCertificate(config, httpSamplerTree); + addCertificate(config, httpSamplerTree, resourceId); if (httpConfig != null) { //根据配置增加全局前后至脚本 JMeterScriptUtil.setScriptByHttpConfig(httpConfig, httpSamplerTree, config, useEnvironment, this.getEnvironmentId(), false); @@ -500,7 +501,7 @@ public class MsHTTPSamplerProxy extends MsTestElement { /** * 加载SSL认证 */ - private void addCertificate(ParameterConfig config, HashTree httpSamplerTree) { + private void addCertificate(ParameterConfig config, HashTree httpSamplerTree, String resourceId) { if (config != null && config.isEffective(this.getProjectId()) && getEnvironmentConfig(config).getSslConfig() != null) { KeyStoreConfig sslConfig = getEnvironmentConfig(config).getSslConfig(); List files = sslConfig.getFiles(); @@ -542,6 +543,7 @@ public class MsHTTPSamplerProxy extends MsTestElement { keystoreConfig.setProperty("startIndex", 0); keystoreConfig.setProperty(ElementConstants.MS_KEYSTORE_FILE_PATH, msKeyStore.getPath()); keystoreConfig.setProperty(ElementConstants.MS_KEYSTORE_FILE_PASSWORD, msKeyStore.getPassword()); + keystoreConfig.setProperty("MS-RESOURCE-ID", resourceId); httpSamplerTree.add(keystoreConfig); config.getKeyStoreMap().put(this.getProjectId(), new MsKeyStore(msKeyStore.getPath(), msKeyStore.getPassword())); } diff --git a/framework/sdk-parent/jmeter/src/main/java/org/apache/jmeter/config/KeystoreConfig.java b/framework/sdk-parent/jmeter/src/main/java/org/apache/jmeter/config/KeystoreConfig.java index 16e4fcfd89..c158360b2f 100644 --- a/framework/sdk-parent/jmeter/src/main/java/org/apache/jmeter/config/KeystoreConfig.java +++ b/framework/sdk-parent/jmeter/src/main/java/org/apache/jmeter/config/KeystoreConfig.java @@ -61,7 +61,8 @@ public class KeystoreConfig extends ConfigTestElement implements TestBean, TestS @Override public void testEnded(String host) { log.info("Destroying Keystore"); - SSLManager.getInstance().destroyKeystore(); + String resourceId = this.getPropertyAsString("MS-RESOURCE-ID"); + SSLManager.getInstance().destroyKeystore(resourceId); } @Override @@ -110,10 +111,23 @@ public class KeystoreConfig extends ConfigTestElement implements TestBean, TestS } catch (IOException e) { log.error(e.getMessage()); } + // 获取请求上的资源ID + String resourceId = this.getPropertyAsString("MS-RESOURCE-ID"); + if (StringUtils.isNotBlank(resourceId)) { + KeystoreDTO dto = new KeystoreDTO(); + dto.setStartIndex(startIndexAsInt); + dto.setEndIndex(endIndexAsInt); + dto.setPreload(this.preload); + dto.setClientCertAliasVarName(this.clientCertAliasVarName); + dto.setPwd(password); + dto.setPath(path); + SSLManager.keyMap.put(resourceId, dto); + } SSLManager.getInstance().configureKeystore(Boolean.parseBoolean(preload), startIndexAsInt, endIndexAsInt, clientCertAliasVarName, in, password); + } /** diff --git a/framework/sdk-parent/jmeter/src/main/java/org/apache/jmeter/config/KeystoreDTO.java b/framework/sdk-parent/jmeter/src/main/java/org/apache/jmeter/config/KeystoreDTO.java new file mode 100644 index 0000000000..b2969c362e --- /dev/null +++ b/framework/sdk-parent/jmeter/src/main/java/org/apache/jmeter/config/KeystoreDTO.java @@ -0,0 +1,13 @@ +package org.apache.jmeter.config; + +import lombok.Data; + +@Data +public class KeystoreDTO { + private int startIndex; + private int endIndex; + private String preload; + private String clientCertAliasVarName; + private String pwd; + private String path; +} diff --git a/framework/sdk-parent/jmeter/src/main/java/org/apache/jmeter/util/SSLManager.java b/framework/sdk-parent/jmeter/src/main/java/org/apache/jmeter/util/SSLManager.java index cba3e8579b..74f6f7ecc4 100644 --- a/framework/sdk-parent/jmeter/src/main/java/org/apache/jmeter/util/SSLManager.java +++ b/framework/sdk-parent/jmeter/src/main/java/org/apache/jmeter/util/SSLManager.java @@ -17,8 +17,12 @@ package org.apache.jmeter.util; +import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.Validate; +import org.apache.jmeter.config.KeystoreDTO; import org.apache.jmeter.gui.GuiPackage; +import org.apache.jmeter.threads.JMeterContext; +import org.apache.jmeter.threads.JMeterContextService; import org.apache.jmeter.util.keystore.JmeterKeyStore; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -30,7 +34,9 @@ import java.io.InputStream; import java.net.HttpURLConnection; import java.security.*; import java.security.cert.CertificateException; +import java.util.HashMap; import java.util.Locale; +import java.util.Map; /** @@ -42,7 +48,6 @@ import java.util.Locale; * more information. *

* TODO? - N.B. does not currently allow the selection of a client certificate. - * */ public abstract class SSLManager { private static final Logger log = LoggerFactory.getLogger(SSLManager.class); @@ -57,20 +62,30 @@ public abstract class SSLManager { private static final String PKCS12 = "pkcs12"; // $NON-NLS-1$ - /** Singleton instance of the manager */ + public static final Map keyMap = new HashMap<>(); + + /** + * Singleton instance of the manager + */ private static SSLManager manager; private static final boolean IS_SSL_SUPPORTED = true; - /** Cache the KeyStore instance */ + /** + * Cache the KeyStore instance + */ private JmeterKeyStore keyStore; - /** Cache the TrustStore instance - null if no truststore name was provided */ + /** + * Cache the TrustStore instance - null if no truststore name was provided + */ private KeyStore trustStore = null; // Have we yet tried to load the truststore? - private volatile boolean truststoreLoaded=false; + private volatile boolean truststoreLoaded = false; - /** Have the password available */ + /** + * Have the password available + */ protected volatile String defaultpw = System.getProperty(KEY_STORE_PASSWORD); private int keystoreAliasStartIndex; @@ -91,8 +106,7 @@ public abstract class SSLManager { /** * Default implementation of setting the Provider * - * @param provider - * the provider to use + * @param provider the provider to use */ protected void setProvider(Provider provider) { if (null != provider) { @@ -102,7 +116,7 @@ public abstract class SSLManager { protected synchronized JmeterKeyStore getKeyStore() { if (null == this.keyStore) { - String fileName = System.getProperty(JAVAX_NET_SSL_KEY_STORE,""); // empty if not provided + String fileName = System.getProperty(JAVAX_NET_SSL_KEY_STORE, ""); // empty if not provided String fileType = System.getProperty(JAVAX_NET_SSL_KEY_STORE_TYPE, // use the system property to determine the type fileName.toLowerCase(Locale.ENGLISH).endsWith(".p12") ? PKCS12 : "JKS"); // otherwise use the name log.info("JmeterKeyStore Location: {} type {}", fileName, fileType); @@ -111,7 +125,7 @@ public abstract class SSLManager { log.info("KeyStore created OK"); } catch (Exception e) { this.keyStore = null; - throw new IllegalArgumentException("Could not create keystore: "+e.getMessage(), e); + throw new IllegalArgumentException("Could not create keystore: " + e.getMessage(), e); } try { @@ -154,9 +168,9 @@ public abstract class SSLManager { * * @return the configured {@link JmeterKeyStore} */ - protected synchronized JmeterKeyStore getKeyStore(InputStream is,String password) { + protected synchronized JmeterKeyStore getKeyStore(InputStream is, String password) { if (null == this.keyStore) { - String fileName = System.getProperty(JAVAX_NET_SSL_KEY_STORE,""); // empty if not provided + String fileName = System.getProperty(JAVAX_NET_SSL_KEY_STORE, ""); // empty if not provided String fileType = System.getProperty(JAVAX_NET_SSL_KEY_STORE_TYPE, // use the system property to determine the type fileName.toLowerCase(Locale.ENGLISH).endsWith(".p12") ? PKCS12 : "JKS"); // otherwise use the name log.info("JmeterKeyStore Location: {} type {}", fileName, fileType); @@ -165,7 +179,7 @@ public abstract class SSLManager { log.info("KeyStore created OK"); } catch (Exception e) { this.keyStore = null; - throw new IllegalArgumentException("Could not create keystore: "+e.getMessage(), e); + throw new IllegalArgumentException("Could not create keystore: " + e.getMessage(), e); } try { @@ -267,7 +281,7 @@ public abstract class SSLManager { /** * Opens and initializes the TrustStore. - * + *

* There are 3 possibilities: *

    *
  • no truststore name provided, in which case the default Java truststore @@ -280,16 +294,14 @@ public abstract class SSLManager { * If the KeyStore object cannot be created, then this is currently treated the * same as if no truststore name was provided. * - * @return - * {@code null} when Java truststore should be used. - * Otherwise the truststore, which may be empty if the file could not be - * loaded. - * + * @return {@code null} when Java truststore should be used. + * Otherwise the truststore, which may be empty if the file could not be + * loaded. */ protected KeyStore getTrustStore() { if (!truststoreLoaded) { - truststoreLoaded=true;// we've tried ... + truststoreLoaded = true;// we've tried ... String fileName = System.getProperty(SSL_TRUST_STORE); if (fileName == null) { @@ -302,7 +314,7 @@ public abstract class SSLManager { log.info("TrustStore created OK, Type: JKS"); } catch (Exception e) { this.trustStore = null; - throw new RuntimeException("Problem creating truststore: "+e.getMessage(), e); + throw new RuntimeException("Problem creating truststore: " + e.getMessage(), e); } try { @@ -342,6 +354,26 @@ public abstract class SSLManager { if (null == SSLManager.manager) { SSLManager.manager = new JsseSSLManager(null); } + try { + // 重新加载认证文件 + JMeterContext threadContext = JMeterContextService.getContext(); + if (SSLManager.manager.keyStore == null && threadContext != null && threadContext.getCurrentSampler() != null) { + + String resourceId = threadContext.getCurrentSampler().getPropertyAsString("MS-RESOURCE-ID"); + log.info("重新加载认证文件{}", resourceId); + if (StringUtils.isNotBlank(resourceId) && keyMap.containsKey(resourceId)) { + KeystoreDTO dto = keyMap.get(resourceId); + // 加载认证文件 + InputStream in = new FileInputStream(new File(dto.getPath())); + SSLManager.manager.configureKeystore(Boolean.parseBoolean(dto.getPreload()), dto.getStartIndex(), + dto.getEndIndex(), dto.getClientCertAliasVarName(), in, dto.getPwd()); + keyMap.remove(resourceId); + log.info("移除认证文件{}", resourceId); + } + } + } catch (Exception e) { + log.error("证书处理失败{}", e.getMessage()); + } return SSLManager.manager; } @@ -358,23 +390,19 @@ public abstract class SSLManager { /** * Configure Keystore * - * @param preload - * flag whether the keystore should be opened within this method, - * or the opening should be delayed - * @param startIndex - * first index to consider for a key - * @param endIndex - * last index to consider for a key - * @param clientCertAliasVarName - * name of the default key, if empty the first key will be used - * as default key + * @param preload flag whether the keystore should be opened within this method, + * or the opening should be delayed + * @param startIndex first index to consider for a key + * @param endIndex last index to consider for a key + * @param clientCertAliasVarName name of the default key, if empty the first key will be used + * as default key */ - public synchronized void configureKeystore(boolean preload, int startIndex, int endIndex, String clientCertAliasVarName,InputStream is,String password) { + public synchronized void configureKeystore(boolean preload, int startIndex, int endIndex, String clientCertAliasVarName, InputStream is, String password) { this.keystoreAliasStartIndex = startIndex; this.keystoreAliasEndIndex = endIndex; this.clientCertAliasVarName = clientCertAliasVarName; - if(preload) { - keyStore = getKeyStore(is,password); + if (preload) { + keyStore = getKeyStore(is, password); } } @@ -382,6 +410,16 @@ public abstract class SSLManager { * Destroy Keystore */ public synchronized void destroyKeystore() { - keyStore=null; + keyStore = null; + } + + /** + * Destroy Keystore + */ + public synchronized void destroyKeystore(String resourceId) { + if (StringUtils.isNotBlank(resourceId)) { + keyMap.remove(resourceId); + } + keyStore = null; } }