/******************************************************************************* * This file is part of OpenNMS(R). * * Copyright (C) 2007-2011 The OpenNMS Group, Inc. * OpenNMS(R) is Copyright (C) 1999-2011 The OpenNMS Group, Inc. * * OpenNMS(R) is a registered trademark of The OpenNMS Group, Inc. * * OpenNMS(R) is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published * by the Free Software Foundation, either version 3 of the License, * or (at your option) any later version. * * OpenNMS(R) is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with OpenNMS(R). If not, see: * http://www.gnu.org/licenses/ * * For more information contact: * OpenNMS(R) Licensing <license@opennms.org> * http://www.opennms.org/ * http://www.opennms.com/ *******************************************************************************/ package org.opennms.netmgt.jetty; import java.io.File; import java.net.InetAddress; import java.util.Map; import java.util.Properties; import java.util.concurrent.ConcurrentHashMap; import org.eclipse.jetty.ajp.Ajp13SocketConnector; import org.eclipse.jetty.http.ssl.SslContextFactory; import org.eclipse.jetty.server.Connector; import org.eclipse.jetty.server.Server; import org.eclipse.jetty.server.handler.HandlerCollection; import org.eclipse.jetty.server.nio.SelectChannelConnector; import org.eclipse.jetty.server.ssl.SslSocketConnector; import org.eclipse.jetty.webapp.WebAppContext; import org.opennms.netmgt.daemon.AbstractServiceDaemon; import org.opennms.serviceregistration.ServiceRegistrationFactory; import org.opennms.serviceregistration.ServiceRegistrationStrategy; /** * Implements Web Application within OpenNMS as a Service Daemon. * * @author <a href="mailto:brozow@opennms.org">Mathew Brozowski</a> * @author <a href="mailto:david@opennms.org">David Hustace</a> */ public class JettyServer extends AbstractServiceDaemon { int m_port = 8080; private Server m_server; private Map<String,ServiceRegistrationStrategy> services = new ConcurrentHashMap<String,ServiceRegistrationStrategy>(); /** * <p>Constructor for JettyServer.</p> */ protected JettyServer() { super("OpenNMS.JettyServer"); } /** {@inheritDoc} */ @Override protected void onInit() { Properties p = System.getProperties(); File homeDir = new File(p.getProperty("opennms.home")); File webappsDir = new File(homeDir, "jetty-webapps"); m_server = new Server(); Connector connector = new SelectChannelConnector(); Integer port = Integer.getInteger("org.opennms.netmgt.jetty.port", m_port); connector.setPort(port); String host = System.getProperty("org.opennms.netmgt.jetty.host"); if (host != null) { connector.setHost(host); } Integer requestHeaderSize = Integer.getInteger("org.opennms.netmgt.jetty.requestHeaderSize"); if(requestHeaderSize != null) { connector.setRequestHeaderSize(requestHeaderSize); } m_server.addConnector(connector); Integer ajp_port = Integer.getInteger("org.opennms.netmgt.jetty.ajp-port"); if (ajp_port != null) { Ajp13SocketConnector ajpConnector = new Ajp13SocketConnector(); ajpConnector.setPort(ajp_port); // Apache AJP connector freaks out with anything larger ajpConnector.setHeaderBufferSize(8096); m_server.addConnector(ajpConnector); } Integer https_port = Integer.getInteger("org.opennms.netmgt.jetty.https-port"); if (https_port != null) { String keyStorePath = System.getProperty("org.opennms.netmgt.jetty.https-keystore", homeDir+File.separator+"etc"+File.separator+"examples"+File.separator+"jetty.keystore"); String keyStorePassword = System.getProperty("org.opennms.netmgt.jetty.https-keystorepassword", "changeit"); String keyManagerPassword = System.getProperty("org.opennms.netmgt.jetty.https-keypassword", "changeit"); SslContextFactory contextFactory = new SslContextFactory(keyStorePath); contextFactory.setKeyStorePassword(keyStorePassword); contextFactory.setKeyManagerPassword(keyManagerPassword); excludeCipherSuites(contextFactory, https_port); SslSocketConnector sslConnector = new SslSocketConnector(contextFactory); sslConnector.setPort(https_port); String httpsHost = System.getProperty("org.opennms.netmgt.jetty.https-host"); if (httpsHost != null) { sslConnector.setHost(httpsHost); } m_server.addConnector(sslConnector); } HandlerCollection handlers = new HandlerCollection(); if (webappsDir.exists()) { File rootDir = null; for (File file: webappsDir.listFiles()) { if (file.isDirectory()) { String contextPath; if ("ROOT".equals(file.getName())) { // Defer this to last to avoid nested context order problems rootDir = file; continue; } else { contextPath = "/" + file.getName(); } addContext(handlers, file, contextPath); registerService(port, contextPath); } } if (rootDir != null) { // If we deferred a ROOT context, handle that now addContext(handlers, rootDir, "/"); registerService(port, "/"); } } m_server.setHandler(handlers); m_server.setStopAtShutdown(true); } /** * <p>addContext</p> * * @param handlers a {@link org.eclipse.jetty.server.handler.HandlerCollection} object. * @param name a {@link java.io.File} object. * @param contextPath a {@link java.lang.String} object. */ protected void addContext(HandlerCollection handlers, File name, String contextPath) { log().warn("adding context: " + contextPath + " -> " + name.getAbsolutePath()); WebAppContext wac = new WebAppContext(); wac.setWar(name.getAbsolutePath()); wac.setContextPath(contextPath); handlers.addHandler(wac); } /** * <p>registerService</p> * * @param port a {@link java.lang.Integer} object. * @param contextPath a {@link java.lang.String} object. */ protected void registerService(Integer port, String contextPath) { String contextName = contextPath.replace("/", ""); try { ServiceRegistrationStrategy srs = ServiceRegistrationFactory.getStrategy(); String host = InetAddress.getLocalHost().getHostName().replace(".local", "").replace(".", "-"); Map<String, String> properties = new ConcurrentHashMap<String, String>(); properties.put("path", contextPath); srs.initialize("HTTP", contextName + "-" + host, port, properties); services.put(contextName, srs); } catch (Throwable e) { log().warn("unable to get a DNS-SD object for context '" + contextPath + "'", e); } } /** * <p>excludeCipherSuites</p> * @param contextFactory * @param https_port * @param sslConnector a {@link org.eclipse.jetty.server.security.SslSocketConnector} object. */ protected void excludeCipherSuites(SslContextFactory contextFactory, Integer port) { String[] defaultExclSuites = { "SSL_DHE_DSS_WITH_DES_CBC_SHA", "SSL_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA", "SSL_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA", "SSL_DHE_RSA_WITH_DES_CBC_SHA", "SSL_RSA_EXPORT_WITH_DES40_CBC_SHA", "SSL_RSA_EXPORT_WITH_RC4_40_MD5", "SSL_RSA_WITH_3DES_EDE_CBC_SHA", "SSL_RSA_WITH_DES_CBC_SHA", "TLS_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA", "TLS_RSA_EXPORT_WITH_DES40_CBC_SHA", "TLS_RSA_WITH_DES_CBC_SHA" }; String[] exclSuites; String exclSuitesString = System.getProperty("org.opennms.netmgt.jetty.https-exclude-cipher-suites"); if (exclSuitesString == null) { log().warn("No excluded SSL/TLS cipher suites specified, using hard-coded defaults"); exclSuites = defaultExclSuites; } else { exclSuites = exclSuitesString.split("\\s*:\\s*"); log().warn("Excluding " + exclSuites.length + " user-specified SSL/TLS cipher suites"); } contextFactory.setExcludeCipherSuites(exclSuites); for (String suite : exclSuites) { log().info("Excluded SSL/TLS cipher suite " + suite + " for connector on port " + port); } } /** {@inheritDoc} */ @Override protected void onStart() { try { m_server.start(); } catch (Throwable e) { log().error("Error starting Jetty Server", e); } for (String key: services.keySet()) { ServiceRegistrationStrategy srs = services.get(key); if (srs != null) { try { srs.register(); } catch (Throwable e) { log().warn("unable to register a DNS-SD object for context '" + key + "'", e); } } } } /** {@inheritDoc} */ @Override protected void onStop() { for (String key: services.keySet()) { ServiceRegistrationStrategy srs = services.get(key); if (srs != null) { try { srs.unregister(); } catch (Throwable e) { log().warn("unable to unregister a DNS-SD object for context '" + key + "'", e); } } } try { m_server.stop(); } catch (Throwable e) { log().error("Error stopping Jetty Server", e); } } }