    001/*
    002 * $HeadURL: http://juliusdavies.ca/svn/not-yet-commons-ssl/tags/commons-ssl-0.3.15/src/java/org/apache/commons/ssl/TomcatServerXML.java $
    003 * $Revision: 121 $
    004 * $Date: 2007-11-13 21:26:57 -0800 (Tue, 13 Nov 2007) $
    005 *
    006 * ====================================================================
    007 * Licensed to the Apache Software Foundation (ASF) under one
    008 * or more contributor license agreements.  See the NOTICE file
    009 * distributed with this work for additional information
    010 * regarding copyright ownership.  The ASF licenses this file
    011 * to you under the Apache License, Version 2.0 (the
    012 * "License"); you may not use this file except in compliance
    013 * with the License.  You may obtain a copy of the License at
    014 *
    015 *   http://www.apache.org/licenses/LICENSE-2.0
    016 *
    017 * Unless required by applicable law or agreed to in writing,
    018 * software distributed under the License is distributed on an
    019 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
    020 * KIND, either express or implied.  See the License for the
    021 * specific language governing permissions and limitations
    022 * under the License.
    023 * ====================================================================
    024 *
    025 * This software consists of voluntary contributions made by many
    026 * individuals on behalf of the Apache Software Foundation.  For more
    027 * information on the Apache Software Foundation, please see
    028 * <http://www.apache.org/>.
    029 *
    030 */
    031
    032package org.apache.commons.ssl;
    033
    034import org.w3c.dom.Document;
    035import org.w3c.dom.Element;
    036import org.w3c.dom.NodeList;
    037
    038import javax.xml.parsers.DocumentBuilder;
    039import javax.xml.parsers.DocumentBuilderFactory;
    040import java.io.File;
    041import java.io.FileInputStream;
    042import java.io.IOException;
    043import java.io.InputStream;
    044import java.util.Collections;
    045import java.util.Map;
    046import java.util.SortedMap;
    047import java.util.TreeMap;
    048
    049/**
    050 * @author Credit Union Central of British Columbia
    051 * @author <a href="http://www.cucbc.com/">www.cucbc.com</a>
    052 * @author <a href="mailto:juliusdavies@cucbc.com">juliusdavies@cucbc.com</a>
    053 * @since 22-Feb-2007
    054 */
    055public class TomcatServerXML {
    056    private final static LogWrapper log = LogWrapper.getLogger(TomcatServerXML.class);
    057
    058    /**
    059     * KeyMaterial extracted from Tomcat's conf/server.xml.  There might be
    060     * several KeyMaterials to extract if Tomcat has different SSL Certificates
    061     * listening on different ports.  This particular KeyMaterial will come from
    062     * the lowest secure port that Tomcat is properly configured to open.
    063     */
    064    public final static KeyMaterial KEY_MATERIAL;
    065
    066    /**
    067     * TrustMaterial extracted from Tomcat's conf/server.xml.  There might be
    068     * several TrustMaterials to extract if Tomcat has different SSL Certificates
    069     * listening on different ports.  This particular TrustMaterial will come
    070     * from the lowest secure port that Tomcat is properly configured to open.
    071     * </p><p>
    072     * There's a good chance this will be set to TrustMaterial.DEFAULT (which
    073     * use's the JVM's '$JAVA_HOME/jre/lib/security/cacerts' file).
    074     * </p><p>
    075     * Note:  With SSLServerSockets, TrustMaterial only matters when the
    076     * incoming client socket (SSLSocket) presents a client certificate.
    077     * </p>
    078     */
    079    public final static TrustMaterial TRUST_MATERIAL;
    080
    081    /**
    082     * new Integer( port ) --> KeyMaterial mapping of SSL Certificates found
    083     * inside Tomcat's conf/server.xml file.
    084     */
    085    public final static SortedMap KEY_MATERIAL_BY_PORT;
    086
    087    /**
    088     * new Integer( port ) --> TrustMaterial mapping of SSL configuration
    089     * found inside Tomcat's conf/server.xml file.
    090     * </p><p>
    091     * Many of these will probably be TrustMaterial.DEFAULT (which uses the
    092     * JVM's '$JAVA_HOME/jre/lib/security/cacerts' file).
    093     * </p><p>
    094     * Note:  With SSLServerSockets, TrustMaterial only matters when the
    095     * incoming client socket (SSLSocket) presents a client certificate.
    096     * </p>
    097     */
    098    public final static SortedMap TRUST_MATERIAL_BY_PORT;
    099
    100    static {
    101        String tomcatHome = System.getProperty("catalina.home");
    102        String serverXML = tomcatHome + "/conf/server.xml";
    103        TreeMap keyMap = new TreeMap();
    104        TreeMap trustMap = new TreeMap();
    105        InputStream in = null;
    106        Document doc = null;
    107        try {
    108            if (tomcatHome != null) {
    109                File f = new File(serverXML);
    110                if (f.exists()) {
    111                    try {
    112                        in = new FileInputStream(serverXML);
    113                    }
    114                    catch (IOException ioe) {
    115                        // oh well, no soup for us.
    116                        log.warn("Commons-SSL failed to load Tomcat's [" + serverXML + "] " + ioe);
    117                    }
    118                }
    119            }
    120            if (in != null) {
    121                DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
    122                try {
    123                    DocumentBuilder db = dbf.newDocumentBuilder();
    124                    doc = db.parse(in);
    125                }
    126                catch (Exception e) {
    127                    log.warn("Commons-SSL failed to parse Tomcat's [" + serverXML + "] " + e);
    128                }
    129            }
    130            if (doc != null) {
    131                loadTomcatConfig(doc, keyMap, trustMap);
    132            }
    133        }
    134        finally {
    135            if (in != null) {
    136                try { in.close(); } catch (Exception e) { /* . */ }
    137            }
    138        }
    139        KEY_MATERIAL_BY_PORT = Collections.unmodifiableSortedMap(keyMap);
    140        TRUST_MATERIAL_BY_PORT = Collections.unmodifiableSortedMap(trustMap);
    141
    142        KeyMaterial km = null;
    143        TrustMaterial tm = null;
    144        if (!keyMap.isEmpty()) {
    145            km = (KeyMaterial) keyMap.get(keyMap.firstKey());
    146        }
    147        if (!trustMap.isEmpty()) {
    148            tm = (TrustMaterial) trustMap.get(trustMap.firstKey());
    149        }
    150        KEY_MATERIAL = km;
    151        TRUST_MATERIAL = tm;
    152
    153    }
    154
    155    private static void loadTomcatConfig(Document d, Map keyMap, Map trustMap) {
    156        final String userHome = System.getProperty("user.home");
    157        NodeList nl = d.getElementsByTagName("Connector");
    158        for (int i = 0; i < nl.getLength(); i++) {
    159            KeyMaterial km = null;
    160            TrustMaterial tm = null;
    161
    162            Element element = (Element) nl.item(i);
    163            String secure = element.getAttribute("secure");
    164            String portString = element.getAttribute("port");
    165            Integer port = null;
    166            String pass;
    167            try {
    168                portString = portString != null ? portString.trim() : "";
    169                port = new Integer(portString);
    170            }
    171            catch (NumberFormatException nfe) {
    172                // oh well
    173            }
    174            if (port != null && Util.isYes(secure)) {
    175                // Key Material
    176                String keystoreFile = element.getAttribute("keystoreFile");
    177                pass = element.getAttribute("keystorePass");
    178                if (!element.hasAttribute("keystoreFile")) {
    179                    keystoreFile = userHome + "/.keystore";
    180                }
    181                if (!element.hasAttribute("keystorePass")) {
    182                    pass = "changeit";
    183                }
    184                char[] keystorePass = pass != null ? pass.toCharArray() : null;
    185
    186                // Trust Material
    187                String truststoreFile = element.getAttribute("truststoreFile");
    188                pass = element.getAttribute("truststorePass");
    189                if (!element.hasAttribute("truststoreFile")) {
    190                    truststoreFile = null;
    191                }
    192                if (!element.hasAttribute("truststorePass")) {
    193                    pass = null;
    194                }
    195                char[] truststorePass = pass != null ? pass.toCharArray() : null;
    196
    197
    198                if (keystoreFile == null) {
    199                    km = null;
    200                } else {
    201                    try {
    202                        km = new KeyMaterial(keystoreFile, keystorePass);
    203                    }
    204                    catch (Exception e) {
    205                        log.warn("Commons-SSL failed to load [" + keystoreFile + "] " + e);
    206                    }
    207                }
    208                if (truststoreFile == null) {
    209                    tm = TrustMaterial.DEFAULT;
    210                } else {
    211                    try {
    212                        tm = new TrustMaterial(truststoreFile, truststorePass);
    213                    }
    214                    catch (Exception e) {
    215                        log.warn("Commons-SSL failed to load [" + truststoreFile + "] " + e);
    216                    }
    217                }
    218
    219                Object o = keyMap.put(port, km);
    220                if (o != null) {
    221                    log.debug("Commons-SSL TomcatServerXML keyMap clobbered port: " + port);
    222                }
    223                o = trustMap.put(port, tm);
    224                if (o != null) {
    225                    log.debug("Commons-SSL TomcatServerXML trustMap clobbered port: " + port);
    226                }
    227            }
    228        }
    229    }
    230
    231}