Skip to content

Commit

Permalink
Test entity manifests (#475)
Browse files Browse the repository at this point in the history
Signed-off-by: oflatt <[email protected]>
Signed-off-by: Shaobo He <[email protected]>
Co-authored-by: oflatt <[email protected]>
  • Loading branch information
shaobo-he-aws and oflatt authored Nov 15, 2024
1 parent d0d8a21 commit 4786741
Show file tree
Hide file tree
Showing 3 changed files with 163 additions and 1 deletion.
1 change: 1 addition & 0 deletions cedar-drt/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ The table below lists all available fuzz targets, including which component of t
| [`simple-parser`](fuzz/fuzz_targets/simple-parser.rs) | Parser | PBT | Test that parsing doesn't crash with random input strings |
| [`validation-pbt`](fuzz/fuzz_targets/validation-pbt.rs) | Validator | PBT | Test that validated policies do not result in type errors |
| [`validation-pbt-type-directed`](fuzz/fuzz_targets/validation-pbt-type-directed.rs) | Validator | PBT | Test that validated policies do not result in type errors using (mostly) well-typed inputs |
| [`entity-manifest-drt-type-directed`](fuzz/fuzz_targets/entity-slicing-pbt-type-directed.rs) | Entity Slicing | DRT | Test that entity slicing produces the same authorization response as without it. |
| [`wildcard-matching`](fuzz/fuzz_targets/wildcard-matching.rs) | String matching algorithm used for the `like` operator | PBT | Test algorithm against a regex-based implementation |
## Logging

Expand Down
9 changes: 8 additions & 1 deletion cedar-drt/fuzz/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ serde_json = "1.0"
cedar-drt = { version = "4.0.0", path = ".." }
cedar-policy = { path = "../../cedar/cedar-policy", version = "4.*" }
cedar-policy-core = { path = "../../cedar/cedar-policy-core", version = "4.*", features = ["arbitrary"] }
cedar-policy-validator = { path = "../../cedar/cedar-policy-validator", version = "4.*", features = ["arbitrary"] }
cedar-policy-validator = { path = "../../cedar/cedar-policy-validator", version = "4.*", features = ["arbitrary", "entity-manifest"] }
cedar-policy-formatter = { path = "../../cedar/cedar-policy-formatter", version = "4.*" }
cedar-testing = { path = "../../cedar/cedar-testing", version = "4.*" }
cedar-policy-generators = { path = "../../cedar-policy-generators", version = "4.*" }
Expand Down Expand Up @@ -109,6 +109,13 @@ path = "fuzz_targets/validation-pbt-type-directed.rs"
test = false
doc = false

[[bin]]
name = "entity-slicing-drt-type-directed"
path = "fuzz_targets/entity-slicing-drt-type-directed.rs"
test = false
doc = false


[[bin]]
name = "validation-drt"
path = "fuzz_targets/validation-drt.rs"
Expand Down
154 changes: 154 additions & 0 deletions cedar-drt/fuzz/fuzz_targets/entity-slicing-drt-type-directed.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,154 @@
/*
* 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.
*/

#![no_main]
use cedar_drt::initialize_log;
use cedar_drt_inner::*;
use cedar_policy_core::ast;
use cedar_policy_core::authorizer::Authorizer;
use cedar_policy_core::entities::Entities;
use cedar_policy_generators::{
abac::{ABACPolicy, ABACRequest},
hierarchy::{Hierarchy, HierarchyGenerator},
schema::Schema,
settings::ABACSettings,
};
use cedar_policy_validator::entity_manifest::compute_entity_manifest;
use cedar_policy_validator::{ValidationMode, Validator, ValidatorSchema};
use libfuzzer_sys::arbitrary::{self, Arbitrary, Unstructured};
use log::debug;
use serde::Serialize;
use std::convert::TryFrom;

/// Input expected by this fuzz target:
/// An ABAC hierarchy, schema, and 8 associated policies
#[derive(Debug, Clone, Serialize)]
struct FuzzTargetInput {
/// generated schema
#[serde(skip)]
pub schema: Schema,
/// generated hierarchy
#[serde(skip)]
pub hierarchy: Hierarchy,
/// the policy which we will see if it validates
pub policy: ABACPolicy,
/// the requests to try, if the policy validates.
/// We try 8 requests per validated policy.
#[serde(skip)]
pub requests: [ABACRequest; 8],
}

/// settings for this fuzz target
const SETTINGS: ABACSettings = ABACSettings {
match_types: true,
enable_extensions: true,
max_depth: 7,
max_width: 7,
enable_additional_attributes: true,
enable_like: true,
enable_action_groups_and_attrs: true,
enable_arbitrary_func_call: true,
enable_unknowns: false,
enable_action_in_constraints: true,
enable_unspecified_apply_spec: true,
};

impl<'a> Arbitrary<'a> for FuzzTargetInput {
fn arbitrary(u: &mut Unstructured<'a>) -> arbitrary::Result<Self> {
let schema: Schema = Schema::arbitrary(SETTINGS.clone(), u)?;
let hierarchy = schema.arbitrary_hierarchy(u)?;
let policy = schema.arbitrary_policy(&hierarchy, u)?;
let requests = [
schema.arbitrary_request(&hierarchy, u)?,
schema.arbitrary_request(&hierarchy, u)?,
schema.arbitrary_request(&hierarchy, u)?,
schema.arbitrary_request(&hierarchy, u)?,
schema.arbitrary_request(&hierarchy, u)?,
schema.arbitrary_request(&hierarchy, u)?,
schema.arbitrary_request(&hierarchy, u)?,
schema.arbitrary_request(&hierarchy, u)?,
];
Ok(Self {
schema,
hierarchy,
policy,
requests,
})
}

fn try_size_hint(
depth: usize,
) -> arbitrary::Result<(usize, Option<usize>), arbitrary::MaxRecursionReached> {
Ok(arbitrary::size_hint::and_all(&[
Schema::arbitrary_size_hint(depth)?,
HierarchyGenerator::size_hint(depth),
Schema::arbitrary_policy_size_hint(&SETTINGS, depth),
Schema::arbitrary_request_size_hint(depth),
Schema::arbitrary_request_size_hint(depth),
Schema::arbitrary_request_size_hint(depth),
Schema::arbitrary_request_size_hint(depth),
Schema::arbitrary_request_size_hint(depth),
Schema::arbitrary_request_size_hint(depth),
Schema::arbitrary_request_size_hint(depth),
Schema::arbitrary_request_size_hint(depth),
]))
}
}

/// helper function that just tells us whether a policyset passes validation
fn passes_validation(validator: &Validator, policyset: &ast::PolicySet) -> bool {
validator
.validate(policyset, ValidationMode::default())
.validation_passed()
}

// The main fuzz target. This is for PBT on the validator
fuzz_target!(|input: FuzzTargetInput| {
initialize_log();
if let Ok(schema) = ValidatorSchema::try_from(input.schema) {
debug!("Schema: {:?}", schema);
if let Ok(entities) = Entities::try_from(input.hierarchy.clone()) {
let validator = Validator::new(schema.clone());
let mut policyset = ast::PolicySet::new();
let policy: ast::StaticPolicy = input.policy.into();
policyset.add_static(policy.clone()).unwrap();
if passes_validation(&validator, &policyset) {
// policy successfully validated, do entity slicing
let manifest = compute_entity_manifest(&schema, &policyset)
.expect("failed to produce entity manifest");

let authorizer = Authorizer::new();
debug!("Policies: {policyset}");
debug!("Entities: {entities}");
for abac_request in input.requests.into_iter() {
let request = ast::Request::from(abac_request);
debug!("Request: {request}");
let entity_slice = manifest
.slice_entities(&entities, &request)
.expect("failed to slice entities");
debug!("Entity slice: {entity_slice}");
let ans_original =
authorizer.is_authorized(request.clone(), &policyset, &entities);
let ans_slice = authorizer.is_authorized(request, &policyset, &entity_slice);
assert_eq!(
ans_original.decision, ans_slice.decision,
"Authorization decision differed with and without entity slicing!"
);
}
}
}
}
});

0 comments on commit 4786741

Please sign in to comment.