Package com.trsst.server

Source Code of com.trsst.server.Server

/*
* Copyright 2013 mpowers
*
* Licensed 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 com.trsst.server;

import java.io.IOException;
import java.math.BigInteger;
import java.net.InetAddress;
import java.net.MalformedURLException;
import java.net.ServerSocket;
import java.net.URL;
import java.net.UnknownHostException;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.security.cert.Certificate;
import java.security.cert.CertificateException;
import java.util.Date;

import org.apache.abdera.protocol.server.servlet.AbderaServlet;
import org.bouncycastle.asn1.x500.X500Name;
import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;
import org.bouncycastle.cert.X509v3CertificateBuilder;
import org.bouncycastle.cert.jcajce.JcaX509CertificateConverter;
import org.bouncycastle.operator.ContentSigner;
import org.bouncycastle.operator.OperatorCreationException;
import org.bouncycastle.operator.jcajce.JcaContentSignerBuilder;
import org.eclipse.jetty.server.Connector;
import org.eclipse.jetty.server.HttpConfiguration;
import org.eclipse.jetty.server.HttpConnectionFactory;
import org.eclipse.jetty.server.SecureRequestCustomizer;
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;

/**
* Jetty-specific configuration to host an Abdera servlet that is configured to
* serve the Trsst protocol.
*
* @author mpowers
*/
public class Server {
    private final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(this
            .getClass());

    int port;
    String path;
    boolean secure;
    private org.eclipse.jetty.server.Server server;
    private ServletContextHandler context;

    public Server() throws Exception {
        this(0, null);
    }

    public Server(int port) throws Exception {
        this(port, null);
    }

    public Server(int port, String path) throws Exception {
        this(port, path, false);
    }

    public Server(boolean secure) throws Exception {
        this(0, null, secure);
    }

    public Server(String path, boolean secure) throws Exception {
        this(0, path, secure);
    }

    public Server(int port, String path, boolean secure) throws Exception {
        try {
            if (path != null) {
                if (path.endsWith("/")) {
                    path = path.substring(0, path.length() - 1);
                }
                if (!path.startsWith("/")) {
                    path = "/" + path;
                }
            } else {
                path = "";
            }
            if (port == 0) {
                port = allocatePort();
            }

            this.secure = secure;
            this.port = port;
            this.path = path;
            start();
        } catch (Exception ioe) {
            log.error("could not start server on " + port + " : " + path, ioe);
            throw ioe;
        }
    }

    /**
     * Generates a new keystore containing a self-signed certificate. Would
     * prefer anon SSL ciphers, but this works albeit with scary warnings.
     *
     * @return a keystore to secure SSL connections.
     */
    private KeyStore getKeyStore() {
        try {
            KeyPairGenerator keyPairGenerator = KeyPairGenerator
                    .getInstance("RSA");
            keyPairGenerator.initialize(1024);
            KeyPair kp = keyPairGenerator.generateKeyPair();
            X509v3CertificateBuilder v3CertGen = new X509v3CertificateBuilder(
                    new X500Name("CN=0.0.0.0, OU=None, O=None, L=None, C=None"),
                    BigInteger.valueOf(new SecureRandom().nextInt()), new Date(
                            System.currentTimeMillis() - 1000L * 60 * 60 * 24
                                    * 30), new Date(System.currentTimeMillis()
                            + (1000L * 60 * 60 * 24 * 365 * 10)), new X500Name(
                            "CN=0.0.0.0, OU=None, O=None, L=None, C=None"),
                    SubjectPublicKeyInfo.getInstance(kp.getPublic()
                            .getEncoded()));
            ContentSigner signer = new JcaContentSignerBuilder(
                    "SHA256WithRSAEncryption").build(kp.getPrivate());
            Certificate certificate = new JcaX509CertificateConverter()
                    .getCertificate(v3CertGen.build(signer));

            final KeyStore keystore = KeyStore.getInstance(KeyStore
                    .getDefaultType());
            keystore.load(null); // bogus: required to "initialize" keystore
            keystore.setEntry("jetty",
                    new KeyStore.PrivateKeyEntry(kp.getPrivate(),
                            new Certificate[] { certificate }),
                    new KeyStore.PasswordProtection("ignored".toCharArray()));

            return keystore;
        } catch (NoSuchAlgorithmException e) {
            log.error(
                    "Could not generate self-signed certificate: missing provider",
                    e);
        } catch (OperatorCreationException e) {
            log.error("Could not generate self-signed certificate", e);
        } catch (CertificateException e) {
            log.error("Could not convert certificate to JCE", e);
        } catch (KeyStoreException e) {
            log.error("Could not generate keystore", e);
        } catch (IOException e) {
            log.error("Could not initialize keystore", e);
        }
        return null;
    }

    /**
     * Grabs a new server port. Borrowed from axiom.
     */
    private int allocatePort() {
        try {
            ServerSocket ss = new ServerSocket(0);
            int port = ss.getLocalPort();
            ss.close();
            return port;
        } catch (IOException ex) {
            log.error("Unable to allocate TCP port; defaulting to 54445.", ex);
            return 54445; // arbitrary port
        }
    }

    public URL getServiceURL() {
        URL result = null;
        String protocol = secure ? "https" : "http";
        try {
            result = new URL(protocol, "localhost", port, path); // default
            result = new URL(protocol, InetAddress.getLocalHost()
                    .getHostAddress(), port, path);
        } catch (MalformedURLException e) {
            // accept default
        } catch (UnknownHostException e) {
            // accept default
        }
        return result;
    }

    public void start() {
        try {
            getJetty().start();
        } catch (Exception e) {
            log.error("Error while starting server", e);
        }
    }

    public void stop() {
        try {
            server.stop();
        } catch (Exception e) {
            log.error("Error while stopping server", e);
        }
        server.destroy();
    }
   
    public ServletContextHandler getServletContextHandler() {
        return context;
    }

    protected ServletHolder createProvidingServletHolder() {
        ServletHolder servletHolder = new ServletHolder(new AbderaServlet());
        servletHolder.setInitParameter(
                "org.apache.abdera.protocol.server.Provider",
                "com.trsst.server.AbderaProvider");
        return servletHolder;
    }

    protected void configureContext(ServletContextHandler context) {
        ServletHolder servletHolder = createProvidingServletHolder();
        context.addServlet(servletHolder, path + "/*");

        HttpConfiguration http_config = new HttpConfiguration();
        ServerConnector http = new ServerConnector(server,
                new HttpConnectionFactory(http_config));
        http.setPort(port);

        if (secure) {

            http_config.setSecureScheme("https");
            http_config.setSecurePort(8443);
            http_config.setOutputBufferSize(32768);

            final KeyStore keystore = getKeyStore();
            SslContextFactory sslContextFactory = new SslContextFactory(true);
            sslContextFactory.setKeyStore(keystore);
            sslContextFactory.setCertAlias("jetty");
            sslContextFactory.setKeyStorePassword("ignored");
            sslContextFactory.setKeyManagerPassword("ignored");
            sslContextFactory.setTrustAll(true);
            HttpConfiguration https_config = new HttpConfiguration(http_config);
            https_config.addCustomizer(new SecureRequestCustomizer());

            ServerConnector https = new ServerConnector(server,
                    new SslConnectionFactory(sslContextFactory, "http/1.1"),
                    new HttpConnectionFactory(https_config));
            https.setPort(port);
            server.setConnectors(new Connector[] { https });

        } else {
            server.setConnectors(new Connector[] { http });
        }
    }

    /**
     * Returns the jetty server.
     */
    public org.eclipse.jetty.server.Server getJetty() {
        if (server == null) {
            server = new org.eclipse.jetty.server.Server(port);
            context = new ServletContextHandler(
                    ServletContextHandler.NO_SESSIONS);
            context.setContextPath("/");
            server.setHandler(context);
            configureContext(context);

            // FIXME: does not work: still getting session cookie
            // see http://stackoverflow.com/questions/20373461
            // ((org.eclipse.jetty.server.session.HashSessionManager) context
            // .getSessionHandler().getSessionManager())
            // .setUsingCookies(false);
        }
        return server;
    }

}
TOP

Related Classes of com.trsst.server.Server

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.