001    /*
002     * $HeadURL: http://juliusdavies.ca/svn/not-yet-commons-ssl/tags/commons-ssl-0.3.11/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    
032    package org.apache.commons.ssl;
033    
034    import org.w3c.dom.Document;
035    import org.w3c.dom.Element;
036    import org.w3c.dom.NodeList;
037    
038    import javax.xml.parsers.DocumentBuilder;
039    import javax.xml.parsers.DocumentBuilderFactory;
040    import java.io.File;
041    import java.io.FileInputStream;
042    import java.io.IOException;
043    import java.io.InputStream;
044    import java.util.Collections;
045    import java.util.Map;
046    import java.util.SortedMap;
047    import 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     */
055    public 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    }