diff --git a/CedarJava/src/main/java/com/cedarpolicy/model/slice/Policy.java b/CedarJava/src/main/java/com/cedarpolicy/model/slice/Policy.java index 7c9e21d2..985e758c 100644 --- a/CedarJava/src/main/java/com/cedarpolicy/model/slice/Policy.java +++ b/CedarJava/src/main/java/com/cedarpolicy/model/slice/Policy.java @@ -69,6 +69,10 @@ public String toString() { return "// Policy ID: " + policyID + "\n" + policySrc; } + public String toJson() throws InternalException, NullPointerException { + return toJsonJni(policySrc); + } + public static Policy parseStaticPolicy(String policyStr) throws InternalException, NullPointerException { var policyText = parsePolicyJni(policyStr); return new Policy(policyText, null); @@ -97,4 +101,6 @@ public static boolean validateTemplateLinkedPolicy(Policy p, EntityUID principal private static native String parsePolicyJni(String policyStr) throws InternalException, NullPointerException; private static native String parsePolicyTemplateJni(String policyTemplateStr) throws InternalException, NullPointerException; private static native boolean validateTemplateLinkedPolicyJni(String templateText, EntityUID principal, EntityUID resource) throws InternalException, NullPointerException; + + private native String toJsonJni(String policyStr) throws InternalException, NullPointerException; } diff --git a/CedarJava/src/test/java/com/cedarpolicy/PolicyTests.java b/CedarJava/src/test/java/com/cedarpolicy/PolicyTests.java index 4457eb39..4ab9f112 100644 --- a/CedarJava/src/test/java/com/cedarpolicy/PolicyTests.java +++ b/CedarJava/src/test/java/com/cedarpolicy/PolicyTests.java @@ -6,9 +6,11 @@ import org.junit.jupiter.api.Test; import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; -import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertNotEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.junit.jupiter.api.Assertions.fail; public class PolicyTests { @Test @@ -99,4 +101,34 @@ public void validateTemplateLinkedPolicyFailsWhenExpected() { Policy.validateTemplateLinkedPolicy(p3, principal, resource); }); } + + @Test + public void staticPolicyToJsonTests() throws InternalException { + assertThrows(NullPointerException.class, () -> { + Policy p = new Policy(null, null); + p.toJson(); + }); + assertThrows(InternalException.class, () -> { + Policy p = new Policy("permit();", null); + p.toJson(); + }); + + Policy p = Policy.parseStaticPolicy("permit(principal, action, resource);"); + String actualJson = p.toJson(); + String expectedJson = "{\"effect\":\"permit\",\"principal\":{\"op\":\"All\"},\"action\":{\"op\":\"All\"}," + + "\"resource\":{\"op\":\"All\"},\"conditions\":[]}"; + assertEquals(expectedJson, actualJson); + } + + @Test + public void policyTemplateToJsonFailureTests() throws InternalException { + try { + String tbody = "permit(principal == ?principal, action, resource in ?resource);"; + Policy template = Policy.parsePolicyTemplate(tbody); + template.toJson(); + fail("Expected InternalException"); + } catch (InternalException e) { + assertTrue(e.getMessage().contains("expected a static policy, got a template containing the slot ?resource")); + } + } } diff --git a/CedarJavaFFI/src/interface.rs b/CedarJavaFFI/src/interface.rs index fc2641c8..01b858bc 100644 --- a/CedarJavaFFI/src/interface.rs +++ b/CedarJavaFFI/src/interface.rs @@ -316,6 +316,26 @@ fn validate_template_linked_policy_internal<'a>( } } +#[jni_fn("com.cedarpolicy.model.slice.Policy")] +pub fn toJsonJni<'a>(mut env: JNIEnv<'a>, _: JClass, policy_jstr: JString<'a>) -> jvalue { + match to_json_internal(&mut env, policy_jstr) { + Err(e) => jni_failed(&mut env, e.as_ref()), + Ok(policy_json) => policy_json.as_jni(), + } +} + +fn to_json_internal<'a>(env: &mut JNIEnv<'a>, policy_jstr: JString<'a>) -> Result> { + if policy_jstr.is_null() { + raise_npe(env) + } else { + let policy_jstring = env.get_string(&policy_jstr)?; + let policy_string = String::from(policy_jstring); + let policy = Policy::from_str(&policy_string)?; + let policy_json = serde_json::to_string(&policy.to_json().unwrap())?; + Ok(JValueGen::Object(env.new_string(&policy_json)?.into())) + } +} + #[jni_fn("com.cedarpolicy.value.EntityIdentifier")] pub fn getEntityIdentifierRepr<'a>(mut env: JNIEnv<'a>, _: JClass, obj: JObject<'a>) -> jvalue { match get_entity_identifier_repr_internal(&mut env, obj) {