|
|
@@ -0,0 +1,104 @@
|
|
|
+package cz.senslog.analytics.server;
|
|
|
+
|
|
|
+import cz.senslog.analytics.server.ws.AuthorizationType;
|
|
|
+import cz.senslog.analytics.server.ws.DisableAuthorizationHandler;
|
|
|
+import cz.senslog.analytics.server.ws.ExceptionHandler;
|
|
|
+import cz.senslog.analytics.server.ws.OpenAPIHandler;
|
|
|
+import cz.senslog.analytics.utils.ResourcesUtils;
|
|
|
+import io.vertx.core.AbstractVerticle;
|
|
|
+import io.vertx.core.Promise;
|
|
|
+import io.vertx.core.http.HttpMethod;
|
|
|
+import io.vertx.core.json.JsonObject;
|
|
|
+import io.vertx.ext.auth.KeyStoreOptions;
|
|
|
+import io.vertx.ext.auth.jwt.JWTAuth;
|
|
|
+import io.vertx.ext.auth.jwt.JWTAuthOptions;
|
|
|
+import io.vertx.ext.web.Router;
|
|
|
+import io.vertx.ext.web.handler.*;
|
|
|
+import io.vertx.ext.web.openapi.RouterBuilder;
|
|
|
+import org.apache.logging.log4j.LogManager;
|
|
|
+import org.apache.logging.log4j.Logger;
|
|
|
+
|
|
|
+import java.nio.file.Path;
|
|
|
+
|
|
|
+import static cz.senslog.analytics.server.ws.AuthorizationType.BEARER;
|
|
|
+import static java.util.Objects.requireNonNull;
|
|
|
+
|
|
|
+public final class HttpVertxServer extends AbstractVerticle {
|
|
|
+ private static final Logger logger = LogManager.getLogger(HttpVertxServer.class);
|
|
|
+
|
|
|
+
|
|
|
+ public HttpVertxServer() {
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public void start(Promise<Void> startPromise) {
|
|
|
+ final AuthorizationType openAPIAuthType = BEARER;
|
|
|
+
|
|
|
+ Path openApiUrl = ResourcesUtils.getPath("openAPISpec.yaml");
|
|
|
+ logger.info("Loading the OpenAPI spec from '{}'", openApiUrl);
|
|
|
+
|
|
|
+ RouterBuilder.create(vertx, requireNonNull(openApiUrl, "Open API Specification was not found as a resource.").toString())
|
|
|
+ .onSuccess(openAPIRouterBuilder -> {
|
|
|
+ logger.info("The OpenAPI specification was loaded successfully.");
|
|
|
+
|
|
|
+ openAPIRouterBuilder.rootHandler(LoggerHandler.create(false, LoggerFormat.SHORT));
|
|
|
+
|
|
|
+ openAPIRouterBuilder.rootHandler(CorsHandler.create()
|
|
|
+ .allowedMethod(HttpMethod.GET)
|
|
|
+ .allowedMethod(HttpMethod.POST)
|
|
|
+ .allowedMethod(HttpMethod.PUT)
|
|
|
+ .allowedMethod(HttpMethod.DELETE)
|
|
|
+
|
|
|
+ .allowedHeader("x-requested-with")
|
|
|
+ .allowedHeader("Access-Control-Allow-Origin")
|
|
|
+ .allowedHeader("Origin")
|
|
|
+ .allowedHeader("Content-Type")
|
|
|
+ .allowedHeader("Accept")
|
|
|
+ );
|
|
|
+
|
|
|
+ JsonObject authConfig = config().getJsonObject("auth");
|
|
|
+ if (authConfig.getBoolean("disabled")) {
|
|
|
+ logger.info("Security schema for all endpoints is disabled.");
|
|
|
+ openAPIRouterBuilder.securityHandler(openAPIAuthType.getSecuritySchemaKey(), DisableAuthorizationHandler.create());
|
|
|
+ } else {
|
|
|
+ logger.info("Setting security schema for the type '{}' with the schema key '{}'.", openAPIAuthType.name(), openAPIAuthType.getSecuritySchemaKey());
|
|
|
+ openAPIRouterBuilder.securityHandler(openAPIAuthType.getSecuritySchemaKey(), JWTAuthHandler.create(JWTAuth.create(vertx, new JWTAuthOptions()
|
|
|
+ .setKeyStore(new KeyStoreOptions()
|
|
|
+ .setPath(authConfig.getString("keystore.path"))
|
|
|
+ .setType(authConfig.getString("keystore.type"))
|
|
|
+ .setPassword(authConfig.getString("keystore.password"))))));
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ // The order matters, so adding the body handler should happen after any PLATFORM or SECURITY_POLICY handler(s).
|
|
|
+ openAPIRouterBuilder.rootHandler(BodyHandler.create());
|
|
|
+
|
|
|
+ OpenAPIHandler apiHandler = OpenAPIHandler.create();
|
|
|
+
|
|
|
+ openAPIRouterBuilder.operation("infoGET").handler(apiHandler::info);
|
|
|
+
|
|
|
+ Router mainRouter = openAPIRouterBuilder.createRouter();
|
|
|
+
|
|
|
+ mainRouter.route().failureHandler(ExceptionHandler.createAsJSON());
|
|
|
+
|
|
|
+ mainRouter.errorHandler(404, h -> h.fail(404,
|
|
|
+ new Throwable(String.format("Resource '%s' not found.", h.request().uri()))
|
|
|
+ ));
|
|
|
+
|
|
|
+ JsonObject serverConfig = config().getJsonObject("server");
|
|
|
+ vertx.createHttpServer()
|
|
|
+ .requestHandler(mainRouter)
|
|
|
+ .listen(serverConfig.getInteger("http.port"))
|
|
|
+ .onSuccess(server -> {
|
|
|
+ logger.info("HTTP server running on port {}.", server.actualPort());
|
|
|
+ startPromise.complete();
|
|
|
+ })
|
|
|
+ .onFailure(fail -> {
|
|
|
+ logger.error(fail);
|
|
|
+ startPromise.fail(fail);
|
|
|
+ });
|
|
|
+ })
|
|
|
+ .onFailure(startPromise::fail);
|
|
|
+ }
|
|
|
+}
|