From 861b8281b8b6b23d03e457932674c7b15eca6780 Mon Sep 17 00:00:00 2001 From: pranavrd Date: Tue, 23 Jul 2024 09:36:38 +0530 Subject: [PATCH 1/2] fix: validation and authentication callback handlers, updated create item flow accordingly --- .../server/apiserver/ApiServerVerticle.java | 56 +-- .../catalogue/server/apiserver/CrudApis.java | 382 +++++++++--------- .../authenticator/AuthenticationService.java | 33 +- .../AuthenticationServiceImpl.java | 163 -------- .../JwtAuthenticationServiceImpl.java | 27 +- .../KcAuthenticationServiceImpl.java | 14 +- .../server/validator/ValidatorService.java | 51 +-- .../validator/ValidatorServiceImpl.java | 246 ++++++----- 8 files changed, 393 insertions(+), 579 deletions(-) delete mode 100644 src/main/java/iudx/catalogue/server/authenticator/AuthenticationServiceImpl.java diff --git a/src/main/java/iudx/catalogue/server/apiserver/ApiServerVerticle.java b/src/main/java/iudx/catalogue/server/apiserver/ApiServerVerticle.java index 0f4ccca3..aa54439b 100644 --- a/src/main/java/iudx/catalogue/server/apiserver/ApiServerVerticle.java +++ b/src/main/java/iudx/catalogue/server/apiserver/ApiServerVerticle.java @@ -89,32 +89,12 @@ public void start() throws Exception { if (isSsL) { LOGGER.debug("Info: Starting HTTPs server"); - /* Read the configuration and set the HTTPs server properties. */ - - keystore = config().getString("keystore"); - keystorePassword = config().getString("keystorePassword"); - - /* - * Default port when ssl is enabled is 8443. If set through config, then that value is taken - */ - port = config().getInteger(PORT) == null ? 8443 : config().getInteger(PORT); - - /* Setup the HTTPs server properties, APIs and port. */ - - serverOptions - .setSsl(true) - .setKeyStoreOptions(new JksOptions().setPath(keystore).setPassword(keystorePassword)); + startHttpsServer(serverOptions); } else { LOGGER.debug("Info: Starting HTTP server"); - /* Setup the HTTP server properties, APIs and port. */ - - serverOptions.setSsl(false); - /* - * Default port when ssl is disabled is 8080. If set through config, then that value is taken - */ - port = config().getInteger(PORT) == null ? 8080 : config().getInteger(PORT); + startHttpServer(serverOptions); } LOGGER.debug("Started HTTP server at port : " + port); @@ -144,7 +124,6 @@ public void start() throws Exception { crudApis.setDbService(dbService); listApis.setDbService(dbService); relApis.setDbService(dbService); - // TODO : set db service for Rating APIs crudApis.setHost(config().getString(HOST)); ratingApis.setHost(config().getString(HOST)); mlayerApis.setHost(config().getString(HOST)); @@ -667,8 +646,7 @@ public void start() throws Exception { router .route(api.getStackRestApis() + "/*") .subRouter( - new StacRestApi( - router, api, config(), validationService, authService, auditingService) + new StacRestApi(router, api, config(), validationService, authService, auditingService) .init()); // Start server @@ -679,6 +657,34 @@ router, api, config(), validationService, authService, auditingService) LOGGER.info("API server deployed on :" + serverOptions.getPort()); } + private void startHttpServer(HttpServerOptions serverOptions) { + /* Setup the HTTP server properties, APIs and port. */ + + serverOptions.setSsl(false); + /* + * Default port when ssl is disabled is 8080. If set through config, then that value is taken + */ + port = config().getInteger(PORT) == null ? 8080 : config().getInteger(PORT); + } + + private void startHttpsServer(HttpServerOptions serverOptions) { + /* Read the configuration and set the HTTPs server properties. */ + + keystore = config().getString("keystore"); + keystorePassword = config().getString("keystorePassword"); + + /* + * Default port when ssl is enabled is 8443. If set through config, then that value is taken + */ + port = config().getInteger(PORT) == null ? 8443 : config().getInteger(PORT); + + /* Setup the HTTPs server properties, APIs and port. */ + + serverOptions + .setSsl(true) + .setKeyStoreOptions(new JksOptions().setPath(keystore).setPassword(keystorePassword)); + } + private void printDeployedEndpoints(Router router) { for (Route route : router.getRoutes()) { if (route.getPath() != null) { diff --git a/src/main/java/iudx/catalogue/server/apiserver/CrudApis.java b/src/main/java/iudx/catalogue/server/apiserver/CrudApis.java index b7068645..4b97a567 100644 --- a/src/main/java/iudx/catalogue/server/apiserver/CrudApis.java +++ b/src/main/java/iudx/catalogue/server/apiserver/CrudApis.java @@ -25,6 +25,7 @@ import iudx.catalogue.server.apiserver.util.RespBuilder; import iudx.catalogue.server.auditing.AuditingService; import iudx.catalogue.server.authenticator.AuthenticationService; +import iudx.catalogue.server.authenticator.model.JwtData; import iudx.catalogue.server.database.DatabaseService; import iudx.catalogue.server.util.Api; import iudx.catalogue.server.validator.ValidatorService; @@ -64,6 +65,24 @@ public CrudApis(Api api, boolean isUac) { this.isUac = isUac; } + private static String getItemType(JsonObject requestBody, HttpServerResponse response) { + Set type = new HashSet(new JsonArray().getList()); + try { + type = new HashSet(requestBody.getJsonArray(TYPE).getList()); + } catch (Exception e) { + LOGGER.error("Fail: Invalid type"); + RespBuilder respBuilder = new RespBuilder() + .withType(TYPE_INVALID_SCHEMA) + .withTitle(TITLE_INVALID_SCHEMA) + .withDetail("Invalid type for item/type not present"); + response.setStatusCode(400) + .end(respBuilder.getResponse()); + } + type.retainAll(ITEM_TYPES); + String itemType = type.toString().replaceAll("\\[", "").replaceAll("\\]", ""); + return itemType; + } + public void setDbService(DatabaseService dbService) { this.dbService = dbService; } @@ -98,223 +117,170 @@ public void createItemHandler(RoutingContext routingContext) { /* Contains the cat-item */ JsonObject requestBody = routingContext.body().asJsonObject(); + HttpServerRequest request = routingContext.request(); + + String postOrPutOperation = request.method().toString(); HttpServerResponse response = routingContext.response(); response.putHeader(HEADER_CONTENT_TYPE, MIME_APPLICATION_JSON); - Set type = new HashSet(new JsonArray().getList()); - try { - type = new HashSet(requestBody.getJsonArray(TYPE).getList()); - } catch (Exception e) { - LOGGER.error("Fail: Invalid type"); - RespBuilder respBuilder = new RespBuilder() - .withType(TYPE_INVALID_SCHEMA) - .withTitle(TITLE_INVALID_SCHEMA) - .withDetail("Invalid type for item/type not present"); - response.setStatusCode(400) - .end(respBuilder.getResponse()); - } - type.retainAll(ITEM_TYPES); - String itemType = type.toString().replaceAll("\\[", "").replaceAll("\\]", ""); + String itemType = getItemType(requestBody, response); LOGGER.debug("Info: itemType;" + itemType); - - // Start insertion flow - - // Json schema validate item - validatorService.validateSchema( - requestBody, - schValHandler -> { - if (schValHandler.failed()) { - - response - .setStatusCode(400) - .end( - new RespBuilder() - .withType(TYPE_INVALID_SCHEMA) - .withTitle(TITLE_INVALID_SCHEMA) - .withDetail(TITLE_INVALID_SCHEMA) - .withResult(schValHandler.cause().getMessage()) - .getResponse()); - return; - } - if (schValHandler.succeeded()) { - LOGGER.debug("Success: Schema validation"); - - JsonObject jwtAuthenticationInfo = new JsonObject(); - - HttpServerRequest request = routingContext.request(); - - // populating jwt authentication info -> - jwtAuthenticationInfo - .put(TOKEN, request.getHeader(HEADER_TOKEN)) - .put(METHOD, REQUEST_POST) - .put(API_ENDPOINT, api.getRouteItems()) - .put(ITEM_TYPE, itemType); - - if (isUac) { - handleItemCreation(routingContext, requestBody, response, jwtAuthenticationInfo); - } else { - if (itemType.equalsIgnoreCase(ITEM_TYPE_COS) - || itemType.equalsIgnoreCase(ITEM_TYPE_OWNER)) { - handleItemCreation(routingContext, requestBody, response, jwtAuthenticationInfo); - } else if (itemType.equalsIgnoreCase(ITEM_TYPE_RESOURCE_SERVER)) { - handleItemCreation(routingContext, requestBody, response, jwtAuthenticationInfo); - } else if (itemType.equals(ITEM_TYPE_PROVIDER)) { - Future resourceServerUrlFuture = - getParentObjectInfo(requestBody.getString(RESOURCE_SVR)); - // add resource server url to provider body - resourceServerUrlFuture.onComplete( - resourceServerUrl -> { - if (resourceServerUrl.succeeded()) { - String rsUrl = resourceServerUrl.result().getString(RESOURCE_SERVER_URL); - // used for relationship apis - String cosId = resourceServerUrl.result().getString(COS_ITEM); - - jwtAuthenticationInfo.put(RESOURCE_SERVER_URL, rsUrl); - requestBody.put(RESOURCE_SERVER_URL, rsUrl); - requestBody.put(COS_ITEM, cosId); - handleItemCreation( - routingContext, requestBody, response, jwtAuthenticationInfo); - } else { - response - .setStatusCode(400) - .end( - new RespBuilder() - .withType(TYPE_LINK_VALIDATION_FAILED) - .withTitle(TITLE_LINK_VALIDATION_FAILED) - .withDetail("Resource Server not found") - .getResponse()); - } - }); - } else { - Future ownerUserIdFuture = - getParentObjectInfo(requestBody.getString(PROVIDER)); - // add provider kc id to requestBody - ownerUserIdFuture.onComplete( - ownerUserId -> { - if (ownerUserId.succeeded()) { - LOGGER.debug(ownerUserId.result()); - String kcId = ownerUserId.result().getString(PROVIDER_USER_ID); - String rsUrl = ownerUserId.result().getString(RESOURCE_SERVER_URL); - // cosId is used for relationship apis - - jwtAuthenticationInfo.put(PROVIDER_USER_ID, kcId); - jwtAuthenticationInfo.put(RESOURCE_SERVER_URL, rsUrl); - requestBody.put(PROVIDER_USER_ID, kcId); - - String cosId = ownerUserId.result().getString(COS_ITEM); - requestBody.put(COS_ITEM, cosId); - handleItemCreation( - routingContext, requestBody, response, jwtAuthenticationInfo); - } else { - response - .setStatusCode(400) - .end( - new RespBuilder() - .withType(TYPE_LINK_VALIDATION_FAILED) - .withTitle(TITLE_LINK_VALIDATION_FAILED) - .withDetail("Provider not found") - .getResponse()); - } - }); - } - } - } - }); + ResultContainer resultContainer = new ResultContainer(); + + validatorService + .validateSchema(requestBody) + .compose(validatedRequestBody -> { + JsonObject jwtAuthenticationInfo = new JsonObject(); + + // populating jwt authentication info -> + jwtAuthenticationInfo + .put(TOKEN, request.getHeader(HEADER_TOKEN)) + .put(METHOD, REQUEST_POST) + .put(API_ENDPOINT, api.getRouteItems()) + .put(ITEM_TYPE, itemType); + JsonObject validatedRequestBodyWithMetaData = getParentObjectMetadata(itemType, validatedRequestBody, response, jwtAuthenticationInfo); + + return authService.tokenInterospect(validatedRequestBodyWithMetaData, jwtAuthenticationInfo); + }) + .compose(jwtData -> { + resultContainer.jwtData = jwtData; + return validatorService.validateItem(requestBody); + }) + .compose(requestBodyWithId -> { + return insertOrUpsertItem(requestBodyWithId, resultContainer.jwtData, postOrPutOperation); + }) + .onSuccess(successHandler -> { +// handleSuccessfulCreation(successHandler, postOrPutOperation); + }) + .onFailure(failureHandler -> { + // TODO: handle all 4xx cases of the compose chain accordingly +// handleCreationFailure(failureHandler); + }); } - - private void handleItemCreation(RoutingContext routingContext, - JsonObject requestBody, - HttpServerResponse response, - JsonObject jwtAuthenticationInfo) { - authService.tokenInterospect(new JsonObject(), - jwtAuthenticationInfo, authHandler -> { - if (authHandler.failed()) { - LOGGER.error("Error: " + authHandler.cause().getMessage()); - response.setStatusCode(401) - .end(new RespBuilder() - .withType(TYPE_TOKEN_INVALID) - .withTitle(TITLE_TOKEN_INVALID) - .withDetail(authHandler.cause().getMessage()) - .getResponse()); - } else { - LOGGER.debug("Success: JWT Auth successful"); - requestBody.put(HTTP_METHOD, routingContext.request().method().toString()); - /* Link Validating the request to ensure item correctness */ - validatorService.validateItem(requestBody, valhandler -> { - if (valhandler.failed()) { - LOGGER.error("Fail: Item validation failed;" + valhandler.cause().getMessage()); - if (valhandler.cause().getMessage().contains("validation failed. Incorrect id")) { - response.setStatusCode(400) - .end(new RespBuilder() - .withType(TYPE_INVALID_UUID) - .withTitle(TITLE_INVALID_UUID) - .withDetail("Syntax of the UUID is incorrect") - .getResponse()); - return; - } - response.setStatusCode(400) - .end(new RespBuilder() - .withType(TYPE_LINK_VALIDATION_FAILED) - .withTitle(TITLE_LINK_VALIDATION_FAILED) - .withDetail(valhandler.cause().getMessage()) - .getResponse()); - } - if (valhandler.succeeded()) { - LOGGER.debug("Success: Item link validation"); - - // If post, create. If put, update - if (routingContext.request().method().toString() == REQUEST_POST) { + private Future insertOrUpsertItem(JsonObject requestBodyWithId, JwtData jwtData, String postOrPutOperation) { + Promise promise = Promise.promise(); + if (postOrPutOperation.equalsIgnoreCase(REQUEST_POST)) { /* Requesting database service, creating a item */ LOGGER.debug("Info: Inserting item"); - dbService.createItem(valhandler.result(), dbhandler -> { + dbService.createItem(requestBodyWithId, dbhandler -> { if (dbhandler.failed()) { LOGGER.error("Fail: Item creation;" + dbhandler.cause().getMessage()); - response.setStatusCode(400) - .end(dbhandler.cause().getMessage()); + promise.fail(dbhandler.cause().getMessage()); } if (dbhandler.succeeded()) { LOGGER.info("Success: Item created;"); - response.setStatusCode(201) - .end(dbhandler.result().toString()); + promise.complete(dbhandler.result()); if (hasAuditService && !isUac) { - updateAuditTable( - authHandler.result(), - new String[]{valhandler.result().getString(ID), - api.getRouteItems(), REQUEST_POST}); + Future.future(fu -> updateAuditInfo( + jwtData, + new String[]{requestBodyWithId.getString(ID), + api.getRouteItems(), REQUEST_POST})); } } }); } else { LOGGER.debug("Info: Updating item"); /* Requesting database service, creating a item */ - dbService.updateItem(valhandler.result(), dbhandler -> { + dbService.updateItem(requestBodyWithId, dbhandler -> { if (dbhandler.succeeded()) { LOGGER.info("Success: Item updated;"); - response.setStatusCode(200) - .end(dbhandler.result().toString()); + promise.complete(dbhandler.result()); if (hasAuditService) { - updateAuditTable(authHandler.result(), - new String[]{valhandler.result().getString(ID), - api.getRouteItems(), REQUEST_PUT}); + Future.future(fu -> updateAuditInfo(jwtData, + new String[]{requestBodyWithId.getString(ID), + api.getRouteItems(), REQUEST_PUT})); } } else if (dbhandler.failed()) { LOGGER.error("Fail: Item update;" + dbhandler.cause().getMessage()); - if (dbhandler.cause().getLocalizedMessage().contains("Doc doesn't exist")) { - response.setStatusCode(404); - } else { - response.setStatusCode(400); - } - response.end(dbhandler.cause().getMessage()); + promise.fail(dbhandler.cause()); } }); } - } - }); - } - }); + return promise.future(); + } + + private JsonObject getParentObjectMetadata(String itemType, + JsonObject requestBody, + HttpServerResponse response, + JsonObject jwtAuthenticationInfo) { + + if (isUac) { + } else { + if (itemType.equalsIgnoreCase(ITEM_TYPE_COS) + || itemType.equalsIgnoreCase(ITEM_TYPE_OWNER)) { + } else if (itemType.equalsIgnoreCase(ITEM_TYPE_RESOURCE_SERVER)) { + } else if (itemType.equals(ITEM_TYPE_PROVIDER)) { + Future resourceServerUrlFuture = + getParentObjectInfo(requestBody.getString(RESOURCE_SVR)); + // add resource server url to provider body + resourceServerUrlFuture.onSuccess(resourceServerUrl -> { + String rsUrl = resourceServerUrl.getString(RESOURCE_SERVER_URL); + // used for relationship apis + String cosId = resourceServerUrl.getString(COS_ITEM); + + jwtAuthenticationInfo.put(RESOURCE_SERVER_URL, rsUrl); + requestBody.put(RESOURCE_SERVER_URL, rsUrl); + requestBody.put(COS_ITEM, cosId); + }).onFailure(parentInfoFailure-> { + response + .setStatusCode(400) + .end( + new RespBuilder() + .withType(TYPE_LINK_VALIDATION_FAILED) + .withTitle(TITLE_LINK_VALIDATION_FAILED) + .withDetail("Resource Server not found") + .getResponse()); + }); + + } else { + Future ownerUserIdFuture = + getParentObjectInfo(requestBody.getString(PROVIDER)); + // add provider kc id to requestBody + ownerUserIdFuture.onSuccess(ownerUserId -> { + LOGGER.debug(ownerUserId); + String kcId = ownerUserId.getString(PROVIDER_USER_ID); + String rsUrl = ownerUserId.getString(RESOURCE_SERVER_URL); + // cosId is used for relationship apis + + jwtAuthenticationInfo.put(PROVIDER_USER_ID, kcId); + jwtAuthenticationInfo.put(RESOURCE_SERVER_URL, rsUrl); + requestBody.put(PROVIDER_USER_ID, kcId); + + String cosId = ownerUserId.getString(COS_ITEM); + requestBody.put(COS_ITEM, cosId); + }).onFailure(parentInfoFailure -> { + response + .setStatusCode(400) + .end( + new RespBuilder() + .withType(TYPE_LINK_VALIDATION_FAILED) + .withTitle(TITLE_LINK_VALIDATION_FAILED) + .withDetail("Provider not found") + .getResponse()); + }); + + } + } + return requestBody; +// authService.tokenInterospect(new JsonObject(), +// jwtAuthenticationInfo, authHandler -> { +// if (authHandler.failed()) { +// } else { +// LOGGER.debug("Success: JWT Auth successful"); +// requestBody.put(HTTP_METHOD, routingContext.request().method().toString()); +// /* Link Validating the request to ensure item correctness */ +// validatorService.validateItem(requestBody, valhandler -> { +// if (valhandler.succeeded()) { +// LOGGER.debug("Success: Item link validation"); +// +// // If post, create. If put, update +// } +// }); +// } +// }); } /** @@ -475,6 +441,8 @@ public void deleteItemHandler(RoutingContext routingContext) { private void handleItemDeletion(HttpServerResponse response, JsonObject jwtAuthenticationInfo, JsonObject requestBody, String itemId) { + // TODO: convert callback handlers to future compose chains + /* authService.tokenInterospect(new JsonObject(), jwtAuthenticationInfo, authHandler -> { if (authHandler.failed()) { @@ -487,7 +455,7 @@ private void handleItemDeletion(HttpServerResponse response, .getResponse()); } else { LOGGER.debug("Success: JWT Auth successful"); - /* Requesting database service, deleting a item */ + // Requesting database service, deleting a item dbService.deleteItem(requestBody, dbHandler -> { if (dbHandler.succeeded()) { LOGGER.info("Success: Item deleted;"); @@ -514,6 +482,7 @@ private void handleItemDeletion(HttpServerResponse response, }); } }); + */ } Future getParentObjectInfo(String itemId) { @@ -575,6 +544,9 @@ public void createInstanceHandler(RoutingContext routingContext, String catAdmin .put(ITEM_TYPE, ITEM_TYPE_INSTANCE) .put(ID, host); // Introspect token and authorize operation + + // TODO: convert callback handlers to future compose chains + /* authService.tokenInterospect(new JsonObject(), authenticationInfo, authhandler -> { if (authhandler.failed()) { response.setStatusCode(401) @@ -585,7 +557,7 @@ public void createInstanceHandler(RoutingContext routingContext, String catAdmin .getResponse()); return; } else { - /* INSTANCE = "" to make sure createItem can be used for onboarding instance and items */ + // INSTANCE = "" to make sure createItem can be used for onboarding instance and items JsonObject body = new JsonObject().put(ID, instance) .put(TYPE, new JsonArray().add(ITEM_TYPE_INSTANCE)) .put(INSTANCE, ""); @@ -603,6 +575,7 @@ public void createInstanceHandler(RoutingContext routingContext, String catAdmin LOGGER.debug("Success: Authenticated instance creation request"); } }); + */ } /** @@ -637,6 +610,8 @@ public void deleteInstanceHandler(RoutingContext routingContext, String catAdmin .put(ITEM_TYPE, ITEM_TYPE_INSTANCE) .put(ID, host); // Introspect token and authorize operation + // TODO: convert callback handlers to future compose chains + /* authService.tokenInterospect(new JsonObject(), authenticationInfo, authhandler -> { if (authhandler.failed()) { response.setStatusCode(401) @@ -647,7 +622,7 @@ public void deleteInstanceHandler(RoutingContext routingContext, String catAdmin .getResponse()); return; } else { - /* INSTANCE = "" to make sure createItem can be used for onboarding instance and items */ + // INSTANCE = "" to make sure createItem can be used for onboarding instance and items JsonObject body = new JsonObject().put(ID, instance) .put(INSTANCE, ""); dbService.deleteItem(body, res -> { @@ -664,6 +639,8 @@ public void deleteInstanceHandler(RoutingContext routingContext, String catAdmin LOGGER.debug("Success: Authenticated instance creation request"); } }); + + */ } /** @@ -707,7 +684,34 @@ private void updateAuditTable(JsonObject jwtDecodedInfo, String[] otherInfo) { }); } + private Future updateAuditInfo(JwtData jwtData, String[] otherInfo) { + + JsonObject auditInfo = jwtData.toJson(); + ZonedDateTime zst = ZonedDateTime.now(); + LOGGER.debug("TIME ZST: " + zst); + long epochTime = getEpochTime(zst); + auditInfo.put(IUDX_ID, otherInfo[0]) + .put(API, otherInfo[1]) + .put(HTTP_METHOD, otherInfo[2]) + .put(EPOCH_TIME, epochTime) + .put(USERID, jwtData.getSub()); + + auditingService.insertAuditngValuesInRmq(auditInfo, auditHandler -> { + if (auditHandler.succeeded()) { + LOGGER.info("message published in RMQ."); + } else { + LOGGER.error("failed to publish message in RMQ."); + } + }); + return Future.succeededFuture(); + } + private long getEpochTime(ZonedDateTime zst) { return zst.toInstant().toEpochMilli(); } + + + final class ResultContainer { + JwtData jwtData; + } } diff --git a/src/main/java/iudx/catalogue/server/authenticator/AuthenticationService.java b/src/main/java/iudx/catalogue/server/authenticator/AuthenticationService.java index 46e53061..33f62188 100644 --- a/src/main/java/iudx/catalogue/server/authenticator/AuthenticationService.java +++ b/src/main/java/iudx/catalogue/server/authenticator/AuthenticationService.java @@ -5,9 +5,11 @@ import io.vertx.codegen.annotations.ProxyGen; import io.vertx.codegen.annotations.VertxGen; import io.vertx.core.AsyncResult; +import io.vertx.core.Future; import io.vertx.core.Handler; import io.vertx.core.Vertx; import io.vertx.core.json.JsonObject; +import iudx.catalogue.server.authenticator.model.JwtData; /** * The Authentication Service. @@ -28,31 +30,28 @@ @ProxyGen public interface AuthenticationService { - /** - * The tokenInterospect method implements the authentication and authorization module using IUDX - * APIs. - * - * - * @param request which is a JsonObject - * @param authenticationInfo which is a JsonObject - * @param handler which is a request handler - * @return AuthenticationService which is a service - */ - - @Fluent - AuthenticationService tokenInterospect(JsonObject request, JsonObject authenticationInfo, - Handler> handler); - /** * The createProxy helps the code generation blocks to generate proxy code. * * @param vertx which is the vertx instance * @param address which is the proxy address - * @return AuthenticationServiceVertxEBProxy which is a service proxy + * @return AuthenticationServiceVertxEBProxy which is a service proxy */ - + @GenIgnore static AuthenticationService createProxy(Vertx vertx, String address) { return new AuthenticationServiceVertxEBProxy(vertx, address); } + + /** + * The tokenInterospect method implements the authentication and authorization module using IUDX + * APIs. + * + * + * @param request which is a JsonObject + * @param authenticationInfo which is a JsonObject + * @return Future which is a vert.x Future of type JwtData + */ + + Future tokenInterospect(JsonObject request, JsonObject authenticationInfo); } diff --git a/src/main/java/iudx/catalogue/server/authenticator/AuthenticationServiceImpl.java b/src/main/java/iudx/catalogue/server/authenticator/AuthenticationServiceImpl.java deleted file mode 100644 index 608a1758..00000000 --- a/src/main/java/iudx/catalogue/server/authenticator/AuthenticationServiceImpl.java +++ /dev/null @@ -1,163 +0,0 @@ -package iudx.catalogue.server.authenticator; - - -import static iudx.catalogue.server.authenticator.Constants.*; -import static iudx.catalogue.server.util.Constants.*; - -import io.vertx.core.AsyncResult; -import io.vertx.core.Future; -import io.vertx.core.Handler; -import io.vertx.core.buffer.Buffer; -import io.vertx.core.http.HttpMethod; -import io.vertx.core.json.JsonArray; -import io.vertx.core.json.JsonObject; -import io.vertx.ext.web.client.HttpResponse; -import io.vertx.ext.web.client.WebClient; -import io.vertx.ext.web.client.predicate.ResponsePredicate; -import java.util.Arrays; -import org.apache.http.HttpStatus; -import org.apache.logging.log4j.LogManager; -import org.apache.logging.log4j.Logger; - - -/** - * The Authentication Service Implementation. - *

Authentication Service Implementation

- *

- * The Authentication Service implementation in the IUDX Catalogue Server implements the definitions - * of the {@link iudx.catalogue.server.authenticator.AuthenticationService}. - *

- * - * @version 1.0 - * @since 2020-05-31 - */ - -public class AuthenticationServiceImpl implements AuthenticationService { - - private static final Logger LOGGER = LogManager.getLogger(AuthenticationServiceImpl.class); - static WebClient webClient; - private String authHost; - private JsonObject config; - - /** - * Constructs a new instance of AuthenticationServiceImpl. - * @param client The web client to use for authentication requests. - * @param authHost The authentication host to send requests to. - * @param config The configuration properties for the authentication service. - */ - public AuthenticationServiceImpl(WebClient client, String authHost, JsonObject config) { - webClient = client; - this.authHost = authHost; - this.config = config; - } - - static void validateAuthInfo(JsonObject authInfo) throws IllegalArgumentException { - if (authInfo.isEmpty()) { - throw new IllegalArgumentException("AuthInfo argument is empty/missing"); - } - String token = authInfo.getString(TOKEN, ""); - String operation = authInfo.getString(OPERATION, ""); - if (token.isBlank() || operation.isBlank()) { - throw new IllegalArgumentException("Token/Operation in authenticationInfo is blank/missing"); - } else if (token.length() > TOKEN_SIZE) { - throw new IllegalArgumentException( - "Supported max size of Token in authenticationInfo is " + TOKEN_SIZE); - } else if (!token.matches(TOKEN_REGEX)) { - throw new IllegalArgumentException( - "Invalid Token pattern, supported pattern " + TOKEN_REGEX); - } - try { - HttpMethod.valueOf(operation); - } catch (IllegalArgumentException e) { - throw new IllegalArgumentException("Invalid operation in the authenticationInfo object"); - } - } - - /** - * {@inheritDoc} - */ - @Override - public AuthenticationService tokenInterospect(JsonObject request, JsonObject authenticationInfo, - Handler> handler) { - JsonObject result = new JsonObject(); - String providerId; - try { - validateAuthInfo(authenticationInfo); - providerId = request.getString(PROVIDER, ""); - if (providerId.isBlank()) { - throw new IllegalArgumentException("Missing provider in request object"); - } - } catch (IllegalArgumentException e) { - result.put(STATUS, ERROR); - result.put(MESSAGE, e.getMessage()); - handler.handle(Future.succeededFuture(result)); - return this; - } - - JsonObject body = new JsonObject(); - body.put(TOKEN, authenticationInfo.getString(TOKEN)); - String tokenIntrospectPath = config.getString("dxAuthBasePath") + AUTH_TIP_PATH; - webClient - .post(443, authHost, tokenIntrospectPath) - .expect(ResponsePredicate.JSON) - .sendJsonObject(body, httpResponseAsyncResult -> { - if (httpResponseAsyncResult.failed()) { - result.put(STATUS, ERROR); - result.put(MESSAGE, AUTH_SERVER_ERROR); - LOGGER.error(AUTH_SERVER_ERROR + ";", httpResponseAsyncResult.cause()); - handler.handle(Future.succeededFuture(result)); - return; - } - HttpResponse response = httpResponseAsyncResult.result(); - if (response.statusCode() != HttpStatus.SC_OK) { - result.put(STATUS, ERROR); - result.put(MESSAGE, response - .bodyAsJsonObject() - .getJsonObject(ERROR) - .getString(MESSAGE)); - handler.handle(Future.succeededFuture(result)); - return; - } - - JsonArray responseRequests = response.bodyAsJsonObject().getJsonArray(REQUEST); - for (Object req : responseRequests) { - JsonObject requestEntry = (JsonObject) req; - String requestId = requestEntry.getString(ID, ""); - if (isPermittedProviderId(requestId, providerId)) { - result.put(STATUS, SUCCESS); - result.put(BODY, new JsonObject()); - handler.handle(Future.succeededFuture(result)); - return; - } - } - - result.put(STATUS, ERROR); - result.put(MESSAGE, "ID/Operations not permitted with presented token"); - handler.handle(Future.succeededFuture(result)); - }); - - return null; - } - - private boolean isPermittedProviderId(String requestId, String providerId) { - String tipProvider = String.join("/", Arrays.asList(requestId.split("/", 3)).subList(0, 2)); - return providerId.equals(tipProvider); - } - - /** - * Iterates through each method in the given array and checks if - * it matches the given operation or if the method is "*", which represents all methods. - * @param methods The list of methods to check. - * @param operation The operation to check against the list of methods. - * @return True if the operation is permitted, false otherwise. - */ - public boolean isPermittedMethod(JsonArray methods, String operation) { - for (Object o : methods) { - String method = (String) o; - if (method.equals("*") || method.equals(operation)) { - return true; - } - } - return false; - } -} diff --git a/src/main/java/iudx/catalogue/server/authenticator/JwtAuthenticationServiceImpl.java b/src/main/java/iudx/catalogue/server/authenticator/JwtAuthenticationServiceImpl.java index fb633d77..89d2d25e 100644 --- a/src/main/java/iudx/catalogue/server/authenticator/JwtAuthenticationServiceImpl.java +++ b/src/main/java/iudx/catalogue/server/authenticator/JwtAuthenticationServiceImpl.java @@ -6,9 +6,7 @@ import static iudx.catalogue.server.authenticator.Constants.RESOURCE_SERVER_URL; import static iudx.catalogue.server.util.Constants.*; -import io.vertx.core.AsyncResult; import io.vertx.core.Future; -import io.vertx.core.Handler; import io.vertx.core.Promise; import io.vertx.core.json.JsonObject; import io.vertx.ext.auth.authentication.TokenCredentials; @@ -152,10 +150,10 @@ Future isValidEndpoint(String endPoint) { * @return a Future containing a JsonObject with user information if the access is allowed, or a * failure if the access is denied */ - public Future validateAccess( + public Future validateAccess( JwtData jwtData, JsonObject authenticationInfo, String itemType) { LOGGER.trace("validateAccess() started"); - Promise promise = Promise.promise(); + Promise promise = Promise.promise(); Method method = Method.valueOf(authenticationInfo.getString(METHOD)); String api = authenticationInfo.getString(API_ENDPOINT); @@ -173,11 +171,11 @@ public Future validateAccess( LOGGER.debug("User access is allowed"); JsonObject response = new JsonObject(); // adding user id, user role and iid to response for auditing purpose - response - .put(USER_ROLE, jwtData.getRole()) - .put(USER_ID, jwtData.getSub()) - .put(IID, jwtData.getIid()); - promise.complete(response); +// response +// .put(USER_ROLE, jwtData.getRole()) +// .put(USER_ID, jwtData.getSub()) +// .put(IID, jwtData.getIid()); + promise.complete(jwtData); } else { LOGGER.error("user access denied"); JsonObject result = new JsonObject().put("401", "no access provided to endpoint"); @@ -187,8 +185,9 @@ public Future validateAccess( } @Override - public AuthenticationService tokenInterospect( - JsonObject request, JsonObject authenticationInfo, Handler> handler) { + public Future tokenInterospect( + JsonObject request, JsonObject authenticationInfo) { + Promise promise = Promise.promise(); String endPoint = authenticationInfo.getString(API_ENDPOINT); String provider = authenticationInfo.getString(PROVIDER_USER_ID, ""); String token = authenticationInfo.getString(TOKEN); @@ -255,12 +254,12 @@ public AuthenticationService tokenInterospect( .onComplete( completeHandler -> { if (completeHandler.succeeded()) { - handler.handle(Future.succeededFuture(completeHandler.result())); + promise.complete(completeHandler.result()); } else { - handler.handle(Future.failedFuture(completeHandler.cause().getMessage())); + promise.fail(completeHandler.cause().getMessage()); } }); - return this; + return promise.future(); } /** diff --git a/src/main/java/iudx/catalogue/server/authenticator/KcAuthenticationServiceImpl.java b/src/main/java/iudx/catalogue/server/authenticator/KcAuthenticationServiceImpl.java index 99ef2648..9c2f0711 100644 --- a/src/main/java/iudx/catalogue/server/authenticator/KcAuthenticationServiceImpl.java +++ b/src/main/java/iudx/catalogue/server/authenticator/KcAuthenticationServiceImpl.java @@ -5,12 +5,9 @@ import com.nimbusds.jose.proc.SecurityContext; import com.nimbusds.jwt.JWTClaimsSet; import com.nimbusds.jwt.proc.JWTProcessor; -import io.vertx.core.AsyncResult; import io.vertx.core.Future; -import io.vertx.core.Handler; import io.vertx.core.Promise; import io.vertx.core.json.JsonObject; -import iudx.catalogue.server.authenticator.authorization.Method; import iudx.catalogue.server.authenticator.model.JwtData; import iudx.catalogue.server.util.Api; import org.apache.logging.log4j.LogManager; @@ -67,8 +64,9 @@ Future decodeKcToken(String token) { } @Override - public AuthenticationService tokenInterospect( - JsonObject request, JsonObject authenticationInfo, Handler> handler) { + public Future tokenInterospect( + JsonObject request, JsonObject authenticationInfo) { + Promise promise = Promise.promise(); String endpoint = authenticationInfo.getString(API_ENDPOINT); // String id = authenticationInfo.getString(ID); String token = authenticationInfo.getString(TOKEN); @@ -100,13 +98,13 @@ public AuthenticationService tokenInterospect( .onComplete( completeHandler -> { if (completeHandler.succeeded()) { - handler.handle(Future.succeededFuture()); + promise.complete(); } else { LOGGER.debug(completeHandler.cause().getMessage()); - handler.handle(Future.failedFuture(completeHandler.cause().getMessage())); + promise.fail(completeHandler.cause().getMessage()); } }); - return this; + return promise.future(); } private Future isValidIssuer(JwtData jwtData, String issuer) { diff --git a/src/main/java/iudx/catalogue/server/validator/ValidatorService.java b/src/main/java/iudx/catalogue/server/validator/ValidatorService.java index 992e0655..3cc48da7 100644 --- a/src/main/java/iudx/catalogue/server/validator/ValidatorService.java +++ b/src/main/java/iudx/catalogue/server/validator/ValidatorService.java @@ -1,30 +1,25 @@ package iudx.catalogue.server.validator; -import io.vertx.codegen.annotations.Fluent; import io.vertx.codegen.annotations.GenIgnore; import io.vertx.codegen.annotations.ProxyGen; import io.vertx.codegen.annotations.VertxGen; -import io.vertx.core.AsyncResult; -import io.vertx.core.Handler; +import io.vertx.core.Future; import io.vertx.core.Vertx; import io.vertx.core.json.JsonObject; /** * The Validator Service. + * *

Validator Service

- *

- * The Validator Service in the IUDX Catalogue Server defines the operations to be performed with - * the IUDX File server. - *

* + *

The Validator Service in the IUDX Catalogue Server defines the operations to be performed with + * the IUDX File server. * * @see io.vertx.codegen.annotations.ProxyGen - * * @see io.vertx.codegen.annotations.VertxGen * @version 1.0 * @since 2020-05-31 */ - @VertxGen @ProxyGen public interface ValidatorService { @@ -36,7 +31,6 @@ public interface ValidatorService { * @param address which is the proxy address * @return ValidatorServiceVertxEBProxy which is a service proxy */ - @GenIgnore static ValidatorService createProxy(Vertx vertx, String address) { return new ValidatorServiceVertxEBProxy(vertx, address); @@ -46,40 +40,29 @@ static ValidatorService createProxy(Vertx vertx, String address) { * The validateSchema method implements the item schema validation. * * @param request which is a JsonObject - * @param handler which is a Request Handler - * @return ValidatorService which is a Service + * @return Future which is a Vert.x Future */ - @Fluent - ValidatorService validateSchema(JsonObject request, Handler> handler); + Future validateSchema(JsonObject request); /** * The validateItem method implements the item validation flow based on the schema of the item. * * @param request which is a JsonObject - * @param handler which is a Request Handler - * @return ValidatorService which is a Service + * @return Future which is a Vert.x Future */ - @Fluent - ValidatorService validateItem(JsonObject request, Handler> handler); - @Fluent - ValidatorService validateRating(JsonObject request, Handler> handler); - - @Fluent - ValidatorService validateMlayerInstance(JsonObject request, - Handler> handler); + /* + * {@inheritDoc} + */ + Future validateItem(JsonObject request); - @Fluent - ValidatorService validateMlayerDomain(JsonObject request, - Handler> handler); + Future validateRating(JsonObject request); - @Fluent - ValidatorService validateMlayerGeoQuery(JsonObject request, - Handler> handler); + Future validateMlayerInstance(JsonObject request); - @Fluent - ValidatorService validateMlayerDatasetId(JsonObject requestData, - Handler> handler); + Future validateMlayerDomain(JsonObject request); + Future validateMlayerGeoQuery(JsonObject request); -} \ No newline at end of file + Future validateMlayerDatasetId(JsonObject requestData); +} diff --git a/src/main/java/iudx/catalogue/server/validator/ValidatorServiceImpl.java b/src/main/java/iudx/catalogue/server/validator/ValidatorServiceImpl.java index 469fd277..845977ee 100644 --- a/src/main/java/iudx/catalogue/server/validator/ValidatorServiceImpl.java +++ b/src/main/java/iudx/catalogue/server/validator/ValidatorServiceImpl.java @@ -4,11 +4,11 @@ import static iudx.catalogue.server.validator.Constants.*; import com.github.fge.jsonschema.core.exceptions.ProcessingException; -import io.vertx.core.AsyncResult; import io.vertx.core.Future; -import io.vertx.core.Handler; +import io.vertx.core.Promise; import io.vertx.core.json.JsonArray; import io.vertx.core.json.JsonObject; +import iudx.catalogue.server.apiserver.util.RespBuilder; import iudx.catalogue.server.database.ElasticClient; import java.io.IOException; import java.text.DateFormat; @@ -95,17 +95,31 @@ public static String getUtcDatetimeAsString() { return utcTime; } - private static String getItemType(JsonObject request, Handler> handler) { + private static String getItemType(JsonObject requestBody) { Set type = new HashSet(new JsonArray().getList()); try { - type = new HashSet(request.getJsonArray(TYPE).getList()); + type = new HashSet(requestBody.getJsonArray(TYPE).getList()); } catch (Exception e) { - LOGGER.error("Item type mismatch"); - handler.handle(Future.failedFuture(VALIDATION_FAILURE_MSG)); + LOGGER.error("Fail: Invalid type"); } type.retainAll(ITEM_TYPES); - String itemType = type.toString().replaceAll("\\[", "").replaceAll("\\]", ""); - return itemType; + return String.join(", ", type); + } + + private static boolean isValidUuid(String uuidString) { + return UUID_PATTERN.matcher(uuidString).matches(); + } + + private static boolean validateId(JsonObject request, boolean isUacInstance) { + if (request.containsKey("id")) { + String id = request.getString("id"); + LOGGER.debug("id in the request body: " + id); + + if (!isValidUuid(id)) { + return true; + } + } else return !isUacInstance || request.containsKey("id"); + return true; } String getReturnTypeForValidation(JsonObject result) { @@ -120,16 +134,14 @@ String getReturnTypeForValidation(JsonObject result) { /* * {@inheritDoc} */ - @SuppressWarnings("unchecked") - public ValidatorService validateSchema( - JsonObject request, Handler> handler) { + @Override + public Future validateSchema(JsonObject request) { + Promise promise = Promise.promise(); LOGGER.debug("Info: Reached Validator service validate schema"); String itemType = null; itemType = - request.containsKey("stack_type") - ? request.getString("stack_type") - : getItemType(request, handler); + request.containsKey("stack_type") ? request.getString("stack_type") : getItemType(request); request.remove("api"); LOGGER.debug("Info: itemType: " + itemType); @@ -154,55 +166,61 @@ public ValidatorService validateSchema( isValidSchema = ownerItemSchema.validate(request.toString()); break; case "patch:Stack": - isValidSchema = stack4PatchValidator.validate(request.toString()); + isValidSchema = stack4PatchValidator.validate(request.toString()); break; case "post:Stack": - isValidSchema = stackSchema4Post.validate(request.toString()); + isValidSchema = stackSchema4Post.validate(request.toString()); break; default: - handler.handle(Future.failedFuture("Invalid Item Type")); - return this; + promise.fail("Invalid Item Type"); + return promise.future(); } - validateSchema(handler); - return this; + return validateSchema(); } /* * {@inheritDoc} */ - @SuppressWarnings("unchecked") @Override - public ValidatorService validateItem( - JsonObject request, Handler> handler) { - + public Future validateItem(JsonObject request) { request.put(CONTEXT, vocContext); String method = (String) request.remove(HTTP_METHOD); - String itemType = getItemType(request, handler); + String itemType = getItemType(request); LOGGER.debug("Info: itemType: " + itemType); + if (!validateId(request, isUacInstance)) { + RespBuilder responseBuilder = + new RespBuilder() + .withType(TYPE_INVALID_UUID) + .withTitle(TITLE_INVALID_UUID) + .withDetail("Invalid Id in Request"); + return Future.failedFuture(responseBuilder.getResponse()); + } + // Validate if Resource if (itemType.equalsIgnoreCase(ITEM_TYPE_RESOURCE)) { - validateResource(request, method, handler); + return validateResource(request, method); } else if (itemType.equalsIgnoreCase(ITEM_TYPE_RESOURCE_SERVER)) { // Validate if Resource Server TODO: More checks and auth rules - validateResourceServer(request, method, handler); + return validateResourceServer(request, method); } else if (itemType.equalsIgnoreCase(ITEM_TYPE_PROVIDER)) { - validateProvider(request, method, handler); + return validateProvider(request, method); } else if (itemType.equalsIgnoreCase(ITEM_TYPE_RESOURCE_GROUP)) { - validateResourceGroup(request, method, handler); + return validateResourceGroup(request, method); } else if (itemType.equalsIgnoreCase(ITEM_TYPE_COS)) { - validateCosItem(request, method, handler); + return validateCosItem(request, method); } else if (itemType.equalsIgnoreCase(ITEM_TYPE_OWNER)) { - validateOwnerItem(request, method, handler); + return validateOwnerItem(request, method); } - return this; + + return Future.failedFuture("Invalid Item Type"); } - private void validateResourceGroup( - JsonObject request, String method, Handler> handler) { - validateId(request, handler, isUacInstance); + private Future validateResourceGroup(JsonObject request, String method) { + // validateId(request, isUacInstance); + Promise promise = Promise.promise(); if (!isUacInstance && !request.containsKey(ID)) { UUID uuid = UUID.randomUUID(); request.put(ID, uuid.toString()); @@ -222,28 +240,28 @@ private void validateResourceGroup( res -> { if (res.failed()) { LOGGER.debug("Fail: DB Error"); - handler.handle(Future.failedFuture(VALIDATION_FAILURE_MSG)); - return; + promise.fail(VALIDATION_FAILURE_MSG); } String returnType = getReturnTypeForValidation(res.result()); LOGGER.debug(returnType); if (res.result().getInteger(TOTAL_HITS) < 1 || !returnType.contains(ITEM_TYPE_PROVIDER)) { LOGGER.debug("Provider does not exist"); - handler.handle(Future.failedFuture("Fail: Provider item doesn't exist")); + promise.fail("Fail: Provider item doesn't exist"); } else if (method.equalsIgnoreCase(REQUEST_POST) && returnType.contains(ITEM_TYPE_RESOURCE_GROUP)) { LOGGER.debug("RG already exists"); - handler.handle(Future.failedFuture("Fail: Resource Group item already exists")); + promise.fail("Fail: Resource Group item already exists"); } else { - handler.handle(Future.succeededFuture(request)); + promise.complete(request); } }); + return promise.future(); } - private void validateProvider( - JsonObject request, String method, Handler> handler) { + private Future validateProvider(JsonObject request, String method) { // Validate if Provider - validateId(request, handler, isUacInstance); + // validateId(request, handler, isUacInstance); + Promise promise = Promise.promise(); if (!isUacInstance && !request.containsKey(ID)) { UUID uuid = UUID.randomUUID(); request.put(ID, uuid.toString()); @@ -266,7 +284,7 @@ private void validateProvider( res -> { if (res.failed()) { LOGGER.debug("Fail: DB Error"); - handler.handle(Future.failedFuture(VALIDATION_FAILURE_MSG)); + promise.fail(VALIDATION_FAILURE_MSG); return; } String returnType = getReturnTypeForValidation(res.result()); @@ -275,21 +293,21 @@ private void validateProvider( LOGGER.debug("res result " + res.result()); if (!returnType.contains(ITEM_TYPE_RESOURCE_SERVER)) { LOGGER.debug("RS does not exist"); - handler.handle(Future.failedFuture("Fail: Resource Server item doesn't exist")); + promise.fail("Fail: Resource Server item doesn't exist"); } else if (method.equalsIgnoreCase(REQUEST_POST) && returnType.contains(ITEM_TYPE_PROVIDER)) { LOGGER.debug("Provider already exists"); - handler.handle( - Future.failedFuture("Fail: Provider item for this resource server already exists")); + promise.fail("Fail: Provider item for this resource server already exists"); } else { - handler.handle(Future.succeededFuture(request)); + promise.complete(request); } }); + return promise.future(); } - private void validateResourceServer( - JsonObject request, String method, Handler> handler) { - validateId(request, handler, isUacInstance); + private Future validateResourceServer(JsonObject request, String method) { + // validateId(request, handler, isUacInstance); + Promise promise = Promise.promise(); if (!isUacInstance && !request.containsKey(ID)) { UUID uuid = UUID.randomUUID(); request.put(ID, uuid.toString()); @@ -311,7 +329,7 @@ private void validateResourceServer( res -> { if (res.failed()) { LOGGER.debug("Fail: DB Error"); - handler.handle(Future.failedFuture(VALIDATION_FAILURE_MSG)); + promise.fail(VALIDATION_FAILURE_MSG); return; } String returnType = getReturnTypeForValidation(res.result()); @@ -319,24 +337,24 @@ private void validateResourceServer( if (res.result().getInteger(TOTAL_HITS) < 1 || !returnType.contains(ITEM_TYPE_COS)) { LOGGER.debug("Cos does not exist"); - handler.handle(Future.failedFuture("Fail: Cos item doesn't exist")); + promise.fail("Fail: Cos item doesn't exist"); } else if (method.equalsIgnoreCase(REQUEST_POST) && returnType.contains(ITEM_TYPE_RESOURCE_SERVER)) { LOGGER.debug("RS already exists"); - handler.handle( - Future.failedFuture( - String.format( - "Fail: Resource Server item with url %s already exists for this COS", - resourceServerUrl))); + promise.fail( + String.format( + "Fail: Resource Server item with url %s already exists for this COS", + resourceServerUrl)); } else { - handler.handle(Future.succeededFuture(request)); + promise.complete(request); } }); + return promise.future(); } - private void validateResource( - JsonObject request, String method, Handler> handler) { - validateId(request, handler, isUacInstance); + private Future validateResource(JsonObject request, String method) { + // validateId(request, handler, isUacInstance); + Promise promise = Promise.promise(); if (!isUacInstance && !request.containsKey("id")) { UUID uuid = UUID.randomUUID(); request.put("id", uuid.toString()); @@ -361,7 +379,7 @@ private void validateResource( res -> { if (res.failed()) { LOGGER.debug("Fail: DB Error"); - handler.handle(Future.failedFuture(VALIDATION_FAILURE_MSG)); + promise.fail(VALIDATION_FAILURE_MSG); return; } String returnType = getReturnTypeForValidation(res.result()); @@ -370,28 +388,29 @@ private void validateResource( if (res.result().getInteger(TOTAL_HITS) < 3 && !returnType.contains(ITEM_TYPE_RESOURCE_SERVER)) { LOGGER.debug("RS does not exist"); - handler.handle(Future.failedFuture("Fail: Resource Server item doesn't exist")); + promise.fail("Fail: Resource Server item doesn't exist"); } else if (res.result().getInteger(TOTAL_HITS) < 3 && !returnType.contains(ITEM_TYPE_PROVIDER)) { LOGGER.debug("Provider does not exist"); - handler.handle(Future.failedFuture("Fail: Provider item doesn't exist")); + promise.fail("Fail: Provider item doesn't exist"); } else if (res.result().getInteger(TOTAL_HITS) < 3 && !returnType.contains(ITEM_TYPE_RESOURCE_GROUP)) { LOGGER.debug("RG does not exist"); - handler.handle(Future.failedFuture("Fail: Resource Group item doesn't exist")); + promise.fail("Fail: Resource Group item doesn't exist"); } else if (method.equalsIgnoreCase(REQUEST_POST) && res.result().getInteger(TOTAL_HITS) > 3) { LOGGER.debug("RI already exists"); - handler.handle(Future.failedFuture("Fail: Resource item already exists")); + promise.fail("Fail: Resource item already exists"); } else { - handler.handle(Future.succeededFuture(request)); + promise.complete(request); } }); + return promise.future(); } - private void validateCosItem( - JsonObject request, String method, Handler> handler) { - validateId(request, handler, isUacInstance); + private Future validateCosItem(JsonObject request, String method) { + // validateId(request, handler, isUacInstance); + Promise promise = Promise.promise(); if (!isUacInstance && !request.containsKey(ID)) { UUID uuid = UUID.randomUUID(); request.put(ID, uuid.toString()); @@ -412,26 +431,27 @@ private void validateCosItem( res -> { if (res.failed()) { LOGGER.debug("Fail: DB Error"); - handler.handle(Future.failedFuture(VALIDATION_FAILURE_MSG)); + promise.fail(VALIDATION_FAILURE_MSG); return; } String returnType = getReturnTypeForValidation(res.result()); LOGGER.debug(returnType); if (res.result().getInteger(TOTAL_HITS) < 1 || !returnType.contains(ITEM_TYPE_OWNER)) { LOGGER.debug("Owner does not exist"); - handler.handle(Future.failedFuture("Fail: Owner item doesn't exist")); + promise.fail("Fail: Owner item doesn't exist"); } else if (method.equalsIgnoreCase(REQUEST_POST) && returnType.contains(ITEM_TYPE_COS)) { LOGGER.debug("COS already exists"); - handler.handle(Future.failedFuture("Fail: COS item already exists")); + promise.fail("Fail: COS item already exists"); } else { - handler.handle(Future.succeededFuture(request)); + promise.complete(request); } }); + return promise.future(); } - private void validateOwnerItem( - JsonObject request, String method, Handler> handler) { - validateId(request, handler, isUacInstance); + private Future validateOwnerItem(JsonObject request, String method) { + // validateId(request, handler, isUacInstance); + Promise promise = Promise.promise(); if (!isUacInstance && !request.containsKey(ID)) { UUID uuid = UUID.randomUUID(); request.put(ID, uuid.toString()); @@ -445,91 +465,59 @@ private void validateOwnerItem( res -> { if (res.failed()) { LOGGER.debug("Fail: DB Error"); - handler.handle(Future.failedFuture(VALIDATION_FAILURE_MSG)); + promise.fail(VALIDATION_FAILURE_MSG); return; } if (method.equalsIgnoreCase(REQUEST_POST) && res.result().getInteger(TOTAL_HITS) > 0) { LOGGER.debug("Owner item already exists"); - handler.handle(Future.failedFuture("Fail: Owner item already exists")); + promise.fail("Fail: Owner item already exists"); } else { - handler.handle(Future.succeededFuture(request)); + promise.complete(request); } }); + return promise.future(); } - private boolean isValidUuid(String uuidString) { - return UUID_PATTERN.matcher(uuidString).matches(); - } - - private void validateId( - JsonObject request, Handler> handler, boolean isUacInstance) { - if (request.containsKey("id")) { - String id = request.getString("id"); - LOGGER.debug("id in the request body: " + id); - - if (!isValidUuid(id)) { - handler.handle(Future.failedFuture("validation failed. Incorrect id")); - } - } else if (isUacInstance && !request.containsKey("id")) { - handler.handle(Future.failedFuture("mandatory id field not present in request body")); - } - } - - private void validateSchema(Handler> handler) { + private Future validateSchema() { + Promise promise = Promise.promise(); isValidSchema - .onSuccess( - x -> handler.handle(Future.succeededFuture(new JsonObject().put(STATUS, SUCCESS)))) + .onSuccess(x -> promise.complete(new JsonObject().put(STATUS, SUCCESS))) .onFailure( x -> { LOGGER.error("Fail: Invalid Schema"); LOGGER.error(x.getMessage()); - handler.handle( - Future.failedFuture(String.valueOf(new JsonArray().add(x.getMessage())))); + promise.fail(String.valueOf(new JsonArray().add(x.getMessage()))); }); + return promise.future(); } @Override - public ValidatorService validateRating( - JsonObject request, Handler> handler) { - + public Future validateRating(JsonObject request) { isValidSchema = ratingValidator.validate(request.toString()); - - validateSchema(handler); - return this; + return validateSchema(); } @Override - public ValidatorService validateMlayerInstance( - JsonObject request, Handler> handler) { + public Future validateMlayerInstance(JsonObject request) { isValidSchema = mlayerInstanceValidator.validate(request.toString()); - validateSchema(handler); - return null; + return validateSchema(); } @Override - public ValidatorService validateMlayerDomain( - JsonObject request, Handler> handler) { + public Future validateMlayerDomain(JsonObject request) { isValidSchema = mlayerDomainValidator.validate(request.toString()); - - validateSchema(handler); - return this; + return validateSchema(); } @Override - public ValidatorService validateMlayerGeoQuery( - JsonObject request, Handler> handler) { + public Future validateMlayerGeoQuery(JsonObject request) { isValidSchema = mlayerGeoQueryValidator.validate(request.toString()); - - validateSchema(handler); - return this; + return validateSchema(); } @Override - public ValidatorService validateMlayerDatasetId( - JsonObject request, Handler> handler) { + public Future validateMlayerDatasetId(JsonObject request) { isValidSchema = mlayerDatasetValidator.validate(request.toString()); - - validateSchema(handler); - return this; + return validateSchema(); } } From de8072ba4c7f661d2f33150efd4ebbd33e8c846d Mon Sep 17 00:00:00 2001 From: pranavrd Date: Fri, 26 Jul 2024 09:32:58 +0530 Subject: [PATCH 2/2] fix: enabled vertx futures based service --- .../catalogue/server/apiserver/CrudApis.java | 455 +++++++++--------- .../server/authenticator/package-info.java | 3 +- .../server/validator/package-info.java | 3 +- 3 files changed, 238 insertions(+), 223 deletions(-) diff --git a/src/main/java/iudx/catalogue/server/apiserver/CrudApis.java b/src/main/java/iudx/catalogue/server/apiserver/CrudApis.java index 4b97a567..f86747d1 100644 --- a/src/main/java/iudx/catalogue/server/apiserver/CrudApis.java +++ b/src/main/java/iudx/catalogue/server/apiserver/CrudApis.java @@ -1,8 +1,10 @@ /** + * + * *

CrudApis.java

+ * * Callback handlers for CRUD */ - package iudx.catalogue.server.apiserver; import static iudx.catalogue.server.apiserver.util.Constants.*; @@ -38,11 +40,10 @@ public final class CrudApis { - private static final Logger LOGGER = LogManager.getLogger(CrudApis.class); private static final Pattern UUID_PATTERN = - Pattern.compile( - "^[a-zA-Z0-9]{8}-[a-zA-Z0-9]{4}-[a-zA-Z0-9]{4}-[a-zA-Z0-9]{4}-[a-zA-Z0-9]{12}$"); + Pattern.compile( + "^[a-zA-Z0-9]{8}-[a-zA-Z0-9]{4}-[a-zA-Z0-9]{4}-[a-zA-Z0-9]{4}-[a-zA-Z0-9]{12}$"); private DatabaseService dbService; private AuthenticationService authService; private ValidatorService validatorService; @@ -52,13 +53,10 @@ public final class CrudApis { private Api api; private boolean isUac; - - /** - * Crud constructor. + * Crud constructor. * - * @param api endpoint for base path - * @TODO Throw error if load failed + * @param api endpoint for base path @TODO Throw error if load failed */ public CrudApis(Api api, boolean isUac) { this.api = api; @@ -71,12 +69,12 @@ private static String getItemType(JsonObject requestBody, HttpServerResponse res type = new HashSet(requestBody.getJsonArray(TYPE).getList()); } catch (Exception e) { LOGGER.error("Fail: Invalid type"); - RespBuilder respBuilder = new RespBuilder() - .withType(TYPE_INVALID_SCHEMA) - .withTitle(TITLE_INVALID_SCHEMA) - .withDetail("Invalid type for item/type not present"); - response.setStatusCode(400) - .end(respBuilder.getResponse()); + RespBuilder respBuilder = + new RespBuilder() + .withType(TYPE_INVALID_SCHEMA) + .withTitle(TITLE_INVALID_SCHEMA) + .withDetail("Invalid type for item/type not present"); + response.setStatusCode(400).end(respBuilder.getResponse()); } type.retainAll(ITEM_TYPES); String itemType = type.toString().replaceAll("\\[", "").replaceAll("\\]", ""); @@ -107,8 +105,7 @@ public void setHost(String host) { /** * Create/Update Item. * - * @param routingContext {@link RoutingContext} - * @TODO Throw error if load failed + * @param routingContext {@link RoutingContext} @TODO Throw error if load failed */ // tag::db-service-calls[] public void createItemHandler(RoutingContext routingContext) { @@ -117,7 +114,7 @@ public void createItemHandler(RoutingContext routingContext) { /* Contains the cat-item */ JsonObject requestBody = routingContext.body().asJsonObject(); - HttpServerRequest request = routingContext.request(); + HttpServerRequest request = routingContext.request(); String postOrPutOperation = request.method().toString(); HttpServerResponse response = routingContext.response(); @@ -131,7 +128,8 @@ public void createItemHandler(RoutingContext routingContext) { validatorService .validateSchema(requestBody) - .compose(validatedRequestBody -> { + .compose( + validatedRequestBody -> { JsonObject jwtAuthenticationInfo = new JsonObject(); // populating jwt authentication info -> @@ -140,154 +138,168 @@ public void createItemHandler(RoutingContext routingContext) { .put(METHOD, REQUEST_POST) .put(API_ENDPOINT, api.getRouteItems()) .put(ITEM_TYPE, itemType); - JsonObject validatedRequestBodyWithMetaData = getParentObjectMetadata(itemType, validatedRequestBody, response, jwtAuthenticationInfo); + JsonObject validatedRequestBodyWithMetaData = + getParentObjectMetadata( + itemType, validatedRequestBody, response, jwtAuthenticationInfo); - return authService.tokenInterospect(validatedRequestBodyWithMetaData, jwtAuthenticationInfo); + return authService.tokenInterospect( + validatedRequestBodyWithMetaData, jwtAuthenticationInfo); }) - .compose(jwtData -> { - resultContainer.jwtData = jwtData; - return validatorService.validateItem(requestBody); - }) - .compose(requestBodyWithId -> { - return insertOrUpsertItem(requestBodyWithId, resultContainer.jwtData, postOrPutOperation); - }) - .onSuccess(successHandler -> { -// handleSuccessfulCreation(successHandler, postOrPutOperation); - }) - .onFailure(failureHandler -> { - // TODO: handle all 4xx cases of the compose chain accordingly -// handleCreationFailure(failureHandler); - }); + .compose( + jwtData -> { + resultContainer.jwtData = jwtData; + return validatorService.validateItem(requestBody); + }) + .compose( + requestBodyWithId -> { + return insertOrUpsertItem( + requestBodyWithId, resultContainer.jwtData, postOrPutOperation); + }) + .onSuccess( + successHandler -> { + handleSuccessfulCreation(successHandler, + postOrPutOperation); + }) + .onFailure( + failureHandler -> { + // TODO: handle all 4xx cases of the compose chain accordingly + // handleCreationFailure(failureHandler); + }); } - private Future insertOrUpsertItem(JsonObject requestBodyWithId, JwtData jwtData, String postOrPutOperation) { - Promise promise = Promise.promise(); - if (postOrPutOperation.equalsIgnoreCase(REQUEST_POST)) { - /* Requesting database service, creating a item */ - LOGGER.debug("Info: Inserting item"); - dbService.createItem(requestBodyWithId, dbhandler -> { - if (dbhandler.failed()) { - LOGGER.error("Fail: Item creation;" + dbhandler.cause().getMessage()); - promise.fail(dbhandler.cause().getMessage()); - } - if (dbhandler.succeeded()) { - LOGGER.info("Success: Item created;"); - promise.complete(dbhandler.result()); - if (hasAuditService && !isUac) { - Future.future(fu -> updateAuditInfo( - jwtData, - new String[]{requestBodyWithId.getString(ID), - api.getRouteItems(), REQUEST_POST})); - } - } - }); - } else { - LOGGER.debug("Info: Updating item"); - /* Requesting database service, creating a item */ - dbService.updateItem(requestBodyWithId, dbhandler -> { - if (dbhandler.succeeded()) { - LOGGER.info("Success: Item updated;"); - promise.complete(dbhandler.result()); - if (hasAuditService) { - Future.future(fu -> updateAuditInfo(jwtData, - new String[]{requestBodyWithId.getString(ID), - api.getRouteItems(), REQUEST_PUT})); - } - } else if (dbhandler.failed()) { - LOGGER.error("Fail: Item update;" + dbhandler.cause().getMessage()); - promise.fail(dbhandler.cause()); - } - }); + private void handleSuccessfulCreation(JsonObject successHandler, String postOrPutOperation) { + + } + + private Future insertOrUpsertItem( + JsonObject requestBodyWithId, JwtData jwtData, String postOrPutOperation) { + Promise promise = Promise.promise(); + if (postOrPutOperation.equalsIgnoreCase(REQUEST_POST)) { + /* Requesting database service, creating a item */ + LOGGER.debug("Info: Inserting item"); + dbService.createItem( + requestBodyWithId, + dbhandler -> { + if (dbhandler.failed()) { + LOGGER.error("Fail: Item creation;" + dbhandler.cause().getMessage()); + promise.fail(dbhandler.cause().getMessage()); + } + if (dbhandler.succeeded()) { + LOGGER.info("Success: Item created;"); + promise.complete(dbhandler.result()); + if (hasAuditService && !isUac) { + Future.future( + fu -> + updateAuditInfo( + jwtData, + new String[] { + requestBodyWithId.getString(ID), api.getRouteItems(), REQUEST_POST + })); + } + } + }); + } else { + LOGGER.debug("Info: Updating item"); + /* Requesting database service, creating a item */ + dbService.updateItem( + requestBodyWithId, + dbhandler -> { + if (dbhandler.succeeded()) { + LOGGER.info("Success: Item updated;"); + promise.complete(dbhandler.result()); + if (hasAuditService) { + Future.future( + fu -> + updateAuditInfo( + jwtData, + new String[] { + requestBodyWithId.getString(ID), api.getRouteItems(), REQUEST_PUT + })); } - return promise.future(); + } else if (dbhandler.failed()) { + LOGGER.error("Fail: Item update;" + dbhandler.cause().getMessage()); + promise.fail(dbhandler.cause()); + } + }); + } + return promise.future(); } - private JsonObject getParentObjectMetadata(String itemType, - JsonObject requestBody, - HttpServerResponse response, - JsonObject jwtAuthenticationInfo) { + private JsonObject getParentObjectMetadata( + String itemType, + JsonObject requestBody, + HttpServerResponse response, + JsonObject jwtAuthenticationInfo) { if (isUac) { } else { - if (itemType.equalsIgnoreCase(ITEM_TYPE_COS) - || itemType.equalsIgnoreCase(ITEM_TYPE_OWNER)) { + if (itemType.equalsIgnoreCase(ITEM_TYPE_COS) || itemType.equalsIgnoreCase(ITEM_TYPE_OWNER)) { } else if (itemType.equalsIgnoreCase(ITEM_TYPE_RESOURCE_SERVER)) { } else if (itemType.equals(ITEM_TYPE_PROVIDER)) { Future resourceServerUrlFuture = getParentObjectInfo(requestBody.getString(RESOURCE_SVR)); // add resource server url to provider body - resourceServerUrlFuture.onSuccess(resourceServerUrl -> { - String rsUrl = resourceServerUrl.getString(RESOURCE_SERVER_URL); - // used for relationship apis - String cosId = resourceServerUrl.getString(COS_ITEM); - - jwtAuthenticationInfo.put(RESOURCE_SERVER_URL, rsUrl); - requestBody.put(RESOURCE_SERVER_URL, rsUrl); - requestBody.put(COS_ITEM, cosId); - }).onFailure(parentInfoFailure-> { - response - .setStatusCode(400) - .end( - new RespBuilder() - .withType(TYPE_LINK_VALIDATION_FAILED) - .withTitle(TITLE_LINK_VALIDATION_FAILED) - .withDetail("Resource Server not found") - .getResponse()); - }); + resourceServerUrlFuture + .onSuccess( + resourceServerUrl -> { + String rsUrl = resourceServerUrl.getString(RESOURCE_SERVER_URL); + // used for relationship apis + String cosId = resourceServerUrl.getString(COS_ITEM); + + jwtAuthenticationInfo.put(RESOURCE_SERVER_URL, rsUrl); + requestBody.put(RESOURCE_SERVER_URL, rsUrl); + requestBody.put(COS_ITEM, cosId); + }) + .onFailure( + parentInfoFailure -> { + response + .setStatusCode(400) + .end( + new RespBuilder() + .withType(TYPE_LINK_VALIDATION_FAILED) + .withTitle(TITLE_LINK_VALIDATION_FAILED) + .withDetail("Resource Server not found") + .getResponse()); + }); } else { - Future ownerUserIdFuture = - getParentObjectInfo(requestBody.getString(PROVIDER)); + Future ownerUserIdFuture = getParentObjectInfo(requestBody.getString(PROVIDER)); // add provider kc id to requestBody - ownerUserIdFuture.onSuccess(ownerUserId -> { - LOGGER.debug(ownerUserId); - String kcId = ownerUserId.getString(PROVIDER_USER_ID); - String rsUrl = ownerUserId.getString(RESOURCE_SERVER_URL); - // cosId is used for relationship apis - - jwtAuthenticationInfo.put(PROVIDER_USER_ID, kcId); - jwtAuthenticationInfo.put(RESOURCE_SERVER_URL, rsUrl); - requestBody.put(PROVIDER_USER_ID, kcId); - - String cosId = ownerUserId.getString(COS_ITEM); - requestBody.put(COS_ITEM, cosId); - }).onFailure(parentInfoFailure -> { - response - .setStatusCode(400) - .end( - new RespBuilder() - .withType(TYPE_LINK_VALIDATION_FAILED) - .withTitle(TITLE_LINK_VALIDATION_FAILED) - .withDetail("Provider not found") - .getResponse()); - }); + ownerUserIdFuture + .onSuccess( + ownerUserId -> { + LOGGER.debug(ownerUserId); + String kcId = ownerUserId.getString(PROVIDER_USER_ID); + String rsUrl = ownerUserId.getString(RESOURCE_SERVER_URL); + // cosId is used for relationship apis + + jwtAuthenticationInfo.put(PROVIDER_USER_ID, kcId); + jwtAuthenticationInfo.put(RESOURCE_SERVER_URL, rsUrl); + requestBody.put(PROVIDER_USER_ID, kcId); + String cosId = ownerUserId.getString(COS_ITEM); + requestBody.put(COS_ITEM, cosId); + }) + .onFailure( + parentInfoFailure -> { + response + .setStatusCode(400) + .end( + new RespBuilder() + .withType(TYPE_LINK_VALIDATION_FAILED) + .withTitle(TITLE_LINK_VALIDATION_FAILED) + .withDetail("Provider not found") + .getResponse()); + }); } } return requestBody; -// authService.tokenInterospect(new JsonObject(), -// jwtAuthenticationInfo, authHandler -> { -// if (authHandler.failed()) { -// } else { -// LOGGER.debug("Success: JWT Auth successful"); -// requestBody.put(HTTP_METHOD, routingContext.request().method().toString()); -// /* Link Validating the request to ensure item correctness */ -// validatorService.validateItem(requestBody, valhandler -> { -// if (valhandler.succeeded()) { -// LOGGER.debug("Success: Item link validation"); -// -// // If post, create. If put, update -// } -// }); -// } -// }); } /** * Get Item. * - * @param routingContext {@link RoutingContext} - * @TODO Throw error if load failed + * @param routingContext {@link RoutingContext} @TODO Throw error if load failed */ // tag::db-service-calls[] public void getItemHandler(RoutingContext routingContext) { @@ -304,35 +316,36 @@ public void getItemHandler(RoutingContext routingContext) { if (validateId(itemId)) { // if (validateId(itemId) == false) { - dbService.getItem(requestBody, dbhandler -> { - if (dbhandler.succeeded()) { - if (dbhandler.result().getInteger(TOTAL_HITS) == 0) { - LOGGER.error("Fail: Item not found"); - JsonObject result = dbhandler.result(); - result.put(STATUS, ERROR); - result.put(TYPE, TYPE_ITEM_NOT_FOUND); - dbhandler.result().put("detail", "doc doesn't exist"); - response.setStatusCode(404) - .end(dbhandler.result().toString()); - } else { - LOGGER.info("Success: Retreived item"); - response.setStatusCode(200) - .end(dbhandler.result().toString()); - } - } else if (dbhandler.failed()) { - LOGGER.error("Fail: Item not found;" + dbhandler.cause().getMessage()); - response.setStatusCode(400) - .end(dbhandler.cause().getMessage()); - } - }); + dbService.getItem( + requestBody, + dbhandler -> { + if (dbhandler.succeeded()) { + if (dbhandler.result().getInteger(TOTAL_HITS) == 0) { + LOGGER.error("Fail: Item not found"); + JsonObject result = dbhandler.result(); + result.put(STATUS, ERROR); + result.put(TYPE, TYPE_ITEM_NOT_FOUND); + dbhandler.result().put("detail", "doc doesn't exist"); + response.setStatusCode(404).end(dbhandler.result().toString()); + } else { + LOGGER.info("Success: Retreived item"); + response.setStatusCode(200).end(dbhandler.result().toString()); + } + } else if (dbhandler.failed()) { + LOGGER.error("Fail: Item not found;" + dbhandler.cause().getMessage()); + response.setStatusCode(400).end(dbhandler.cause().getMessage()); + } + }); } else { LOGGER.error("Fail: Invalid request payload"); - response.setStatusCode(400) - .end(new RespBuilder() - .withType(TYPE_INVALID_UUID) - .withTitle(TITLE_INVALID_UUID) - .withDetail("The id is invalid") - .getResponse()); + response + .setStatusCode(400) + .end( + new RespBuilder() + .withType(TYPE_INVALID_UUID) + .withTitle(TITLE_INVALID_UUID) + .withDetail("The id is invalid") + .getResponse()); } } @@ -438,9 +451,11 @@ public void deleteItemHandler(RoutingContext routingContext) { } } - private void handleItemDeletion(HttpServerResponse response, - JsonObject jwtAuthenticationInfo, - JsonObject requestBody, String itemId) { + private void handleItemDeletion( + HttpServerResponse response, + JsonObject jwtAuthenticationInfo, + JsonObject requestBody, + String itemId) { // TODO: convert callback handlers to future compose chains /* authService.tokenInterospect(new JsonObject(), @@ -487,8 +502,7 @@ private void handleItemDeletion(HttpServerResponse response, Future getParentObjectInfo(String itemId) { Promise promise = Promise.promise(); - JsonObject req = new JsonObject().put(ID, itemId) - .put(SEARCH_TYPE, "getParentObjectInfo"); + JsonObject req = new JsonObject().put(ID, itemId).put(SEARCH_TYPE, "getParentObjectInfo"); LOGGER.debug(req); dbService.searchQuery( @@ -496,10 +510,11 @@ Future getParentObjectInfo(String itemId) { handler -> { if (handler.succeeded()) { if (handler.result().getInteger(TOTAL_HITS) != 1) { - RespBuilder respBuilder = new RespBuilder() - .withType(TYPE_ITEM_NOT_FOUND) - .withTitle(TITLE_ITEM_NOT_FOUND) - .withDetail("Fail: Doc doesn't exist, can't perform operation"); + RespBuilder respBuilder = + new RespBuilder() + .withType(TYPE_ITEM_NOT_FOUND) + .withTitle(TITLE_ITEM_NOT_FOUND) + .withDetail("Fail: Doc doesn't exist, can't perform operation"); promise.fail(respBuilder.getResponse()); } else { promise.complete(handler.result().getJsonArray("results").getJsonObject(0)); @@ -516,7 +531,7 @@ Future getParentObjectInfo(String itemId) { * * @param routingContext the routing context for handling HTTP requests and responses * @param catAdmin he catalogue admin for the item - * @throws RuntimeException if item creation fails + * @throws RuntimeException if item creation fails */ public void createInstanceHandler(RoutingContext routingContext, String catAdmin) { @@ -526,23 +541,19 @@ public void createInstanceHandler(RoutingContext routingContext, String catAdmin HttpServerRequest request = routingContext.request(); response.putHeader(HEADER_CONTENT_TYPE, MIME_APPLICATION_JSON); - JsonObject authenticationInfo = new JsonObject(); String instance = routingContext.queryParams().get(ID); - - // Start insertion flow - // Json schema validate item - authenticationInfo.put(TOKEN, - request.getHeader(HEADER_TOKEN)) - .put(METHOD, REQUEST_POST) - .put(API_ENDPOINT, api.getRouteInstance()) - .put(ITEM_TYPE, ITEM_TYPE_INSTANCE) - .put(ID, host); + authenticationInfo + .put(TOKEN, request.getHeader(HEADER_TOKEN)) + .put(METHOD, REQUEST_POST) + .put(API_ENDPOINT, api.getRouteInstance()) + .put(ITEM_TYPE, ITEM_TYPE_INSTANCE) + .put(ID, host); // Introspect token and authorize operation // TODO: convert callback handlers to future compose chains @@ -582,10 +593,10 @@ public void createInstanceHandler(RoutingContext routingContext, String catAdmin * Deletes the specified instance from the database. * * @param routingContext the routing context - * @param catAdmin the catalogue admin + * @param catAdmin the catalogue admin * @throws NullPointerException if routingContext is null - * @throws RuntimeException if the instance cannot be deleted - * @TODO call auditing service after successful deletion + * @throws RuntimeException if the instance cannot be deleted @TODO call auditing service after + * successful deletion */ public void deleteInstanceHandler(RoutingContext routingContext, String catAdmin) { @@ -599,16 +610,15 @@ public void deleteInstanceHandler(RoutingContext routingContext, String catAdmin String instance = routingContext.queryParams().get(ID); - // Start insertion flow - // Json schema validate item - authenticationInfo.put(TOKEN, request.getHeader(HEADER_TOKEN)) - .put(METHOD, REQUEST_DELETE) - .put(API_ENDPOINT, api.getRouteInstance()) - .put(ITEM_TYPE, ITEM_TYPE_INSTANCE) - .put(ID, host); + authenticationInfo + .put(TOKEN, request.getHeader(HEADER_TOKEN)) + .put(METHOD, REQUEST_DELETE) + .put(API_ENDPOINT, api.getRouteInstance()) + .put(ITEM_TYPE, ITEM_TYPE_INSTANCE) + .put(ID, host); // Introspect token and authorize operation // TODO: convert callback handlers to future compose chains /* @@ -646,13 +656,11 @@ public void deleteInstanceHandler(RoutingContext routingContext, String catAdmin /** * Check if the itemId contains certain invalid characters. * - * * @param itemId which is a String - * @return true if the item ID contains invalid characters, false otherwise + * @return true if the item ID contains invalid characters, false otherwise */ private boolean validateId(String itemId) { return UUID_PATTERN.matcher(itemId).matches(); - } /** @@ -668,20 +676,23 @@ private void updateAuditTable(JsonObject jwtDecodedInfo, String[] otherInfo) { ZonedDateTime zst = ZonedDateTime.now(); LOGGER.debug("TIME ZST: " + zst); long epochTime = getEpochTime(zst); - auditInfo.put(IUDX_ID, otherInfo[0]) - .put(API, otherInfo[1]) - .put(HTTP_METHOD, otherInfo[2]) - .put(EPOCH_TIME, epochTime) - .put(USERID, jwtDecodedInfo.getString(USER_ID)); + auditInfo + .put(IUDX_ID, otherInfo[0]) + .put(API, otherInfo[1]) + .put(HTTP_METHOD, otherInfo[2]) + .put(EPOCH_TIME, epochTime) + .put(USERID, jwtDecodedInfo.getString(USER_ID)); LOGGER.debug("audit data: " + auditInfo.encodePrettily()); - auditingService.insertAuditngValuesInRmq(auditInfo, auditHandler -> { - if (auditHandler.succeeded()) { - LOGGER.info("message published in RMQ."); - } else { - LOGGER.error("failed to publish message in RMQ."); - } - }); + auditingService.insertAuditngValuesInRmq( + auditInfo, + auditHandler -> { + if (auditHandler.succeeded()) { + LOGGER.info("message published in RMQ."); + } else { + LOGGER.error("failed to publish message in RMQ."); + } + }); } private Future updateAuditInfo(JwtData jwtData, String[] otherInfo) { @@ -690,19 +701,22 @@ private Future updateAuditInfo(JwtData jwtData, String[] otherInfo) { ZonedDateTime zst = ZonedDateTime.now(); LOGGER.debug("TIME ZST: " + zst); long epochTime = getEpochTime(zst); - auditInfo.put(IUDX_ID, otherInfo[0]) + auditInfo + .put(IUDX_ID, otherInfo[0]) .put(API, otherInfo[1]) .put(HTTP_METHOD, otherInfo[2]) .put(EPOCH_TIME, epochTime) .put(USERID, jwtData.getSub()); - auditingService.insertAuditngValuesInRmq(auditInfo, auditHandler -> { - if (auditHandler.succeeded()) { - LOGGER.info("message published in RMQ."); - } else { - LOGGER.error("failed to publish message in RMQ."); - } - }); + auditingService.insertAuditngValuesInRmq( + auditInfo, + auditHandler -> { + if (auditHandler.succeeded()) { + LOGGER.info("message published in RMQ."); + } else { + LOGGER.error("failed to publish message in RMQ."); + } + }); return Future.succeededFuture(); } @@ -710,7 +724,6 @@ private long getEpochTime(ZonedDateTime zst) { return zst.toInstant().toEpochMilli(); } - final class ResultContainer { JwtData jwtData; } diff --git a/src/main/java/iudx/catalogue/server/authenticator/package-info.java b/src/main/java/iudx/catalogue/server/authenticator/package-info.java index 7b0e0a96..e113c78f 100644 --- a/src/main/java/iudx/catalogue/server/authenticator/package-info.java +++ b/src/main/java/iudx/catalogue/server/authenticator/package-info.java @@ -1,5 +1,6 @@ @ModuleGen(groupPackage = "iudx.catalogue.server.authenticator", - name = "iudx-catalogue-authentication-service") + name = "iudx-catalogue-authentication-service", +useFutures = true) package iudx.catalogue.server.authenticator; import io.vertx.codegen.annotations.ModuleGen; diff --git a/src/main/java/iudx/catalogue/server/validator/package-info.java b/src/main/java/iudx/catalogue/server/validator/package-info.java index 88d1e323..f1fbfd04 100644 --- a/src/main/java/iudx/catalogue/server/validator/package-info.java +++ b/src/main/java/iudx/catalogue/server/validator/package-info.java @@ -1,5 +1,6 @@ @ModuleGen(groupPackage = "iudx.catalogue.server.validator", - name = "iudx-catalogue-server-validator-service") + name = "iudx-catalogue-server-validator-service", +useFutures = true) package iudx.catalogue.server.validator; import io.vertx.codegen.annotations.ModuleGen;