/** * Exposes the HTTP adapter's configuration properties as a Spring bean. * * @return The configuration properties. */ @Bean @ConfigurationProperties(prefix = "hono.http") public HttpProtocolAdapterProperties adapterProperties() { return new HttpProtocolAdapterProperties(); }
private Future<HttpServer> bindSecureHttpServer(final Router router) { if (isSecurePortEnabled()) { final Future<HttpServer> result = Future.future(); final String bindAddress = server == null ? getConfig().getBindAddress() : "?"; if (server == null) { server = vertx.createHttpServer(getHttpServerOptions()); } server.requestHandler(router::accept).listen(done -> { if (done.succeeded()) { LOG.info("secure http server listening on {}:{}", bindAddress, server.actualPort()); result.complete(done.result()); } else { LOG.error("error while starting up secure http server", done.cause()); result.fail(done.cause()); } }); return result; } else { return Future.succeededFuture(); } }
private Future<HttpServer> bindInsecureHttpServer(final Router router) { if (isInsecurePortEnabled()) { final Future<HttpServer> result = Future.future(); final String bindAddress = insecureServer == null ? getConfig().getInsecurePortBindAddress() : "?"; if (insecureServer == null) { insecureServer = vertx.createHttpServer(getInsecureHttpServerOptions()); } insecureServer.requestHandler(router).listen(done -> { if (done.succeeded()) { LOG.info("insecure http server listening on {}:{}", bindAddress, insecureServer.actualPort()); result.complete(done.result()); } else { LOG.error("error while starting up insecure http server", done.cause()); result.fail(done.cause()); } }); return result; } else { return Future.succeededFuture(); } }
private void addEventApiRoutes(final Router router, final Handler<RoutingContext> authHandler) { // support CORS headers for PUTing events router.routeWithRegex("\\/event\\/[^\\/]+\\/.*").handler(CorsHandler.create(getConfig().getCorsAllowedOrigin()) .allowedMethod(HttpMethod.PUT) .allowedHeader(Constants.HEADER_TIME_TIL_DISCONNECT) .allowedHeader(HttpHeaders.AUTHORIZATION.toString()) .allowedHeader(HttpHeaders.CONTENT_TYPE.toString())); if (getConfig().isAuthenticationRequired()) { // support CORS headers for POSTing events router.route("/event").handler(CorsHandler.create(getConfig().getCorsAllowedOrigin()) .allowedMethod(HttpMethod.POST) .allowedHeader(Constants.HEADER_TIME_TIL_DISCONNECT) .allowedHeader(HttpHeaders.AUTHORIZATION.toString()) .allowedHeader(HttpHeaders.CONTENT_TYPE.toString())); // require auth for POSTing events router.route(HttpMethod.POST, "/event").handler(authHandler); // route for posting events using tenant and device ID determined as part of // device authentication router.route(HttpMethod.POST, "/event").handler(this::handlePostEvent); // require auth for PUTing events router.route(HttpMethod.PUT, "/event/*").handler(authHandler); // route for asserting that authenticated device's tenant matches tenant from path variables router.route(HttpMethod.PUT, String.format("/event/:%s/:%s", PARAM_TENANT, PARAM_DEVICE_ID)) .handler(this::assertTenant); } // route for sending event messages router.route(HttpMethod.PUT, String.format("/event/:%s/:%s", PARAM_TENANT, PARAM_DEVICE_ID)) .handler(ctx -> uploadEventMessage(ctx, getTenantParam(ctx), getDeviceIdParam(ctx))); }
/** * Gets the options to use for creating the insecure http server. * <p> * Subclasses may override this method in order to customize the server. * <p> * This method returns default options with the host and port being set to the corresponding values * from the <em>config</em> properties and using a maximum chunk size of 4096 bytes. * * @return The http server options. */ protected HttpServerOptions getInsecureHttpServerOptions() { final HttpServerOptions options = new HttpServerOptions(); options.setHost(getConfig().getInsecurePortBindAddress()).setPort(getConfig().getInsecurePort(getInsecurePortDefaultValue())).setMaxChunkSize(4096); return options; }
/** * Gets the options to use for creating the TLS secured http server. * <p> * Subclasses may override this method in order to customize the server. * <p> * This method returns default options with the host and port being set to the corresponding values * from the <em>config</em> properties and using a maximum chunk size of 4096 bytes. * * @return The http server options. */ protected HttpServerOptions getHttpServerOptions() { final HttpServerOptions options = new HttpServerOptions(); options.setHost(getConfig().getBindAddress()).setPort(getConfig().getPort(getPortDefaultValue())) .setMaxChunkSize(4096); addTlsKeyCertOptions(options); addTlsTrustOptions(options); return options; }
@Override protected void addRoutes(final Router router) { if (getConfig().isAuthenticationRequired()) { final ChainAuthHandler authHandler = new HonoChainAuthHandler(); authHandler.append(new X509AuthHandler( Optional.ofNullable(clientCertAuthProvider).orElse( new X509AuthProvider(getCredentialsServiceClient(), getConfig())), getTenantServiceClient(), tracer)); authHandler.append(new HonoBasicAuthHandler( Optional.ofNullable(usernamePasswordAuthProvider).orElse( new UsernamePasswordAuthProvider(getCredentialsServiceClient(), getConfig())), getConfig().getRealm())); addTelemetryApiRoutes(router, authHandler); addEventApiRoutes(router, authHandler); addCommandResponseRoutes(router, authHandler); } else { LOG.warn("device authentication has been disabled"); LOG.warn("any device may publish data on behalf of all other devices"); addTelemetryApiRoutes(router, null); addEventApiRoutes(router, null); addCommandResponseRoutes(router, null); } }
private void handle401(final RoutingContext ctx) { HttpUtils.unauthorized(ctx, "Basic realm=\"" + getConfig().getRealm() + "\""); }
/** * Creates the router for handling requests. * <p> * This method creates a router instance with the following routes: * <ol> * <li>A default route limiting the body size of requests to the maximum payload size set in the <em>config</em> properties.</li> * </ol> * * @return The newly created router (never {@code null}). */ protected Router createRouter() { final Router router = Router.router(vertx); LOG.info("limiting size of inbound request body to {} bytes", getConfig().getMaxPayloadSize()); router.route().handler(BodyHandler.create(DEFAULT_UPLOADS_DIRECTORY).setBodyLimit(getConfig().getMaxPayloadSize())); addTracingHandler(router, -5); // add default handler for failed routes router.route().order(-1).failureHandler(new DefaultFailureHandler()); return router; }
private void addTelemetryApiRoutes(final Router router, final Handler<RoutingContext> authHandler) { router.routeWithRegex("\\/telemetry\\/[^\\/]+\\/.*").handler(CorsHandler.create(getConfig().getCorsAllowedOrigin()) .allowedMethod(HttpMethod.PUT) .allowedHeader(Constants.HEADER_QOS_LEVEL) .allowedHeader(HttpHeaders.CONTENT_TYPE.toString())); if (getConfig().isAuthenticationRequired()) { router.route("/telemetry").handler(CorsHandler.create(getConfig().getCorsAllowedOrigin()) .allowedMethod(HttpMethod.POST) .allowedHeader(Constants.HEADER_QOS_LEVEL)
/** * Gets the options to use for creating the insecure http server. * <p> * Subclasses may override this method in order to customize the server. * <p> * This method returns default options with the host and port being set to the corresponding values * from the <em>config</em> properties and using a maximum chunk size of 4096 bytes. * * @return The http server options. */ protected HttpServerOptions getInsecureHttpServerOptions() { final HttpServerOptions options = new HttpServerOptions(); options.setHost(getConfig().getInsecurePortBindAddress()).setPort(getConfig().getInsecurePort(getInsecurePortDefaultValue())).setMaxChunkSize(4096); return options; }
/** * Gets the options to use for creating the TLS secured http server. * <p> * Subclasses may override this method in order to customize the server. * <p> * This method returns default options with the host and port being set to the corresponding values * from the <em>config</em> properties and using a maximum chunk size of 4096 bytes. * * @return The http server options. */ protected HttpServerOptions getHttpServerOptions() { final HttpServerOptions options = new HttpServerOptions(); options.setHost(getConfig().getBindAddress()).setPort(getConfig().getPort(getPortDefaultValue())) .setMaxChunkSize(4096); addTlsKeyCertOptions(options); addTlsTrustOptions(options); return options; }
@Override protected void addRoutes(final Router router) { if (getConfig().isAuthenticationRequired()) { final ChainAuthHandler authHandler = ChainAuthHandler.create(); authHandler.append(new X509AuthHandler( new TenantServiceBasedX509Authentication(getTenantServiceClient(), tracer), Optional.ofNullable(clientCertAuthProvider).orElse( new X509AuthProvider(getCredentialsServiceClient(), getConfig(), tracer)))); authHandler.append(new HonoBasicAuthHandler( Optional.ofNullable(usernamePasswordAuthProvider).orElse( new UsernamePasswordAuthProvider(getCredentialsServiceClient(), getConfig(), tracer)), getConfig().getRealm(), tracer)); addTelemetryApiRoutes(router, authHandler); addEventApiRoutes(router, authHandler); addCommandResponseRoutes(router, authHandler); } else { LOG.warn("device authentication has been disabled"); LOG.warn("any device may publish data on behalf of all other devices"); addTelemetryApiRoutes(router, null); addEventApiRoutes(router, null); addCommandResponseRoutes(router, null); } }
private void handle401(final RoutingContext ctx) { HttpUtils.unauthorized(ctx, "Basic realm=\"" + getConfig().getRealm() + "\""); }
/** * Creates the router for handling requests. * <p> * This method creates a router instance with the following routes: * <ol> * <li>A default route limiting the body size of requests to the maximum payload size set in the <em>config</em> properties.</li> * </ol> * * @return The newly created router (never {@code null}). */ protected Router createRouter() { final Router router = Router.router(vertx); LOG.info("limiting size of inbound request body to {} bytes", getConfig().getMaxPayloadSize()); router.route().handler(BodyHandler.create(DEFAULT_UPLOADS_DIRECTORY).setBodyLimit(getConfig().getMaxPayloadSize())); addTracingHandler(router, -5); // add default handler for failed routes router.route().order(-1).failureHandler(new DefaultFailureHandler()); return router; }
private void addCommandResponseRoutes(final Router router, final Handler<RoutingContext> authHandler) { router.routeWithRegex("\\/control\\/res\\/[^\\/]+\\/[^\\/]+\\/.*").handler(CorsHandler.create(getConfig().getCorsAllowedOrigin()) .allowedMethod(HttpMethod.PUT) .allowedHeader(Constants.HEADER_COMMAND_RESPONSE_STATUS) .allowedHeader(HttpHeaders.CONTENT_TYPE.toString())); if (getConfig().isAuthenticationRequired()) { router.route("/control/res/*").handler(CorsHandler.create(getConfig().getCorsAllowedOrigin()) .allowedMethod(HttpMethod.POST) .allowedHeader(Constants.HEADER_COMMAND_RESPONSE_STATUS)
/** * Exposes the HTTP adapter's configuration properties as a Spring bean. * * @return The configuration properties. */ @Bean @ConfigurationProperties(prefix = "hono.http") public HttpProtocolAdapterProperties adapterProperties() { return new HttpProtocolAdapterProperties(); }
private Future<HttpServer> bindSecureHttpServer(final Router router) { if (isSecurePortEnabled()) { final Future<HttpServer> result = Future.future(); final String bindAddress = server == null ? getConfig().getBindAddress() : "?"; if (server == null) { server = vertx.createHttpServer(getHttpServerOptions()); } server.requestHandler(router).listen(done -> { if (done.succeeded()) { LOG.info("secure http server listening on {}:{}", bindAddress, server.actualPort()); result.complete(done.result()); } else { LOG.error("error while starting up secure http server", done.cause()); result.fail(done.cause()); } }); return result; } else { return Future.succeededFuture(); } }
private Future<HttpServer> bindInsecureHttpServer(final Router router) { if (isInsecurePortEnabled()) { final Future<HttpServer> result = Future.future(); final String bindAddress = insecureServer == null ? getConfig().getInsecurePortBindAddress() : "?"; if (insecureServer == null) { insecureServer = vertx.createHttpServer(getInsecureHttpServerOptions()); } insecureServer.requestHandler(router::accept).listen(done -> { if (done.succeeded()) { LOG.info("insecure http server listening on {}:{}", bindAddress, insecureServer.actualPort()); result.complete(done.result()); } else { LOG.error("error while starting up insecure http server", done.cause()); result.fail(done.cause()); } }); return result; } else { return Future.succeededFuture(); } }
private void addCommandResponseRoutes(final Router router, final Handler<RoutingContext> authHandler) { router.routeWithRegex("\\/control\\/res\\/[^\\/]+\\/[^\\/]+\\/.*").handler(CorsHandler.create(getConfig().getCorsAllowedOrigin()) .allowedMethod(HttpMethod.PUT) .allowedHeader(Constants.HEADER_COMMAND_RESPONSE_STATUS) .allowedHeader(HttpHeaders.CONTENT_TYPE.toString())); if (getConfig().isAuthenticationRequired()) { router.route("/control/res/*").handler(CorsHandler.create(getConfig().getCorsAllowedOrigin()) .allowedMethod(HttpMethod.POST) .allowedHeader(Constants.HEADER_COMMAND_RESPONSE_STATUS)