-
-
Save Victorq10/7bd3eb61c7d654afe3de514dca746fb8 to your computer and use it in GitHub Desktop.
SSL Config Example For Vert.x 3.0.0
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package com.zanclus.socialshell; | |
import com.zanclus.socialshell.utils.AbstractLoggingVerticle; | |
import static io.vertx.ext.auth.shiro.LDAPAuthRealmConstants.*; | |
import io.vertx.core.AsyncResult; | |
import io.vertx.core.Future; | |
import io.vertx.core.Verticle; | |
import io.vertx.core.http.HttpServerOptions; | |
import io.vertx.core.json.JsonObject; | |
import io.vertx.core.net.JksOptions; | |
import io.vertx.core.net.PemKeyCertOptions; | |
import io.vertx.core.net.PfxOptions; | |
import io.vertx.ext.apex.Router; | |
import io.vertx.ext.apex.handler.StaticHandler; | |
import io.vertx.ext.apex.handler.sockjs.BridgeOptions; | |
import io.vertx.ext.apex.handler.sockjs.PermittedOptions; | |
import io.vertx.ext.apex.handler.sockjs.SockJSHandler; | |
import io.vertx.ext.auth.AuthProvider; | |
import io.vertx.ext.auth.shiro.ShiroAuthProvider; | |
import io.vertx.ext.auth.shiro.ShiroAuthRealmType; | |
import java.io.FileOutputStream; | |
import java.io.IOException; | |
import java.security.InvalidKeyException; | |
import java.security.KeyStore; | |
import java.security.KeyStoreException; | |
import java.security.NoSuchAlgorithmException; | |
import java.security.NoSuchProviderException; | |
import java.security.PrivateKey; | |
import java.security.SignatureException; | |
import java.security.cert.CertificateException; | |
import java.security.cert.X509Certificate; | |
import java.util.Date; | |
import java.util.logging.Level; | |
import java.util.logging.Logger; | |
import sun.security.tools.keytool.CertAndKeyGen; | |
import sun.security.x509.X500Name; | |
/** | |
* A {@link Verticle} which starts up the HTTP server for the web application UI. Based on the given | |
* configuration, the web server may be configured for SSL using a self-generated SSL cert or a provided SSL certificate | |
* file. The application accepts P12, PEM, and JKS files. | |
* | |
* The web server also configures handlers for the Auth Service and the {@link SockJSHandler} event bus bridge. | |
* | |
* @author <a href="https://github.com/InfoSec812">Deven Phillips</a> | |
*/ | |
public class WebServerVerticle extends AbstractLoggingVerticle { | |
/** | |
* Start this {@link Verticle} asynchronously and notify the deploying verticle on success or failure | |
* @param startFuture A {@link Future} with which to notify the deploying {@link Verticle} about success or failure | |
* @throws Exception If there is an uncaught error. | |
*/ | |
@Override | |
public void start(final Future<Void> startFuture) throws Exception { | |
final JsonObject config = context.config().getJsonObject("webserver"); | |
final JsonObject authCfg = context.config().getJsonObject("authentication"); | |
final String bindAddress; | |
final int bindPort; | |
final String webRoot; | |
if (config.containsKey("bind-address")) { | |
bindAddress = config.getString("bind-address"); | |
} else { | |
bindAddress = "0.0.0.0"; | |
} | |
if (config.containsKey("bind-port")) { | |
bindPort = config.getInteger("bind-port"); | |
} else { | |
bindPort = 8080; | |
} | |
if (config.containsKey("webroot")) { | |
webRoot = config.getString("webroot"); | |
} else { | |
webRoot = "webroot/"; | |
} | |
Router router = Router.router(vertx); | |
SockJSHandler sockjs = SockJSHandler.create(vertx); | |
BridgeOptions opts; | |
opts = new BridgeOptions() | |
// Allow inbound events going to the terminal session | |
.addInboundPermitted(new PermittedOptions() | |
.setAddressRegex("^terminal\\.to\\.server\\..*$") | |
.setRequiredRole("session")) | |
// Allow inbound events giving control of the terminal to an invited collaborator | |
.addInboundPermitted(new PermittedOptions() | |
.setAddressRegex("^delegate\\.control\\..*$") | |
.setRequiredRole("session")) | |
// Allow inbound events revoking control from invited collaborator | |
.addInboundPermitted(new PermittedOptions() | |
.setAddressRegex("^revoke\\.control\\..*$") | |
.setRequiredRole("session")) | |
// Allow inbound events for chat messages coming from the client for a given session | |
.addInboundPermitted(new PermittedOptions() | |
.setAddressRegex("^chat\\.to\\.server\\..*$") | |
.setRequiredRole("session")) | |
// Allow inbound events requesting control of a shared terminal | |
.addInboundPermitted(new PermittedOptions() | |
.setAddressRegex("^request\\.control\\..*$") | |
.setRequiredRole("session")) | |
// Allow inbound events releasing control of a shared terminal | |
.addInboundPermitted(new PermittedOptions() | |
.setAddressRegex("^release\\.control\\..*$") | |
.setRequiredRole("session")) | |
// Allow outbound events from the terminal session to the UI | |
.addOutboundPermitted(new PermittedOptions() | |
.setAddressRegex("^server\\.to\\.terminal\\..*$") | |
.setRequiredRole("session")) | |
// Allow outbound events from the server to participants in a session's chat | |
.addOutboundPermitted(new PermittedOptions() | |
.setAddressRegex("^server\\.to\\.chat\\..*$") | |
.setRequiredRole("session")) | |
// Allow outbound events to the UI indicating that control was granted | |
.addOutboundPermitted(new PermittedOptions() | |
.setAddressRegex("^control\\.granted\\..*$") | |
.setRequiredRole("session")) | |
// Allow outbound events to the UI indicating that control was revoked | |
.addOutboundPermitted(new PermittedOptions() | |
.setAddressRegex("^control\\.revoked\\..*$") | |
.setRequiredRole("session")); | |
sockjs.bridge(opts); | |
AuthProvider authProvider; | |
if (authCfg.containsKey("auth-provider")) { | |
switch(authCfg.getString("auth-provider")) { | |
case "ldap": | |
authProvider = ShiroAuthProvider.create(vertx, ShiroAuthRealmType.LDAP, authCfg); | |
break; | |
case "jdbc": | |
break; | |
default: {}; | |
} | |
} | |
router.route("/eventbus/*").handler(sockjs); | |
router.route().handler(StaticHandler.create(webRoot).setIndexPage("index.html")); | |
// If SSL is requested, prepare the SSL configuration off of the event bus to prevent blocking. | |
if (config.containsKey("ssl") && config.getBoolean("ssl")) { | |
vertx.executeBlocking(future -> { | |
HttpServerOptions httpOpts = new HttpServerOptions(); | |
if (config.containsKey("certificate-path")) { | |
String certPath = config.getString("certificate-path"); | |
// Use a Java Keystore File | |
if (certPath.toLowerCase().endsWith("jks") && config.getString("certificate-password")!=null) { | |
httpOpts.setKeyStoreOptions(new JksOptions() | |
.setPassword(config.getString("certificate-password")) | |
.setPath(certPath)); | |
httpOpts.setSsl(true); | |
// Use a PKCS12 keystore | |
} else if ( config.getString("certificate-password")!=null && | |
certPath.matches("^.*\\.(pfx|p12|PFX|P12)$")) { | |
httpOpts.setPfxKeyCertOptions(new PfxOptions() | |
.setPassword(config.getString("certificate-password")) | |
.setPath(certPath)); | |
httpOpts.setSsl(true); | |
// Use a PEM key/cert pair | |
} else if (certPath.matches("^.*\\.(pem|PEM)$")) { | |
httpOpts.setPemKeyCertOptions(new PemKeyCertOptions() | |
.setCertPath(certPath) | |
.setKeyPath(certPath)); | |
httpOpts.setSsl(true); | |
} else { | |
startFuture.fail("A certificate file was provided, but a password for that file was not."); | |
} | |
} else { | |
try { | |
// Generate a self-signed key pair and certificate. | |
KeyStore store = KeyStore.getInstance("JKS"); | |
store.load(null, null); | |
CertAndKeyGen keypair = new CertAndKeyGen("RSA", "SHA1WithRSA", null); | |
X500Name x500Name = new X500Name("localhost", "IT", "unknown", "unknown", "unknown", "unknown"); | |
keypair.generate(1024); | |
PrivateKey privKey = keypair.getPrivateKey(); | |
X509Certificate[] chain = new X509Certificate[1]; | |
chain[0] = keypair.getSelfCertificate(x500Name, new Date(), (long) 365 * 24 * 60 * 60); | |
store.setKeyEntry("selfsigned", privKey, "changeit".toCharArray(), chain); | |
store.store(new FileOutputStream(".keystore"), "changeit".toCharArray()); | |
httpOpts.setKeyStoreOptions(new JksOptions().setPath(".keystore").setPassword("changeit")); | |
httpOpts.setSsl(true); | |
} catch (KeyStoreException|IOException|NoSuchAlgorithmException|CertificateException|NoSuchProviderException|InvalidKeyException|SignatureException ex) { | |
Logger.getLogger(WebServerVerticle.class.getName()).log(Level.SEVERE, "Failed to generate a self-signed cert and other SSL configuration methods failed.", ex); | |
startFuture.fail(ex); | |
} | |
} | |
future.complete(httpOpts); | |
}, (AsyncResult<HttpServerOptions> result) -> { | |
if (!result.failed()) { | |
vertx.createHttpServer(result.result()).requestHandler(router::accept).listen(bindPort, bindAddress); | |
log.info("SSL Web server now listening"); | |
startFuture.complete(); | |
} | |
}); | |
} else { | |
// No SSL requested, start a non-SSL HTTP server. | |
vertx.createHttpServer().requestHandler(router::accept).listen(bindPort, bindAddress); | |
log.info("Web server now listening"); | |
startFuture.complete(); | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment