mirror of https://github.com/apache/jmeter.git
Bug 52033 - Allowing multiple certificates (JKS)
git-svn-id: https://svn.apache.org/repos/asf/jakarta/jmeter/trunk@1187840 13f79535-47bb-0310-9956-ffa450edef68
Former-commit-id: 4df8794c51
This commit is contained in:
parent
f5042794dc
commit
c83fa55265
|
|
@ -78,6 +78,11 @@ xml.parser=org.apache.xerces.parsers.SAXParser
|
|||
# set the value to 'false' to reset the SSL context each iteration
|
||||
#https.use.cached.ssl.context=true
|
||||
|
||||
# Start and end index to be used with keystores with many entries
|
||||
# The default is to use entry 0, i.e. the first
|
||||
#https.keyStoreStartIndex=0
|
||||
#https.keyStoreEndIndex=0
|
||||
|
||||
#---------------------------------------------------------------------------
|
||||
# Look and Feel configuration
|
||||
#---------------------------------------------------------------------------
|
||||
|
|
|
|||
|
|
@ -70,6 +70,9 @@ public class JsseSSLManager extends SSLManager {
|
|||
|
||||
private static final int cps;
|
||||
|
||||
//@GuardedBy("this")
|
||||
private static int last_user;
|
||||
|
||||
static {
|
||||
log.info("Using default SSL protocol: "+DEFAULT_SSL_PROTOCOL);
|
||||
log.info("SSL session context: "+(SHARED_SESSION_CONTEXT ? "shared" : "per-thread"));
|
||||
|
|
@ -314,8 +317,12 @@ public class JsseSSLManager extends SSLManager {
|
|||
*/
|
||||
public String[] getClientAliases(String keyType, Principal[] issuers) {
|
||||
log.debug("WrappedX509Manager: getClientAliases: ");
|
||||
log.debug(this.store.getAlias());
|
||||
return new String[] { this.store.getAlias() };
|
||||
int count = this.store.getAliasCount();
|
||||
String[] aliases = new String[count];
|
||||
for(int i = 0; i < aliases.length; i++) {
|
||||
aliases[i] = this.store.getAlias(i);
|
||||
}
|
||||
return aliases;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -343,7 +350,7 @@ public class JsseSSLManager extends SSLManager {
|
|||
*/
|
||||
public X509Certificate[] getCertificateChain(String alias) {
|
||||
log.debug("WrappedX509Manager: getCertificateChain(" + alias + ")");
|
||||
return this.store.getCertificateChain();
|
||||
return this.store.getCertificateChain(alias);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -354,8 +361,9 @@ public class JsseSSLManager extends SSLManager {
|
|||
* @return The PrivateKey value
|
||||
*/
|
||||
public PrivateKey getPrivateKey(String alias) {
|
||||
log.debug("WrappedX509Manager: getPrivateKey: " + this.store.getPrivateKey());
|
||||
return this.store.getPrivateKey();
|
||||
PrivateKey privateKey = this.store.getPrivateKey(alias);
|
||||
log.debug("WrappedX509Manager: getPrivateKey: " + privateKey);
|
||||
return privateKey;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -372,14 +380,28 @@ public class JsseSSLManager extends SSLManager {
|
|||
* @see javax.net.ssl.X509KeyManager#chooseClientAlias(String[], Principal[], Socket)
|
||||
*/
|
||||
public String chooseClientAlias(String[] keyType, Principal[] issuers, Socket socket) {
|
||||
String alias = this.store.getAlias();
|
||||
log.debug("ClientAlias: " + alias);
|
||||
log.debug("keyType: " + keyType[0]);
|
||||
int aliasCount = this.store.getAliasCount();
|
||||
String alias = this.store.getAlias(getNextIndex(aliasCount));
|
||||
if (alias == null || alias.length() == 0) {
|
||||
log.debug("ClientAlias not found.");
|
||||
}
|
||||
return alias;
|
||||
}
|
||||
|
||||
private int getNextIndex(int aliasCount) {
|
||||
if (aliasCount == 1) {
|
||||
return 0;
|
||||
}
|
||||
synchronized(this) {
|
||||
last_user ++;
|
||||
if (last_user >= aliasCount) {
|
||||
last_user = 0;
|
||||
}
|
||||
return last_user;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Choose the server alias for the SSLServerSockets. This are not used
|
||||
* in JMeter.
|
||||
|
|
|
|||
|
|
@ -64,7 +64,7 @@ public abstract class SSLManager {
|
|||
private static final Provider sslProvider = null;
|
||||
|
||||
/** Cache the KeyStore instance */
|
||||
private JmeterKeyStore keyStore;
|
||||
private volatile JmeterKeyStore keyStore;
|
||||
|
||||
/** Cache the TrustStore instance - null if no truststore name was provided */
|
||||
private KeyStore trustStore = null;
|
||||
|
|
@ -126,7 +126,9 @@ public abstract class SSLManager {
|
|||
if (initStore.exists()) {
|
||||
fileInputStream = new FileInputStream(initStore);
|
||||
this.keyStore.load(fileInputStream, getPassword());
|
||||
log.info("Keystore loaded OK from file, found alias: "+keyStore.getAlias());
|
||||
if (log.isInfoEnabled()) {
|
||||
log.info("Total of " + keyStore.getAliasCount() + " aliases loaded OK from keystore");
|
||||
}
|
||||
} else {
|
||||
log.warn("Keystore file not found, loading empty keystore");
|
||||
this.defaultpw = ""; // Ensure not null
|
||||
|
|
|
|||
|
|
@ -23,21 +23,35 @@ import java.security.KeyStore;
|
|||
import java.security.PrivateKey;
|
||||
import java.security.cert.Certificate;
|
||||
import java.security.cert.X509Certificate;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Enumeration;
|
||||
|
||||
import org.apache.jmeter.util.JMeterUtils;
|
||||
|
||||
/**
|
||||
* Use this Keystore to wrap the normal KeyStore implementation.
|
||||
*
|
||||
*/
|
||||
public class DefaultKeyStore extends JmeterKeyStore {
|
||||
private X509Certificate[] certChain;
|
||||
private X509Certificate[][] certChains;
|
||||
|
||||
private PrivateKey key;
|
||||
private PrivateKey[] keys;
|
||||
|
||||
private String alias;
|
||||
private String[] names;
|
||||
|
||||
private final KeyStore store;
|
||||
|
||||
private static final String KEY_STORE_START_INDEX = "https.keyStoreStartIndex"; // $NON-NLS-1$
|
||||
private static final String KEY_STORE_END_INDEX = "https.keyStoreEndIndex"; // $NON-NLS-1$
|
||||
|
||||
private static final int startIndex;
|
||||
private static final int endIndex;
|
||||
|
||||
static {
|
||||
startIndex = JMeterUtils.getPropDefault(KEY_STORE_START_INDEX, 0);
|
||||
endIndex = JMeterUtils.getPropDefault(KEY_STORE_END_INDEX, 0);
|
||||
}
|
||||
|
||||
public DefaultKeyStore(String type) throws Exception {
|
||||
this.store = KeyStore.getInstance(type);
|
||||
}
|
||||
|
|
@ -46,54 +60,96 @@ public class DefaultKeyStore extends JmeterKeyStore {
|
|||
@Override
|
||||
public void load(InputStream is, String pword) throws Exception {
|
||||
store.load(is, pword.toCharArray());
|
||||
PrivateKey _key = null;
|
||||
X509Certificate[] _certChain = null;
|
||||
|
||||
ArrayList<String> v_names = new ArrayList<String>();
|
||||
ArrayList<PrivateKey> v_keys = new ArrayList<PrivateKey>();
|
||||
ArrayList<X509Certificate[]> v_certChains = new ArrayList<X509Certificate[]>();
|
||||
|
||||
if (null != is){ // No point checking an empty keystore
|
||||
|
||||
PrivateKey _key = null;
|
||||
int index = 0;
|
||||
Enumeration<String> aliases = store.aliases();
|
||||
while (aliases.hasMoreElements()) {
|
||||
this.alias = aliases.nextElement();
|
||||
String alias = aliases.nextElement();
|
||||
if (store.isKeyEntry(alias)) {
|
||||
_key = (PrivateKey) store.getKey(alias, pword.toCharArray());
|
||||
Certificate[] chain = store.getCertificateChain(alias);
|
||||
_certChain = new X509Certificate[chain.length];
|
||||
|
||||
for (int i = 0; i < chain.length; i++) {
|
||||
_certChain[i] = (X509Certificate) chain[i];
|
||||
if ((index >= startIndex && index <= endIndex)) {
|
||||
_key = (PrivateKey) store.getKey(alias, pword.toCharArray());
|
||||
if (null == _key) {
|
||||
throw new Exception("No key found for alias: " + alias); // Should not happen
|
||||
}
|
||||
Certificate[] chain = store.getCertificateChain(alias);
|
||||
if (null == chain) {
|
||||
throw new Exception("No certificate chain found for alias: " + alias);
|
||||
}
|
||||
v_names.add(alias);
|
||||
v_keys.add(_key);
|
||||
v_certChains.add((X509Certificate[]) chain);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
index++;
|
||||
}
|
||||
|
||||
if (null == _key) {
|
||||
throw new Exception("No key found");
|
||||
}
|
||||
if (null == _certChain) {
|
||||
throw new Exception("No certificate chain found");
|
||||
throw new Exception("No key(s) found");
|
||||
}
|
||||
}
|
||||
|
||||
this.key = _key;
|
||||
this.certChain = _certChain;
|
||||
/*
|
||||
* Note: if is == null, the arrays will be empty
|
||||
*/
|
||||
int v_size = v_names.size();
|
||||
|
||||
this.names = new String[v_size];
|
||||
this.names = v_names.toArray(names);
|
||||
|
||||
this.keys = new PrivateKey[v_size];
|
||||
this.keys = v_keys.toArray(keys);
|
||||
|
||||
this.certChains = new X509Certificate[v_size][];
|
||||
this.certChains = v_certChains.toArray(certChains);
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
@Override
|
||||
public final X509Certificate[] getCertificateChain() {
|
||||
return this.certChain;
|
||||
public final X509Certificate[] getCertificateChain(String alias) {
|
||||
int entry = findAlias(alias);
|
||||
if (entry >=0) {
|
||||
return this.certChains[entry];
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
@Override
|
||||
public final PrivateKey getPrivateKey() {
|
||||
return this.key;
|
||||
public final PrivateKey getPrivateKey(String alias) {
|
||||
int entry = findAlias(alias);
|
||||
if (entry >=0) {
|
||||
return this.keys[entry];
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
@Override
|
||||
public final String getAlias() {
|
||||
return this.alias;
|
||||
public final String getAlias(int index) {
|
||||
int length = this.names.length;
|
||||
if (length == 0 && index == 0) { // i.e. is == null
|
||||
return null;
|
||||
}
|
||||
if (index >= length || index < 0) {
|
||||
throw new ArrayIndexOutOfBoundsException(index);
|
||||
}
|
||||
return this.names[index];
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getAliasCount() {
|
||||
return this.names.length;
|
||||
}
|
||||
|
||||
private int findAlias(String alias) {
|
||||
for(int i = 0; i < names.length; i++) {
|
||||
if (alias.equals(names[i])){
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -34,16 +34,18 @@ public abstract class JmeterKeyStore {
|
|||
public abstract void load(InputStream is, String password) throws Exception;
|
||||
|
||||
/**
|
||||
* Get the ordered certificate chain.
|
||||
* Get the ordered certificate chain for a specific alias.
|
||||
*/
|
||||
public abstract X509Certificate[] getCertificateChain();
|
||||
public abstract X509Certificate[] getCertificateChain(String alias);
|
||||
|
||||
public abstract String getAlias();
|
||||
public abstract int getAliasCount();
|
||||
|
||||
public abstract String getAlias(int index);
|
||||
|
||||
/**
|
||||
* Return the private Key
|
||||
* Return the private Key for a specific alias
|
||||
*/
|
||||
public abstract PrivateKey getPrivateKey();
|
||||
public abstract PrivateKey getPrivateKey(String alias);
|
||||
|
||||
public static final JmeterKeyStore getInstance(String type) throws Exception {
|
||||
// JAVA 1.4 now handles all keystore types, so just use default
|
||||
|
|
|
|||
|
|
@ -137,6 +137,7 @@ Mirror server now uses default port 8081, was 8080 before 2.5.1.
|
|||
<h3>HTTP Samplers</h3>
|
||||
<ul>
|
||||
<li>Bug 51981 - Better support for file: protocol in HTTP sampler</li>
|
||||
<li>Bug 52033 - Allowing multiple certificates (JKS)</li>
|
||||
</ul>
|
||||
|
||||
<h3>Other samplers</h3>
|
||||
|
|
|
|||
Loading…
Reference in New Issue