diff --git a/cedar-example-use-cases/run.sh b/cedar-example-use-cases/run.sh index 282e7ff..bfb8aa2 100755 --- a/cedar-example-use-cases/run.sh +++ b/cedar-example-use-cases/run.sh @@ -20,6 +20,12 @@ validate "tags_n_roles" "policies.cedar" "policies.cedarschema" authorize "tags_n_roles" "policies.cedar" "entities.json" "policies.cedarschema" format "tags_n_roles" "policies.cedar" +# Tax preparer +echo -e "\nTesting Tax preparer..." +validate "tax_preprarer" "policies.cedar" "policies.cedarschema" "linked" +authorize "tax_preprarer" "policies.cedar" "entities.json" "policies.cedarschema" "linked" +format "tax_preprarer" "policies.cedar" + # Sales org static echo -e "\nTesting Sales Orgs (static)..." validate "sales_orgs/static" "policies.cedar" "policies.cedarschema" @@ -32,13 +38,13 @@ validate "sales_orgs/templated" "policies.cedar" "policies.cedarschema" "linked" authorize "sales_orgs/templated" "policies.cedar" "entities.json" "policies.cedarschema" "linked" #format "sales_orgs/templated" "policies.cedar" -# Hotel chains +# Hotel chains static echo -e "\nTesting Hotels (static)..." validate "hotel_chains/static" "policies.cedar" "policies.cedarschema" authorize "hotel_chains/static" "policies.cedar" "entities.json" "policies.cedarschema" #format "hotel_chains/static" "policies.cedar" -# Hotel chains +# Hotel chains templated echo -e "\nTesting Hotels (templated)..." validate "hotel_chains/templated" "policies.cedar" "policies.cedarschema" "linked" authorize "hotel_chains/templated" "policies.cedar" "entities.json" "policies.cedarschema" "linked" diff --git a/cedar-example-use-cases/tax_preprarer/ALLOW/alice_read_ABC.json b/cedar-example-use-cases/tax_preprarer/ALLOW/alice_read_ABC.json new file mode 100644 index 0000000..15d81e4 --- /dev/null +++ b/cedar-example-use-cases/tax_preprarer/ALLOW/alice_read_ABC.json @@ -0,0 +1,16 @@ +{ + "principal": "Taxpreparer::Professional::\"Alice\"", + "action": "Taxpreparer::Action::\"viewDocument\"", + "resource": "Taxpreparer::Document::\"ABC\"", + "context": { + "consent": { + "client": { + "__entity": { + "type": "Taxpreparer::Client", + "id": "Ramon" + } + }, + "team_region_list": [ "IAD", "JFK" ] + } + } +} diff --git a/cedar-example-use-cases/tax_preprarer/ALLOW/alice_read_DEF.json b/cedar-example-use-cases/tax_preprarer/ALLOW/alice_read_DEF.json new file mode 100644 index 0000000..d30e70e --- /dev/null +++ b/cedar-example-use-cases/tax_preprarer/ALLOW/alice_read_DEF.json @@ -0,0 +1,16 @@ +{ + "principal": "Taxpreparer::Professional::\"Alice\"", + "action": "Taxpreparer::Action::\"viewDocument\"", + "resource": "Taxpreparer::Document::\"DEF\"", + "context": { + "consent": { + "client": { + "__entity": { + "type": "Taxpreparer::Client", + "id": "Ramon" + } + }, + "team_region_list": [ "IAD", "JFK" ] + } + } +} diff --git a/cedar-example-use-cases/tax_preprarer/ALLOW/bob_read_DEF.json b/cedar-example-use-cases/tax_preprarer/ALLOW/bob_read_DEF.json new file mode 100644 index 0000000..b1f1e4a --- /dev/null +++ b/cedar-example-use-cases/tax_preprarer/ALLOW/bob_read_DEF.json @@ -0,0 +1,16 @@ +{ + "principal": "Taxpreparer::Professional::\"Bob\"", + "action": "Taxpreparer::Action::\"viewDocument\"", + "resource": "Taxpreparer::Document::\"DEF\"", + "context": { + "consent": { + "client": { + "__entity": { + "type": "Taxpreparer::Client", + "id": "Ramon" + } + }, + "team_region_list": [ "IAD", "JFK" ] + } + } +} diff --git a/cedar-example-use-cases/tax_preprarer/DENY/alice_read_ABC.json b/cedar-example-use-cases/tax_preprarer/DENY/alice_read_ABC.json new file mode 100644 index 0000000..eb92b12 --- /dev/null +++ b/cedar-example-use-cases/tax_preprarer/DENY/alice_read_ABC.json @@ -0,0 +1,16 @@ +{ + "principal": "Taxpreparer::Professional::\"Alice\"", + "action": "Taxpreparer::Action::\"viewDocument\"", + "resource": "Taxpreparer::Document::\"ABC\"", + "context": { + "consent": { + "client": { + "__entity": { + "type": "Taxpreparer::Client", + "id": "Ramon" + } + }, + "team_region_list": [ "JFK" ] + } + } +} diff --git a/cedar-example-use-cases/tax_preprarer/DENY/bob_read_ABC.json b/cedar-example-use-cases/tax_preprarer/DENY/bob_read_ABC.json new file mode 100644 index 0000000..ea92995 --- /dev/null +++ b/cedar-example-use-cases/tax_preprarer/DENY/bob_read_ABC.json @@ -0,0 +1,16 @@ +{ + "principal": "Taxpreparer::Professional::\"Bob\"", + "action": "Taxpreparer::Action::\"viewDocument\"", + "resource": "Taxpreparer::Document::\"ABC\"", + "context": { + "consent": { + "client": { + "__entity": { + "type": "Taxpreparer::Client", + "id": "Ramon" + } + }, + "team_region_list": [ "IAD", "JFK" ] + } + } +} diff --git a/cedar-example-use-cases/tax_preprarer/README.md b/cedar-example-use-cases/tax_preprarer/README.md new file mode 100644 index 0000000..b6351b9 --- /dev/null +++ b/cedar-example-use-cases/tax_preprarer/README.md @@ -0,0 +1,36 @@ +# Taxpreparer policies + +This use-case simulates an organization that prepares taxes for its clients. + +## Use-case + +A `Professional` needs to access a `Client`'s `Document` in order to prepare their taxes. There are two rules that grant access: + +1. That the `Professional` has been granted access to the document. This could be because + + a. she belongs to an _organization_ whose features (service line, location, etc.) are a match for features of the `Document`, or + + b. because she has been granted _ad hoc_ access. +2. That the `Client` has given consent for professionals in a particular country to look at documents they own. A consent is modeled as a `Consent` entity, which is passed in with the authorization request's `context`. + +Rules 1a and 2 are expressed as static policies, and rule 1b is expressed as a link to a template. + +Rules 2 is expressed as a `forbid` rule so that it affects any _ad hoc_ `permit` policies added later. Alternatively, it could have been expressed as an additional `when` clause in the `permit` policies, both the static one and the template. + +## Tests + +The test setup defines the following entities, in `entities.json`: + +- `Professional`s `Alice` and `Bob`. They are both part of `org-1` in the `corporate` serviceline, and are located at `IAD` and `JFK`, respectively. +- `Client` `Ramon` is contracting with the `corporate` serviceline +- `Document`s `ABC` and `DEF`, owned by `Ramon`, and located at `IAD` and `JFK`, respectively. + +The setup also includes file `linked`, which links the ad-hoc access template to grant `Alice` access to document `DEF`. + +Then we have five scenarios: + +1. Alice requests access to ABC -- this is allowed per rules 1a and 2: Alice is part of the appropriate serviceline, organization, and location, and the request shows that her particular location has been consented to +2. Alice requests access to DEF -- this is allowed per rules 1b and 2: She has been granted ad hoc access, and the request shows that her particular location has been consented to +3. Bob requests access to DEF -- this is allowed per rules 1a and 2. +4. Alice requests access to ABC -- this time the request is denied because rule 2 is not satisfied: the provided consent does not include Alice's location +5. Bob requests access to ABC -- this is not allowed because neither rules 1a nor 1b are satisfied. \ No newline at end of file diff --git a/cedar-example-use-cases/tax_preprarer/entities.json b/cedar-example-use-cases/tax_preprarer/entities.json new file mode 100644 index 0000000..6a394af --- /dev/null +++ b/cedar-example-use-cases/tax_preprarer/entities.json @@ -0,0 +1,76 @@ +[ + { + "uid": { + "type": "Taxpreparer::Professional", + "id": "Alice" + }, + "attrs": { + "location": "IAD", + "assigned_orgs": [ + { + "organization": "org-1", + "serviceline": "corporate", + "location": "IAD" + } + ] + }, + "parents": [] + }, + { + "uid": { + "type": "Taxpreparer::Professional", + "id": "Bob" + }, + "attrs": { + "location": "JFK", + "assigned_orgs": [ + { + "organization": "org-1", + "serviceline": "corporate", + "location": "JFK" + } + ] + }, + "parents": [] + }, + { + "uid": { + "type": "Taxpreparer::Client", + "id": "Ramon" + }, + "attrs": { + "organization": "org-1" + }, + "parents": [] + }, + { + "uid": { + "type": "Taxpreparer::Document", + "id": "ABC" + }, + "attrs": { + "serviceline": "corporate", + "location": "IAD", + "owner": { + "type": "Taxpreparer::Client", + "id": "Ramon" + } + }, + "parents": [] + }, + { + "uid": { + "type": "Taxpreparer::Document", + "id": "DEF" + }, + "attrs": { + "serviceline": "corporate", + "location": "JFK", + "owner": { + "type": "Taxpreparer::Client", + "id": "Ramon" + } + }, + "parents": [] + } +] \ No newline at end of file diff --git a/cedar-example-use-cases/tax_preprarer/linked b/cedar-example-use-cases/tax_preprarer/linked new file mode 100644 index 0000000..cd13371 --- /dev/null +++ b/cedar-example-use-cases/tax_preprarer/linked @@ -0,0 +1,10 @@ +[ + { + "template_id": "adhoc-access", + "link_id": "AliceView", + "args": { + "?principal": "Taxpreparer::Professional::\"Alice\"", + "?resource": "Taxpreparer::Document::\"DEF\"" + } + } +] \ No newline at end of file diff --git a/cedar-example-use-cases/tax_preprarer/policies.cedar b/cedar-example-use-cases/tax_preprarer/policies.cedar new file mode 100644 index 0000000..2eae25a --- /dev/null +++ b/cedar-example-use-cases/tax_preprarer/policies.cedar @@ -0,0 +1,39 @@ +// Rule 1a: organization-level access +permit ( + principal, + action == Taxpreparer::Action::"viewDocument", + resource +) +when +{ + principal.assigned_orgs + .contains + ( + {organization + :resource.owner.organization, + serviceline + :resource.serviceline, + location + :resource.location} + ) +}; + +// Rule 1b: ad hoc access (per linked template) +@id("adhoc-access") +permit ( + principal == ?principal, + action == Taxpreparer::Action::"viewDocument", + resource == ?resource +); + +// Rule 2: consent must be given by a document's owner +forbid ( + principal, + action == Taxpreparer::Action::"viewDocument", + resource +) +unless +{ + context.consent.client == resource.owner && + context.consent.team_region_list.contains(principal.location) +}; \ No newline at end of file diff --git a/cedar-example-use-cases/tax_preprarer/policies.cedarschema b/cedar-example-use-cases/tax_preprarer/policies.cedarschema new file mode 100644 index 0000000..b3d1a44 --- /dev/null +++ b/cedar-example-use-cases/tax_preprarer/policies.cedarschema @@ -0,0 +1,33 @@ +namespace Taxpreparer { + type orgInfo = { + organization: String, + serviceline: String, + location: String, + }; + // A tax-preparing professional + entity Professional = { + assigned_orgs: Set, + location: String, + }; + // A client's tax document + entity Document = { + serviceline: String, + location: String, + owner: Client, + }; + // A client + entity Client = { + organization: String + }; + // The record of consent from a client to view a doc + type Consent = { + client: Client, + team_region_list: Set + }; + + action viewDocument appliesTo { + principal: [Professional], + resource: [Document], + context: { consent: Consent } + }; +}