All Downloads are FREE. Search and download functionalities are using the official Maven repository.

edu.uiuc.ncsa.security.util.ssl.MyTrustManager Maven / Gradle / Ivy

package edu.uiuc.ncsa.security.util.ssl;

/**
 * Trust manager formerly part of MyProxy, but universally useful.
 */


import edu.uiuc.ncsa.security.core.util.MyLoggingFacade;
import edu.uiuc.ncsa.security.util.pkcs.CertUtil;

import javax.net.ssl.X509TrustManager;
import java.io.File;
import java.io.FileInputStream;
import java.net.InetAddress;
import java.security.GeneralSecurityException;
import java.security.cert.*;
import java.util.Arrays;
import java.util.Date;
import java.util.HashSet;
import java.util.Set;

public class MyTrustManager implements X509TrustManager {
    boolean debugOn = false; // set to false for release
    boolean stackTracesOn = false; // set to false for use as a library, true for standalone release

    public MyTrustManager(MyLoggingFacade logger, String trustRootPath) {
        this(logger, trustRootPath, null);
    }

    public MyTrustManager(MyLoggingFacade logger, String trustRootPath, String serverDN) {
        this.trustRootPath = trustRootPath;
        this.logger = logger;
        this.serverDN = serverDN;
    }

    public boolean hasServerDN() {
        return serverDN != null;
    }

    public String getServerDN() {
        return serverDN;
    }

    public void setServerDN(String serverDN) {
        this.serverDN = serverDN;
    }

    String serverDN = null;

    MyLoggingFacade logger;

    public MyLoggingFacade getLogger() {
        if (logger == null) {
            logger = new MyLoggingFacade(MyTrustManager.class.getName());
            logger.setDebugOn(debugOn);
        }
        return logger;
    }


    public final String DEFAULT_TRUST_ROOT_PATH = "/etc/grid-security/certificates";

    String trustRootPath = DEFAULT_TRUST_ROOT_PATH;

    public String getTrustRootPath() {
        return trustRootPath;
    }

    public void setTrustRootPath(String trustRootPath) {
        this.trustRootPath = trustRootPath;
    }

    public boolean isRequestTrustRoots() {
        return requestTrustRoots;
    }

    public void setRequestTrustRoots(boolean requestTrustRoots) {
        this.requestTrustRoots = requestTrustRoots;
    }

    boolean requestTrustRoots;

    public String getHost() {
        return host;
    }

    public void setHost(String host) {
        this.host = host;
    }

    void dbg(String x) {
        if (debugOn) {
            System.out.println(getClass().getName() + "(" + (new Date()) + "): " + x);
            getLogger().info(getClass().getName() + "(" + (new Date()) + "): " + x);
        }
    }

    String host;

    public X509Certificate[] getAcceptedIssuers() {
        X509Certificate[] issuers = null;
        String certDirPath = getTrustRootPath();
        // Comment: This might fail for any number of reasons, such as having the
        // trust root path not exist. Throwing exceptions will not work here since
        // they will be intercepted by the SSL layer and not propagated to the caller...
        if (certDirPath == null) {
            dbg("cert dir path null. Aborting");
            return null;
        }
        File dir = new File(certDirPath);
        if (!dir.isDirectory()) {
            dbg(" cert dir path is not a directory. Aborting.");
            return null;
        }
        String[] certFilenames = dir.list();
        String[] certData = new String[certFilenames.length];
        for (int i = 0; i < certFilenames.length; i++) {
            try {
                FileInputStream fileStream = new FileInputStream(
                        certDirPath + File.separator + certFilenames[i]);
                byte[] buffer = new byte[fileStream.available()];
                fileStream.read(buffer);
                certData[i] = new String(buffer);
                fileStream.close();
            } catch (Exception e) {
                dbg("Exception Reading issues " + e.getMessage());
                // ignore
            }
        }
        try {
            issuers = CertUtil.getX509CertsFromStringList(certData, certFilenames);
            dbg("Got " + issuers.length + " issuers.");
        } catch (Exception e) {
            if (stackTracesOn) e.printStackTrace();
            dbg("Exception getting issuers. Returning null. " + e.getMessage());
        }
        return issuers;
    }

    public void checkClientTrusted(X509Certificate[] certs, String authType)
            throws CertificateException {
        throw new CertificateException(
                "checkClientTrusted not implemented by " + getClass().getName());
    }

    public void checkServerTrusted(X509Certificate[] certs, String authType)
            throws CertificateException {
        checkServerCertPath(certs);
        checkServerDN(certs[0]);
    }

    protected void checkServerCertPath(X509Certificate[] certs)
            throws CertificateException {
        try {
            CertPathValidator validator = CertPathValidator
                    .getInstance(CertPathValidator.getDefaultType());
            CertificateFactory certFactory = CertificateFactory
                    .getInstance("X.509");
            CertPath certPath = certFactory.generateCertPath(Arrays
                    .asList(certs));
            X509Certificate[] acceptedIssuers = getAcceptedIssuers();
            if (acceptedIssuers == null) {
                String certDir = getTrustRootPath();
                if (certDir != null) {
                    throw new CertificateException(
                            "no CA certificates found in " + certDir);
                } else if (!isRequestTrustRoots()) {
                    throw new CertificateException(
                            "no CA certificates directory found");
                }
                getLogger()
                        .info("no trusted CAs configured -- bootstrapping trust from MyProxy server");
                acceptedIssuers = new X509Certificate[1];
                acceptedIssuers[0] = certs[certs.length - 1];
            }
            Set trustAnchors = new HashSet(
                    acceptedIssuers.length);
            for (int i = 0; i < acceptedIssuers.length; i++) {
                TrustAnchor ta = new TrustAnchor(acceptedIssuers[i], null);
                trustAnchors.add(ta);
            }
            PKIXParameters pkixParameters = new PKIXParameters(trustAnchors);
            pkixParameters.setRevocationEnabled(false);
            validator.validate(certPath, pkixParameters);
        } catch (CertificateException e) {
            if (stackTracesOn) e.printStackTrace();
            throw e;
        } catch (GeneralSecurityException e) {
            if (stackTracesOn) e.printStackTrace();
            throw new CertificateException(e);
        } catch (Throwable t) {
            if (stackTracesOn) t.printStackTrace();
        }
    }

    /**
     * Parses the server DN for the CN and does a few sanity checks on the result before returning.
     *
     * @param subject
     * @return
     * @throws CertificateException
     */
    private String getCommonName(String subject) throws CertificateException {
        int index = subject.indexOf("CN=");
        if (index == -1) {
            throw new CertificateException("Server certificate subject ("
                    + subject + "does not contain a CN component.");
        }
        String CN = subject.substring(index + 3);
        index = CN.indexOf(',');
        if (index >= 0) {
            CN = CN.substring(0, index);
        }
        if ((index = CN.indexOf('/')) >= 0) {
            String service = CN.substring(0, index);
            CN = CN.substring(index + 1);
            if (!service.equals("host") && !service.equals("myproxy")) {
                dbg("common name =\"" + CN + "\" has unknown server element \"" + subject + "\"");

                throw new CertificateException(
                        "Server certificate subject CN contains unknown server element: "
                                + subject);
            }
        }

        return CN;
    }

    // Note that System.err is used because that will go to catalina.out whereas the current logging will send
    // these toa  central log that is very hard to sift through.
    private void checkServerDN(X509Certificate cert)
            throws CertificateException {
        // Essentially, we have to check that the CN and the host match,
        MyLoggingFacade ll = getLogger();
        String CN = getCommonName(cert.getSubjectX500Principal().getName());
        //System.err.println(getClass().getSimpleName() + ".checkServerDN: CN on cert = " + CN);
        if (hasServerDN()) {
                        // Fixes OAUTH-176: server DN can be overridden
            String configuredCN = getCommonName(getServerDN());
          //  System.err.println(getClass().getSimpleName() + ".checkServerDN: Configured serverDN has CN = " + configuredCN);

            if(CN.equals(configuredCN)){
            //    System.err.println(getClass().getSimpleName() + ".checkServerDN: Configured serverDN == CN, returning");
                 return;
            }
            //System.err.println(getClass().getSimpleName() + ".checkServerDN: Configured serverDN check failed.");


        }
        //System.err.println(getClass().getSimpleName() + ".checkServerDN: Checking cert CN against hostname");

        // So if the serDN and the returned hostname do NOT match, check the cert name against the hostname
        if (getHost().equals("localhost")) {
            try {
                setHost(InetAddress.getLocalHost().getHostName());
            } catch (Exception e) {
                // ignore
            }
        }
        //System.err.println(getClass().getSimpleName() + ".checkServerDN: Configured host = " + getHost());
        //System.err.println(getClass().getSimpleName() + ".checkServerDN: host=CN? " + CN.equals(getHost()));

        if (!CN.equals(getHost())) {
            dbg("common name =\"" + CN + "\" does not match host from reverse lookup = \"" + host + "\"");
            throw new CertificateException(
                    "Server certificate subject CN (" + CN
                            + ") does not match server hostname (" + host
                            + ").");
        }
        dbg("Success! common name =\"" + CN + "\" matches host = \"" + host + "\"");

    }

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy