com.github.tomakehurst.wiremock.http.ssl.CompositeTrustManager Maven / Gradle / Ivy
Show all versions of wiremock-standalone Show documentation
/*
* Copyright (C) 2020-2023 Thomas Akehurst
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.github.tomakehurst.wiremock.http.ssl;
import static java.util.Arrays.asList;
import static java.util.Arrays.copyOf;
import java.net.Socket;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import javax.net.ssl.SSLEngine;
import javax.net.ssl.X509ExtendedTrustManager;
import javax.net.ssl.X509TrustManager;
/**
* Implementation of {@link X509ExtendedTrustManager} that delegates to multiple nested
* X509ExtendedTrustManagers.
*
* {@link javax.net.ssl.SSLContext#init(javax.net.ssl.KeyManager[], javax.net.ssl.TrustManager[],
* java.security.SecureRandom)} accepts an array of {@link javax.net.ssl.TrustManager} instances,
* but {@link sun.security.ssl.SSLContextImpl#chooseTrustManager(javax.net.ssl.TrustManager[])}
* chooses the first instance of X509TrustManager in the array. So in order to provide a composite
* trust manager that will trust based on the decision of more than one X509TrustManager we need to
* create a new implementation that delegates its decision to one or more real X509TrustManager
* instances.
*
*
The contract of this class is that a check will pass if it passes against any of its trust
* managers. If it passes against none of them, the {@link CertificateException} thrown by the last
* of them is propagated.
*/
class CompositeTrustManager extends X509ExtendedTrustManager {
private final List trustManagers;
private final X509Certificate[] acceptedIssuers;
CompositeTrustManager(List trustManagers) {
if (trustManagers.isEmpty()) {
throw new IllegalArgumentException("A trust manager must be provided");
}
this.trustManagers = new ArrayList<>(trustManagers);
this.acceptedIssuers = loadAcceptedIssuers(this.trustManagers);
}
private X509Certificate[] loadAcceptedIssuers(List trustManagers) {
List result = new ArrayList<>();
for (X509TrustManager trustManager : trustManagers) {
result.addAll(asList(trustManager.getAcceptedIssuers()));
}
return result.toArray(new X509Certificate[0]);
}
@Override
public void checkClientTrusted(final X509Certificate[] chain, final String authType)
throws CertificateException {
checkAllTrustManagers(tm -> tm.checkClientTrusted(chain, authType));
}
@Override
public void checkServerTrusted(final X509Certificate[] chain, final String authType)
throws CertificateException {
checkAllTrustManagers(tm -> tm.checkServerTrusted(chain, authType));
}
@Override
public void checkClientTrusted(
final X509Certificate[] chain, final String authType, final Socket socket)
throws CertificateException {
checkAllTrustManagers(tm -> tm.checkClientTrusted(chain, authType, socket));
}
@Override
public void checkServerTrusted(
final X509Certificate[] chain, final String authType, final Socket socket)
throws CertificateException {
checkAllTrustManagers(tm -> tm.checkServerTrusted(chain, authType, socket));
}
@Override
public void checkClientTrusted(
final X509Certificate[] chain, final String authType, final SSLEngine engine)
throws CertificateException {
checkAllTrustManagers(tm -> tm.checkClientTrusted(chain, authType, engine));
}
@Override
public void checkServerTrusted(
final X509Certificate[] chain, final String authType, final SSLEngine engine)
throws CertificateException {
checkAllTrustManagers(tm -> tm.checkServerTrusted(chain, authType, engine));
}
@Override
public X509Certificate[] getAcceptedIssuers() {
return copyOf(acceptedIssuers, acceptedIssuers.length);
}
private void checkAllTrustManagers(CertificateChecker certificateChecker)
throws CertificateException {
for (Iterator iterator = trustManagers.iterator();
iterator.hasNext(); ) {
X509ExtendedTrustManager tm = iterator.next();
try {
certificateChecker.check(tm);
break;
} catch (CertificateException e) {
if (!iterator.hasNext()) {
throw e;
}
}
}
}
private interface CertificateChecker {
void check(X509ExtendedTrustManager tm) throws CertificateException;
}
}