precision.coder
precision.coder

Reputation: 41

How to secure Vert.x 3.3 Eventbus Bridge with Keycloak

I'm currently writing a simple prototype Vert.x 3.3 application (Latest Github build using Jitpack.io) that tries to secure http endpoints and the eventbus with Keycloak.

I have two verticals and static index page with a button to send messages. Everything works fine unsecured but I don't know how to secure the SockJS eventbus bridge with Keycloak. Securing the http endpoint works fine.

Since Vert.x 3.3 is not officially released yet I haven't been able to find very much information. http://vertx.io/blog/vertx-3-and-keycloak-tutorial/ only covered securing the http endpoint and the 3.21 documentation on requiring authorization is specifically for using the BasicAuthHandler which I'm not sure how to modify to work with Keycloak: http://vertx.io/docs/vertx-web/java/#_requiring_authorisation_for_messages

Currently I have the following code:

public class VertxEventBusTest extends AbstractVerticle {

@Override
public void start(Future<Void> startFuture) throws Exception {
System.out.println("Primary Verticle Started");
Router router = Router.router(vertx);
HttpServer server = vertx.createHttpServer().requestHandler(router::accept);

OAuth2Auth oAuth2Auth = OAuth2Auth.createKeycloak(vertx, OAuth2FlowType.AUTH_CODE, getKeycloakJson());
OAuth2AuthHandler oAuth2AuthHandler = OAuth2AuthHandler.create(oAuth2Auth, "http://localhost:8091");
oAuth2AuthHandler.setupCallback(router.get("/callback"));

SockJSHandlerOptions options = new SockJSHandlerOptions().setHeartbeatInterval(2000);
BridgeOptions bridgeOptions = new BridgeOptions();
bridgeOptions.addInboundPermitted(new PermittedOptions().setAddress("click"));
bridgeOptions.addOutboundPermitted(new PermittedOptions().setAddress("click"));
SockJSHandler sockJSHandler = SockJSHandler.create(vertx, options).bridge(bridgeOptions);
router.route("/").handler(oAuth2AuthHandler);
router.route("/eventbus/*").handler(oAuth2AuthHandler);
router.route("/eventbus/*").handler(sockJSHandler);

vertx.eventBus().<JsonObject>consumer("click", msg -> System.out.println("Msg Received on Verticle1: " + msg.body()));

router.route().handler(StaticHandler.create().setWebRoot("webroot"));

server.listen(8091, result -> {
  if (result.succeeded()) {
    startFuture.complete();
  } else {
    startFuture.fail(result.cause());
  }
});
}

private JsonObject getKeycloakJson() {
return new JsonObject("{\n" +
                          "  \"realm\": \"Prototype\",\n" +
                          "  \"realm-public-key\": \"<public key>",\n" +
                          "  \"auth-server-url\": \"http://localhost:8180/auth\",\n" +
                          "  \"ssl-required\": \"external\",\n" +
                          "  \"resource\": \"prototype-eventbus\",\n" +
                          "  \"credentials\": {\n" +
                          "    \"secret\": \"<secret>\"\n" +
                          "  }\n" +
                          "}");
  }
}

My Static Html is:

<head>
  <meta charset="UTF-8">
  <script src='sockjs-0.3.4.js'></script>
  <script src='vertx-eventbus.js'></script>
  <script src='index-js.js'></script>
  <title>VERT.X Test</title>
</head>
<body onload="load()">
<!-- JavaScript includes. -->

<button onclick="zclicker()">Test Click</button>
</body>
</html>

Javascript:

var eb = new EventBus('http://localhost:8091/eventbus');

function load() {
  eb.onopen = function () {
    eb.registerHandler('click', function (data) {})
  };
}

function zclicker() {
  eb.publish('click', {
    'clicked': true
  });
}

When running the vertical there are no errors but chrome developer tools shows the following error after login through keycloak:

XMLHttpRequest cannot load http://localhost:8180/auth/realms/Prototype/protocol/openid-connect/auth?re…direct_uri%3D%2Feventbus%2Finfo&state=&client_id=prototype-eventbus&scope=. No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost:8091' is therefore not allowed access.

Upvotes: 4

Views: 978

Answers (1)

Will
Will

Reputation: 6721

That looks like a CORS issue.

By the looks of your error you might just be able to add the following header in the response:

Access-Control-Allow-Origin: *

or

Access-Control-Allow-Origin: http://localhost:8091

depending on how much you care about security.

That's usually sufficient for simple GET for text/html, but if you want to handle other content types (eg JSON) or PUT / or DELETE methods, then you'll have to add more headers to allow them.

Some resources:

http://enable-cors.org/server.html

http://www.html5rocks.com/en/tutorials/cors/

Upvotes: 1

Related Questions