diff --git a/CedarJava/config/checkstyle/suppressions.xml b/CedarJava/config/checkstyle/suppressions.xml
index 90607ad..5d51c99 100644
--- a/CedarJava/config/checkstyle/suppressions.xml
+++ b/CedarJava/config/checkstyle/suppressions.xml
@@ -9,5 +9,5 @@
-
+
\ No newline at end of file
diff --git a/CedarJava/src/main/java/com/cedarpolicy/BasicAuthorizationEngine.java b/CedarJava/src/main/java/com/cedarpolicy/BasicAuthorizationEngine.java
index 2832899..2cdde63 100644
--- a/CedarJava/src/main/java/com/cedarpolicy/BasicAuthorizationEngine.java
+++ b/CedarJava/src/main/java/com/cedarpolicy/BasicAuthorizationEngine.java
@@ -169,13 +169,18 @@ private static class AuthorizationRequest extends com.cedarpolicy.model.Authoriz
}
@JsonInclude(JsonInclude.Include.NON_ABSENT)
- private static final class PartialAuthorizationRequest {
+ private static final class PartialAuthorizationRequest extends com.cedarpolicy.model.PartialAuthorizationRequest {
@JsonProperty private final PolicySet policies;
@JsonProperty private final Set entities;
- @JsonProperty public final com.cedarpolicy.model.PartialAuthorizationRequest request;
PartialAuthorizationRequest(com.cedarpolicy.model.PartialAuthorizationRequest request, PolicySet policySet, Set entities) {
- this.request = request;
+ super(
+ request.principal,
+ request.action,
+ request.resource,
+ request.context,
+ request.schema,
+ request.enableRequestValidation);
this.policies = policySet;
this.entities = entities;
}
diff --git a/CedarJava/src/main/java/com/cedarpolicy/model/PartialAuthorizationResponse.java b/CedarJava/src/main/java/com/cedarpolicy/model/PartialAuthorizationResponse.java
index aa3e70b..29e14a9 100644
--- a/CedarJava/src/main/java/com/cedarpolicy/model/PartialAuthorizationResponse.java
+++ b/CedarJava/src/main/java/com/cedarpolicy/model/PartialAuthorizationResponse.java
@@ -2,137 +2,71 @@
import com.cedarpolicy.Experimental;
import com.cedarpolicy.ExperimentalFeature;
-import com.cedarpolicy.model.AuthorizationSuccessResponse.Decision;
import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonProperty;
-import com.fasterxml.jackson.databind.JsonNode;
-import com.google.common.collect.ImmutableMap;
-import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.ImmutableList;
-import java.util.Map;
-import java.util.Set;
+import java.util.ArrayList;
+import java.util.Optional;
@Experimental(ExperimentalFeature.PARTIAL_EVALUATION)
public class PartialAuthorizationResponse {
- private final Decision decision;
- private final ImmutableSet satisfied;
- private final ImmutableSet errored;
- private final ImmutableSet mayBeDetermining;
- private final ImmutableSet mustBeDetermining;
- private final ImmutableMap residuals;
- private final ImmutableSet nontrivialResiduals;
- private final ImmutableSet warnings;
-
- public PartialAuthorizationResponse(Decision decision, Set satisfied, Set errored,
- Set mayBeDetermining, Set mustBeDetermining, Map residuals,
- Set nontrivialResiduals, Set warnings) {
- this.decision = decision;
- // note that ImmutableSet.copyOf() attempts to avoid a full copy when possible
- // see https://github.com/google/guava/wiki/ImmutableCollectionsExplained
- this.satisfied = ImmutableSet.copyOf(satisfied);
- this.errored = ImmutableSet.copyOf(errored);
- this.mayBeDetermining = ImmutableSet.copyOf(mayBeDetermining);
- this.mustBeDetermining = ImmutableSet.copyOf(mustBeDetermining);
- this.residuals = ImmutableMap.copyOf(residuals);
- this.nontrivialResiduals = ImmutableSet.copyOf(nontrivialResiduals);
- if (warnings == null) {
- this.warnings = ImmutableSet.of(); // empty
- } else {
- this.warnings = ImmutableSet.copyOf(warnings);
- }
- }
-
/**
- * The optional decision returned by partial authorization
- *
- * @return a nullable reference to the decision (null means that no conclusive decision can be made)
+ * Is this a success or a failure response
*/
- public Decision getDecision() {
- return this.decision;
- }
-
+ @JsonProperty("type")
+ public final SuccessOrFailure type;
/**
- * The map from policy ids to residuals
- *
- * @return map of residuals
+ * This will be present if and only if `type` is `Success`.
*/
- public Map getResiduals() {
- return this.residuals;
- }
-
+ @JsonProperty("response")
+ public final Optional success;
/**
- * Set of policies that are satisfied by the partial request
- *
- * @return set of policy ids
+ * This will be present if and only if `type` is `Failure`.
*/
- public Set getSatisfied() {
- return this.satisfied;
- }
-
+ @JsonProperty("errors")
+ public final Optional> errors;
/**
- * Set of policies that errored during the partial authorization
- *
- * @return set of policy ids
+ * Warnings can be produced regardless of whether we have a `Success` or `Failure`.
*/
- public Set getErrored() {
- return this.errored;
- }
+ @JsonProperty("warnings")
+ public final ImmutableList warnings;
/**
- * Over approximation of policies that determine the auth decision
- *
- * @return set of policy ids
+ * If `type` is `Success`, `success` should be present and `errors` empty.
+ * If `type` is `Failure`, `errors` should be present and `success` empty.
*/
- public Set getMayBeDetermining() {
- return this.mayBeDetermining;
- }
-
- /**
- * Under approximation of policies that determine the auth decision
- *
- * @return set of policy ids
- */
- public Set getMustBeDetermining() {
- return this.mustBeDetermining;
+ @JsonCreator
+ public PartialAuthorizationResponse(
+ @JsonProperty("type") SuccessOrFailure type,
+ @JsonProperty("response") Optional success,
+ @JsonProperty("errors") Optional> errors,
+ @JsonProperty("warnings") ArrayList warnings
+ ) {
+ this.type = type;
+ this.success = success;
+ this.errors = errors.map((list) -> ImmutableList.copyOf(list));
+ if (warnings == null) {
+ this.warnings = ImmutableList.of(); // empty
+ } else {
+ this.warnings = ImmutableList.copyOf(warnings);
+ }
}
- /**
- * Set of non-trivial residual policies
- *
- * @return set of policy ids
- */
- public Set getNontrivialResiduals() {
- return this.nontrivialResiduals;
+ @Override
+ public String toString() {
+ final String warningsString = warnings.isEmpty() ? "" : "\nwith warnings: " + warnings;
+ if (type == SuccessOrFailure.Success) {
+ return "SUCCESS: " + success.get() + warningsString;
+ } else {
+ return "FAILURE: " + errors.get() + warningsString;
+ }
}
- /**
- * Deserializer factory method for PartialAuthorizationResponse.
- * @param nested Deserialized object for nested JSON object.
- * @param decision Deserialized `decision` attribute of nested JSON object.
- * @param satisfied Deserialized `satisfied` attribute of nested JSON object.
- * @param errored Deserialized `errored` attribute of nested JSON object.
- * @param mayBeDetermining Deserialized `mayBeDetermining` attribute of nested JSON object.
- * @param mustBeDetermining Deserialized `mustBeDetermining` attribute of nested JSON object.
- * @param residuals Deserialized `residual` attribute of nested JSON object.
- * @param nontrivialResiduals Deserialized `nontrivialResiduals` attribute of nested JSON object.
- * @param warnings Deserialized `warnings` attribute of nested JSON object.
- * @return
- */
- @JsonCreator
- public static PartialAuthorizationResponse createPartialAuthorizationResponse(
- @JsonProperty("response") PartialAuthorizationResponse nested,
- @JsonProperty("decision") Decision decision,
- @JsonProperty("satisfied") Set satisfied,
- @JsonProperty("errored") Set errored,
- @JsonProperty("mayBeDetermining") Set mayBeDetermining,
- @JsonProperty("mustBeDetermining") Set mustBeDetermining,
- @JsonProperty("residuals") Map residuals,
- @JsonProperty("nontrivialResiduals") Set nontrivialResiduals,
- @JsonProperty("warnings") Set warnings) {
- if (nested != null) {
- return nested;
- }
- return new PartialAuthorizationResponse(decision, satisfied, errored, mayBeDetermining, mustBeDetermining,
- residuals, nontrivialResiduals, warnings);
+ public enum SuccessOrFailure {
+ @JsonProperty("residuals")
+ Success,
+ @JsonProperty("failure")
+ Failure,
}
}
diff --git a/CedarJava/src/main/java/com/cedarpolicy/model/PartialAuthorizationSuccessResponse.java b/CedarJava/src/main/java/com/cedarpolicy/model/PartialAuthorizationSuccessResponse.java
new file mode 100644
index 0000000..a6592a5
--- /dev/null
+++ b/CedarJava/src/main/java/com/cedarpolicy/model/PartialAuthorizationSuccessResponse.java
@@ -0,0 +1,159 @@
+/*
+ * Copyright Cedar Contributors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.cedarpolicy.model;
+
+import java.util.Map;
+import java.util.Set;
+
+import com.cedarpolicy.Experimental;
+import com.cedarpolicy.ExperimentalFeature;
+import com.fasterxml.jackson.annotation.JsonCreator;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import com.fasterxml.jackson.databind.JsonNode;
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.ImmutableSet;
+
+/**
+ * Successful partial authorization response
+ */
+@Experimental(ExperimentalFeature.PARTIAL_EVALUATION)
+public final class PartialAuthorizationSuccessResponse {
+ private final AuthorizationSuccessResponse.Decision decision;
+ private final ImmutableSet satisfied;
+ private final ImmutableSet errored;
+ private final ImmutableSet mayBeDetermining;
+ private final ImmutableSet mustBeDetermining;
+ private final ImmutableMap residuals;
+ private final ImmutableSet nontrivialResiduals;
+ private final ImmutableSet warnings;
+
+ public PartialAuthorizationSuccessResponse(
+ AuthorizationSuccessResponse.Decision decision, Set satisfied, Set errored,
+ Set mayBeDetermining, Set mustBeDetermining, Map residuals,
+ Set nontrivialResiduals, Set warnings) {
+ this.decision = decision;
+ // note that ImmutableSet.copyOf() attempts to avoid a full copy when possible
+ // see https://github.com/google/guava/wiki/ImmutableCollectionsExplained
+ this.satisfied = ImmutableSet.copyOf(satisfied);
+ this.errored = ImmutableSet.copyOf(errored);
+ this.mayBeDetermining = ImmutableSet.copyOf(mayBeDetermining);
+ this.mustBeDetermining = ImmutableSet.copyOf(mustBeDetermining);
+ this.residuals = ImmutableMap.copyOf(residuals);
+ this.nontrivialResiduals = ImmutableSet.copyOf(nontrivialResiduals);
+ if (warnings == null) {
+ this.warnings = ImmutableSet.of(); // empty
+ } else {
+ this.warnings = ImmutableSet.copyOf(warnings);
+ }
+ }
+
+ /**
+ * Deserializer factory method for PartialAuthorizationResponse.
+ *
+ * @param nested Deserialized object for nested JSON object.
+ * @param decision Deserialized `decision` attribute of nested JSON object.
+ * @param satisfied Deserialized `satisfied` attribute of nested JSON object.
+ * @param errored Deserialized `errored` attribute of nested JSON object.
+ * @param mayBeDetermining Deserialized `mayBeDetermining` attribute of nested JSON object.
+ * @param mustBeDetermining Deserialized `mustBeDetermining` attribute of nested JSON object.
+ * @param residuals Deserialized `residual` attribute of nested JSON object.
+ * @param nontrivialResiduals Deserialized `nontrivialResiduals` attribute of nested JSON object.
+ * @param warnings Deserialized `warnings` attribute of nested JSON object.
+ * @return
+ */
+ @JsonCreator
+ public static PartialAuthorizationSuccessResponse createPartialAuthorizationSuccessResponse(
+ @JsonProperty("response") PartialAuthorizationSuccessResponse nested,
+ @JsonProperty("decision") AuthorizationSuccessResponse.Decision decision,
+ @JsonProperty("satisfied") Set satisfied,
+ @JsonProperty("errored") Set errored,
+ @JsonProperty("mayBeDetermining") Set mayBeDetermining,
+ @JsonProperty("mustBeDetermining") Set mustBeDetermining,
+ @JsonProperty("residuals") Map residuals,
+ @JsonProperty("nontrivialResiduals") Set nontrivialResiduals,
+ @JsonProperty("warnings") Set warnings) {
+ if (nested != null) {
+ return nested;
+ }
+ return new PartialAuthorizationSuccessResponse(decision, satisfied, errored, mayBeDetermining,
+ mustBeDetermining,
+ residuals, nontrivialResiduals, warnings);
+ }
+
+ /**
+ * The optional decision returned by partial authorization
+ *
+ * @return a nullable reference to the decision (null means that no conclusive decision can be made)
+ */
+ public AuthorizationSuccessResponse.Decision getDecision() {
+ return this.decision;
+ }
+
+ /**
+ * The map from policy ids to residuals
+ *
+ * @return map of residuals
+ */
+ public Map getResiduals() {
+ return this.residuals;
+ }
+
+ /**
+ * Set of policies that are satisfied by the partial request
+ *
+ * @return set of policy ids
+ */
+ public Set getSatisfied() {
+ return this.satisfied;
+ }
+
+ /**
+ * Set of policies that errored during the partial authorization
+ *
+ * @return set of policy ids
+ */
+ public Set getErrored() {
+ return this.errored;
+ }
+
+ /**
+ * Over approximation of policies that determine the auth decision
+ *
+ * @return set of policy ids
+ */
+ public Set getMayBeDetermining() {
+ return this.mayBeDetermining;
+ }
+
+ /**
+ * Under approximation of policies that determine the auth decision
+ *
+ * @return set of policy ids
+ */
+ public Set getMustBeDetermining() {
+ return this.mustBeDetermining;
+ }
+
+ /**
+ * Set of non-trivial residual policies
+ *
+ * @return set of policy ids
+ */
+ public Set getNontrivialResiduals() {
+ return this.nontrivialResiduals;
+ }
+}
diff --git a/CedarJava/src/test/java/com/cedarpolicy/AuthTests.java b/CedarJava/src/test/java/com/cedarpolicy/AuthTests.java
index 1314aca..8b4aa7d 100644
--- a/CedarJava/src/test/java/com/cedarpolicy/AuthTests.java
+++ b/CedarJava/src/test/java/com/cedarpolicy/AuthTests.java
@@ -71,9 +71,9 @@ public void concrete() {
assumePartialEvaluation(() -> {
try {
final PartialAuthorizationResponse response = auth.isAuthorizedPartial(q, policySet, new HashSet<>());
- assertEquals(Decision.Allow, response.getDecision());
- assertEquals(response.getMustBeDetermining().iterator().next(), "p0");
- assertTrue(response.getNontrivialResiduals().isEmpty());
+ assertEquals(Decision.Allow, response.success.orElseThrow().getDecision());
+ assertEquals(response.success.orElseThrow().getMustBeDetermining().iterator().next(), "p0");
+ assertTrue(response.success.orElseThrow().getNontrivialResiduals().isEmpty());
} catch (Exception e) {
fail("error: " + e.toString());
}
@@ -92,21 +92,21 @@ public void residual() {
assumePartialEvaluation(() -> {
try {
final PartialAuthorizationResponse response = auth.isAuthorizedPartial(q, policySet, new HashSet<>());
- assertTrue(response.getDecision() == null);
- assertEquals("p0", response.getResiduals().entrySet().iterator().next().getKey());
+ assertTrue(response.success.orElseThrow().getDecision() == null);
+ assertEquals("p0", response.success.orElseThrow().getResiduals().entrySet().iterator().next().getKey());
} catch (Exception e) {
fail("error: " + e.toString());
}
});
}
- private Executable assumePartialEvaluation(Executable executable) {
- return () -> {
- try {
- executable.execute();
- } catch (MissingExperimentalFeatureException e) {
- System.err.println("Skipping assertions: " + e.getMessage());
- }
- };
+ private void assumePartialEvaluation(Executable executable) {
+ try {
+ executable.execute();
+ } catch (MissingExperimentalFeatureException e) {
+ System.err.println("Skipping assertions: " + e.getMessage());
+ } catch (Throwable e) {
+ throw new RuntimeException(e);
+ }
}
}
diff --git a/CedarJava/src/test/java/com/cedarpolicy/JSONTests.java b/CedarJava/src/test/java/com/cedarpolicy/JSONTests.java
index 0a5e1ff..b3824e4 100644
--- a/CedarJava/src/test/java/com/cedarpolicy/JSONTests.java
+++ b/CedarJava/src/test/java/com/cedarpolicy/JSONTests.java
@@ -73,7 +73,7 @@ public void testAuthConcretePartialResponse() {
"{ \"response\": { \"decision\":\"allow\", \"satisfied\": [], \"errored\": [\"p0\"], \"mayBeDetermining\": [], \"mustBeDetermining\": [\"p1\"], \"residuals\": {\"p2\": 3}, \"nontrivialResiduals\": [] } }";
try {
PartialAuthorizationResponse r = objectReader().forType(PartialAuthorizationResponse.class).readValue(src);
- assertTrue(r.getDecision() == Decision.Allow);
+ assertTrue(r.success.orElseThrow().getDecision() == Decision.Allow);
} catch (JsonProcessingException e) {
fail(e);
}
@@ -85,7 +85,7 @@ public void testAuthResidualPartialResponse() {
final String src = "{ \"response\": { \"decision\":\"allow\", \"satisfied\": [], \"errored\": [\"p0\"], \"mayBeDetermining\": [], \"mustBeDetermining\": [\"p1\"], \"residuals\": {\"p0\": " + policy + " }, \"nontrivialResiduals\": [] } }";
try {
PartialAuthorizationResponse r = objectReader().forType(PartialAuthorizationResponse.class).readValue(src);
- var residuals = r.getResiduals();
+ var residuals = r.success.orElseThrow().getResiduals();
assertEquals(1, residuals.size());
assertEquals("p0", residuals.entrySet().iterator().next().getKey());
assertJSONEqual(CedarJson.objectMapper().readTree(policy),