001/*
002 * $HeadURL: http://juliusdavies.ca/svn/not-yet-commons-ssl/tags/commons-ssl-0.3.9/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}