Skip to content

Instantly share code, notes, and snippets.

@InfoSec812
Last active November 3, 2022 16:56
Show Gist options
  • Star 10 You must be signed in to star a gist
  • Fork 5 You must be signed in to fork a gist
  • Save InfoSec812/a45eb3b7ba9d4b2a9b94 to your computer and use it in GitHub Desktop.
Save InfoSec812/a45eb3b7ba9d4b2a9b94 to your computer and use it in GitHub Desktop.
SSL Config Example For Vert.x 3.0.0
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();
}
}
}
@WEBOWNIA
Copy link

WEBOWNIA commented Jul 3, 2015

In version 3.0.0... setRequiredRole is the same setRequiredAuthority.... ?

@kamaljeetrathi
Copy link

I am setting
httpClientOptions.setSsl(true).setPemKeyCertOptions(new PemKeyCertOptions().setKeyPath(keyCrtFile).setCertPath(certCrtFile).setCertPath(caCrtFile));

as path and I have three certificate file which need to be authenticate ca.pem,cert.pem,key.pem
its giving me error
SEVERE: java.lang.RuntimeException: Missing -----BEGIN PRIVATE KEY----- delimiter

@datagenn
Copy link

@kamaljeetrathi

You need to convert PKCS8 to PK8
openssl pkcs8 -topk8 -inform PEM -outform PEM -in ca.key -out ca-new.pem -nocrypt

@datagenn
Copy link

Also, if using this code in Production, don't use 'SHA1WithRSA' as it is insecure and not even supported by Google Chrome any longer; use 'SHA256WithRSA' instead.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment