diff --git a/java/middleware-commons/src/main/java/dev/sunbirdrc/registry/middleware/util/JSONUtil.java b/java/middleware-commons/src/main/java/dev/sunbirdrc/registry/middleware/util/JSONUtil.java index b16c8bc46..9e76a2f2b 100644 --- a/java/middleware-commons/src/main/java/dev/sunbirdrc/registry/middleware/util/JSONUtil.java +++ b/java/middleware-commons/src/main/java/dev/sunbirdrc/registry/middleware/util/JSONUtil.java @@ -569,6 +569,21 @@ public static ObjectNode getSearchPageUrls(JsonNode inputNode, long defaultLimit return result; } + public static ObjectNode getRootSearchPageUrls(JsonNode inputNode, long defaultLimit, long defaultOffset, long totalCount, String url) throws IOException { + ObjectNode result = JsonNodeFactory.instance.objectNode(); + JsonNode searchNode = objectMapper.readTree(inputNode.toString()); + String entityName = searchNode.fieldNames().next(); + long limit = searchNode.get(entityName).get(LIMIT) == null ? defaultLimit : searchNode.get(entityName).get(LIMIT).asLong(defaultLimit); + long offset = searchNode.get(entityName).get(OFFSET) == null ? defaultOffset : searchNode.get(entityName).get(OFFSET).asLong(defaultOffset); + ((ObjectNode) searchNode.at("/" + entityName)).set(OFFSET, JsonNodeFactory.instance.numberNode(offset - limit)); + String prevPageToken = Base64.getEncoder().encodeToString(searchNode.toString().getBytes(StandardCharsets.UTF_8)); + ((ObjectNode) searchNode.at("/" + entityName)).set(OFFSET, JsonNodeFactory.instance.numberNode(offset + limit)); + String nextPageToken = Base64.getEncoder().encodeToString(searchNode.toString().getBytes(StandardCharsets.UTF_8)); + if(offset - limit >=0) result.put(PREV_PAGE, url + "?search=" + prevPageToken); + if(offset + limit < totalCount) result.put(NEXT_PAGE, url + "?search=" + nextPageToken); + return result; + } + public static ObjectNode parseSearchToken(String endcodedValue) { try { byte[] decoded = Base64.getDecoder().decode(endcodedValue); diff --git a/java/registry/src/main/java/dev/sunbirdrc/registry/controller/RegistryUtilsController.java b/java/registry/src/main/java/dev/sunbirdrc/registry/controller/RegistryUtilsController.java index d88efcec2..96ab15a4a 100644 --- a/java/registry/src/main/java/dev/sunbirdrc/registry/controller/RegistryUtilsController.java +++ b/java/registry/src/main/java/dev/sunbirdrc/registry/controller/RegistryUtilsController.java @@ -1,6 +1,7 @@ package dev.sunbirdrc.registry.controller; import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.node.ObjectNode; import com.google.common.io.ByteStreams; import com.google.gson.Gson; import com.google.gson.JsonArray; @@ -40,6 +41,8 @@ import java.util.List; import java.util.Map; +import static dev.sunbirdrc.registry.middleware.util.Constants.TOTAL_COUNT; + @RestController public class RegistryUtilsController { @@ -80,6 +83,11 @@ public class RegistryUtilsController { @Value("${audit.frame.store}") public String auditStoreType; + @Value("${search.offset:0}") + private int searchOffset; + @Value("${search.limit:2000}") + private int searchLimit; + @RequestMapping(value = "/utils/sign", method = RequestMethod.POST) public ResponseEntity generateSignature(HttpServletRequest requestModel) { ResponseParams responseParams = new ResponseParams(); @@ -269,16 +277,21 @@ public ResponseEntity registryHealth() { } @ResponseBody - @RequestMapping(value = "/audit", method = RequestMethod.POST) - public ResponseEntity fetchAudit() { + @RequestMapping(value = "/audit", method = {RequestMethod.POST, RequestMethod.GET}) + public ResponseEntity fetchAudit(HttpServletRequest request, @RequestParam(value = "search", required = false) String searchQueryString) { ResponseParams responseParams = new ResponseParams(); Response response = new Response(Response.API_ID.AUDIT, "OK", responseParams); JsonNode payload = apiMessage.getRequest().getRequestMapNode(); + if(searchQueryString != null) { + payload = JSONUtil.parseSearchToken(searchQueryString); + } if (auditEnabled && Constants.DATABASE.equals(auditStoreType)) { try { watch.start("RegistryController.audit"); JsonNode result = registryHelper.getAuditLog(payload, null); - + String resultEntity = result.fieldNames().next(); + ObjectNode pageUrls = JSONUtil.getRootSearchPageUrls(payload, searchLimit, searchOffset, result.get(resultEntity).get(TOTAL_COUNT).asLong(), request.getRequestURL().toString()); + ((ObjectNode) result.get(resultEntity)).setAll(pageUrls); response.setResult(result); responseParams.setStatus(Response.Status.SUCCESSFUL); watch.stop("RegistryController.searchEntity"); diff --git a/java/registry/src/main/java/dev/sunbirdrc/registry/service/impl/AuditDBImpl.java b/java/registry/src/main/java/dev/sunbirdrc/registry/service/impl/AuditDBImpl.java index c36558b10..b752442c0 100644 --- a/java/registry/src/main/java/dev/sunbirdrc/registry/service/impl/AuditDBImpl.java +++ b/java/registry/src/main/java/dev/sunbirdrc/registry/service/impl/AuditDBImpl.java @@ -57,6 +57,7 @@ public void doAudit(AuditRecord auditRecord, JsonNode inputNode, Shard shard) { } JsonNode rootNode = convertAuditRecordToJson(auditRecord, entityType); + signAudit(entityType, rootNode); auditToDB(rootNode, entityType, shard); } catch (AuditFailedException e) { diff --git a/java/registry/src/main/java/dev/sunbirdrc/registry/service/impl/AuditFileImpl.java b/java/registry/src/main/java/dev/sunbirdrc/registry/service/impl/AuditFileImpl.java index 495bb790a..8035a2b16 100644 --- a/java/registry/src/main/java/dev/sunbirdrc/registry/service/impl/AuditFileImpl.java +++ b/java/registry/src/main/java/dev/sunbirdrc/registry/service/impl/AuditFileImpl.java @@ -33,7 +33,9 @@ public void doAudit(AuditRecord auditRecord, JsonNode inputNode, Shard shard) th try { // If the audit is stored as file, fetchAudit from audit entity will not come to this point. AuditFileWriter auditWriter = new AuditFileWriter(); - auditWriter.auditToFile(auditRecord); + JsonNode rootNode = convertAuditRecordToJson(auditRecord, auditRecord.getEntityType()); + signAudit(auditRecord.getEntityType(), rootNode); + auditWriter.auditToFile(rootNode); // sendAuditToActor(auditRecord, inputNode, auditRecord.getEntityType()); } catch (Exception e) { @@ -45,7 +47,6 @@ public void doAudit(AuditRecord auditRecord, JsonNode inputNode, Shard shard) th @Override public String getAuditProvider() { - return Constants.FILE; } } diff --git a/java/registry/src/main/java/dev/sunbirdrc/registry/service/impl/AuditServiceImpl.java b/java/registry/src/main/java/dev/sunbirdrc/registry/service/impl/AuditServiceImpl.java index dff4264c4..b83309e7f 100644 --- a/java/registry/src/main/java/dev/sunbirdrc/registry/service/impl/AuditServiceImpl.java +++ b/java/registry/src/main/java/dev/sunbirdrc/registry/service/impl/AuditServiceImpl.java @@ -1,11 +1,13 @@ package dev.sunbirdrc.registry.service.impl; import java.io.IOException; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; +import java.util.*; +import dev.sunbirdrc.registry.config.GenericConfiguration; import dev.sunbirdrc.registry.exception.AuditFailedException; +import dev.sunbirdrc.registry.exception.SignatureException; +import dev.sunbirdrc.registry.helper.SignatureHelper; +import dev.sunbirdrc.registry.middleware.util.OSSystemFields; import org.apache.commons.lang3.exception.ExceptionUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -58,6 +60,9 @@ public class AuditServiceImpl implements IAuditService { @Value("${audit.frame.suffixSeparator}") private String auditSuffixSeparator; + @Value("${audit.vc-enabled:false}") + private boolean auditVCEnabled; + @Autowired private IDefinitionsManager definitionsManager; @@ -67,6 +72,12 @@ public class AuditServiceImpl implements IAuditService { @Autowired private AuditProviderFactory auditProviderFactory; + @Autowired(required = false) + private SignatureHelper signatureHelper; + + @Value("${signature.enabled:false}") + private boolean signatureEnabled; + @Value("${search.providerName}") private String searchProvider; @@ -177,5 +188,18 @@ public String getAuditProvider() { return null; } + protected void signAudit(String entityType, JsonNode rootNode) throws SignatureException.CreationException, SignatureException.UnreachableException { + if(signatureEnabled && auditVCEnabled) { + Object credentialTemplate = definitionsManager.getCredentialTemplate(entityType); + if(credentialTemplate == null || credentialTemplate.toString().isEmpty()) return; + Map requestBodyMap = new HashMap<>(); + requestBodyMap.put("title", entityType); + requestBodyMap.put("data", rootNode.get(entityType)); + requestBodyMap.put("credentialTemplate", credentialTemplate); + Object signedCredentials = signatureHelper.sign(requestBodyMap); + OSSystemFields.credentials.setCredential(GenericConfiguration.getSignatureProvider(), rootNode.get(entityType), signedCredentials); + } + } + } diff --git a/java/registry/src/main/java/dev/sunbirdrc/registry/util/AuditFileWriter.java b/java/registry/src/main/java/dev/sunbirdrc/registry/util/AuditFileWriter.java index 9ebc35171..f08666ecb 100644 --- a/java/registry/src/main/java/dev/sunbirdrc/registry/util/AuditFileWriter.java +++ b/java/registry/src/main/java/dev/sunbirdrc/registry/util/AuditFileWriter.java @@ -1,5 +1,6 @@ package dev.sunbirdrc.registry.util; +import com.fasterxml.jackson.databind.JsonNode; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; @@ -19,7 +20,7 @@ public class AuditFileWriter { private static Logger logger = LoggerFactory.getLogger(AuditFileWriter.class); @Async("auditExecutor") - public void auditToFile(AuditRecord auditRecord) throws JsonProcessingException { + public void auditToFile(JsonNode auditRecord) throws JsonProcessingException { ObjectMapper objectMapper = new ObjectMapper(); String auditString = objectMapper.writeValueAsString(auditRecord); logger.info("{}", auditString); diff --git a/java/registry/src/main/resources/application.yml b/java/registry/src/main/resources/application.yml index c4972a3e2..f919b8887 100644 --- a/java/registry/src/main/resources/application.yml +++ b/java/registry/src/main/resources/application.yml @@ -233,6 +233,7 @@ certificate: # Note : Database Stores the created audit schema in audit_schema folder. audit: enabled: ${audit_enabled:true} + vc-enabled: ${audit_vc_enabled:false} frame: store: ${audit_frame_store:DATABASE} suffix: ${audit_suffix:Audit} @@ -473,6 +474,7 @@ signature: audit: enabled: ${audit_enabled:false} + vc-enabled: ${audit_vc_enabled:false} frame: store: ${audit_frame_store:DATABASE} suffix: ${audit_suffix:Audit}