From 9adfa895594db60c985f1fc8ff1d7806ade2b912 Mon Sep 17 00:00:00 2001 From: Arnab Dutta Date: Fri, 2 Feb 2024 12:49:45 +0530 Subject: [PATCH 01/10] feat: backend changes to implement short codes in webhooks to pass dynamic info on webhook execution Signed-off-by: Arnab Dutta --- .../adminui/model/webhook/AuiFeature.java | 15 ++- .../adminui/model/webhook/ShortCode.java | 36 +++++++ .../adminui/model/webhook/WebhookEntry.java | 6 +- .../adminui/rest/webhook/WebhookResource.java | 10 +- .../service/webhook/WebhookCallable.java | 21 ++-- .../service/webhook/WebhookService.java | 18 +++- .../ca/plugin/adminui/utils/CommonUtils.java | 100 ++++++++++++++++++ .../webhook/trigger-webooks-request.json | 4 + .../webhook/trigger-webooks-response.json | 20 ++++ .../example/webhook/trigger-webooks.json | 21 ---- .../docs/jans-admin-ui-plugin-swagger.yaml | 56 ++++++---- 11 files changed, 249 insertions(+), 58 deletions(-) create mode 100644 jans-config-api/plugins/admin-ui-plugin/src/main/java/io/jans/ca/plugin/adminui/model/webhook/ShortCode.java create mode 100644 jans-config-api/plugins/admin-ui-plugin/src/main/resources/example/webhook/trigger-webooks-request.json create mode 100644 jans-config-api/plugins/admin-ui-plugin/src/main/resources/example/webhook/trigger-webooks-response.json delete mode 100644 jans-config-api/plugins/admin-ui-plugin/src/main/resources/example/webhook/trigger-webooks.json diff --git a/jans-config-api/plugins/admin-ui-plugin/src/main/java/io/jans/ca/plugin/adminui/model/webhook/AuiFeature.java b/jans-config-api/plugins/admin-ui-plugin/src/main/java/io/jans/ca/plugin/adminui/model/webhook/AuiFeature.java index 519658102e9..264ca147e42 100644 --- a/jans-config-api/plugins/admin-ui-plugin/src/main/java/io/jans/ca/plugin/adminui/model/webhook/AuiFeature.java +++ b/jans-config-api/plugins/admin-ui-plugin/src/main/java/io/jans/ca/plugin/adminui/model/webhook/AuiFeature.java @@ -23,6 +23,8 @@ public class AuiFeature extends Entry implements Serializable { private String jansScope; @AttributeName(name = "webhookId") private List webhookIdsMapped; + @AttributeName(name = "shortCode") + private List shortCode; public String getAuiFeatureId() { return auiFeatureId; @@ -58,13 +60,23 @@ public void setWebhookIdsMapped(List webhookIdsMapped) { } } + public List getShortCode() { + return shortCode; + } + + public void setShortCode(List shortCode) { + if(shortCode != null) { + this.shortCode = Lists.newArrayList(Sets.newHashSet(shortCode)); + } + } + @Override public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; if (!super.equals(o)) return false; AuiFeature that = (AuiFeature) o; - return auiFeatureId.equals(that.auiFeatureId) && displayName.equals(that.displayName) && jansScope.equals(that.jansScope) && Objects.equals(webhookIdsMapped, that.webhookIdsMapped); + return auiFeatureId.equals(that.auiFeatureId) && displayName.equals(that.displayName) && jansScope.equals(that.jansScope); } @Override @@ -79,6 +91,7 @@ public String toString() { ", displayName='" + displayName + '\'' + ", jansScope='" + jansScope + '\'' + ", webhookIdsMapped=" + webhookIdsMapped + + ", shortCode=" + shortCode + '}'; } } diff --git a/jans-config-api/plugins/admin-ui-plugin/src/main/java/io/jans/ca/plugin/adminui/model/webhook/ShortCode.java b/jans-config-api/plugins/admin-ui-plugin/src/main/java/io/jans/ca/plugin/adminui/model/webhook/ShortCode.java new file mode 100644 index 00000000000..7601a8fb0d0 --- /dev/null +++ b/jans-config-api/plugins/admin-ui-plugin/src/main/java/io/jans/ca/plugin/adminui/model/webhook/ShortCode.java @@ -0,0 +1,36 @@ +package io.jans.ca.plugin.adminui.model.webhook; + +import io.jans.orm.annotation.JsonObject; + +import java.io.Serializable; +import java.util.Map; + +public class ShortCode implements Serializable { + private String webhookId; + @JsonObject + Map shortCodes; + + public String getWebhookId() { + return webhookId; + } + + public void setWebhookId(String webhookId) { + this.webhookId = webhookId; + } + + public Map getShortCodes() { + return shortCodes; + } + + public void setShortCodes(Map shortCodes) { + this.shortCodes = shortCodes; + } + + @Override + public String toString() { + return "ShortCode{" + + "webhookId='" + webhookId + '\'' + + ", shortCodes=" + shortCodes + + '}'; + } +} diff --git a/jans-config-api/plugins/admin-ui-plugin/src/main/java/io/jans/ca/plugin/adminui/model/webhook/WebhookEntry.java b/jans-config-api/plugins/admin-ui-plugin/src/main/java/io/jans/ca/plugin/adminui/model/webhook/WebhookEntry.java index e03a5466d96..a173300b14d 100644 --- a/jans-config-api/plugins/admin-ui-plugin/src/main/java/io/jans/ca/plugin/adminui/model/webhook/WebhookEntry.java +++ b/jans-config-api/plugins/admin-ui-plugin/src/main/java/io/jans/ca/plugin/adminui/model/webhook/WebhookEntry.java @@ -37,7 +37,7 @@ public class WebhookEntry extends Entry implements Serializable { private String url; @AttributeName(name = "httpRequestBody") @JsonObject - private Map httpRequestBody; + private Map httpRequestBody; @NotNull @AttributeName(name = "httpMethod") private String httpMethod; @@ -125,14 +125,14 @@ public void setDescription(String description) { this.description = description; } - public Map getHttpRequestBody() { + public Map getHttpRequestBody() { if (httpRequestBody == null) { httpRequestBody = new HashMap<>(); } return httpRequestBody; } - public void setHttpRequestBody(Map httpRequestBody) { + public void setHttpRequestBody(Map httpRequestBody) { this.httpRequestBody = httpRequestBody; } diff --git a/jans-config-api/plugins/admin-ui-plugin/src/main/java/io/jans/ca/plugin/adminui/rest/webhook/WebhookResource.java b/jans-config-api/plugins/admin-ui-plugin/src/main/java/io/jans/ca/plugin/adminui/rest/webhook/WebhookResource.java index 426ad57f581..4a255914949 100644 --- a/jans-config-api/plugins/admin-ui-plugin/src/main/java/io/jans/ca/plugin/adminui/rest/webhook/WebhookResource.java +++ b/jans-config-api/plugins/admin-ui-plugin/src/main/java/io/jans/ca/plugin/adminui/rest/webhook/WebhookResource.java @@ -4,6 +4,7 @@ import io.jans.ca.plugin.adminui.model.auth.GenericResponse; import io.jans.ca.plugin.adminui.model.exception.ApplicationException; import io.jans.ca.plugin.adminui.model.webhook.AuiFeature; +import io.jans.ca.plugin.adminui.model.webhook.ShortCode; import io.jans.ca.plugin.adminui.model.webhook.WebhookEntry; import io.jans.ca.plugin.adminui.service.webhook.WebhookService; import io.jans.ca.plugin.adminui.utils.AppConstants; @@ -312,16 +313,17 @@ public Response deleteWebhook(@Parameter(description = "Webhook identifier") @Pa @Operation(summary = "Trigger webhooks mapped to featureId", description = "Trigger webhooks mapped to featureId", operationId = "trigger-webhook", tags = { "Admin UI - Webhooks"}, security = @SecurityRequirement(name = "oauth2", scopes = {SCOPE_WEBHOOK_READ})) @ApiResponses(value = { - @ApiResponse(responseCode = "200", description = "Ok", content = @Content(mediaType = MediaType.APPLICATION_JSON, schema = @Schema(implementation = AuiFeature.class), examples = @ExampleObject(name = "Response json example", value = "example/webhook/trigger-webooks.json"))), + @ApiResponse(responseCode = "200", description = "Ok", content = @Content(mediaType = MediaType.APPLICATION_JSON, schema = @Schema(implementation = AuiFeature.class), examples = @ExampleObject(name = "Response json example", value = "example/webhook/trigger-webooks-response.json"))), @ApiResponse(responseCode = "400", description = "Bad Request", content = @Content(mediaType = MediaType.APPLICATION_JSON, schema = @Schema(implementation = GenericResponse.class, description = "License response"))), @ApiResponse(responseCode = "401", description = "Unauthorized"), @ApiResponse(responseCode = "404", description = "Not Found"), @ApiResponse(responseCode = "500", description = "InternalServerError", content = @Content(mediaType = MediaType.APPLICATION_JSON, schema = @Schema(implementation = GenericResponse.class, description = "License response")))}) - @GET + @POST @Path(TRIGGER_PATH + FEATURE_ID_PATH_VARIABLE) @ProtectedApi(scopes = {SCOPE_WEBHOOK_READ}) @Produces(MediaType.APPLICATION_JSON) - public Response triggerWebhook(@Parameter(description = "Admin UI feature identifier") @PathParam(AppConstants.ADMIN_UI_FEATURE_ID) @NotNull String featureId) { + public Response triggerWebhook(@Parameter(description = "Admin UI feature identifier") @PathParam(AppConstants.ADMIN_UI_FEATURE_ID) @NotNull String featureId, + @Valid @NotNull List shortCodes) { try { if (log.isDebugEnabled()) { log.debug("Triggering all webhooks for Admin UI feature - featureId: {}", escapeLog(featureId)); @@ -338,7 +340,7 @@ public Response triggerWebhook(@Parameter(description = "Admin UI feature identi log.error(ErrorResponse.NO_WEBHOOK_FOUND.getDescription()); throw new ApplicationException(Response.Status.INTERNAL_SERVER_ERROR.getStatusCode(), ErrorResponse.NO_WEBHOOK_FOUND.getDescription()); } - List responseList = webhookService.triggerEnabledWebhooks(Sets.newHashSet(featureObj.getWebhookIdsMapped())); + List responseList = webhookService.triggerEnabledWebhooks(Sets.newHashSet(featureObj.getWebhookIdsMapped()), shortCodes); return Response.ok(responseList).build(); } catch (ApplicationException e) { diff --git a/jans-config-api/plugins/admin-ui-plugin/src/main/java/io/jans/ca/plugin/adminui/service/webhook/WebhookCallable.java b/jans-config-api/plugins/admin-ui-plugin/src/main/java/io/jans/ca/plugin/adminui/service/webhook/WebhookCallable.java index 46748945ebb..22e3c5a3431 100644 --- a/jans-config-api/plugins/admin-ui-plugin/src/main/java/io/jans/ca/plugin/adminui/service/webhook/WebhookCallable.java +++ b/jans-config-api/plugins/admin-ui-plugin/src/main/java/io/jans/ca/plugin/adminui/service/webhook/WebhookCallable.java @@ -3,6 +3,7 @@ import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.node.ObjectNode; +import com.google.common.collect.Lists; import com.google.common.collect.Maps; import io.jans.ca.plugin.adminui.model.auth.GenericResponse; import io.jans.ca.plugin.adminui.model.exception.ApplicationException; @@ -52,6 +53,10 @@ public GenericResponse call() throws ApplicationException { JsonNode jsonNode = objectMapper.createObjectNode(); ((ObjectNode) jsonNode).put("webhookId", webhook.getWebhookId()); ((ObjectNode) jsonNode).put("webhookName", webhook.getDisplayName()); + ((ObjectNode) jsonNode).put("webhookMethod", webhook.getHttpMethod()); + if(Lists.newArrayList("POST", "PUT", "PATCH").contains(webhook.getHttpMethod())) { + ((ObjectNode) jsonNode).put("webhookRequestBody", webhook.getHttpRequestBody().toString()); + } if (response.getStatus() == Response.Status.OK.getStatusCode() || response.getStatus() == Response.Status.CREATED.getStatusCode() || response.getStatus() == Response.Status.ACCEPTED.getStatusCode()) { @@ -95,16 +100,12 @@ private Invocation checkHttpMethod(Invocation.Builder request) { private Map setRequestBody(WebhookEntry webhook) { try { Map body = new HashMap<>(); - webhook.getHttpHeaders().stream() - .filter(Objects::nonNull) - .forEach(header -> { - if (header.getKey().equalsIgnoreCase(AppConstants.CONTENT_TYPE) && header.getKey().equalsIgnoreCase(AppConstants.APPLICATION_JSON)) { - Map reqBody = webhook.getHttpRequestBody(); - for (String key : reqBody.keySet()) { - body.put(key, reqBody.get(key)); - } - } - }); + if (webhook.getHttpHeaders().stream().anyMatch(header -> header.getKey().equals(AppConstants.CONTENT_TYPE))) { + Map reqBody = webhook.getHttpRequestBody(); + for (String key : reqBody.keySet()) { + body.put(key, reqBody.get(key)); + } + } return body; } catch (Exception ex) { log.error("Error in parsing request-body.", ex); diff --git a/jans-config-api/plugins/admin-ui-plugin/src/main/java/io/jans/ca/plugin/adminui/service/webhook/WebhookService.java b/jans-config-api/plugins/admin-ui-plugin/src/main/java/io/jans/ca/plugin/adminui/service/webhook/WebhookService.java index bc54abd8e2f..7b944fd9a61 100644 --- a/jans-config-api/plugins/admin-ui-plugin/src/main/java/io/jans/ca/plugin/adminui/service/webhook/WebhookService.java +++ b/jans-config-api/plugins/admin-ui-plugin/src/main/java/io/jans/ca/plugin/adminui/service/webhook/WebhookService.java @@ -6,6 +6,7 @@ import io.jans.ca.plugin.adminui.model.auth.GenericResponse; import io.jans.ca.plugin.adminui.model.exception.ApplicationException; import io.jans.ca.plugin.adminui.model.webhook.AuiFeature; +import io.jans.ca.plugin.adminui.model.webhook.ShortCode; import io.jans.ca.plugin.adminui.model.webhook.WebhookEntry; import io.jans.ca.plugin.adminui.utils.AppConstants; import io.jans.ca.plugin.adminui.utils.CommonUtils; @@ -325,13 +326,15 @@ public void validateWebhookEntry(WebhookEntry webhookEntry) throws ApplicationEx * @param webhookIds A set of webhook IDs. * @return The method is returning a List of Strings. */ - public List triggerEnabledWebhooks(Set webhookIds) throws ApplicationException { + public List triggerEnabledWebhooks(Set webhookIds, List shortCodes) throws ApplicationException { ExecutorService executor = Executors.newFixedThreadPool(10); List responseList = new ArrayList<>(); List> callables = new ArrayList<>(); List webhooks = getWebhookByIds(webhookIds); for (WebhookEntry webhook : webhooks) { validateWebhookEntry(webhook); + ShortCode shortCodeObj = shortCodes.stream().filter(shortCode -> shortCode.getWebhookId().equals(webhook.getWebhookId())).findAny().orElse(null); + replaceShortCodeWithValues(webhook, shortCodeObj); if (webhook.isJansEnabled()) { Callable callable = new WebhookCallable(webhook, log); callables.add(callable); @@ -352,6 +355,19 @@ public List triggerEnabledWebhooks(Set webhookIds) thro return responseList; } + private void replaceShortCodeWithValues(WebhookEntry webhook, ShortCode shortCodeObj) { + if (shortCodeObj == null) { + return; + } + log.info("CommonUtils.hasShortCode(webhook.getUrl()) {}", CommonUtils.hasShortCode(webhook.getUrl())); + if (CommonUtils.hasShortCode(webhook.getUrl())) { + webhook.setUrl(CommonUtils.replacePlaceholders(webhook.getUrl(), shortCodeObj.getShortCodes())); + } + + if (CommonUtils.hasShortCode(webhook.getHttpRequestBody()) && Lists.newArrayList("POST", "PUT", "PATCH").contains(webhook.getHttpMethod())) { + webhook.setHttpRequestBody(CommonUtils.replacePlaceholders(webhook.getHttpRequestBody(), shortCodeObj.getShortCodes())); + } + } private static String idFromName(String name) { return UUID.nameUUIDFromBytes(name.getBytes(UTF_8)).toString(); diff --git a/jans-config-api/plugins/admin-ui-plugin/src/main/java/io/jans/ca/plugin/adminui/utils/CommonUtils.java b/jans-config-api/plugins/admin-ui-plugin/src/main/java/io/jans/ca/plugin/adminui/utils/CommonUtils.java index cd1af720283..e2cc1bbcd63 100644 --- a/jans-config-api/plugins/admin-ui-plugin/src/main/java/io/jans/ca/plugin/adminui/utils/CommonUtils.java +++ b/jans-config-api/plugins/admin-ui-plugin/src/main/java/io/jans/ca/plugin/adminui/utils/CommonUtils.java @@ -5,6 +5,7 @@ import io.jans.ca.plugin.adminui.model.auth.GenericResponse; import jakarta.inject.Inject; import org.apache.commons.codec.binary.Base64; +import org.apache.commons.text.StringSubstitutor; import org.slf4j.Logger; import java.io.UnsupportedEncodingException; @@ -17,8 +18,11 @@ import java.time.ZonedDateTime; import java.time.format.DateTimeFormatter; import java.util.Collection; +import java.util.HashMap; import java.util.Locale; import java.util.Map; +import java.util.regex.Matcher; +import java.util.regex.Pattern; public class CommonUtils { @Inject @@ -78,4 +82,100 @@ public static boolean isEmptyOrNullCollection(Collection collection) { public static boolean isEmptyOrNullCollection(final Map m) { return m == null || m.isEmpty(); } + + public static boolean hasShortCode(Map map) { + // Use regular expression to match placeholders in keys like "${placeholder}" + String pattern = "\\$\\{(\\w+)}"; + Pattern placeholderPattern = Pattern.compile(pattern); + + // Iterate through map keys and check for placeholders + for (Object value : map.values()) { + System.out.println(value); + System.out.println(value.toString()); + Matcher matcher = placeholderPattern.matcher(value.toString()); + if (matcher.find()) { + System.out.println("True"); + // Placeholder found in key + return true; + } + } + + // No placeholders found in any key + return false; + } + + public static boolean hasShortCode(String input) { + // Use regular expression to match placeholders like "${placeholder}" + String pattern = "\\$\\{(\\w+)}"; + Pattern placeholderPattern = Pattern.compile(pattern); + + // Create a Matcher and check for placeholders + Matcher matcher = placeholderPattern.matcher(input); + return matcher.find(); + } + + public static Map replacePlaceholders(Map map, Map placeholderValues) { + final Pattern placeholderPattern = Pattern.compile("\\$\\{(\\w+)\\}"); + Map replacedMap = new HashMap<>(); + + for (Map.Entry entry : map.entrySet()) { + String value = entry.getValue().toString(); + String replacedValue = value; + + Matcher matcher = placeholderPattern.matcher(value); + while (matcher.find()) { + String placeholderKey = matcher.group(1); + Object replacement = placeholderValues.get(placeholderKey); // Get replacement from placeholder values map + if (replacement != null) { + replacedValue = replacedValue.replace(matcher.group(0), replacement.toString()); + } + } + + replacedMap.put(entry.getKey(), replacedValue); + } + + return replacedMap; + } + + public static String replacePlaceholders(String url, Map placeholderValues) { + final Pattern placeholderPattern = Pattern.compile("\\$\\{(\\w+)\\}"); + Matcher matcher = placeholderPattern.matcher(url); + StringBuffer sb = new StringBuffer(); + + while (matcher.find()) { + String placeholderKey = matcher.group(1); + Object replacement = placeholderValues.get(placeholderKey); + if (replacement != null) { + matcher.appendReplacement(sb, replacement.toString()); // Efficient replacement using appendReplacement + } + } + + matcher.appendTail(sb); // Append remaining string + return sb.toString(); + } + + /*public static void main(String[] args) { + String url = "https://example.com/users/${userId}/profile?name=${userName}"; + Map map = new HashMap<>(); + Map map1 = new HashMap<>(); + map1.put("id",1); + map1.put("price","${price}"); + map1.put("add","${add}"); + + map.put("id",1); + map.put("price","${price}"); + map.put("add",map1); + map.put("userId","11111111111111111111111111"); + map.put("userName","Arnab"); + + + + Map values = new HashMap<>(); + values.put("price",10); + values.put("add","+"); + values.put("userId","11111111111111111111111111"); + values.put("userName","Arnab"); + System.out.println("============"+replacePlaceholders(map, values)); + System.out.println("============"+replacePlaceholders(url, values)); + }*/ } \ No newline at end of file diff --git a/jans-config-api/plugins/admin-ui-plugin/src/main/resources/example/webhook/trigger-webooks-request.json b/jans-config-api/plugins/admin-ui-plugin/src/main/resources/example/webhook/trigger-webooks-request.json new file mode 100644 index 00000000000..431e11ee09a --- /dev/null +++ b/jans-config-api/plugins/admin-ui-plugin/src/main/resources/example/webhook/trigger-webooks-request.json @@ -0,0 +1,4 @@ +[{ + "webhookId": "0a8e784b-2394-3a34-89d3-4a09d245aa32", + "shortCodes": {"price": 100} +}] \ No newline at end of file diff --git a/jans-config-api/plugins/admin-ui-plugin/src/main/resources/example/webhook/trigger-webooks-response.json b/jans-config-api/plugins/admin-ui-plugin/src/main/resources/example/webhook/trigger-webooks-response.json new file mode 100644 index 00000000000..42f9271b15d --- /dev/null +++ b/jans-config-api/plugins/admin-ui-plugin/src/main/resources/example/webhook/trigger-webooks-response.json @@ -0,0 +1,20 @@ +[{ + "success": true, + "responseMessage": "{\"id\":101,\"title\":\"iPhone 9\",\"price\":\"100\",\"description\":\"An apple mobile which is nothing like apple\"}", + "responseCode": 200, + "responseObject": { + "webhookId": "0a8e784b-2394-3a34-89d3-4a09d245aa32", + "webhookName": "Webhook1", + "webhookMethod": "POST", + "webhookRequestBody": "{dummy={a=b}, price=100, description=An apple mobile which is nothing like apple, id=1, title=iPhone 9}" + } +}, { + "success": true, + "responseMessage": "{\"users\":[{\"id\":1,\"firstName\":\"Terry\",\"lastName\":\"Medhurst\",\"maidenName\":\"Smitham\",\"age\":50,\"gender\":\"male\",\"email\":\"atuny0@sohu.com\",\"phone\":\"+63 791 675 8914\",\"username\":\"atuny0\",\"password\":\"9uQFF1Lh\",\"birthDate\":\"2000-12-25\",\"image\":\"https://robohash.org/Terry.png?set=set4\",\"bloodGroup\":\"A-\",\"height\":189,\"weight\":75.4,\"eyeColor\":\"Green\",\"hair\":{\"color\":\"Black\",\"type\":\"Strands\"},\"domain\":\"slashdot.org\",\"ip\":\"117.29.86.254\",\"address\":{\"address\":\"1745 T Street Southeast\",\"city\":\"Washington\",\"coordinates\":{\"lat\":38.867033,\"lng\":-76.979235},\"postalCode\":\"20020\",\"state\":\"DC\"},\"macAddress\":\"13:69:BA:56:A3:74\",\"university\":\"Capitol University\",\"bank\":{\"cardExpire\":\"06/22\",\"cardNumber\":\"50380955204220685\",\"cardType\":\"maestro\",\"currency\":\"Peso\",\"iban\":\"NO17 0695 2754 967\"},\"company\":{\"address\":{\"address\":\"629 Debbie Drive\",\"city\":\"Nashville\",\"coordinates\":{\"lat\":36.208114,\"lng\":-86.58621199999999},\"postalCode\":\"37076\",\"state\":\"TN\"},\"department\":\"Marketing\",\"name\":\"Blanda-O'Keefe\",\"title\":\"Help Desk Operator\"},\"ein\":\"20-9487066\",\"ssn\":\"661-64-2976\",\"userAgent\":\"Mozilla/5.0 (Windows NT 6.1) AppleWebKit/534.24 (KHTML, like Gecko) Chrome/12.0.702.0 Safari/534.24\",\"crypto\":{\"coin\":\"Bitcoin\",\"wallet\":\"0xb9fc2fe63b2a6c003f1c324c3bfa53259162181a\",\"network\":\"Ethereum (ERC20)\"}},{\"id\":2,\"firstName\":\"Sheldon\",\"lastName\":\"Quigley\",\"maidenName\":\"Cole\",\"age\":28,\"gender\":\"male\",\"email\":\"hbingley1@plala.or.jp\",\"phone\":\"+7 813 117 7139\",\"username\":\"hbingley1\",\"password\":\"CQutx25i8r\",\"birthDate\":\"2003-08-02\",\"image\":\"https://robohash.org/Sheldon.png?set=set4\",\"bloodGroup\":\"O+\",\"height\":187,\"weight\":74,\"eyeColor\":\"Brown\",\"hair\":{\"color\":\"Blond\",\"type\":\"Curly\"},\"domain\":\"51.la\",\"ip\":\"253.240.20.181\",\"address\":{\"address\":\"6007 Applegate Lane\",\"city\":\"Louisville\",\"coordinates\":{\"lat\":38.1343013,\"lng\":-85.6498512},\"postalCode\":\"40219\",\"state\":\"KY\"}", + "responseCode": 200, + "responseObject": { + "webhookId": "bf21de5b-adb9-3581-82f5-76bb335f1cbd", + "webhookName": "Dummyuser-test", + "webhookMethod": "GET" + } +}] \ No newline at end of file diff --git a/jans-config-api/plugins/admin-ui-plugin/src/main/resources/example/webhook/trigger-webooks.json b/jans-config-api/plugins/admin-ui-plugin/src/main/resources/example/webhook/trigger-webooks.json deleted file mode 100644 index 99c9ca96f01..00000000000 --- a/jans-config-api/plugins/admin-ui-plugin/src/main/resources/example/webhook/trigger-webooks.json +++ /dev/null @@ -1,21 +0,0 @@ -[{ - "success": true, - "responseMessage": "{\n \"id\": 101\n}", - "responseCode": 201 -}, { - "success": true, - "responseMessage": "{\n \"id\": 102\n}", - "responseCode": 200 -}, { - "success": true, - "responseMessage": "{\n \"id\": 103\n}", - "responseCode": 200 -}, { - "success": true, - "responseMessage": "{\n \"id\": 104\n}", - "responseCode": 201 -}, { - "success": true, - "responseMessage": "{\n \"id\": 105\n}", - "responseCode": 201 -}] \ No newline at end of file diff --git a/jans-config-api/plugins/docs/jans-admin-ui-plugin-swagger.yaml b/jans-config-api/plugins/docs/jans-admin-ui-plugin-swagger.yaml index 78da52eb279..9b728984587 100644 --- a/jans-config-api/plugins/docs/jans-admin-ui-plugin-swagger.yaml +++ b/jans-config-api/plugins/docs/jans-admin-ui-plugin-swagger.yaml @@ -1341,7 +1341,7 @@ paths: - oauth2: - https://jans.io/oauth/jans-auth-server/config/adminui/webhook.readonly /admin-ui/webhook/trigger/{featureId}: - get: + post: tags: - Admin UI - Webhooks summary: Trigger webhooks mapped to featureId @@ -1354,6 +1354,14 @@ paths: required: true schema: type: string + requestBody: + content: + '*/*': + schema: + type: array + items: + $ref: '#/components/schemas/ShortCode' + required: true responses: "200": description: Ok @@ -1367,24 +1375,23 @@ paths: value: | [{ "success": true, - "responseMessage": "{\n \"id\": 101\n}", - "responseCode": 201 - }, { - "success": true, - "responseMessage": "{\n \"id\": 102\n}", - "responseCode": 200 - }, { - "success": true, - "responseMessage": "{\n \"id\": 103\n}", - "responseCode": 200 - }, { - "success": true, - "responseMessage": "{\n \"id\": 104\n}", - "responseCode": 201 + "responseMessage": "{\"id\":101,\"title\":\"iPhone 9\",\"price\":\"100\",\"description\":\"An apple mobile which is nothing like apple\"}", + "responseCode": 200, + "responseObject": { + "webhookId": "0a8e784b-2394-3a34-89d3-4a09d245aa32", + "webhookName": "Webhook1", + "webhookMethod": "POST", + "webhookRequestBody": "{dummy={a=b}, price=100, description=An apple mobile which is nothing like apple, id=1, title=iPhone 9}" + } }, { "success": true, - "responseMessage": "{\n \"id\": 105\n}", - "responseCode": 201 + "responseMessage": "{\"users\":[{\"id\":1,\"firstName\":\"Terry\",\"lastName\":\"Medhurst\",\"maidenName\":\"Smitham\",\"age\":50,\"gender\":\"male\",\"email\":\"atuny0@sohu.com\",\"phone\":\"+63 791 675 8914\",\"username\":\"atuny0\",\"password\":\"9uQFF1Lh\",\"birthDate\":\"2000-12-25\",\"image\":\"https://robohash.org/Terry.png?set=set4\",\"bloodGroup\":\"A-\",\"height\":189,\"weight\":75.4,\"eyeColor\":\"Green\",\"hair\":{\"color\":\"Black\",\"type\":\"Strands\"},\"domain\":\"slashdot.org\",\"ip\":\"117.29.86.254\",\"address\":{\"address\":\"1745 T Street Southeast\",\"city\":\"Washington\",\"coordinates\":{\"lat\":38.867033,\"lng\":-76.979235},\"postalCode\":\"20020\",\"state\":\"DC\"},\"macAddress\":\"13:69:BA:56:A3:74\",\"university\":\"Capitol University\",\"bank\":{\"cardExpire\":\"06/22\",\"cardNumber\":\"50380955204220685\",\"cardType\":\"maestro\",\"currency\":\"Peso\",\"iban\":\"NO17 0695 2754 967\"},\"company\":{\"address\":{\"address\":\"629 Debbie Drive\",\"city\":\"Nashville\",\"coordinates\":{\"lat\":36.208114,\"lng\":-86.58621199999999},\"postalCode\":\"37076\",\"state\":\"TN\"},\"department\":\"Marketing\",\"name\":\"Blanda-O'Keefe\",\"title\":\"Help Desk Operator\"},\"ein\":\"20-9487066\",\"ssn\":\"661-64-2976\",\"userAgent\":\"Mozilla/5.0 (Windows NT 6.1) AppleWebKit/534.24 (KHTML, like Gecko) Chrome/12.0.702.0 Safari/534.24\",\"crypto\":{\"coin\":\"Bitcoin\",\"wallet\":\"0xb9fc2fe63b2a6c003f1c324c3bfa53259162181a\",\"network\":\"Ethereum (ERC20)\"}},{\"id\":2,\"firstName\":\"Sheldon\",\"lastName\":\"Quigley\",\"maidenName\":\"Cole\",\"age\":28,\"gender\":\"male\",\"email\":\"hbingley1@plala.or.jp\",\"phone\":\"+7 813 117 7139\",\"username\":\"hbingley1\",\"password\":\"CQutx25i8r\",\"birthDate\":\"2003-08-02\",\"image\":\"https://robohash.org/Sheldon.png?set=set4\",\"bloodGroup\":\"O+\",\"height\":187,\"weight\":74,\"eyeColor\":\"Brown\",\"hair\":{\"color\":\"Blond\",\"type\":\"Curly\"},\"domain\":\"51.la\",\"ip\":\"253.240.20.181\",\"address\":{\"address\":\"6007 Applegate Lane\",\"city\":\"Louisville\",\"coordinates\":{\"lat\":38.1343013,\"lng\":-85.6498512},\"postalCode\":\"40219\",\"state\":\"KY\"}", + "responseCode": 200, + "responseObject": { + "webhookId": "bf21de5b-adb9-3581-82f5-76bb335f1cbd", + "webhookName": "Dummyuser-test", + "webhookMethod": "GET" + } }] "400": description: Bad Request @@ -1518,7 +1525,7 @@ components: httpRequestBody: type: object additionalProperties: - type: string + type: object httpMethod: type: string jansEnabled: @@ -1624,6 +1631,10 @@ components: type: array items: type: string + shortCode: + type: array + items: + type: string baseDn: type: string PagedResult: @@ -1642,6 +1653,15 @@ components: type: array items: type: object + ShortCode: + type: object + properties: + webhookId: + type: string + shortCodes: + type: object + additionalProperties: + type: object securitySchemes: oauth2: type: oauth2 From e48b313048390822ec546d176f4af169f733e024 Mon Sep 17 00:00:00 2001 From: Arnab Dutta Date: Fri, 2 Feb 2024 13:02:01 +0530 Subject: [PATCH 02/10] feat: backend changes to implement short codes in webhooks to pass dynamic info on webhook execution Signed-off-by: Arnab Dutta --- .../adminui/rest/webhook/WebhookResource.java | 1 + .../docs/jans-admin-ui-plugin-swagger.yaml | 16 +++++++++++----- 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/jans-config-api/plugins/admin-ui-plugin/src/main/java/io/jans/ca/plugin/adminui/rest/webhook/WebhookResource.java b/jans-config-api/plugins/admin-ui-plugin/src/main/java/io/jans/ca/plugin/adminui/rest/webhook/WebhookResource.java index 4a255914949..c0153524c21 100644 --- a/jans-config-api/plugins/admin-ui-plugin/src/main/java/io/jans/ca/plugin/adminui/rest/webhook/WebhookResource.java +++ b/jans-config-api/plugins/admin-ui-plugin/src/main/java/io/jans/ca/plugin/adminui/rest/webhook/WebhookResource.java @@ -312,6 +312,7 @@ public Response deleteWebhook(@Parameter(description = "Webhook identifier") @Pa @Operation(summary = "Trigger webhooks mapped to featureId", description = "Trigger webhooks mapped to featureId", operationId = "trigger-webhook", tags = { "Admin UI - Webhooks"}, security = @SecurityRequirement(name = "oauth2", scopes = {SCOPE_WEBHOOK_READ})) + @RequestBody(description = "Webhook object", content = @Content(mediaType = MediaType.APPLICATION_JSON, schema = @Schema(implementation = ShortCode.class), examples = @ExampleObject(name = "Request json example", value = "example/webhook/trigger-webooks-request.json"))) @ApiResponses(value = { @ApiResponse(responseCode = "200", description = "Ok", content = @Content(mediaType = MediaType.APPLICATION_JSON, schema = @Schema(implementation = AuiFeature.class), examples = @ExampleObject(name = "Response json example", value = "example/webhook/trigger-webooks-response.json"))), @ApiResponse(responseCode = "400", description = "Bad Request", content = @Content(mediaType = MediaType.APPLICATION_JSON, schema = @Schema(implementation = GenericResponse.class, description = "License response"))), diff --git a/jans-config-api/plugins/docs/jans-admin-ui-plugin-swagger.yaml b/jans-config-api/plugins/docs/jans-admin-ui-plugin-swagger.yaml index 9b728984587..678418b5ae3 100644 --- a/jans-config-api/plugins/docs/jans-admin-ui-plugin-swagger.yaml +++ b/jans-config-api/plugins/docs/jans-admin-ui-plugin-swagger.yaml @@ -1355,13 +1355,19 @@ paths: schema: type: string requestBody: + description: Webhook object content: - '*/*': + application/json: schema: - type: array - items: - $ref: '#/components/schemas/ShortCode' - required: true + $ref: '#/components/schemas/ShortCode' + examples: + Request json example: + description: Request json example + value: | + [{ + "webhookId": "0a8e784b-2394-3a34-89d3-4a09d245aa32", + "shortCodes": {"price": 100} + }] responses: "200": description: Ok From 974a6c140aa28d044f79470925b200f3fddb47d9 Mon Sep 17 00:00:00 2001 From: Arnab Dutta Date: Wed, 7 Feb 2024 18:12:08 +0530 Subject: [PATCH 03/10] feat: removed shortCode cloumn from features table Signed-off-by: Arnab Dutta --- .../adminui/model/webhook/AuiFeature.java | 15 ++------------- .../{ShortCode.java => ShortCodeRequest.java} | 16 ++++++++-------- .../adminui/rest/webhook/WebhookResource.java | 6 +++--- .../adminui/service/webhook/WebhookService.java | 17 +++++++++-------- .../webhook/trigger-webooks-request.json | 2 +- .../docs/jans-admin-ui-plugin-swagger.yaml | 12 ++++-------- 6 files changed, 27 insertions(+), 41 deletions(-) rename jans-config-api/plugins/admin-ui-plugin/src/main/java/io/jans/ca/plugin/adminui/model/webhook/{ShortCode.java => ShortCodeRequest.java} (54%) diff --git a/jans-config-api/plugins/admin-ui-plugin/src/main/java/io/jans/ca/plugin/adminui/model/webhook/AuiFeature.java b/jans-config-api/plugins/admin-ui-plugin/src/main/java/io/jans/ca/plugin/adminui/model/webhook/AuiFeature.java index 264ca147e42..dd0bdd9a706 100644 --- a/jans-config-api/plugins/admin-ui-plugin/src/main/java/io/jans/ca/plugin/adminui/model/webhook/AuiFeature.java +++ b/jans-config-api/plugins/admin-ui-plugin/src/main/java/io/jans/ca/plugin/adminui/model/webhook/AuiFeature.java @@ -2,12 +2,14 @@ import io.jans.orm.annotation.AttributeName; import io.jans.orm.annotation.DataEntry; +import io.jans.orm.annotation.JsonObject; import io.jans.orm.annotation.ObjectClass; import io.jans.orm.model.base.Entry; import org.python.google.common.collect.Lists; import org.python.google.common.collect.Sets; import java.io.Serializable; +import java.util.ArrayList; import java.util.List; import java.util.Objects; @@ -23,8 +25,6 @@ public class AuiFeature extends Entry implements Serializable { private String jansScope; @AttributeName(name = "webhookId") private List webhookIdsMapped; - @AttributeName(name = "shortCode") - private List shortCode; public String getAuiFeatureId() { return auiFeatureId; @@ -60,16 +60,6 @@ public void setWebhookIdsMapped(List webhookIdsMapped) { } } - public List getShortCode() { - return shortCode; - } - - public void setShortCode(List shortCode) { - if(shortCode != null) { - this.shortCode = Lists.newArrayList(Sets.newHashSet(shortCode)); - } - } - @Override public boolean equals(Object o) { if (this == o) return true; @@ -91,7 +81,6 @@ public String toString() { ", displayName='" + displayName + '\'' + ", jansScope='" + jansScope + '\'' + ", webhookIdsMapped=" + webhookIdsMapped + - ", shortCode=" + shortCode + '}'; } } diff --git a/jans-config-api/plugins/admin-ui-plugin/src/main/java/io/jans/ca/plugin/adminui/model/webhook/ShortCode.java b/jans-config-api/plugins/admin-ui-plugin/src/main/java/io/jans/ca/plugin/adminui/model/webhook/ShortCodeRequest.java similarity index 54% rename from jans-config-api/plugins/admin-ui-plugin/src/main/java/io/jans/ca/plugin/adminui/model/webhook/ShortCode.java rename to jans-config-api/plugins/admin-ui-plugin/src/main/java/io/jans/ca/plugin/adminui/model/webhook/ShortCodeRequest.java index 7601a8fb0d0..43339691e10 100644 --- a/jans-config-api/plugins/admin-ui-plugin/src/main/java/io/jans/ca/plugin/adminui/model/webhook/ShortCode.java +++ b/jans-config-api/plugins/admin-ui-plugin/src/main/java/io/jans/ca/plugin/adminui/model/webhook/ShortCodeRequest.java @@ -5,10 +5,10 @@ import java.io.Serializable; import java.util.Map; -public class ShortCode implements Serializable { +public class ShortCodeRequest implements Serializable { private String webhookId; @JsonObject - Map shortCodes; + Map shortcodeValueMap; public String getWebhookId() { return webhookId; @@ -18,19 +18,19 @@ public void setWebhookId(String webhookId) { this.webhookId = webhookId; } - public Map getShortCodes() { - return shortCodes; + public Map getShortcodeValueMap() { + return shortcodeValueMap; } - public void setShortCodes(Map shortCodes) { - this.shortCodes = shortCodes; + public void setShortcodeValueMap(Map shortcodeValueMap) { + this.shortcodeValueMap = shortcodeValueMap; } @Override public String toString() { - return "ShortCode{" + + return "ShortCodeRequest{" + "webhookId='" + webhookId + '\'' + - ", shortCodes=" + shortCodes + + ", shortcodeValueMap=" + shortcodeValueMap + '}'; } } diff --git a/jans-config-api/plugins/admin-ui-plugin/src/main/java/io/jans/ca/plugin/adminui/rest/webhook/WebhookResource.java b/jans-config-api/plugins/admin-ui-plugin/src/main/java/io/jans/ca/plugin/adminui/rest/webhook/WebhookResource.java index c0153524c21..08e83135b90 100644 --- a/jans-config-api/plugins/admin-ui-plugin/src/main/java/io/jans/ca/plugin/adminui/rest/webhook/WebhookResource.java +++ b/jans-config-api/plugins/admin-ui-plugin/src/main/java/io/jans/ca/plugin/adminui/rest/webhook/WebhookResource.java @@ -4,7 +4,7 @@ import io.jans.ca.plugin.adminui.model.auth.GenericResponse; import io.jans.ca.plugin.adminui.model.exception.ApplicationException; import io.jans.ca.plugin.adminui.model.webhook.AuiFeature; -import io.jans.ca.plugin.adminui.model.webhook.ShortCode; +import io.jans.ca.plugin.adminui.model.webhook.ShortCodeRequest; import io.jans.ca.plugin.adminui.model.webhook.WebhookEntry; import io.jans.ca.plugin.adminui.service.webhook.WebhookService; import io.jans.ca.plugin.adminui.utils.AppConstants; @@ -312,7 +312,7 @@ public Response deleteWebhook(@Parameter(description = "Webhook identifier") @Pa @Operation(summary = "Trigger webhooks mapped to featureId", description = "Trigger webhooks mapped to featureId", operationId = "trigger-webhook", tags = { "Admin UI - Webhooks"}, security = @SecurityRequirement(name = "oauth2", scopes = {SCOPE_WEBHOOK_READ})) - @RequestBody(description = "Webhook object", content = @Content(mediaType = MediaType.APPLICATION_JSON, schema = @Schema(implementation = ShortCode.class), examples = @ExampleObject(name = "Request json example", value = "example/webhook/trigger-webooks-request.json"))) + @RequestBody(description = "Webhook object", content = @Content(mediaType = MediaType.APPLICATION_JSON, schema = @Schema(implementation = ShortCodeRequest.class), examples = @ExampleObject(name = "Request json example", value = "example/webhook/trigger-webooks-request.json"))) @ApiResponses(value = { @ApiResponse(responseCode = "200", description = "Ok", content = @Content(mediaType = MediaType.APPLICATION_JSON, schema = @Schema(implementation = AuiFeature.class), examples = @ExampleObject(name = "Response json example", value = "example/webhook/trigger-webooks-response.json"))), @ApiResponse(responseCode = "400", description = "Bad Request", content = @Content(mediaType = MediaType.APPLICATION_JSON, schema = @Schema(implementation = GenericResponse.class, description = "License response"))), @@ -324,7 +324,7 @@ public Response deleteWebhook(@Parameter(description = "Webhook identifier") @Pa @ProtectedApi(scopes = {SCOPE_WEBHOOK_READ}) @Produces(MediaType.APPLICATION_JSON) public Response triggerWebhook(@Parameter(description = "Admin UI feature identifier") @PathParam(AppConstants.ADMIN_UI_FEATURE_ID) @NotNull String featureId, - @Valid @NotNull List shortCodes) { + @Valid @NotNull List shortCodes) { try { if (log.isDebugEnabled()) { log.debug("Triggering all webhooks for Admin UI feature - featureId: {}", escapeLog(featureId)); diff --git a/jans-config-api/plugins/admin-ui-plugin/src/main/java/io/jans/ca/plugin/adminui/service/webhook/WebhookService.java b/jans-config-api/plugins/admin-ui-plugin/src/main/java/io/jans/ca/plugin/adminui/service/webhook/WebhookService.java index 7b944fd9a61..4e45e59cb90 100644 --- a/jans-config-api/plugins/admin-ui-plugin/src/main/java/io/jans/ca/plugin/adminui/service/webhook/WebhookService.java +++ b/jans-config-api/plugins/admin-ui-plugin/src/main/java/io/jans/ca/plugin/adminui/service/webhook/WebhookService.java @@ -6,7 +6,7 @@ import io.jans.ca.plugin.adminui.model.auth.GenericResponse; import io.jans.ca.plugin.adminui.model.exception.ApplicationException; import io.jans.ca.plugin.adminui.model.webhook.AuiFeature; -import io.jans.ca.plugin.adminui.model.webhook.ShortCode; +import io.jans.ca.plugin.adminui.model.webhook.ShortCodeRequest; import io.jans.ca.plugin.adminui.model.webhook.WebhookEntry; import io.jans.ca.plugin.adminui.utils.AppConstants; import io.jans.ca.plugin.adminui.utils.CommonUtils; @@ -49,7 +49,8 @@ public class WebhookService { */ public List getAllAuiFeatures() throws ApplicationException { try { - return entryManager.findEntries(AppConstants.ADMIN_UI_FEATURES_DN, AuiFeature.class, null); + final Filter filter = Filter.createPresenceFilter("auiFeatureId"); + return entryManager.findEntries(AppConstants.ADMIN_UI_FEATURES_DN, AuiFeature.class, filter); } catch (Exception e) { log.error(ErrorResponse.FETCH_DATA_ERROR.getDescription(), e); throw new ApplicationException(Response.Status.INTERNAL_SERVER_ERROR.getStatusCode(), ErrorResponse.FETCH_DATA_ERROR.getDescription()); @@ -326,14 +327,14 @@ public void validateWebhookEntry(WebhookEntry webhookEntry) throws ApplicationEx * @param webhookIds A set of webhook IDs. * @return The method is returning a List of Strings. */ - public List triggerEnabledWebhooks(Set webhookIds, List shortCodes) throws ApplicationException { + public List triggerEnabledWebhooks(Set webhookIds, List shortCodes) throws ApplicationException { ExecutorService executor = Executors.newFixedThreadPool(10); List responseList = new ArrayList<>(); List> callables = new ArrayList<>(); List webhooks = getWebhookByIds(webhookIds); for (WebhookEntry webhook : webhooks) { validateWebhookEntry(webhook); - ShortCode shortCodeObj = shortCodes.stream().filter(shortCode -> shortCode.getWebhookId().equals(webhook.getWebhookId())).findAny().orElse(null); + ShortCodeRequest shortCodeObj = shortCodes.stream().filter(shortCode -> shortCode.getWebhookId().equals(webhook.getWebhookId())).findAny().orElse(null); replaceShortCodeWithValues(webhook, shortCodeObj); if (webhook.isJansEnabled()) { Callable callable = new WebhookCallable(webhook, log); @@ -355,17 +356,17 @@ public List triggerEnabledWebhooks(Set webhookIds, List return responseList; } - private void replaceShortCodeWithValues(WebhookEntry webhook, ShortCode shortCodeObj) { + private void replaceShortCodeWithValues(WebhookEntry webhook, ShortCodeRequest shortCodeObj) { if (shortCodeObj == null) { return; } - log.info("CommonUtils.hasShortCode(webhook.getUrl()) {}", CommonUtils.hasShortCode(webhook.getUrl())); + if (CommonUtils.hasShortCode(webhook.getUrl())) { - webhook.setUrl(CommonUtils.replacePlaceholders(webhook.getUrl(), shortCodeObj.getShortCodes())); + webhook.setUrl(CommonUtils.replacePlaceholders(webhook.getUrl(), shortCodeObj.getShortcodeValueMap())); } if (CommonUtils.hasShortCode(webhook.getHttpRequestBody()) && Lists.newArrayList("POST", "PUT", "PATCH").contains(webhook.getHttpMethod())) { - webhook.setHttpRequestBody(CommonUtils.replacePlaceholders(webhook.getHttpRequestBody(), shortCodeObj.getShortCodes())); + webhook.setHttpRequestBody(CommonUtils.replacePlaceholders(webhook.getHttpRequestBody(), shortCodeObj.getShortcodeValueMap())); } } diff --git a/jans-config-api/plugins/admin-ui-plugin/src/main/resources/example/webhook/trigger-webooks-request.json b/jans-config-api/plugins/admin-ui-plugin/src/main/resources/example/webhook/trigger-webooks-request.json index 431e11ee09a..0edecf6f859 100644 --- a/jans-config-api/plugins/admin-ui-plugin/src/main/resources/example/webhook/trigger-webooks-request.json +++ b/jans-config-api/plugins/admin-ui-plugin/src/main/resources/example/webhook/trigger-webooks-request.json @@ -1,4 +1,4 @@ [{ "webhookId": "0a8e784b-2394-3a34-89d3-4a09d245aa32", - "shortCodes": {"price": 100} + "shortcodeValueMap": {"price": 100} }] \ No newline at end of file diff --git a/jans-config-api/plugins/docs/jans-admin-ui-plugin-swagger.yaml b/jans-config-api/plugins/docs/jans-admin-ui-plugin-swagger.yaml index 678418b5ae3..00072af26b0 100644 --- a/jans-config-api/plugins/docs/jans-admin-ui-plugin-swagger.yaml +++ b/jans-config-api/plugins/docs/jans-admin-ui-plugin-swagger.yaml @@ -1359,14 +1359,14 @@ paths: content: application/json: schema: - $ref: '#/components/schemas/ShortCode' + $ref: '#/components/schemas/ShortCodeRequest' examples: Request json example: description: Request json example value: | [{ "webhookId": "0a8e784b-2394-3a34-89d3-4a09d245aa32", - "shortCodes": {"price": 100} + "shortcodeValueMap": {"price": 100} }] responses: "200": @@ -1637,10 +1637,6 @@ components: type: array items: type: string - shortCode: - type: array - items: - type: string baseDn: type: string PagedResult: @@ -1659,12 +1655,12 @@ components: type: array items: type: object - ShortCode: + ShortCodeRequest: type: object properties: webhookId: type: string - shortCodes: + shortcodeValueMap: type: object additionalProperties: type: object From 3e1ee399b2797ed63d9e8af97922535b341386f1 Mon Sep 17 00:00:00 2001 From: Arnab Dutta Date: Wed, 7 Feb 2024 23:27:43 +0530 Subject: [PATCH 04/10] feat: adding webhook permissions in admin-ui configuration Signed-off-by: Arnab Dutta --- .../jans-auth/role-scope-mappings.json | 65 ++++++++++++------- 1 file changed, 43 insertions(+), 22 deletions(-) diff --git a/jans-linux-setup/jans_setup/templates/jans-auth/role-scope-mappings.json b/jans-linux-setup/jans_setup/templates/jans-auth/role-scope-mappings.json index 6eb085353e3..10a8e12a2af 100644 --- a/jans-linux-setup/jans_setup/templates/jans-auth/role-scope-mappings.json +++ b/jans-linux-setup/jans_setup/templates/jans-auth/role-scope-mappings.json @@ -342,131 +342,149 @@ "defaultPermissionInToken": false, "tag": "ssa" }, - { + { "permission": "https://jans.io/oauth/config/organization.readonly", "description": "", "defaultPermissionInToken": false, "tag": "organization" }, - { + { "permission": "https://jans.io/oauth/config/organization.write", "description": "", "defaultPermissionInToken": false, "tag": "organization" }, - { + { "permission": "https://jans.io/oauth/config/user.readonly", "description": "", "defaultPermissionInToken": false, "tag": "user" }, - { + { "permission": "https://jans.io/oauth/config/user.write", "description": "", "defaultPermissionInToken": false, "tag": "user" }, - { + { "permission": "https://jans.io/oauth/config/user.delete", "description": "", "defaultPermissionInToken": false, "tag": "user" }, - { + { "permission": "https://jans.io/oauth/config/agama.readonly", "description": "", "defaultPermissionInToken": false, "tag": "agama" }, - { + { "permission": "https://jans.io/oauth/config/agama.write", "description": "", "defaultPermissionInToken": false, "tag": "agama" }, - { + { "permission": "https://jans.io/oauth/config/agama.delete", "description": "", "defaultPermissionInToken": false, "tag": "agama" }, - { + { "permission": "https://jans.io/oauth/jans-auth-server/session.readonly", "description": "", "defaultPermissionInToken": false, "tag": "session" }, - { + { "permission": "https://jans.io/oauth/jans-auth-server/session.delete", "description": "", "defaultPermissionInToken": false, "tag": "session" }, - { + { "permission": "https://jans.io/oauth/config/plugin.readonly", "description": "", "defaultPermissionInToken": false, "tag": "plugin" }, - { + { "permission": "https://jans.io/oauth/config/properties.readonly", "description": "", "defaultPermissionInToken": false, "tag": "properties" }, - { + { "permission": "https://jans.io/oauth/config/properties.write", "description": "", "defaultPermissionInToken": false, "tag": "properties" }, - { + { "permission": "https://jans.io/oauth/client/authorizations.readonly", "description": "", "defaultPermissionInToken": false, "tag": "authorizations" }, - { + { "permission": "https://jans.io/oauth/client/authorizations.delete", "description": "", "defaultPermissionInToken": false, "tag": "authorizations" }, - { + { "permission":"https://jans.io/oauth/config/jans-link.readonly", "description": "", "defaultPermissionInToken": false, "tag": "jans-link" }, - { + { "permission": "https://jans.io/oauth/config/jans-link.write", "description": "", "defaultPermissionInToken": false, "tag": "jans-link" }, - { + { "permission": "https://jans.io/oauth/config/saml-config.readonly", "description": "", "defaultPermissionInToken": false, "tag": "saml-config" }, - { + { "permission": "https://jans.io/oauth/config/saml-config.write", "description": "", "defaultPermissionInToken": false, "tag": "saml-config" }, - { + { "permission": "https://jans.io/oauth/config/saml-scope.readonly", "description": "", "defaultPermissionInToken": false, "tag": "saml-scope" }, - { + { "permission": "https://jans.io/oauth/config/saml-scope.write", "description": "", "defaultPermissionInToken": false, "tag": "saml-scope" + }, + { + "permission": "https://jans.io/oauth/jans-auth-server/config/adminui/webhook.readonly", + "description": "", + "defaultPermissionInToken": false, + "tag": "webhook" + }, + { + "permission": "https://jans.io/oauth/jans-auth-server/config/adminui/webhook.write", + "description": "", + "defaultPermissionInToken": false, + "tag": "webhook" + }, + { + "permission": "https://jans.io/oauth/jans-auth-server/config/adminui/webhook.delete", + "description": "", + "defaultPermissionInToken": false, + "tag": "webhook" } ], "rolePermissionMapping": [ @@ -641,7 +659,10 @@ "https://jans.io/oauth/jans-auth-server/config/properties.write", "https://jans.io/auth/ssa.admin", "https://jans.io/auth/ssa.portal", - "https://jans.io/auth/ssa.developer" + "https://jans.io/auth/ssa.developer", + "https://jans.io/oauth/jans-auth-server/config/adminui/webhook.readonly", + "https://jans.io/oauth/jans-auth-server/config/adminui/webhook.write", + "https://jans.io/oauth/jans-auth-server/config/adminui/webhook.delete" ] } ] From 0756653ded0af5cbb686fe17aab3a63b1142e639 Mon Sep 17 00:00:00 2001 From: Arnab Dutta Date: Thu, 8 Feb 2024 18:14:08 +0530 Subject: [PATCH 05/10] feat: correct sonar code smells Signed-off-by: Arnab Dutta --- .../adminui/model/webhook/AuiFeature.java | 6 ++---- .../model/webhook/ShortCodeRequest.java | 2 +- .../adminui/rest/webhook/WebhookResource.java | 5 +++-- .../service/webhook/WebhookCallable.java | 5 ++--- .../service/webhook/WebhookService.java | 18 ++++++++++-------- .../ca/plugin/adminui/utils/CommonUtils.java | 9 --------- 6 files changed, 18 insertions(+), 27 deletions(-) diff --git a/jans-config-api/plugins/admin-ui-plugin/src/main/java/io/jans/ca/plugin/adminui/model/webhook/AuiFeature.java b/jans-config-api/plugins/admin-ui-plugin/src/main/java/io/jans/ca/plugin/adminui/model/webhook/AuiFeature.java index dd0bdd9a706..c845256334d 100644 --- a/jans-config-api/plugins/admin-ui-plugin/src/main/java/io/jans/ca/plugin/adminui/model/webhook/AuiFeature.java +++ b/jans-config-api/plugins/admin-ui-plugin/src/main/java/io/jans/ca/plugin/adminui/model/webhook/AuiFeature.java @@ -2,18 +2,16 @@ import io.jans.orm.annotation.AttributeName; import io.jans.orm.annotation.DataEntry; -import io.jans.orm.annotation.JsonObject; import io.jans.orm.annotation.ObjectClass; import io.jans.orm.model.base.Entry; import org.python.google.common.collect.Lists; import org.python.google.common.collect.Sets; import java.io.Serializable; -import java.util.ArrayList; import java.util.List; import java.util.Objects; -@DataEntry(sortBy = { "auiFeatureId" }) +@DataEntry(sortBy = {"auiFeatureId"}) @ObjectClass(value = "auiFeatures") public class AuiFeature extends Entry implements Serializable { @@ -55,7 +53,7 @@ public List getWebhookIdsMapped() { } public void setWebhookIdsMapped(List webhookIdsMapped) { - if(webhookIdsMapped != null) { + if (webhookIdsMapped != null) { this.webhookIdsMapped = Lists.newArrayList(Sets.newHashSet(webhookIdsMapped)); } } diff --git a/jans-config-api/plugins/admin-ui-plugin/src/main/java/io/jans/ca/plugin/adminui/model/webhook/ShortCodeRequest.java b/jans-config-api/plugins/admin-ui-plugin/src/main/java/io/jans/ca/plugin/adminui/model/webhook/ShortCodeRequest.java index 43339691e10..21278d1c817 100644 --- a/jans-config-api/plugins/admin-ui-plugin/src/main/java/io/jans/ca/plugin/adminui/model/webhook/ShortCodeRequest.java +++ b/jans-config-api/plugins/admin-ui-plugin/src/main/java/io/jans/ca/plugin/adminui/model/webhook/ShortCodeRequest.java @@ -8,7 +8,7 @@ public class ShortCodeRequest implements Serializable { private String webhookId; @JsonObject - Map shortcodeValueMap; + transient Map shortcodeValueMap; public String getWebhookId() { return webhookId; diff --git a/jans-config-api/plugins/admin-ui-plugin/src/main/java/io/jans/ca/plugin/adminui/rest/webhook/WebhookResource.java b/jans-config-api/plugins/admin-ui-plugin/src/main/java/io/jans/ca/plugin/adminui/rest/webhook/WebhookResource.java index 08e83135b90..0be81479684 100644 --- a/jans-config-api/plugins/admin-ui-plugin/src/main/java/io/jans/ca/plugin/adminui/rest/webhook/WebhookResource.java +++ b/jans-config-api/plugins/admin-ui-plugin/src/main/java/io/jans/ca/plugin/adminui/rest/webhook/WebhookResource.java @@ -30,6 +30,7 @@ import jakarta.ws.rs.*; import jakarta.ws.rs.core.MediaType; import jakarta.ws.rs.core.Response; +import org.apache.commons.collections.CollectionUtils; import org.python.google.common.collect.Sets; import org.slf4j.Logger; @@ -332,12 +333,12 @@ public Response triggerWebhook(@Parameter(description = "Admin UI feature identi HashSet featureIdSet = Sets.newHashSet(); featureIdSet.add(featureId); List featureList = webhookService.getAuiFeaturesByIds(featureIdSet); - if (CommonUtils.isEmptyOrNullCollection(featureList)) { + if (CollectionUtils.isEmpty(featureList)) { log.error(ErrorResponse.WEBHOOK_RECORD_NOT_EXIST.getDescription()); throw new ApplicationException(Response.Status.BAD_REQUEST.getStatusCode(), ErrorResponse.WEBHOOK_RECORD_NOT_EXIST.getDescription()); } AuiFeature featureObj = featureList.get(0); - if (CommonUtils.isEmptyOrNullCollection(featureObj.getWebhookIdsMapped())) { + if (CollectionUtils.isEmpty(featureObj.getWebhookIdsMapped())) { log.error(ErrorResponse.NO_WEBHOOK_FOUND.getDescription()); throw new ApplicationException(Response.Status.INTERNAL_SERVER_ERROR.getStatusCode(), ErrorResponse.NO_WEBHOOK_FOUND.getDescription()); } diff --git a/jans-config-api/plugins/admin-ui-plugin/src/main/java/io/jans/ca/plugin/adminui/service/webhook/WebhookCallable.java b/jans-config-api/plugins/admin-ui-plugin/src/main/java/io/jans/ca/plugin/adminui/service/webhook/WebhookCallable.java index 22e3c5a3431..a9f9672c016 100644 --- a/jans-config-api/plugins/admin-ui-plugin/src/main/java/io/jans/ca/plugin/adminui/service/webhook/WebhookCallable.java +++ b/jans-config-api/plugins/admin-ui-plugin/src/main/java/io/jans/ca/plugin/adminui/service/webhook/WebhookCallable.java @@ -16,7 +16,7 @@ import jakarta.ws.rs.core.MediaType; import jakarta.ws.rs.core.Response; import org.slf4j.Logger; - +import org.apache.commons.collections.MapUtils; import java.util.HashMap; import java.util.Map; import java.util.Objects; @@ -82,7 +82,7 @@ private Invocation checkHttpMethod(Invocation.Builder request) { case "POST": case "PUT": case "PATCH": - if (CommonUtils.isEmptyOrNullCollection(webhook.getHttpRequestBody())) { + if (MapUtils.isEmpty(webhook.getHttpRequestBody())) { break; } Map requestBody = setRequestBody(webhook); @@ -112,5 +112,4 @@ private Map setRequestBody(WebhookEntry webhook) { return Maps.newHashMap(); } } - } diff --git a/jans-config-api/plugins/admin-ui-plugin/src/main/java/io/jans/ca/plugin/adminui/service/webhook/WebhookService.java b/jans-config-api/plugins/admin-ui-plugin/src/main/java/io/jans/ca/plugin/adminui/service/webhook/WebhookService.java index 4e45e59cb90..bb70732b0ec 100644 --- a/jans-config-api/plugins/admin-ui-plugin/src/main/java/io/jans/ca/plugin/adminui/service/webhook/WebhookService.java +++ b/jans-config-api/plugins/admin-ui-plugin/src/main/java/io/jans/ca/plugin/adminui/service/webhook/WebhookService.java @@ -23,7 +23,8 @@ import jakarta.ws.rs.core.Response; import org.python.google.common.collect.Sets; import org.slf4j.Logger; - +import org.apache.commons.collections.CollectionUtils; +import org.apache.commons.collections.MapUtils; import javax.validation.Valid; import java.util.*; import java.util.concurrent.*; @@ -42,6 +43,8 @@ public class WebhookService { @Inject ConfigurationFactory configurationFactory; + public static final String AUI_FEATURE_ID = "auiFeatureId"; + /** * The function retrieves all AuiFeature objects from the entryManager and returns them as a List. * @@ -49,7 +52,7 @@ public class WebhookService { */ public List getAllAuiFeatures() throws ApplicationException { try { - final Filter filter = Filter.createPresenceFilter("auiFeatureId"); + final Filter filter = Filter.createPresenceFilter(AUI_FEATURE_ID); return entryManager.findEntries(AppConstants.ADMIN_UI_FEATURES_DN, AuiFeature.class, filter); } catch (Exception e) { log.error(ErrorResponse.FETCH_DATA_ERROR.getDescription(), e); @@ -136,15 +139,15 @@ public List getWebhookByIds(Set ids) { public List getWebhooksByFeatureId(String featureId) { try { - Filter filter = Filter.createSubstringFilter("auiFeatureId", null, new String[]{featureId}, null); + Filter filter = Filter.createSubstringFilter(AUI_FEATURE_ID, null, new String[]{featureId}, null); List features = entryManager.findEntries(AppConstants.ADMIN_UI_FEATURES_DN, AuiFeature.class, filter); - if (CommonUtils.isEmptyOrNullCollection(features)) { + if (CollectionUtils.isEmpty(features)) { log.error(ErrorResponse.WEBHOOK_RECORD_NOT_EXIST.getDescription()); throw new ApplicationException(Response.Status.BAD_REQUEST.getStatusCode(), ErrorResponse.WEBHOOK_RECORD_NOT_EXIST.getDescription()); } AuiFeature feature = features.get(0); List webhooksIds = feature.getWebhookIdsMapped(); - if (CommonUtils.isEmptyOrNullCollection(webhooksIds)) { + if (CollectionUtils.isEmpty(webhooksIds)) { log.error(ErrorResponse.NO_WEBHOOK_FOUND.getDescription()); throw new ApplicationException(Response.Status.BAD_REQUEST.getStatusCode(), ErrorResponse.NO_WEBHOOK_FOUND.getDescription()); } @@ -167,7 +170,7 @@ public List getAuiFeaturesByIds(Set ids) { Filter searchFilter = null; List filters = new ArrayList<>(); for (String id : ids) { - Filter filter = Filter.createSubstringFilter("auiFeatureId", null, new String[]{id}, null); + Filter filter = Filter.createSubstringFilter(AUI_FEATURE_ID, null, new String[]{id}, null); filters.add(filter); } searchFilter = Filter.createORFilter(filters); @@ -309,7 +312,7 @@ public void validateWebhookEntry(WebhookEntry webhookEntry) throws ApplicationEx throw new ApplicationException(Response.Status.BAD_REQUEST.getStatusCode(), ErrorResponse.WEBHOOK_HTTP_METHOD_EMPTY.getDescription()); } if (Lists.newArrayList("POST", "PUT", "PATCH").contains(webhookEntry.getHttpMethod())) { - if (CommonUtils.isEmptyOrNullCollection(webhookEntry.getHttpRequestBody())) { + if (MapUtils.isEmpty(webhookEntry.getHttpRequestBody())) { log.error(ErrorResponse.WEBHOOK_REQUEST_BODY_EMPTY.getDescription()); throw new ApplicationException(Response.Status.BAD_REQUEST.getStatusCode(), ErrorResponse.WEBHOOK_REQUEST_BODY_EMPTY.getDescription()); } @@ -378,7 +381,6 @@ private static String dnOfWebhook(String id, String baseDn) { return String.format("webhookId=%s,%s", id, baseDn); } - public int getRecordMaxCount() { log.trace(" MaxCount details - ApiAppConfiguration.MaxCount():{}, DEFAULT_MAX_COUNT:{} ", configurationFactory.getApiAppConfiguration().getMaxCount(), ApiConstants.DEFAULT_MAX_COUNT); diff --git a/jans-config-api/plugins/admin-ui-plugin/src/main/java/io/jans/ca/plugin/adminui/utils/CommonUtils.java b/jans-config-api/plugins/admin-ui-plugin/src/main/java/io/jans/ca/plugin/adminui/utils/CommonUtils.java index e2cc1bbcd63..699203d3fc7 100644 --- a/jans-config-api/plugins/admin-ui-plugin/src/main/java/io/jans/ca/plugin/adminui/utils/CommonUtils.java +++ b/jans-config-api/plugins/admin-ui-plugin/src/main/java/io/jans/ca/plugin/adminui/utils/CommonUtils.java @@ -5,7 +5,6 @@ import io.jans.ca.plugin.adminui.model.auth.GenericResponse; import jakarta.inject.Inject; import org.apache.commons.codec.binary.Base64; -import org.apache.commons.text.StringSubstitutor; import org.slf4j.Logger; import java.io.UnsupportedEncodingException; @@ -75,14 +74,6 @@ public static GenericResponse createGenericResponse(boolean result, int response return genericResponse; } - public static boolean isEmptyOrNullCollection(Collection collection) { - return (collection == null || collection.isEmpty()); - } - - public static boolean isEmptyOrNullCollection(final Map m) { - return m == null || m.isEmpty(); - } - public static boolean hasShortCode(Map map) { // Use regular expression to match placeholders in keys like "${placeholder}" String pattern = "\\$\\{(\\w+)}"; From 1d758315c2e586727dc92452c11f2101a2f4b95d Mon Sep 17 00:00:00 2001 From: Arnab Dutta Date: Thu, 8 Feb 2024 18:45:19 +0530 Subject: [PATCH 06/10] feat: correct sonar code smells Signed-off-by: Arnab Dutta --- .../io/jans/ca/plugin/adminui/model/webhook/WebhookEntry.java | 2 +- .../main/java/io/jans/ca/plugin/adminui/utils/CommonUtils.java | 3 --- 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/jans-config-api/plugins/admin-ui-plugin/src/main/java/io/jans/ca/plugin/adminui/model/webhook/WebhookEntry.java b/jans-config-api/plugins/admin-ui-plugin/src/main/java/io/jans/ca/plugin/adminui/model/webhook/WebhookEntry.java index a173300b14d..bd2dbc4dc59 100644 --- a/jans-config-api/plugins/admin-ui-plugin/src/main/java/io/jans/ca/plugin/adminui/model/webhook/WebhookEntry.java +++ b/jans-config-api/plugins/admin-ui-plugin/src/main/java/io/jans/ca/plugin/adminui/model/webhook/WebhookEntry.java @@ -37,7 +37,7 @@ public class WebhookEntry extends Entry implements Serializable { private String url; @AttributeName(name = "httpRequestBody") @JsonObject - private Map httpRequestBody; + private transient Map httpRequestBody; @NotNull @AttributeName(name = "httpMethod") private String httpMethod; diff --git a/jans-config-api/plugins/admin-ui-plugin/src/main/java/io/jans/ca/plugin/adminui/utils/CommonUtils.java b/jans-config-api/plugins/admin-ui-plugin/src/main/java/io/jans/ca/plugin/adminui/utils/CommonUtils.java index 699203d3fc7..03c496ebdbf 100644 --- a/jans-config-api/plugins/admin-ui-plugin/src/main/java/io/jans/ca/plugin/adminui/utils/CommonUtils.java +++ b/jans-config-api/plugins/admin-ui-plugin/src/main/java/io/jans/ca/plugin/adminui/utils/CommonUtils.java @@ -81,11 +81,8 @@ public static boolean hasShortCode(Map map) { // Iterate through map keys and check for placeholders for (Object value : map.values()) { - System.out.println(value); - System.out.println(value.toString()); Matcher matcher = placeholderPattern.matcher(value.toString()); if (matcher.find()) { - System.out.println("True"); // Placeholder found in key return true; } From 8cecb2f5246280f6a7c246f0c8e201a07d454fa2 Mon Sep 17 00:00:00 2001 From: Arnab Dutta Date: Wed, 14 Feb 2024 12:46:42 +0530 Subject: [PATCH 07/10] feat: add datatypes to table columns Signed-off-by: Arnab Dutta --- .../static/rdbm/sql_data_types.json | 35 ++++++++++++++++++- 1 file changed, 34 insertions(+), 1 deletion(-) diff --git a/jans-linux-setup/jans_setup/static/rdbm/sql_data_types.json b/jans-linux-setup/jans_setup/static/rdbm/sql_data_types.json index cdefd0d93ab..f10640f5305 100644 --- a/jans-linux-setup/jans_setup/static/rdbm/sql_data_types.json +++ b/jans-linux-setup/jans_setup/static/rdbm/sql_data_types.json @@ -1105,5 +1105,38 @@ "spanner": { "type": "ARRAY" } - } + }, + "webhookId": { + "mysql": { + "type": "TEXT" + }, + "pgsql": { + "type": "TEXT" + }, + "spanner": { + "type": "STRING(MAX)" + } + }, + "url": { + "mysql": { + "type": "TEXT" + }, + "pgsql": { + "type": "TEXT" + }, + "spanner": { + "type": "STRING(MAX)" + } + }, + "httpRequestBody": { + "mysql": { + "type": "TEXT" + }, + "pgsql": { + "type": "TEXT" + }, + "spanner": { + "type": "STRING(MAX)" + } + } } From 9d228ee2e19871fcffeb7db943bf258a3f860ad2 Mon Sep 17 00:00:00 2001 From: Arnab Dutta Date: Mon, 19 Feb 2024 20:03:01 +0530 Subject: [PATCH 08/10] fix: error in triggrering webhook Signed-off-by: Arnab Dutta --- .../service/webhook/WebhookCallable.java | 80 +++++++++++-------- .../plugin/adminui/utils/ErrorResponse.java | 6 +- 2 files changed, 48 insertions(+), 38 deletions(-) diff --git a/jans-config-api/plugins/admin-ui-plugin/src/main/java/io/jans/ca/plugin/adminui/service/webhook/WebhookCallable.java b/jans-config-api/plugins/admin-ui-plugin/src/main/java/io/jans/ca/plugin/adminui/service/webhook/WebhookCallable.java index a9f9672c016..690845b929f 100644 --- a/jans-config-api/plugins/admin-ui-plugin/src/main/java/io/jans/ca/plugin/adminui/service/webhook/WebhookCallable.java +++ b/jans-config-api/plugins/admin-ui-plugin/src/main/java/io/jans/ca/plugin/adminui/service/webhook/WebhookCallable.java @@ -11,12 +11,14 @@ import io.jans.ca.plugin.adminui.utils.AppConstants; import io.jans.ca.plugin.adminui.utils.ClientFactory; import io.jans.ca.plugin.adminui.utils.CommonUtils; +import io.jans.ca.plugin.adminui.utils.ErrorResponse; import jakarta.ws.rs.client.Entity; import jakarta.ws.rs.client.Invocation; import jakarta.ws.rs.core.MediaType; import jakarta.ws.rs.core.Response; -import org.slf4j.Logger; import org.apache.commons.collections.MapUtils; +import org.slf4j.Logger; + import java.util.HashMap; import java.util.Map; import java.util.Objects; @@ -33,40 +35,52 @@ public WebhookCallable(WebhookEntry webhook, Logger log) { @Override public GenericResponse call() throws ApplicationException { - log.debug("Webhook processing started. Id: {}. Name: {}, URL : {}, HttpMethod: {}", webhook.getWebhookId(), webhook.getDisplayName(), webhook.getUrl(), webhook.getHttpMethod()); - Invocation.Builder request = ClientFactory.instance().getClientBuilder(webhook.getUrl()); - //getting all headers - webhook.getHttpHeaders().stream() - .filter(Objects::nonNull) - .forEach(header -> request.header(header.getKey(), header.getValue())); - //Call rest endpoint - Invocation invocation = checkHttpMethod(request); - if (invocation == null) { - log.error("Error in creating invocation object for rest call (Name: {}, Id: {})", webhook.getDisplayName(), webhook.getWebhookId()); - return CommonUtils.createGenericResponse(false, - Response.Status.INTERNAL_SERVER_ERROR.getStatusCode(), - "Error in creating invocation object for rest call (Name: " + webhook.getDisplayName() + ", Id: " + webhook.getWebhookId() + ")"); - } - Response response = invocation.invoke(); ObjectMapper objectMapper = new ObjectMapper(); - log.debug("Webhook (Name: {}, Id: {}) response status code: {}", webhook.getDisplayName(), webhook.getWebhookId(), response.getStatus()); JsonNode jsonNode = objectMapper.createObjectNode(); - ((ObjectNode) jsonNode).put("webhookId", webhook.getWebhookId()); - ((ObjectNode) jsonNode).put("webhookName", webhook.getDisplayName()); - ((ObjectNode) jsonNode).put("webhookMethod", webhook.getHttpMethod()); - if(Lists.newArrayList("POST", "PUT", "PATCH").contains(webhook.getHttpMethod())) { - ((ObjectNode) jsonNode).put("webhookRequestBody", webhook.getHttpRequestBody().toString()); - } - if (response.getStatus() == Response.Status.OK.getStatusCode() || - response.getStatus() == Response.Status.CREATED.getStatusCode() || - response.getStatus() == Response.Status.ACCEPTED.getStatusCode()) { - String responseData = response.readEntity(String.class); - log.debug("Webhook (Name: {}, Id: {}) responseData : {}", webhook.getDisplayName(), webhook.getWebhookId(), responseData); - return CommonUtils.createGenericResponse(true, response.getStatus(), responseData, jsonNode); - } else { - String responseData = response.readEntity(String.class); - log.error("Webhook (Name: {}, Id: {}) responseData : {}", webhook.getDisplayName(), webhook.getWebhookId(), responseData); - return CommonUtils.createGenericResponse(false, response.getStatus(), responseData, jsonNode); + try { + log.debug("Webhook processing started. Id: {}. Name: {}, URL : {}, HttpMethod: {}", webhook.getWebhookId(), webhook.getDisplayName(), webhook.getUrl(), webhook.getHttpMethod()); + Invocation.Builder request = ClientFactory.instance().getClientBuilder(webhook.getUrl()); + //getting all headers + webhook.getHttpHeaders().stream() + .filter(Objects::nonNull) + .forEach(header -> request.header(header.getKey(), header.getValue())); + //Call rest endpoint + Invocation invocation = checkHttpMethod(request); + if (invocation == null) { + log.error("Error in creating invocation object for rest call (Name: {}, Id: {})", webhook.getDisplayName(), webhook.getWebhookId()); + return CommonUtils.createGenericResponse(false, + Response.Status.INTERNAL_SERVER_ERROR.getStatusCode(), + "Error in creating invocation object for rest call (Name: " + webhook.getDisplayName() + ", Id: " + webhook.getWebhookId() + ")"); + } + Response response = invocation.invoke(); + log.debug("Webhook (Name: {}, Id: {}) response status code: {}", webhook.getDisplayName(), webhook.getWebhookId(), response.getStatus()); + + ((ObjectNode) jsonNode).put("webhookId", webhook.getWebhookId()); + ((ObjectNode) jsonNode).put("webhookName", webhook.getDisplayName()); + ((ObjectNode) jsonNode).put("webhookMethod", webhook.getHttpMethod()); + if (Lists.newArrayList("POST", "PUT", "PATCH").contains(webhook.getHttpMethod())) { + ((ObjectNode) jsonNode).put("webhookRequestBody", webhook.getHttpRequestBody().toString()); + } + if (response.getStatus() == Response.Status.OK.getStatusCode() || + response.getStatus() == Response.Status.CREATED.getStatusCode() || + response.getStatus() == Response.Status.ACCEPTED.getStatusCode()) { + String responseData = response.readEntity(String.class); + log.debug("Webhook (Name: {}, Id: {}) responseData : {}", webhook.getDisplayName(), webhook.getWebhookId(), responseData); + return CommonUtils.createGenericResponse(true, response.getStatus(), responseData, jsonNode); + } else { + String responseData = response.readEntity(String.class); + log.error("Webhook (Name: {}, Id: {}) responseData : {}", webhook.getDisplayName(), webhook.getWebhookId(), responseData); + return CommonUtils.createGenericResponse(false, response.getStatus(), responseData, jsonNode); + } + } catch (Exception e) { + log.error(ErrorResponse.WEBHOOK_TRIGGER_ERROR.getDescription(), e); + ((ObjectNode) jsonNode).put("webhookId", webhook.getWebhookId()); + ((ObjectNode) jsonNode).put("webhookName", webhook.getDisplayName()); + ((ObjectNode) jsonNode).put("webhookMethod", webhook.getHttpMethod()); + if (Lists.newArrayList("POST", "PUT", "PATCH").contains(webhook.getHttpMethod())) { + ((ObjectNode) jsonNode).put("webhookRequestBody", webhook.getHttpRequestBody().toString()); + } + return CommonUtils.createGenericResponse(false, Response.Status.INTERNAL_SERVER_ERROR.getStatusCode(), e.getMessage(), jsonNode); } } diff --git a/jans-config-api/plugins/admin-ui-plugin/src/main/java/io/jans/ca/plugin/adminui/utils/ErrorResponse.java b/jans-config-api/plugins/admin-ui-plugin/src/main/java/io/jans/ca/plugin/adminui/utils/ErrorResponse.java index 4454ca157f5..2ee09b9d520 100644 --- a/jans-config-api/plugins/admin-ui-plugin/src/main/java/io/jans/ca/plugin/adminui/utils/ErrorResponse.java +++ b/jans-config-api/plugins/admin-ui-plugin/src/main/java/io/jans/ca/plugin/adminui/utils/ErrorResponse.java @@ -1,13 +1,8 @@ package io.jans.ca.plugin.adminui.utils; public enum ErrorResponse { - GET_ACCESS_TOKEN_ERROR("Error in getting access token."), GET_API_PROTECTION_TOKEN_ERROR("Error in generating token to access Jans Config Api endpoints."), - GET_USER_INFO_ERROR("Error in getting User-Info."), - AUTHORIZATION_CODE_BLANK("Bad Request: Authourization `code` blank or empty."), USER_INFO_JWT_BLANK("User-Info jwt is blank or empty. Generating token with default scopes."), - CODE_OR_TOKEN_REQUIRED("Bad Request: Either `code` or `access_token` is required."), - CODE_VERIFIER_REQUIRED("Bad Request: `code_verifier` is required."), CHECK_LICENSE_ERROR("Error in checking license status. Check logs for further details."), ERROR_IN_LICENSE_CONFIGURATION_VALIDATION("Error in validating license configuration."), ACTIVATE_LICENSE_ERROR("Error in activating License. Check logs for further details."), @@ -53,6 +48,7 @@ public enum ErrorResponse { WEBHOOK_REQUEST_BODY_EMPTY("HTTP request-body for webhook is required for POST/PUT/PATCH request."), WEBHOOK_SAVE_ERROR("Error in saving webhook."), WEBHOOK_SEARCH_ERROR("Error in fetching webhook."), + WEBHOOK_TRIGGER_ERROR("Error in triggering webhook."), WEBHOOK_UPDATE_ERROR("Error in updating webhook."), WEBHOOK_ID_MISSING("Webhook Id is missing in request."), WEBHOOK_DELETE_ERROR("Error in removing webhook."), From 59d2b62409485678cedc434f26a0016947e0fbb2 Mon Sep 17 00:00:00 2001 From: Arnab Dutta Date: Sat, 24 Feb 2024 16:43:57 +0530 Subject: [PATCH 09/10] fix: remove commented code Signed-off-by: Arnab Dutta --- .../ca/plugin/adminui/utils/CommonUtils.java | 25 ------------------- 1 file changed, 25 deletions(-) diff --git a/jans-config-api/plugins/admin-ui-plugin/src/main/java/io/jans/ca/plugin/adminui/utils/CommonUtils.java b/jans-config-api/plugins/admin-ui-plugin/src/main/java/io/jans/ca/plugin/adminui/utils/CommonUtils.java index 03c496ebdbf..f16b41eb6cf 100644 --- a/jans-config-api/plugins/admin-ui-plugin/src/main/java/io/jans/ca/plugin/adminui/utils/CommonUtils.java +++ b/jans-config-api/plugins/admin-ui-plugin/src/main/java/io/jans/ca/plugin/adminui/utils/CommonUtils.java @@ -141,29 +141,4 @@ public static String replacePlaceholders(String url, Map placeho matcher.appendTail(sb); // Append remaining string return sb.toString(); } - - /*public static void main(String[] args) { - String url = "https://example.com/users/${userId}/profile?name=${userName}"; - Map map = new HashMap<>(); - Map map1 = new HashMap<>(); - map1.put("id",1); - map1.put("price","${price}"); - map1.put("add","${add}"); - - map.put("id",1); - map.put("price","${price}"); - map.put("add",map1); - map.put("userId","11111111111111111111111111"); - map.put("userName","Arnab"); - - - - Map values = new HashMap<>(); - values.put("price",10); - values.put("add","+"); - values.put("userId","11111111111111111111111111"); - values.put("userName","Arnab"); - System.out.println("============"+replacePlaceholders(map, values)); - System.out.println("============"+replacePlaceholders(url, values)); - }*/ } \ No newline at end of file From 818be8da85dbe7ccf698e362700cf0efb0cad821 Mon Sep 17 00:00:00 2001 From: Arnab Dutta Date: Sat, 24 Feb 2024 17:17:49 +0530 Subject: [PATCH 10/10] fix: removing compilation error Signed-off-by: Arnab Dutta --- .../ca/plugin/adminui/service/adminui/AdminUIService.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/jans-config-api/plugins/admin-ui-plugin/src/main/java/io/jans/ca/plugin/adminui/service/adminui/AdminUIService.java b/jans-config-api/plugins/admin-ui-plugin/src/main/java/io/jans/ca/plugin/adminui/service/adminui/AdminUIService.java index ad286f843b2..461a2bb1032 100644 --- a/jans-config-api/plugins/admin-ui-plugin/src/main/java/io/jans/ca/plugin/adminui/service/adminui/AdminUIService.java +++ b/jans-config-api/plugins/admin-ui-plugin/src/main/java/io/jans/ca/plugin/adminui/service/adminui/AdminUIService.java @@ -92,7 +92,7 @@ public AdminRole getRoleObjByName(String role) throws ApplicationException { try { AdminConf adminConf = entryManager.find(AdminConf.class, AppConstants.ADMIN_UI_CONFIG_DN); List roles = adminConf.getDynamic().getRoles().stream().filter(ele -> ele.getRole().equals(role)).collect(Collectors.toList()); - if (!CommonUtils.isEmptyOrNullCollection(roles)) { + if (!CollectionUtils.isEmpty(roles)) { return roles.get(0); } log.error(ErrorResponse.ROLE_NOT_FOUND.getDescription()); @@ -208,7 +208,7 @@ public AdminPermission getPermissionObjByName(String permission) throws Applicat try { AdminConf adminConf = entryManager.find(AdminConf.class, AppConstants.ADMIN_UI_CONFIG_DN); List permissions = adminConf.getDynamic().getPermissions().stream().filter(ele -> ele.getPermission().equals(permission)).collect(Collectors.toList()); - if (!CommonUtils.isEmptyOrNullCollection(permissions)) { + if (!CollectionUtils.isEmpty(permissions)) { return permissions.get(0); } log.error(ErrorResponse.ROLE_NOT_FOUND.getDescription()); @@ -385,7 +385,7 @@ public RolePermissionMapping getAdminUIRolePermissionsMapping(String role) throw List roleScopeMappings = adminConf.getDynamic().getRolePermissionMapping() .stream().filter(ele -> ele.getRole().equalsIgnoreCase(role)) .collect(Collectors.toList()); - if (!CommonUtils.isEmptyOrNullCollection(roleScopeMappings)) { + if (!CollectionUtils.isEmpty(roleScopeMappings)) { return roleScopeMappings.get(0); } log.error(ErrorResponse.ROLE_PERMISSION_MAP_NOT_FOUND.getDescription());