/* (c) 2016 Open Source Geospatial Foundation - all rights reserved
* This code is licensed under the GPL 2.0 license, available at the root
* application directory.
*/
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*
*/
package org.geoserver.wps.remote.plugin.server;
import java.io.IOException;
import java.util.List;
import org.apache.vysper.xmpp.extension.xep0124.BoshEndpoint;
import org.apache.vysper.xmpp.extension.xep0124.BoshServlet;
import org.apache.vysper.xmpp.server.Endpoint;
import org.apache.vysper.xmpp.server.ServerRuntimeContext;
import org.eclipse.jetty.http.HttpVersion;
import org.eclipse.jetty.server.Connector;
import org.eclipse.jetty.server.Handler;
import org.eclipse.jetty.server.HttpConfiguration;
import org.eclipse.jetty.server.HttpConnectionFactory;
import org.eclipse.jetty.server.SecureRequestCustomizer;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.server.ServerConnector;
import org.eclipse.jetty.server.SslConnectionFactory;
import org.eclipse.jetty.servlet.ServletContextHandler;
import org.eclipse.jetty.servlet.ServletHolder;
import org.eclipse.jetty.util.ssl.SslContextFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.io.Resource;
/**
* Based on original {@link BoshEndpoint}, which uses an old version of jetty-server and jetty-security.
*
*
* Allows HTTP clients to communicate via the BOSH protocol with Vysper.
* <p>
* See http://xmpp.org/extensions/xep-0124.html and http://xmpp.org/extensions/xep-0206.html
*
* @author The Apache MINA Project (dev@mina.apache.org)
* @author Alessio Fabiani, GeoSolutions S.A.S. *
*/
public class XMPPBoshEndpoint implements Endpoint {
protected final static Logger logger = LoggerFactory.getLogger(XMPPBoshEndpoint.class);
protected ServerRuntimeContext serverRuntimeContext;
protected int port = 5222;
protected Server server;
protected boolean isSSLEnabled;
protected String sslKeystorePath;
protected String sslKeystorePassword;
protected List<String> accessControlAllowOrigin;
protected String contextPath = "/";
public void setServerRuntimeContext(ServerRuntimeContext serverRuntimeContext) {
this.serverRuntimeContext = serverRuntimeContext;
}
/**
* Setter for the listen port
*
* @param port
*/
public void setPort(int port) {
this.port = port;
}
/**
* Configures the SSL keystore
* <p>
* Required if SSL is enabled. Also, setting the keystore password is required.
*
* @see #setSSLCertificateKeystorePassword
* @param keystorePath the path to the Java keystore
* @throws IOException
*/
public void setSSLCertificateKeystore(Resource keystorePath) throws IOException {
sslKeystorePath = keystorePath.getFile().getAbsolutePath();
}
/**
* Configures the SSL keystore
* <p>
* Required if SSL is enabled. Also, setting the keystore password is required.
*
* @see #setSSLCertificateKeystorePassword
* @param keystorePath the path to the Java keystore
*/
public void setSSLCertificateKeystore(String keystorePath) {
sslKeystorePath = keystorePath;
}
/**
* Configures the SSL keystore password.
* <p>
* Required if SSL is enabled. Also, the keystore must be set using {@link #setSSLCertificateKeystore(String)} } The password is used both for
* accessing the keystore and for recovering the key from the keystore. The unique password is a limitation, you cannot use different passwords
* for the keystore and for the key.
*
* @param password the password used as the keystore password and also used when recovering the key from the keystore
*/
public void setSSLCertificateKeystorePassword(String password) {
sslKeystorePassword = password;
}
/**
* Enables/disables SSL for this endpoint.
* <p>
* If SSL is enabled it requires SSL certificate information that can be configured with {@link #setSSLCertificateInfo(String, String)}
*
* @param value
*/
public void setSSLEnabled(boolean value) {
isSSLEnabled = value;
}
/**
* Get the list of domains allowed to access this endpoint
*
* @return The list of allowed domains
*/
public List<String> getAccessControlAllowOrigin() {
return accessControlAllowOrigin;
}
/**
* Set the list of domains allowed to access this endpoint
*
* @param accessControlAllowOrigin The list of allowed domains
*/
public void setAccessControlAllowOrigin(List<String> accessControlAllowOrigin) {
this.accessControlAllowOrigin = accessControlAllowOrigin;
}
/**
* Determines the context URI where the BOSH transport will be accessible. The default is as 'root context' under '/'.
*
* @param contextPath
*/
public void setContextPath(String contextPath) {
if (contextPath == null)
contextPath = "/";
this.contextPath = contextPath;
}
/**
* create a basic Jetty server including a connector on the configured port override in subclass to create a different kind of setup or to reuse
* an existing instance
*
* @return
*/
protected Server createJettyServer() {
Server server = new Server();
ServerConnector connector;
// HTTP Configuration
// HttpConfiguration is a collection of configuration information
// appropriate for http and https. The default scheme for http is
// <code>http</code> of course, as the default for secured http is
// <code>https</code> but we show setting the scheme to show it can be
// done. The port for secured communication is also set here.
HttpConfiguration http_config = new HttpConfiguration();
http_config.setSecureScheme("https");
http_config.setSecurePort(port);
http_config.setOutputBufferSize(32768);
if (isSSLEnabled) {
// SSL Context Factory for HTTPS
// SSL requires a certificate so we configure a factory for ssl contents
// with information pointing to what keystore the ssl connection needs
// to know about. Much more configuration is available the ssl context,
// including things like choosing the particular certificate out of a
// keystore to be used.
SslContextFactory sslContextFactory = new SslContextFactory();
sslContextFactory.setKeyStorePath(sslKeystorePath);
sslContextFactory.setKeyManagerPassword(sslKeystorePassword);
sslContextFactory.setKeyStorePassword(sslKeystorePassword);
// HTTPS Configuration
// A new HttpConfiguration object is needed for the next connector and
// you can pass the old one as an argument to effectively clone the
// contents. On this HttpConfiguration object we add a
// SecureRequestCustomizer which is how a new connector is able to
// resolve the https connection before handing control over to the Jetty
// Server.
HttpConfiguration https_config = new HttpConfiguration(http_config);
SecureRequestCustomizer src = new SecureRequestCustomizer();
// src.setStsMaxAge(2000);
// src.setStsIncludeSubDomains(true);
https_config.addCustomizer(src);
// HTTPS connector
// We create a second ServerConnector, passing in the http configuration
// we just made along with the previously created ssl context factory.
// Next we set the port and a longer idle timeout.
connector = new ServerConnector(server,
new SslConnectionFactory(sslContextFactory, HttpVersion.HTTP_1_1.asString()),
new HttpConnectionFactory(https_config));
connector.setIdleTimeout(500000);
} else {
connector = new ServerConnector(server,
new HttpConnectionFactory(http_config));
connector.setIdleTimeout(30000);
}
connector.setPort(port);
server.setConnectors(new Connector[] { connector });
return server;
}
/**
* create handler for BOSH. for a different handler setup, override in a subclass. for more than one handler, add them to a
* org.eclipse.jetty.server.handler.ContextHandlerCollection and return the collection
*
* @return
*/
protected Handler createHandler() {
ServletContextHandler boshContext = new ServletContextHandler(
ServletContextHandler.SESSIONS);
boshContext.setContextPath(contextPath);
BoshServlet boshServlet = new BoshServlet();
boshServlet.setServerRuntimeContext(serverRuntimeContext);
boshServlet.setAccessControlAllowOrigin(accessControlAllowOrigin);
boshContext.addServlet(new ServletHolder(boshServlet), "/");
return boshContext;
}
/**
* @throws IOException
* @throws RuntimeException a wrapper of the possible {@link java.lang.Exception} that Jetty can throw at start-up
*/
public void start() throws IOException {
server = createJettyServer();
Handler handler = createHandler();
server.setHandler(handler);
try {
server.start();
} catch (Exception e) {
throw new RuntimeException(e);
}
}
public void stop() {
try {
server.stop();
} catch (Exception e) {
logger.warn("Could not stop the Jetty server", e);
}
}
}