fix(接口测试): 修复大批量场景执行偶发证书认证失败问题
Signed-off-by: fit2-zhao <yong.zhao@fit2cloud.com>
This commit is contained in:
parent
488ed0fa90
commit
4712d98627
|
@ -620,9 +620,11 @@ public class ElementUtil {
|
||||||
return processor;
|
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-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<String> preOperates = new ArrayList<String>() {{
|
private static final List<String> preOperates = new ArrayList<String>() {{
|
||||||
|
|
|
@ -129,7 +129,8 @@ public class MsHTTPSamplerProxy extends MsTestElement {
|
||||||
}
|
}
|
||||||
sampler.setProperty(TestElement.TEST_CLASS, HTTPSamplerProxy.class.getName());
|
sampler.setProperty(TestElement.TEST_CLASS, HTTPSamplerProxy.class.getName());
|
||||||
sampler.setProperty(TestElement.GUI_CLASS, SaveService.aliasToClass("HttpTestSampleGui"));
|
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.setMethod(this.getMethod());
|
||||||
sampler.setContentEncoding(StandardCharsets.UTF_8.name());
|
sampler.setContentEncoding(StandardCharsets.UTF_8.name());
|
||||||
sampler.setFollowRedirects(this.isFollowRedirects());
|
sampler.setFollowRedirects(this.isFollowRedirects());
|
||||||
|
@ -227,7 +228,7 @@ public class MsHTTPSamplerProxy extends MsTestElement {
|
||||||
if (this.authManager != null && MsAuthManager.mechanismMap.containsKey(this.authManager.getVerification())) {
|
if (this.authManager != null && MsAuthManager.mechanismMap.containsKey(this.authManager.getVerification())) {
|
||||||
this.authManager.setAuth(httpSamplerTree, this.authManager, sampler);
|
this.authManager.setAuth(httpSamplerTree, this.authManager, sampler);
|
||||||
}
|
}
|
||||||
addCertificate(config, httpSamplerTree);
|
addCertificate(config, httpSamplerTree, resourceId);
|
||||||
if (httpConfig != null) {
|
if (httpConfig != null) {
|
||||||
//根据配置增加全局前后至脚本
|
//根据配置增加全局前后至脚本
|
||||||
JMeterScriptUtil.setScriptByHttpConfig(httpConfig, httpSamplerTree, config, useEnvironment, this.getEnvironmentId(), false);
|
JMeterScriptUtil.setScriptByHttpConfig(httpConfig, httpSamplerTree, config, useEnvironment, this.getEnvironmentId(), false);
|
||||||
|
@ -500,7 +501,7 @@ public class MsHTTPSamplerProxy extends MsTestElement {
|
||||||
/**
|
/**
|
||||||
* 加载SSL认证
|
* 加载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) {
|
if (config != null && config.isEffective(this.getProjectId()) && getEnvironmentConfig(config).getSslConfig() != null) {
|
||||||
KeyStoreConfig sslConfig = getEnvironmentConfig(config).getSslConfig();
|
KeyStoreConfig sslConfig = getEnvironmentConfig(config).getSslConfig();
|
||||||
List<KeyStoreFile> files = sslConfig.getFiles();
|
List<KeyStoreFile> files = sslConfig.getFiles();
|
||||||
|
@ -542,6 +543,7 @@ public class MsHTTPSamplerProxy extends MsTestElement {
|
||||||
keystoreConfig.setProperty("startIndex", 0);
|
keystoreConfig.setProperty("startIndex", 0);
|
||||||
keystoreConfig.setProperty(ElementConstants.MS_KEYSTORE_FILE_PATH, msKeyStore.getPath());
|
keystoreConfig.setProperty(ElementConstants.MS_KEYSTORE_FILE_PATH, msKeyStore.getPath());
|
||||||
keystoreConfig.setProperty(ElementConstants.MS_KEYSTORE_FILE_PASSWORD, msKeyStore.getPassword());
|
keystoreConfig.setProperty(ElementConstants.MS_KEYSTORE_FILE_PASSWORD, msKeyStore.getPassword());
|
||||||
|
keystoreConfig.setProperty("MS-RESOURCE-ID", resourceId);
|
||||||
httpSamplerTree.add(keystoreConfig);
|
httpSamplerTree.add(keystoreConfig);
|
||||||
config.getKeyStoreMap().put(this.getProjectId(), new MsKeyStore(msKeyStore.getPath(), msKeyStore.getPassword()));
|
config.getKeyStoreMap().put(this.getProjectId(), new MsKeyStore(msKeyStore.getPath(), msKeyStore.getPassword()));
|
||||||
}
|
}
|
||||||
|
|
|
@ -61,7 +61,8 @@ public class KeystoreConfig extends ConfigTestElement implements TestBean, TestS
|
||||||
@Override
|
@Override
|
||||||
public void testEnded(String host) {
|
public void testEnded(String host) {
|
||||||
log.info("Destroying Keystore");
|
log.info("Destroying Keystore");
|
||||||
SSLManager.getInstance().destroyKeystore();
|
String resourceId = this.getPropertyAsString("MS-RESOURCE-ID");
|
||||||
|
SSLManager.getInstance().destroyKeystore(resourceId);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -110,10 +111,23 @@ public class KeystoreConfig extends ConfigTestElement implements TestBean, TestS
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
log.error(e.getMessage());
|
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),
|
SSLManager.getInstance().configureKeystore(Boolean.parseBoolean(preload),
|
||||||
startIndexAsInt,
|
startIndexAsInt,
|
||||||
endIndexAsInt,
|
endIndexAsInt,
|
||||||
clientCertAliasVarName, in, password);
|
clientCertAliasVarName, in, password);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -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;
|
||||||
|
}
|
|
@ -17,8 +17,12 @@
|
||||||
|
|
||||||
package org.apache.jmeter.util;
|
package org.apache.jmeter.util;
|
||||||
|
|
||||||
|
import org.apache.commons.lang3.StringUtils;
|
||||||
import org.apache.commons.lang3.Validate;
|
import org.apache.commons.lang3.Validate;
|
||||||
|
import org.apache.jmeter.config.KeystoreDTO;
|
||||||
import org.apache.jmeter.gui.GuiPackage;
|
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.apache.jmeter.util.keystore.JmeterKeyStore;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
@ -30,7 +34,9 @@ import java.io.InputStream;
|
||||||
import java.net.HttpURLConnection;
|
import java.net.HttpURLConnection;
|
||||||
import java.security.*;
|
import java.security.*;
|
||||||
import java.security.cert.CertificateException;
|
import java.security.cert.CertificateException;
|
||||||
|
import java.util.HashMap;
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -42,7 +48,6 @@ import java.util.Locale;
|
||||||
* more information.
|
* more information.
|
||||||
* <p>
|
* <p>
|
||||||
* TODO? - N.B. does not currently allow the selection of a client certificate.
|
* TODO? - N.B. does not currently allow the selection of a client certificate.
|
||||||
*
|
|
||||||
*/
|
*/
|
||||||
public abstract class SSLManager {
|
public abstract class SSLManager {
|
||||||
private static final Logger log = LoggerFactory.getLogger(SSLManager.class);
|
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$
|
private static final String PKCS12 = "pkcs12"; // $NON-NLS-1$
|
||||||
|
|
||||||
/** Singleton instance of the manager */
|
public static final Map<String, KeystoreDTO> keyMap = new HashMap<>();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Singleton instance of the manager
|
||||||
|
*/
|
||||||
private static SSLManager manager;
|
private static SSLManager manager;
|
||||||
|
|
||||||
private static final boolean IS_SSL_SUPPORTED = true;
|
private static final boolean IS_SSL_SUPPORTED = true;
|
||||||
|
|
||||||
/** Cache the KeyStore instance */
|
/**
|
||||||
|
* Cache the KeyStore instance
|
||||||
|
*/
|
||||||
private JmeterKeyStore keyStore;
|
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;
|
private KeyStore trustStore = null;
|
||||||
// Have we yet tried to load the truststore?
|
// 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);
|
protected volatile String defaultpw = System.getProperty(KEY_STORE_PASSWORD);
|
||||||
|
|
||||||
private int keystoreAliasStartIndex;
|
private int keystoreAliasStartIndex;
|
||||||
|
@ -91,8 +106,7 @@ public abstract class SSLManager {
|
||||||
/**
|
/**
|
||||||
* Default implementation of setting the Provider
|
* Default implementation of setting the Provider
|
||||||
*
|
*
|
||||||
* @param provider
|
* @param provider the provider to use
|
||||||
* the provider to use
|
|
||||||
*/
|
*/
|
||||||
protected void setProvider(Provider provider) {
|
protected void setProvider(Provider provider) {
|
||||||
if (null != provider) {
|
if (null != provider) {
|
||||||
|
@ -102,7 +116,7 @@ public abstract class SSLManager {
|
||||||
|
|
||||||
protected synchronized JmeterKeyStore getKeyStore() {
|
protected synchronized JmeterKeyStore getKeyStore() {
|
||||||
if (null == this.keyStore) {
|
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
|
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
|
fileName.toLowerCase(Locale.ENGLISH).endsWith(".p12") ? PKCS12 : "JKS"); // otherwise use the name
|
||||||
log.info("JmeterKeyStore Location: {} type {}", fileName, fileType);
|
log.info("JmeterKeyStore Location: {} type {}", fileName, fileType);
|
||||||
|
@ -111,7 +125,7 @@ public abstract class SSLManager {
|
||||||
log.info("KeyStore created OK");
|
log.info("KeyStore created OK");
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
this.keyStore = null;
|
this.keyStore = null;
|
||||||
throw new IllegalArgumentException("Could not create keystore: "+e.getMessage(), e);
|
throw new IllegalArgumentException("Could not create keystore: " + e.getMessage(), e);
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
@ -154,9 +168,9 @@ public abstract class SSLManager {
|
||||||
*
|
*
|
||||||
* @return the configured {@link JmeterKeyStore}
|
* @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) {
|
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
|
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
|
fileName.toLowerCase(Locale.ENGLISH).endsWith(".p12") ? PKCS12 : "JKS"); // otherwise use the name
|
||||||
log.info("JmeterKeyStore Location: {} type {}", fileName, fileType);
|
log.info("JmeterKeyStore Location: {} type {}", fileName, fileType);
|
||||||
|
@ -165,7 +179,7 @@ public abstract class SSLManager {
|
||||||
log.info("KeyStore created OK");
|
log.info("KeyStore created OK");
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
this.keyStore = null;
|
this.keyStore = null;
|
||||||
throw new IllegalArgumentException("Could not create keystore: "+e.getMessage(), e);
|
throw new IllegalArgumentException("Could not create keystore: " + e.getMessage(), e);
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
@ -267,7 +281,7 @@ public abstract class SSLManager {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Opens and initializes the TrustStore.
|
* Opens and initializes the TrustStore.
|
||||||
*
|
* <p>
|
||||||
* There are 3 possibilities:
|
* There are 3 possibilities:
|
||||||
* <ul>
|
* <ul>
|
||||||
* <li>no truststore name provided, in which case the default Java truststore
|
* <li>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
|
* If the KeyStore object cannot be created, then this is currently treated the
|
||||||
* same as if no truststore name was provided.
|
* same as if no truststore name was provided.
|
||||||
*
|
*
|
||||||
* @return
|
* @return {@code null} when Java truststore should be used.
|
||||||
* {@code null} when Java truststore should be used.
|
|
||||||
* Otherwise the truststore, which may be empty if the file could not be
|
* Otherwise the truststore, which may be empty if the file could not be
|
||||||
* loaded.
|
* loaded.
|
||||||
*
|
|
||||||
*/
|
*/
|
||||||
protected KeyStore getTrustStore() {
|
protected KeyStore getTrustStore() {
|
||||||
if (!truststoreLoaded) {
|
if (!truststoreLoaded) {
|
||||||
|
|
||||||
truststoreLoaded=true;// we've tried ...
|
truststoreLoaded = true;// we've tried ...
|
||||||
|
|
||||||
String fileName = System.getProperty(SSL_TRUST_STORE);
|
String fileName = System.getProperty(SSL_TRUST_STORE);
|
||||||
if (fileName == null) {
|
if (fileName == null) {
|
||||||
|
@ -302,7 +314,7 @@ public abstract class SSLManager {
|
||||||
log.info("TrustStore created OK, Type: JKS");
|
log.info("TrustStore created OK, Type: JKS");
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
this.trustStore = null;
|
this.trustStore = null;
|
||||||
throw new RuntimeException("Problem creating truststore: "+e.getMessage(), e);
|
throw new RuntimeException("Problem creating truststore: " + e.getMessage(), e);
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
@ -342,6 +354,26 @@ public abstract class SSLManager {
|
||||||
if (null == SSLManager.manager) {
|
if (null == SSLManager.manager) {
|
||||||
SSLManager.manager = new JsseSSLManager(null);
|
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;
|
return SSLManager.manager;
|
||||||
}
|
}
|
||||||
|
@ -358,23 +390,19 @@ public abstract class SSLManager {
|
||||||
/**
|
/**
|
||||||
* Configure Keystore
|
* Configure Keystore
|
||||||
*
|
*
|
||||||
* @param preload
|
* @param preload flag whether the keystore should be opened within this method,
|
||||||
* flag whether the keystore should be opened within this method,
|
|
||||||
* or the opening should be delayed
|
* or the opening should be delayed
|
||||||
* @param startIndex
|
* @param startIndex first index to consider for a key
|
||||||
* first index to consider for a key
|
* @param endIndex last index to consider for a key
|
||||||
* @param endIndex
|
* @param clientCertAliasVarName name of the default key, if empty the first key will be used
|
||||||
* 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
|
* 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.keystoreAliasStartIndex = startIndex;
|
||||||
this.keystoreAliasEndIndex = endIndex;
|
this.keystoreAliasEndIndex = endIndex;
|
||||||
this.clientCertAliasVarName = clientCertAliasVarName;
|
this.clientCertAliasVarName = clientCertAliasVarName;
|
||||||
if(preload) {
|
if (preload) {
|
||||||
keyStore = getKeyStore(is,password);
|
keyStore = getKeyStore(is, password);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -382,6 +410,16 @@ public abstract class SSLManager {
|
||||||
* Destroy Keystore
|
* Destroy Keystore
|
||||||
*/
|
*/
|
||||||
public synchronized void destroyKeystore() {
|
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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue