/* See LICENSE for licensing and NOTICE for copyright. */
package org.ldaptive.ssl;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import javax.net.ssl.X509TrustManager;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Trust manager that delegates to multiple trust managers.
*
* @author Middleware Services
*/
public class AggregateTrustManager implements X509TrustManager
{
/** Enum to define how trust managers should be processed. */
public enum Strategy {
/** all trust managers must succeed. */
ALL,
/** any trust manager must succeed. */
ANY
}
/** Logger for this class. */
protected final Logger logger = LoggerFactory.getLogger(getClass());
/** Trust managers to invoke. */
private final X509TrustManager[] trustManagers;
/** Whether to require all trust managers succeed. */
private final Strategy trustStrategy;
/**
* Creates a new aggregate trust manager with the ALL {@link Strategy}.
*
* @param managers to aggregate
*/
public AggregateTrustManager(final X509TrustManager... managers)
{
this(Strategy.ALL, managers);
}
/**
* Creates a new aggregate trust manager.
*
* @param strategy for processing trust managers
* @param managers to aggregate
*/
public AggregateTrustManager(final Strategy strategy, final X509TrustManager... managers)
{
if (strategy == null) {
throw new NullPointerException("Strategy cannot be null");
}
trustStrategy = strategy;
trustManagers = managers;
}
@Override
public void checkClientTrusted(final X509Certificate[] chain, final String authType)
throws CertificateException
{
if (trustManagers != null) {
CertificateException certEx = null;
for (X509TrustManager tm : trustManagers) {
try {
tm.checkClientTrusted(chain, authType);
logger.debug("checkClientTrusted for {} succeeded", tm);
if (trustStrategy == Strategy.ANY) {
return;
}
} catch (CertificateException e) {
logger.debug("checkClientTrusted for {} failed", tm);
if (trustStrategy == Strategy.ALL) {
throw e;
}
if (certEx == null) {
certEx = e;
}
}
}
if (certEx != null) {
throw certEx;
}
}
}
@Override
public void checkServerTrusted(final X509Certificate[] chain, final String authType)
throws CertificateException
{
if (trustManagers != null) {
CertificateException certEx = null;
for (X509TrustManager tm : trustManagers) {
try {
tm.checkServerTrusted(chain, authType);
logger.debug("checkServerTrusted for {} succeeded", tm);
if (trustStrategy == Strategy.ANY) {
return;
}
} catch (CertificateException e) {
logger.debug("checkServerTrusted for {} failed", tm);
if (trustStrategy == Strategy.ALL) {
throw e;
}
if (certEx == null) {
certEx = e;
}
}
}
if (certEx != null) {
throw certEx;
}
}
}
@Override
public X509Certificate[] getAcceptedIssuers()
{
final List<X509Certificate> issuers = new ArrayList<>();
if (trustManagers != null) {
for (X509TrustManager tm : trustManagers) {
logger.debug("invoking getAcceptedIssuers for {}", tm);
Collections.addAll(issuers, tm.getAcceptedIssuers());
}
}
return issuers.toArray(new X509Certificate[issuers.size()]);
}
@Override
public String toString()
{
return
String.format(
"[%s@%d::trustManagers=%s, trustStrategy=%s]",
getClass().getName(),
hashCode(),
Arrays.toString(trustManagers),
trustStrategy);
}
}