Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use PE to implement GetLists #121

Merged
merged 6 commits into from
Jun 17, 2024
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions tinytodo/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -24,4 +24,5 @@ use-templates = []
version = "4.0.0"
git = "https://github.com/cedar-policy/cedar"
branch = "main"
features = ["partial-eval"]
#Do not add any lines below this. CI relies on the previous line being the second-to-last line in the file
2 changes: 1 addition & 1 deletion tinytodo/policies.cedar
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// Policy 0: Any User can create a list and see what lists they own
permit (
principal,
action in [Action::"CreateList", Action::"GetLists"],
action == Action::"CreateList",
shaobo-he-aws marked this conversation as resolved.
Show resolved Hide resolved
resource == Application::"TinyTodo"
);

Expand Down
46 changes: 37 additions & 9 deletions tinytodo/src/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,13 @@

use itertools::Itertools;
use lazy_static::lazy_static;
use std::path::PathBuf;
use std::{collections::HashMap, path::PathBuf};
use tracing::{error, info, trace};

use cedar_policy::{
Authorizer, Context, Decision, Diagnostics, EntityTypeName, HumanSchemaError, ParseErrors,
PolicySet, PolicySetError, Request, Schema, SchemaError, ValidationMode, Validator,
Authorizer, Context, Decision, Diagnostics, Entities, EntityTypeName, HumanSchemaError,
ParseErrors, PolicySet, PolicySetError, Request, RequestBuilder, RestrictedExpression, Schema,
SchemaError, ValidationMode, Validator,
};

use thiserror::Error;
Expand Down Expand Up @@ -511,14 +512,41 @@ impl AppContext {
}

fn get_lists(&self, r: GetLists) -> Result<AppResponse> {
let t: EntityTypeName = "List".parse().unwrap();
self.is_authorized(&r.uid, &*ACTION_GET_LISTS, &*APPLICATION_TINY_TODO)?;
let resource_ty: EntityTypeName = "List".parse().unwrap();
let entities: Entities = self.entities.as_entities(&self.schema);
let partial_request = RequestBuilder::default()
.action(Some(ACTION_GET_LIST.as_ref().clone().into()))
.principal(Some(cedar_policy::EntityUid::from(EntityUid::from(
r.uid.clone(),
))))
.build();
let partial_response =
self.authorizer
.is_authorized_partial(&partial_request, &self.policies, &entities);
Comment on lines +521 to +523
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe add a comment explain what's going on here, because readers might be confused.

What we are trying to simulate is the following:

  • For all entities L of type List, is_authorized(principal,GET_LIST, L ) ? If so, add to collection

What we are doing here instead is

  • Let res = is_authorized_partial(principal,GET_LIST, unknown ).
  • For all entities L of type List, is res .reauthorize( unknown = L ) ? If so, add to collection

The benefit is that we are partially evaluating some of the policies so the reauthorization requires less work. Even more, we imagine that a future implementation of the entity store can implement the reauthorize logic more directly/efficiently, e.g., as a DB query.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Noted. Will fix it in another PR.


let slice = self
.entities
.euids()
.filter(|euid| euid.type_name() == &resource_ty);

Ok(AppResponse::Lists(
self.entities
.euids()
.filter(|euid| euid.type_name() == &t)
.filter(|euid| self.is_authorized(&r.uid, &*ACTION_GET_LIST, euid).is_ok())
slice
.filter(|euid| matches!(
partial_response.reauthorize(
HashMap::from_iter(
std::iter::once(
("resource".into(), RestrictedExpression::new_entity_uid(cedar_policy::EntityUid::from((*euid).clone())))
)
),
shaobo-he-aws marked this conversation as resolved.
Show resolved Hide resolved
&self.authorizer,
Request::new(
None,
None,
None,
Context::empty(),
None).expect("should be a valid request"),
&entities),
Ok(r) if matches!(r.decision(), Some(Decision::Allow))))
.cloned()
.collect::<Vec<EntityUid>>()
.into(),
Expand Down
2 changes: 1 addition & 1 deletion tinytodo/tinytodo.cedarschema
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ action DeleteList, GetList, UpdateList appliesTo {
principal: [User],
resource: [List]
};
action CreateList, GetLists appliesTo {
action CreateList appliesTo {
principal: [User],
resource: [Application]
};
Expand Down
Loading