diff --git a/build.gradle b/build.gradle index 901ae55bf8..5bf557a9ca 100644 --- a/build.gradle +++ b/build.gradle @@ -509,10 +509,6 @@ dependencies { //Password generation implementation 'org.passay:passay:1.6.3' - //JSON path - implementation 'com.jayway.jsonpath:json-path:2.8.0' - implementation 'net.minidev:json-smart:2.5.0' - implementation "org.apache.kafka:kafka-clients:${kafka_version}" runtimeOnly 'net.minidev:accessors-smart:2.4.7' diff --git a/src/main/java/org/opensearch/security/dlic/rest/api/AuditApiAction.java b/src/main/java/org/opensearch/security/dlic/rest/api/AuditApiAction.java index 00808675ac..488a72c958 100644 --- a/src/main/java/org/opensearch/security/dlic/rest/api/AuditApiAction.java +++ b/src/main/java/org/opensearch/security/dlic/rest/api/AuditApiAction.java @@ -16,7 +16,6 @@ import com.google.common.annotations.VisibleForTesting; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; -import com.google.common.collect.ImmutableSet; import org.opensearch.cluster.service.ClusterService; import org.opensearch.common.settings.Settings; import org.opensearch.core.rest.RestStatus; @@ -137,7 +136,7 @@ public class AuditApiAction extends AbstractApiAction { private final List readonlyFields; public static class AuditRequestContentValidator extends RequestContentValidator { - private static final Set DISABLED_REST_CATEGORIES = ImmutableSet.of( + public static final Set DISABLED_REST_CATEGORIES = Set.of( AuditCategory.BAD_HEADERS, AuditCategory.SSL_EXCEPTION, AuditCategory.AUTHENTICATED, @@ -146,7 +145,7 @@ public static class AuditRequestContentValidator extends RequestContentValidator AuditCategory.MISSING_PRIVILEGES ); - private static final Set DISABLED_TRANSPORT_CATEGORIES = ImmutableSet.of( + public static final Set DISABLED_TRANSPORT_CATEGORIES = Set.of( AuditCategory.BAD_HEADERS, AuditCategory.SSL_EXCEPTION, AuditCategory.AUTHENTICATED, diff --git a/src/main/java/org/opensearch/security/dlic/rest/api/RolesApiAction.java b/src/main/java/org/opensearch/security/dlic/rest/api/RolesApiAction.java index a7f9708e6e..76ff702455 100644 --- a/src/main/java/org/opensearch/security/dlic/rest/api/RolesApiAction.java +++ b/src/main/java/org/opensearch/security/dlic/rest/api/RolesApiAction.java @@ -11,11 +11,11 @@ package org.opensearch.security.dlic.rest.api; +import com.fasterxml.jackson.core.JsonPointer; import com.fasterxml.jackson.databind.JsonNode; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; -import com.jayway.jsonpath.JsonPath; -import com.jayway.jsonpath.ReadContext; +import org.apache.commons.lang3.tuple.Pair; import org.opensearch.cluster.service.ClusterService; import org.opensearch.common.inject.Inject; import org.opensearch.common.settings.Settings; @@ -34,6 +34,8 @@ import java.io.IOException; import java.util.List; import java.util.Map; +import java.util.Objects; +import java.util.stream.StreamSupport; import static org.opensearch.security.dlic.rest.api.RequestHandler.methodNotImplementedHandler; import static org.opensearch.security.dlic.rest.support.Utils.addRoutesPrefix; @@ -51,11 +53,11 @@ public class RolesApiAction extends AbstractApiAction { ) ); - public static class RoleValidator extends RequestContentValidator { + public static class RoleRequestContentValidator extends RequestContentValidator { private static final Salt SALT = new Salt(new byte[] { 1, 2, 3, 4, 5, 1, 2, 3, 4, 5, 1, 2, 3, 4, 5, 6 }); - protected RoleValidator(ValidationContext validationContext) { + protected RoleRequestContentValidator(ValidationContext validationContext) { super(validationContext); } @@ -70,27 +72,29 @@ public ValidationResult validate(RestRequest request, JsonNode jsonCon } private ValidationResult validateMaskedFields(final JsonNode content) { - final ReadContext ctx = JsonPath.parse(content.toString()); - final List maskedFields = ctx.read("$..masked_fields[*]"); - if (maskedFields != null) { - for (String mf : maskedFields) { - if (!validateMaskedFieldSyntax(mf)) { - this.validationError = ValidationError.WRONG_DATATYPE; - return ValidationResult.error(RestStatus.BAD_REQUEST, this); - } - } + StreamSupport.stream(content.withArray(JsonPointer.compile("/index_permissions")).spliterator(), false) + .flatMap( + indexPermissionsNode -> StreamSupport.stream(indexPermissionsNode.withArray("/masked_fields").spliterator(), false) + ) + .map(this::validateMaskedFieldSyntax) + .filter(Objects::nonNull) + .forEach(wrongMaskedField -> { + this.validationError = ValidationError.WRONG_DATATYPE; + wrongDataTypes.put("Masked field not valid: " + wrongMaskedField.getLeft(), wrongMaskedField.getRight()); + }); + if (validationError != ValidationError.NONE) { + return ValidationResult.error(RestStatus.BAD_REQUEST, this); } return ValidationResult.success(content); } - private boolean validateMaskedFieldSyntax(String mf) { + private Pair validateMaskedFieldSyntax(final JsonNode maskedFieldNode) { try { - new MaskedField(mf, SALT).isValid(); + new MaskedField(maskedFieldNode.asText(), SALT).isValid(); } catch (Exception e) { - wrongDataTypes.put("Masked field not valid: " + mf, e.getMessage()); - return false; + return Pair.of(maskedFieldNode.asText(), e.getMessage()); } - return true; + return null; } } @@ -146,7 +150,7 @@ public ValidationResult isAllowedToChangeImmutableEntity( @Override public RequestContentValidator createRequestContentValidator(Object... params) { - return new RoleValidator(new RequestContentValidator.ValidationContext() { + return new RoleRequestContentValidator(new RequestContentValidator.ValidationContext() { @Override public Object[] params() { return params; diff --git a/src/test/java/org/opensearch/security/dlic/rest/api/AuditApiActionRequestContentValidatorTest.java b/src/test/java/org/opensearch/security/dlic/rest/api/AuditApiActionRequestContentValidatorTest.java new file mode 100644 index 0000000000..2629e41a8a --- /dev/null +++ b/src/test/java/org/opensearch/security/dlic/rest/api/AuditApiActionRequestContentValidatorTest.java @@ -0,0 +1,80 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * The OpenSearch Contributors require contributions made to + * this file be licensed under the Apache-2.0 license or a + * compatible open source license. + * + * Modifications Copyright OpenSearch Contributors. See + * GitHub history for details. + */ + +package org.opensearch.security.dlic.rest.api; + +import com.fasterxml.jackson.databind.InjectableValues; +import org.junit.Test; +import org.opensearch.common.settings.Settings; +import org.opensearch.core.common.bytes.BytesArray; +import org.opensearch.core.rest.RestStatus; +import org.opensearch.security.DefaultObjectMapper; +import org.opensearch.security.auditlog.config.AuditConfig; +import org.opensearch.security.auditlog.impl.AuditCategory; +import org.opensearch.security.compliance.ComplianceConfig; +import org.opensearch.security.util.FakeRestRequest; + +import java.io.IOException; +import java.util.Map; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; + +public class AuditApiActionRequestContentValidatorTest extends AbstractApiActionValidationTest { + + @Test + public void validateAuditDisabledRestCategories() throws IOException { + InjectableValues.Std injectableValues = new InjectableValues.Std(); + injectableValues.addValue(Settings.class, Settings.EMPTY); + DefaultObjectMapper.inject(injectableValues); + final var auditApiActionRequestContentValidator = new AuditApiAction(clusterService, threadPool, securityApiDependencies) + .createEndpointValidator() + .createRequestContentValidator(); + + final var disabledTransportCategories = AuditApiAction.AuditRequestContentValidator.DISABLED_TRANSPORT_CATEGORIES.stream() + .map(Enum::name) + .collect(Collectors.toList()); + final var auditConfig = new AuditConfig( + true, + AuditConfig.Filter.from(Map.of("disabled_rest_categories", disabledTransportCategories)), + ComplianceConfig.DEFAULT + ); + final var content = DefaultObjectMapper.writeValueAsString(objectMapper.valueToTree(auditConfig), false); + var result = auditApiActionRequestContentValidator.validate(FakeRestRequest.builder().withContent(new BytesArray(content)).build()); + assertFalse(result.isValid()); + assertEquals(RestStatus.BAD_REQUEST, result.status()); + } + + @Test + public void validateAuditDisabledTransportCategories() throws IOException { + InjectableValues.Std injectableValues = new InjectableValues.Std(); + injectableValues.addValue(Settings.class, Settings.EMPTY); + DefaultObjectMapper.inject(injectableValues); + final var auditApiActionRequestContentValidator = new AuditApiAction(clusterService, threadPool, securityApiDependencies) + .createEndpointValidator() + .createRequestContentValidator(); + + final var disabledRestCategories = Stream.of(AuditCategory.COMPLIANCE_DOC_WRITE, AuditCategory.COMPLIANCE_DOC_READ) + .map(Enum::name) + .collect(Collectors.toList()); + final var auditConfig = new AuditConfig( + true, + AuditConfig.Filter.from(Map.of("disabled_transport_categories", disabledRestCategories)), + ComplianceConfig.DEFAULT + ); + final var content = DefaultObjectMapper.writeValueAsString(objectMapper.valueToTree(auditConfig), false); + var result = auditApiActionRequestContentValidator.validate(FakeRestRequest.builder().withContent(new BytesArray(content)).build()); + assertFalse(result.isValid()); + assertEquals(RestStatus.BAD_REQUEST, result.status()); + } +} diff --git a/src/test/java/org/opensearch/security/dlic/rest/api/RolesApiActionRequestContentValidatorTest.java b/src/test/java/org/opensearch/security/dlic/rest/api/RolesApiActionRequestContentValidatorTest.java new file mode 100644 index 0000000000..cab192093c --- /dev/null +++ b/src/test/java/org/opensearch/security/dlic/rest/api/RolesApiActionRequestContentValidatorTest.java @@ -0,0 +1,179 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * The OpenSearch Contributors require contributions made to + * this file be licensed under the Apache-2.0 license or a + * compatible open source license. + * + * Modifications Copyright OpenSearch Contributors. See + * GitHub history for details. + */ + +package org.opensearch.security.dlic.rest.api; + +import com.fasterxml.jackson.databind.node.ObjectNode; +import org.junit.Test; +import org.opensearch.core.common.bytes.BytesArray; +import org.opensearch.security.util.FakeRestRequest; + +import java.io.IOException; + +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +public class RolesApiActionRequestContentValidatorTest extends AbstractApiActionValidationTest { + + @Test + public void doesNotValidateMaskedFields() throws IOException { + + final var requestContentValidator = new RolesApiAction(clusterService, threadPool, securityApiDependencies) + .createEndpointValidator() + .createRequestContentValidator(); + + // no masked fields + final var noMaskedFields = objectMapper.createObjectNode() + .set( + "index_permissions", + objectMapper.createArrayNode() + .add( + objectMapper.createObjectNode() + .set("index_patterns", objectMapper.createArrayNode().add("a*")) + .put("dls", "") + .set("fls", objectMapper.createArrayNode()) + .set("allowed_actions", objectMapper.createArrayNode().add("read")) + ) + .add( + objectMapper.createObjectNode() + .set("index_patterns", objectMapper.createArrayNode().add("b*")) + .put("dls", "") + .set("fls", objectMapper.createArrayNode()) + .set("allowed_actions", objectMapper.createArrayNode().add("write")) + ) + .add( + objectMapper.createObjectNode() + .set("index_patterns", objectMapper.createArrayNode().add("c*")) + .put("dls", "") + .set("fls", objectMapper.createArrayNode()) + .set("allowed_actions", objectMapper.createArrayNode().add("read").add("write")) + + ) + ); + + var result = requestContentValidator.validate( + FakeRestRequest.builder().withContent(new BytesArray(noMaskedFields.toString())).build() + ); + assertTrue(result.isValid()); + result = requestContentValidator.validate( + FakeRestRequest.builder().withContent(new BytesArray(noMaskedFields.toString())).build(), + noMaskedFields + ); + assertTrue(result.isValid()); + } + + @Test + public void validateOnlySpecifiedMaskedFields() throws IOException { + final var requestContentValidator = new RolesApiAction(clusterService, threadPool, securityApiDependencies) + .createEndpointValidator() + .createRequestContentValidator(); + final var specifiedMaskedFields = objectMapper.createObjectNode() + .set( + "index_permissions", + objectMapper.createArrayNode() + .add( + objectMapper.createObjectNode() + .set("index_patterns", objectMapper.createArrayNode().add("a*")) + .put("dls", "") + .set("fls", objectMapper.createArrayNode()) + .set("masked_fields", objectMapper.nullNode()) + .set("allowed_actions", objectMapper.createArrayNode().add("read")) + ) + .add( + objectMapper.createObjectNode() + .set("index_patterns", objectMapper.createArrayNode().add("b*")) + .put("dls", "") + .set("fls", objectMapper.createArrayNode()) + .set("allowed_actions", objectMapper.createArrayNode().add("write")) + ) + .add( + objectMapper.createObjectNode() + .set("index_patterns", objectMapper.createArrayNode().add("c*")) + .put("dls", "") + .set("fls", objectMapper.createArrayNode()) + .set("masked_fields", objectMapper.createArrayNode().add("aaa::").add("bbb")) + .set("allowed_actions", objectMapper.createArrayNode().add("read").add("write")) + + ) + ); + var result = requestContentValidator.validate( + FakeRestRequest.builder().withContent(new BytesArray(specifiedMaskedFields.toString())).build() + ); + assertFalse(result.isValid()); + var errorMessage = xContentToJsonNode(result.errorMessage()); + assertTrue(errorMessage.toString(), errorMessage.toString().contains("aaa::")); + + result = requestContentValidator.validate( + FakeRestRequest.builder().withContent(new BytesArray(specifiedMaskedFields.toString())).build(), + specifiedMaskedFields + ); + assertFalse(result.isValid()); + errorMessage = xContentToJsonNode(result.errorMessage()); + assertTrue(errorMessage.toString(), errorMessage.toString().contains("aaa::")); + } + + @Test + public void validateAllMaskedFields() throws IOException { + final var requestContentValidator = new RolesApiAction(clusterService, threadPool, securityApiDependencies) + .createEndpointValidator() + .createRequestContentValidator(); + final var invalidMaskedFields = objectMapper.createObjectNode() + .set( + "index_permissions", + objectMapper.createArrayNode() + .add( + objectMapper.createObjectNode() + .set("index_patterns", objectMapper.createArrayNode().add("a*")) + .put("dls", "") + .set("fls", objectMapper.createArrayNode()) + .set("masked_fields", objectMapper.createArrayNode().add("aaa").add("bbb")) + .set("allowed_actions", objectMapper.createArrayNode().add("read")) + ) + .add( + objectMapper.createObjectNode() + .set("index_patterns", objectMapper.createArrayNode().add("b*")) + .put("dls", "") + .set("fls", objectMapper.createArrayNode()) + .set("masked_fields", objectMapper.createArrayNode().add("aaa::").add("bbb::").add("ccc:::")) + .set("allowed_actions", objectMapper.createArrayNode().add("write")) + ) + .add( + objectMapper.createObjectNode() + .set("index_patterns", objectMapper.createArrayNode().add("c*")) + .put("dls", "") + .set("fls", objectMapper.createArrayNode()) + .set("masked_fields", objectMapper.createArrayNode().add("ddd::").add("eee")) + .set("allowed_actions", objectMapper.createArrayNode().add("read").add("write")) + + ) + ); + var result = requestContentValidator.validate( + FakeRestRequest.builder().withContent(new BytesArray(invalidMaskedFields.toString())).build() + ); + assertFalse(result.isValid()); + var errorMessage = xContentToJsonNode(result.errorMessage()).toString(); + assertTrue(errorMessage, errorMessage.contains("aaa::")); + assertTrue(errorMessage, errorMessage.contains("bbb::")); + assertTrue(errorMessage, errorMessage.contains("ccc:::")); + assertTrue(errorMessage, errorMessage.contains("ddd::")); + + result = requestContentValidator.validate( + FakeRestRequest.builder().withContent(new BytesArray(invalidMaskedFields.toString())).build(), + invalidMaskedFields + ); + assertFalse(result.isValid()); + errorMessage = xContentToJsonNode(result.errorMessage()).toString(); + assertTrue(errorMessage, errorMessage.contains("aaa::")); + assertTrue(errorMessage, errorMessage.contains("bbb::")); + assertTrue(errorMessage, errorMessage.contains("ccc:::")); + assertTrue(errorMessage, errorMessage.contains("ddd::")); + } +} diff --git a/src/test/java/org/opensearch/security/ssl/SecuritySSLReloadCertsActionTests.java b/src/test/java/org/opensearch/security/ssl/SecuritySSLReloadCertsActionTests.java index ea22981251..0376253b06 100644 --- a/src/test/java/org/opensearch/security/ssl/SecuritySSLReloadCertsActionTests.java +++ b/src/test/java/org/opensearch/security/ssl/SecuritySSLReloadCertsActionTests.java @@ -11,11 +11,7 @@ package org.opensearch.security.ssl; -import com.google.common.collect.ImmutableList; -import com.google.common.collect.ImmutableMap; -import net.minidev.json.JSONArray; -import net.minidev.json.JSONObject; -import net.minidev.json.parser.JSONParser; +import com.fasterxml.jackson.databind.JsonNode; import org.junit.After; import org.junit.Assert; import org.junit.Before; @@ -48,8 +44,8 @@ public class SecuritySSLReloadCertsActionTests extends SingleClusterTest { private final String HTTP_CERTIFICATES_LIST_KEY = "http_certificates_list"; private final String TRANSPORT_CERTIFICATES_LIST_KEY = "transport_certificates_list"; - private final List> NODE_CERT_DETAILS = ImmutableList.of( - ImmutableMap.of( + private final List> NODE_CERT_DETAILS = List.of( + Map.of( "issuer_dn", "CN=Example Com Inc. Signing CA,OU=Example Com Inc. Signing CA,O=Example Com Inc.,DC=example,DC=com", "subject_dn", @@ -63,8 +59,8 @@ public class SecuritySSLReloadCertsActionTests extends SingleClusterTest { ) ); - private final List> NEW_NODE_CERT_DETAILS = ImmutableList.of( - ImmutableMap.of( + private final List> NEW_NODE_CERT_DETAILS = List.of( + Map.of( "issuer_dn", "CN=Example Com Inc. Signing CA,OU=Example Com Inc. Signing CA,O=Example Com Inc.,DC=example,DC=com", "subject_dn", @@ -96,12 +92,11 @@ public void checkClusterHealth() throws Exception { RestHelper rh = getRestHelperAdminUser(); String clusterHealthResponse = rh.executeSimpleRequest("_cluster/health"); - JSONParser parser = new JSONParser(); - JSONObject clusterHealthResponseJson = (JSONObject) parser.parse(clusterHealthResponse); - Assert.assertEquals("green", clusterHealthResponseJson.get("status")); + final var clusterHealthResponseJson = DefaultObjectMapper.readTree(clusterHealthResponse); + Assert.assertEquals("green", clusterHealthResponseJson.get("status").asText()); String catNodesResponse = rh.executeSimpleRequest("_cat/nodes?format=json"); - JSONArray catNodesResponseJson = (JSONArray) parser.parse(catNodesResponse); + final var catNodesResponseJson = DefaultObjectMapper.readTree(catNodesResponse);// (JSONArray) parser.parse(catNodesResponse); Assert.assertEquals(clusterConfiguration.getNodes(), catNodesResponseJson.size()); } @@ -111,8 +106,8 @@ public void testReloadTransportSSLCertsPass() throws Exception { RestHelper rh = getRestHelperAdminUser(); String certDetailsResponse = rh.executeSimpleRequest(GET_CERT_DETAILS_ENDPOINT); - JSONObject expectedJsonResponse = getInitCertDetailsExpectedResponse(); - Assert.assertEquals(expectedJsonResponse.toString(), certDetailsResponse); + final var expectedJsonResponse = getInitCertDetailsExpectedResponse(); + Assert.assertEquals(expectedJsonResponse, DefaultObjectMapper.readTree(certDetailsResponse)); // Test Valid Case: Change transport file details to "ssl/pem/node-new.crt.pem" and "ssl/pem/node-new.key.pem" updateFiles(newCertFilePath, pemCertFilePath); @@ -128,8 +123,8 @@ public void testReloadHttpSSLCertsPass() throws Exception { RestHelper rh = getRestHelperAdminUser(); String certDetailsResponse = rh.executeSimpleRequest(GET_CERT_DETAILS_ENDPOINT); - JSONObject expectedJsonResponse = getInitCertDetailsExpectedResponse(); - Assert.assertEquals(expectedJsonResponse.toString(), certDetailsResponse); + final var expectedJsonResponse = getInitCertDetailsExpectedResponse(); + Assert.assertEquals(expectedJsonResponse, DefaultObjectMapper.readTree(certDetailsResponse)); // Test Valid Case: Change rest file details to "ssl/pem/node-new.crt.pem" and "ssl/pem/node-new.key.pem" updateFiles(newCertFilePath, pemCertFilePath); @@ -162,8 +157,8 @@ public void testReloadTransportSSLSameCertsPass() throws Exception { String certDetailsResponse = rh.executeSimpleRequest(GET_CERT_DETAILS_ENDPOINT); - JSONObject expectedJsonResponse = getInitCertDetailsExpectedResponse(); - Assert.assertEquals(expectedJsonResponse.toString(), certDetailsResponse); + final var expectedJsonResponse = getInitCertDetailsExpectedResponse(); + Assert.assertEquals(expectedJsonResponse, DefaultObjectMapper.readTree(certDetailsResponse)); // Test Valid Case: Reload same certificate updateFiles(defaultCertFilePath, pemCertFilePath); @@ -178,8 +173,8 @@ public void testReloadHttpSSLSameCertsPass() throws Exception { RestHelper rh = getRestHelperAdminUser(); String certDetailsResponse = rh.executeSimpleRequest(GET_CERT_DETAILS_ENDPOINT); - JSONObject expectedJsonResponse = getInitCertDetailsExpectedResponse(); - Assert.assertEquals(expectedJsonResponse.toString(), certDetailsResponse); + final var expectedJsonResponse = getInitCertDetailsExpectedResponse(); + Assert.assertEquals(expectedJsonResponse, DefaultObjectMapper.readTree(certDetailsResponse)); // Test Valid Case: Reload same certificate updateFiles(defaultCertFilePath, pemCertFilePath); @@ -196,39 +191,49 @@ public void testReloadHttpSSLSameCertsPass() throws Exception { * @return True if all assertions pass * @throws Exception if rest api failed */ - private void assertReloadCertificateSuccess(RestHelper rh, String updateChannel, JSONObject expectedCertResponse) throws Exception { + private void assertReloadCertificateSuccess(RestHelper rh, String updateChannel, JsonNode expectedCertResponse) throws Exception { String reloadEndpoint = updateChannel.equals("http") ? RELOAD_HTTP_CERTS_ENDPOINT : RELOAD_TRANSPORT_CERTS_ENDPOINT; RestHelper.HttpResponse reloadCertsResponse = rh.executePutRequest(reloadEndpoint, null); Assert.assertEquals(200, reloadCertsResponse.getStatusCode()); - JSONObject expectedJsonResponse = new JSONObject(); - expectedJsonResponse.appendField("message", String.format("updated %s certs", updateChannel)); + final var expectedJsonResponse = DefaultObjectMapper.objectMapper.createObjectNode(); + expectedJsonResponse.put("message", String.format("updated %s certs", updateChannel)); Assert.assertEquals(expectedJsonResponse.toString(), reloadCertsResponse.getBody()); String certDetailsResponse = rh.executeSimpleRequest(GET_CERT_DETAILS_ENDPOINT); - Assert.assertEquals(expectedCertResponse.toString(), certDetailsResponse); + Assert.assertEquals(expectedCertResponse, DefaultObjectMapper.readTree(certDetailsResponse)); } private void updateFiles(String srcFile, String dstFile) { FileHelper.copyFileContents(FileHelper.getAbsoluteFilePathFromClassPath(srcFile).toString(), dstFile); } - private JSONObject getUpdatedCertDetailsExpectedResponse(String updateChannel) { + private JsonNode getUpdatedCertDetailsExpectedResponse(String updateChannel) { String updateKey = (Objects.equals(updateChannel, "http")) ? HTTP_CERTIFICATES_LIST_KEY : TRANSPORT_CERTIFICATES_LIST_KEY; String oldKey = (Objects.equals(updateChannel, "http")) ? TRANSPORT_CERTIFICATES_LIST_KEY : HTTP_CERTIFICATES_LIST_KEY; - JSONObject updatedCertDetailsResponse = new JSONObject(); - updatedCertDetailsResponse.appendField(updateKey, NEW_NODE_CERT_DETAILS); - updatedCertDetailsResponse.appendField(oldKey, NODE_CERT_DETAILS); + final var updatedCertDetailsResponse = DefaultObjectMapper.objectMapper.createObjectNode(); + updatedCertDetailsResponse.set(updateKey, buildCertsInfoNode(NEW_NODE_CERT_DETAILS)); + updatedCertDetailsResponse.set(oldKey, buildCertsInfoNode(NODE_CERT_DETAILS)); return updatedCertDetailsResponse; } - private JSONObject getInitCertDetailsExpectedResponse() { - JSONObject initCertDetailsResponse = new JSONObject(); - initCertDetailsResponse.appendField(HTTP_CERTIFICATES_LIST_KEY, NODE_CERT_DETAILS); - initCertDetailsResponse.appendField(TRANSPORT_CERTIFICATES_LIST_KEY, NODE_CERT_DETAILS); + private JsonNode getInitCertDetailsExpectedResponse() { + final var initCertDetailsResponse = DefaultObjectMapper.objectMapper.createObjectNode(); + initCertDetailsResponse.set(HTTP_CERTIFICATES_LIST_KEY, buildCertsInfoNode(NODE_CERT_DETAILS)); + initCertDetailsResponse.set(TRANSPORT_CERTIFICATES_LIST_KEY, buildCertsInfoNode(NODE_CERT_DETAILS)); return initCertDetailsResponse; } + private JsonNode buildCertsInfoNode(final List> certsInfo) { + final var nodeCertDetailsArray = DefaultObjectMapper.objectMapper.createArrayNode(); + certsInfo.forEach(m -> { + final var o = DefaultObjectMapper.objectMapper.createObjectNode(); + m.forEach(o::put); + nodeCertDetailsArray.add(o); + }); + return nodeCertDetailsArray; + } + /** * kirk is configured as admin user in initTestCluster * @return RestHelper to execute rest actions against the cluster