cedar-policy / cedar Goto Github PK
View Code? Open in Web Editor NEWImplementation of the Cedar Policy Language
Home Page: https://www.cedarpolicy.com
License: Apache License 2.0
Implementation of the Cedar Policy Language
Home Page: https://www.cedarpolicy.com
License: Apache License 2.0
Cedar language features
We would like to be able to use placeholders like ?principal
and ?resource
in the when
/unless
conditions.
Placeholders are evaluated in the conditions.
The alternative seems to be creating multiple different policies, rather than using the template linking feature to re-use the same policy. This is unappealing because of the maintenance burden of applying changes to the underlying logic to a large number of existing policies.
An example of a policy that would use this:
@id("Admin")
permit(
principal == ?principal,
action,
resource)
when {
// take any action in the scope that you're admin on
resource in ?resource
// allow access up the tree for navigation
|| (action == Action::"Navigate" && ?resource in resource)
};
This policy is intended to allow someone to administer a particular resource subtree in the resource hierarchy, and also to navigate down to their subtree.
This could be broken up into:
@id("AdminAdmin")
permit(
principal == ?principal,
action,
resource in ?resource); // take any action in the scope that you're admin on;
@id("AdminNavigate")
permit(
principal == ?principal,
action == Action::"Navigate",
?resource in resource); // allow access up the tree for navigation
to avoid supporting placeholders in the conditions, but then it would be possible to get into strange states where someone had AdminAdmin
applied, but not AdminNavigate
, which is undesirable.
Notes:
Admin
policy above currently appears to work, though the docs say it shouldn't?resource in resource
is not allowed ("Placeholders can appear in only the policy head on the right-hand side of the == or in operators.") but it also appears to workOther
Be able to do partial evaluation in the CLI
Introduce an optional parameter "--partial" in the CLI, so to change the entity mode to partial and be able to do partial authorization and give residual result.
None
No response
Cedar language features
We would like to be able to use template linking to grant permissions on patterns of resources, for example "Shohreh has the Editor policy on all Documents matching *.pdf".
This depends on #81
Allow the like
operator to accept expressions, not just literal strings on the RHS. Support like on entities, with the logic that the LHS entity must be the same EntityType as the RHS entity and the LHS entity's name must be like
the RHS entity.
@id("Editor")
permit(
principal == ?principal,
action in [Action::"Read", Action::"Write", Action::"Comment"],
resource like ?resource
);
To achieve this goal today, we can create more policies with the wildcards in literal strings, but we would prefer to use policy templates so that the templates can evolve.
If #94 is implemented, one option would be to separate the type check from the name check:
resource.name like ?resource.name
&& resource is Document
If there were more placeholders than just ?principal
and ?resource
, maybe a string placeholder would be better:
resource.name like ?pattern
&& resource is Document
No response
Cedar grammar changes/additions
Manually editing https://github.com/cedar-policy/cedar/blob/main/cedar-policy-core/src/parser/grammar.lalrpop we can get a nice navigable railroad diagram.
Copy and paste the EBNF
shown bellow on https://www.bottlecaps.de/rr/ui on the tab Edit Grammar
the click on the tab View Diagram
to see/download a navigable railroad diagram.
Policies ::= Policy*
Annotations ::= ('@' Ident '(' String ')')*
Policy ::= "label" ('permit' | 'forbid') '(' VariableDef* ')' Cond* ';'
VariableDef ::= Variable (':' Name)? (('in' | '==') Expr)?
// Identifier, but not the special ones
// The special ones, play multiple roles
Cond ::= ('when' | 'unless') '{' Expr '}'
Expr ::= Or | 'if' Expr 'then' Expr 'else' Expr
Or ::= And ('||' And)*
And ::= Relation ('&&' Relation)*
Relation ::= Add (RelOp Add)* | Add HAS Add | Add LIKE Add
RelOp ::= '<' | '<=' | '>=' | '>' | '!=' | '==' | 'in'
Add ::= Mult (('+' | '-') Mult)*
Mult ::= Unary (('*' | '/' | '%') Unary)*
Unary ::= ('!' '!'* | '-' '-'*)? Member
Member ::= Primary MemAccess*
MemAccess ::= '.' IDENT | '(' ExprList? ')' | '[' Expr ']'
Primary ::= LITERAL |
Ref |
Name |
Slot |
'(' Expr ')' |
'[' ExprList? ']' |
'{' MapOrFieldInits? '}'
Name ::= IDENT ('::' IDENT)*
// NameInline is exactly the same as Name (and needs to remain so), but the
// inlining gets around an LR(1) problem in the definition of `Ref`
Ref ::= Name '::' (STR | '{' RefInits? '}')
RefInit ::= IDENT ':' LITERAL
RecInit ::= Expr ':' Expr | IDENT ':' Expr
LITERAL ::= BOOL | INT | STR
// Whitespace and comments
// r"\s*" => { }, // The default whitespace skipping is disabled an `ignore pattern` is specified
// r"//[^\n\r]*[\n\r]*" => { }, // Skip `// comments`
// \("[^"]+"\) => \(\S+[^,]\),
// Special Identifiers (begin expressions)
TRUE ::= "true"
FALSE ::= "false"
IF ::= "if"
// Common Identifiers
PERMIT ::= "permit"
FORBID ::= "forbid"
WHEN ::= "when"
UNLESS ::= "unless"
IN ::= "in"
HAS ::= "has"
LIKE ::= "like"
THEN ::= "then"
ELSE ::= "else"
// main idents
PRINCIPAL ::= "principal"
ACTION ::= "action"
RESOURCE ::= "resource"
CONTEXT ::= "context"
// Valid slots, hardcoded for now, may be generalized later
PRINCIPAL_SLOT ::= "?principal"
RESOURCE_SLOT ::= "?resource"
// data input
IDENTIFIER ::= [_a-zA-Z][_a-zA-Z0-9]*
// The `NUMBER` token is a positive integer.
// Negative number literals are negation operations.
NUMBER ::= [0-9]+
STRINGLIT ::= '"'(.|[^"\])*'"'
// other tokens used
//"@",
//".", ",", ";", ":", "::",
//"(", ")", "{", "}", "[", "]",
//"==", "!=", "<", "<=", ">=", ">",
//"||", "&&",
//"+", "-", "*", "/", "%",
//"!",
Shown above
Shown above
No response
Cedar validation features
We would like a way to verify in advance that policies will not raise arithmetic overflow errors during evaluation.
Runtime errors of any kind are a potential source of unintended behavior in users' policies, and the possibility of arithmetic overflow errors in particular makes certain kinds of reasoning about Cedar code difficult.
Enhance validation to be able to rule out arithmetic overflow errors. In essence, the Long
type will be parameterized with lower and upper bounds on the value. We start by having the schema state the assumed bounds for each attribute of type Long
. Then, for each arithmetic operator in a policy, the validator will compute bounds for the result and report a validation error if the result bounds exceed the range of a Cedar Long
.
Parts of the implementation:
At one point, we considered changing Cedar's integer type to be unbounded (so it could never "overflow"), but we were concerned that operating on "big integers" could become too slow.
No response
Cedar grammar changes/additions
In general, the AST type tries to represent only well-typed policies, but there are a few exceptions.
For example, the parser currently allows expressions like "foo".some_ident
and 1["some string"]
even though these are clearly ill-typed, and will result in type errors at during authorization (or validation).
Make terms of the form LITERAL {Access}
a parse error to make these "obvious" errors easier to catch.
The easiest way to do this is probably to extend the ExprOrSpecial
type in cedar-policy-core/src/parser/cst_to_ast.rs with a general case for literals and then adjust the match cases in the implementation of to_expr_or_special
for cst::Member
.
N/A
No response
Cedar Parser
Cedar EST generator crashes when attempting to generate an EST for a policy with an invalid attribute name.
EST generation should fail gracefully
Given the following the policy:
permit(principal, action, resource) when { resource.name.like == "test" };
The cli can be crashed as follows:
cargo run check-parse --policies ./policies.cedar
Resulting in:
thread 'main' panicked at 'not implemented: other idents?', cedar-policy-core/src/est/expr.rs:1187:33
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
No response
No response
No response
No response
No response
Cedar validation features
The typechecker currently supports singleton boolean types True
and False
. When an expression has one of the types, it means the typechecker has shown that it will always evaluate to true
or false
for a particular request type environment. If an expression has the same singleton boolean type across all valid environments, then we can conclude that it always evaluates to the same value for every request. It seems unlikely that this is intentional, as it is likely to lead to dead code inside policies.
For example:
permit(principal, action, resource) when {
if principal has attr1 then
principal.attr1
else
principal.attr2
}
This policies is likely indented to apply some authorization logic if the optional attribute attr1
is present, and apply some fallback logic otherwise. If attr1
is not an optional attribute but is in fact never present, the condition will have type False
. If it is not a possible attribute for any principal entity type, the condition will have type False
across all query environments, so the then
branch will never be executed. We could notice this and report an error or warning.
n/a
No response
Cedar language features
Customers need ways to programmatically consume the syntax of Cedar policies. This task will simplify the developer experience for building permissions management UX for their end users by enabling them to programmatically parse Cedar policy.
N/A
N/A
N/A
User level API changes
EvaluationError
is currently exposed through cedar/api.rs
as a string message (code copied below). This may encourage users to pattern match on our error messages, which are subject to change. We should consider updating this to match cedar-policy-core's EvaluationError
(per the TODO), or construct some new enum.
/// Errors encountered while evaluating policies or expressions, or making
/// authorization decisions.
#[derive(Debug, Clone, PartialEq, Eq, Error)]
pub enum EvaluationError {
/// Error message, as string.
/// TODO in the future this can/should be the actual Core `EvaluationError`
#[error("{0}")]
StringMessage(String),
}
See above.
N/A
No response
Cedar language features
library for calling Cedar from golang
A package similar to https://github.com/cedar-policy/cedar-java but for golang, approved for aws internal use
Making our own. We just lack the dev time to expend on supporting this at the moment.
We're currently planning to use AVP but want to explore calling the cedar library directly
Cedar language features
Currently, if you provide policies using Policy::from_str()
or similar, the policy is converted to EST "eagerly" even if the EST is never demanded via Policy::to_json()
. This slows down the critical path of important operations such as is_authorized()
. The conversion to EST should instead be done lazily, on-demand.
The cedar_policy::Policy
type does need to carry some "lossless" representation (see discussion on #125 for context) in order to properly support Policy::to_json()
. Currently, that's the EST, but it could instead be the CST or policy text format, which could be converted to EST on demand. If we just swapped it out directly, though, we'd have the opposite problem, where if you provide that policy as EST (via Policy::from_json()
), it would have to be converted to CST or text on the critical path. The most flexible solution, that keeps both paths fast, would be to store either the EST or the CST/text, whichever is provided, and convert to the other on demand.
Discussed above.
Requested by a customer
Other
We can deploy rustc-style error message reporting (i.e., with colors, highlighting, and explanatory links).
We can use existing libraries like miette.
Or we can perform better formatting of the error messages.
No response
Cedar language features
In this slack thread: https://cedar-policy.slack.com/archives/C0547KH7R19/p1684968294619939
If we use a schema file when parsing an entities file, we give errors for incorrect attributes. We don't give similar errors for incorrect parent types.
When we use a schema file to parse entities, we should give errors for incorrect parent types.
N/A
No response
Cedar language features, User level API changes
Currently is_authorized is slow if you pass in enough entities with enough attributes. This is due to https://github.com/cedar-policy/cedar/blob/dcd5232721576f139c1ff30ad0695ddcb94f9b1d/cedar-policy-core/src/evaluator.rs#LL139C11-L139C11
which loops over all attributes in all entities.
It should be possible for users to compute EntityAttrValues once and use it for many authorization calls.
Modify the API so users have the option to compute EntityAttrValues before calling is_authorized additionally, modify is_authorized so it can take an EntityAttrValues (or some alternative) and skip this part of the computation.
Alternatively, we could change from eager Entity Attribute evaluation to lazy evaluation with caching.
No response
Cedar validation features
Some schema parsing errors report where the error occurred in the source JSON file. All of these errors are generated by serde when it parses JSON text into our intermediate schema representation. We want to provide similar information for the errors generated when converting the intermediate structures into the final form used for validation.
For this example schema an error is reported because the entity type B
appears in a memberOftypesList
without being defined, but the error does not say where this memberOfTypes
list is in the schema document.
{
"entityTypes": {
"A": { "memberOfTypes": [ "B" ] }
},
"actions": {}
}
Serde does not have an obvious mechanism for passing source location through to deserialized structures, but it does seem to be possible. I found an issue on the serde-json repo (serde-rs/json#637). While it doesn't look like direct support is planned, there is a crate linked that does something like what we want. It's not quite exactly what we need, but the implementation shows how we could do this ourselves.
If that doesn't pan out, I have two ideas for how we can still improve our error reporting. First, we can move more of our schema parsing steps into custom serde deserailzers. An error reported by a deserializer will automatically be annotated with the source locations. Where this isn't possible, we can still improve our error messages by including more information that we do have. For example, the error for an undefined entity type in a memberOfTypes
could include the name of the entity type declarations containing the error in addition to the name of the undeclared type.
(Original discussed in #149)
Cedar validation features
The validator sometimes gives imprecise types to expressions using in
.
principal in []
will type as Bool
when principal is Unspecified, although we could give the more precise type of False
.action in action
or principal in principal
will type as Bool
, even though we could give them type True
.Action::"read"
is a descendant of Action::"read_or_write"
, then Action::"read"
in Action::"read_or_write"
will type as Bool
, even though we could type it as True
.n/a
n/a
No response
Cedar Parser
The CST-AST conversion desugars a > b
into b < a
and a >= b
into b <= a
. That changes the evaluation order, which is visible to users via its effect on which error gets reported if both a
and b
raise an error and possibly via performance differences as well. The effect on error reporting could be confusing to users: Cedar's evaluation order is generally left to right, so if an expression a op b
raises an error from b
, I think an average user might think that means a
evaluated successfully and might get led down a wrong path during debugging.
When an expression of the form a > b
is evaluated, a
should be evaluated before b
, as with most other Cedar binary operators.
This can be reproduced using the cedar
command-line tool:
% cedar evaluate 'context.nosuch < (4294967296 * 4294967296)'
error while evaluating the expression: record does not have the required attribute: nosuch
% cedar evaluate 'context.nosuch > (4294967296 * 4294967296)'
error while evaluating the expression: integer overflow while attempting to multiply 4294967296 by 4294967296
In both commands of this example, both the left and the right operand raise an error. The <
operator propagates the error from the left operand, while the >
operator propagates the error from the right operand.
Included in the "reproduction steps".
Included in the "reproduction steps".
No response
Linux
A possible solution that doesn't require adding any more operators to the AST: change the desugaring of a > b
to !(a <= b)
, and change the desugaring of a >= b
to !(a < b)
.
Other
To make Cedar more useful, it would be nice to have native support for other languages besides Rust.
While it's possible to integrate with non-Rust runtimes via FFI, this is not an ideal approach for Go, where applications are typically compiled from complete source code into a static binary. With Rust FFI, it would be either necessary to distribute libraries for the various OS/architecture combinations supported by Go (for which there is currently no standardized way), or always compile the Rust code in-place (requiring a Rust build environment in addition to Go).
A Go-native implementation would be the ideal solution, reducing overhead and build dependencies.
Alternatively, an SDK using a Go-Rust integration layer like https://github.com/mediremi/rust-plus-golang could be provided, but this doesn't solve the multiple-OS/CPU-architecture problem well.
No response
User level API changes, Other
The policy debugger proceeds through the evaluation of a set policies, one step at a time, and answers the question of βwhyβ a policy did or did not fire.
N/A
N/A
No response
Other
The CLI always calls the validator in the default (strict) mode. I'd like to add a command-line flag to allow permissive mode.
Extending lib.rs
in the cedar-policy-cli
directory to support an additional validation flag.
The only alternative is not to allow calling permissive mode from the CLI at all, but this seems weird since we support it in the library APIs
No response
Cedar language features
Currently, if the entities JSON file contains two or more entries with the same UID, all but one will be silently dropped. We should instead error out in this case.
This is potentially a breaking change: Cedar users could have stored entity JSON data which contains duplicates, and this change would mean that their stored and previously-valid JSON data is no longer valid. This could also break a Cedar user whose entity slicing algorithm is fetching entities from some database and not being too careful to avoid fetching the same entity twice. Thus, the change should target Cedar 3.0. However, I do think the change is worth making for Cedar 3.0, to avoid the papercuts possible when silently dropping duplicate entities.
We should also do a thorough audit of our schema JSON, entities JSON, and policy JSON formats to ensure there are no other places that duplicate [entities, entity type declarations, action declarations, attribute declarations, etc] are silently dropped. Cedar 3.0 should be uniform in rejecting duplicate declarations.
JSON parsing should fail when encountering duplicates of the above kinds.
We could do nothing; dropping duplicate entries is the expected behavior in many JSON parsers, particularly in JSON maps. In this case though, I think the error is likely to be more helpful than the dropping-duplicates behavior.
We could add a flag to JSON parsing functions allowing the user to select between the two behaviors. But that adds complexity to our APIs and in this case I think it's better for Cedar to be opinionated.
No response
Other
Our (transitive, through criterion) atty dependency is outdated. The version used has a security vulnerability. We aren't exposed to it but once a new version of criterion is released we should upgrade so we don't have the transitive atty dependency.
No response
No response
No response
No response
No response
No response
No response
User level API changes
cedar-policy-core
contains Entities::to_json
but cedar-policy
doesn't expose this.
Add Entities::to_json
.
none
No response
Cedar validation features
The current approach to schema-based validation assumes that the schema file is complete: If an entity, or attribute, is not specified in the schema, then the validator assumes it does not exist. This means that, for example, an attribute access x.f
when f
is not present in the schema will result in a type error. In this document we sketch out a design for relaxing this constraint, calling the resulting algorithm partial-schema validation
.
Partial-schema validation relaxes the assumption that the schema is complete. In other words, just because a policy references an attribute not mentioned in the schema, that doesnβt mean that the validator should flag an error.
NA
NA
NA
User level API changes
Problem: When providing an EST to the Policy::from_json
method, then displaying that policy, the displayed policy contains when {true}
.
Not sure about best implementation, but a blanket update to Policy
's Display
trait might not be what we want. This would swallow when {true}
clauses even if the customer wants it there (because they're using a different flow).
Expectation: if an EST has no conditions, we should not render a when clause.
string parsing - not ideal
This is used in building gui tools for policy authoring
Cedar Parser
Slot Ids are currently allowed in condition clauses, when they should be restricted to policy scopes:
permit(principal, action, resource) when {
resource == ?resource
};
parses.
While we may want to expand templates to support this in the future, our documentation currently claims we do not.
The above should produce a parse error.
permit(principal, action, resource) when {
resource == ?resource
};
Does not fail to parse
No response
No response
No response
No response
No response
Cedar validation features
The validator does not provide great error messages. Improve them.
The error messages should include:
entityTypes
part of the schema has a blank string in its memberOfTypes
array, the error message is about a parse error that suggests no obvious fix. In general, malformed schemas seem not to yield intuitive error messages.shape
other than a record, you should get an error message that tells you that specificallyAdditional context with use-cases below.
Per #135 it might be nice to provide a (P,A,R,C) tuple that shows why something is an error, when that is possible.
Nothing for it!
In tinytodo, when I comment out the resource has owner &&
part of policy1 (the second policy) of policies.cedar
and validate, I get this error:
[ tinytodo ]> cedar validate --schema tinytodo.cedarschema.json --policies policies.cedar
Validation Results:
Validation error on policy policy1 at offset 300-314: Attribute not found in record or entity owner
It would be useful to know which type the attribute is missing from. Here, it should be the type Application
.
If I introduce a typo, e.g., changing resource.readers
to resource.reders
, it's the same: The type (List
) is not given when it says the attribute is not found.
In tinytodo, when I introduce a type error when { 3 < resource.readers }
instead of when { principal in resource.readers }
in policy2 (the third policy), I get the error Expected one of [{"type":"Long"}] but saw {"type":"Entity","name":"Team"}
. It might be nice to make this more prosaic, e.g., Expected type 'Long' but saw entity type 'Team'
.
In tinytodo, if I change "Team"
on line 7 of tinytodo.cedarschema.json
to be ""
instead (making an entity of type User
's memberOfTypes
the empty string) I get the error: failed to parse schema from file tinytodo.cedarschema.json: Parse error in entity type: Unrecognized EOF found at 0 Expected one of ACTION, CONTEXT, ELSE, FALSE, FORBID, HAS, IDENTIFIER, IF, IN, LIKE, PERMIT, PRINCIPAL, RESOURCE, THEN, TRUE, UNLESS or WHEN
-- at the least it would be nice to know what line/column the error is on.
If just after line 86 of tinytodo.cedarschema.json
I add "context": {}
after the resourceTypes: [ ... ]
part (adding a comma where needed), I get the cryptic error message failed to parse schema from file tinytodo.cedarschema.json: JSON Schema file could not be parsed: data did not match any variant of untagged enum SchemaType at line 88 column 5
. The issue is that context
cannot be mapped to an empty {}
: If present you need to give it a "type": "Record"
etc.
Schemas and Validation
The actions
section of the schema lists entity IDs, whereas the entityTypes
section lists entity types. If a user mistakenly includes the Action
entity type (and any namespace) as part of their action ID, the error messages are confusing.
Ideally, the error message can identify the user's mistake more clearly, and do better at suggesting a fix. The suggestion would need to account for this particular mistake of including part of the type/namespace in the action ID.
In tinytodo's tinytodo.cedarschema.json
, modify the actions
element "createList"
to instead be "Action::CreateList"
. When validating polices.cedar
we get the error message
Validation error on policy policy0: Unrecognized action id Action::"CreateList", did you mean Action::"GetList"?
This is confusing! With this change, we are defining an action entity Action::"Action::CreateList"
. This is not what the user intended, because they failed to appreciate the distinction between entity IDs and entity types.
No response
No response
No response
No response
No response
Policy Evaluation
cedar-policy-core
has features for the ipaddr
and decimal
extensions, which are optional but enabled by default. But if you actually disable them, tests are not passing.
cargo test --no-default-features
should pass.
main
(I reproduced on 4b9e8b4)cd cedar-policy-core
or cd cedar-policy-validator
cargo test --no-default-features
No response
< snipped output above this, assuming that this is reproducible >
failures:
entities::json_parsing_tests::more_escapes
entities::schema_based_parsing_tests::missing_record_attr
entities::schema_based_parsing_tests::parents_wrong_type
entities::schema_based_parsing_tests::type_mismatch_entity_record
entities::schema_based_parsing_tests::type_mismatch_entity_types
entities::schema_based_parsing_tests::type_mismatch_extension_types
entities::schema_based_parsing_tests::type_mismatch_in_record_attr
entities::schema_based_parsing_tests::type_mismatch_set_element
entities::schema_based_parsing_tests::type_mismatch_string_long
entities::schema_based_parsing_tests::unexpected_entity_attr
entities::schema_based_parsing_tests::unexpected_record_attr
entities::schema_based_parsing_tests::with_and_without_schema
evaluator::test::partial_ext_unfold
evaluator::test::restricted_expressions
test result: FAILED. 318 passed; 14 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.36s
error: test failed, to rerun pass `--lib`
No response
No response
No response
Cedar validation features
Add support for enumerations of bool
, string
, and long
types in schemas, and use this information when doing policy validation.
Maintaining backward compatibility with JSON schema as much as possible, we can match its enum
feature. For example:
"type": "Record",
"attributes": {
"color": {
"type": "String"
"enum": ["red", "blue", "green"]
}
}
The enum
part limits the color
attribute to one of three possibilities. We would permit enumerations of this flavor for numbers and booleans too.
We can extend the validator to support singleton types for strings and numbers, and to allow union types for strings, booleans, and numbers. We have singleton types for booleans already, where bool
is equivalent to the union true|false
. This feature would generalize the same approach to numbers and strings.
For the future addition of numeric ranges to schemas, you could technically have both enumerations and ranges, but the enumeration can be checked against the range at validation time, and then the range can be ignored.
The only alternative is to not support the feature, or perhaps to support it using a different syntax.
Enumerations are a common need, and this change supports them in Cedar. It avoids the mistake of expecting a string (say) to match only a few values, but then it inadverentently matches too many.
Enumerations are particularly useful for policy building UIs -- the UI can look at the schema to know what values are valid for a particular attribute.
Cedar language features
Implementation of RFC 9. See comments there.
User level API changes
It would be nice to have more ergonomic ways of writing down policy and entity ids. Currently you have write them as a string, and then call .parse()
on them. For fully static data, this is cumbersome and delays error detection until runtime.
One solution here would be to have macros for writing ids. You could image something like:
entityuid!(#r"User::"Alice""#)
Parse rules would be checked at compile time, allowing you skip calling .unwrap
or handling the error, and making it compile time error if the ID was invalid.
The current situation is workable.
This is somewhat inspired by serde_json
s json!
macro.
Schemas and Validation
An action's group membership requires a fully qualified name even when the specified group is within the same namespace.
When a referenced entity is defined in the same namespace in which it is referenced, I'd expect it not to require namespace qualification.
Use the Cedar CLI to validate the policy permit(principal,action,resource);
using the schema given below.
If you attempt to validate a policy using the following schema, you will see the error.
{
"ExampleCo::Personnel": {
"entityTypes": {},
"actions": {
"read": {},
"viewPhoto": {
"memberOf": [
{
"id": "read",
"type": "Action"
}
]
}
}
}
}
The error goes away if you change the value of type
to be ExampleCo::Personnel::Action
instead.
failed to parse schema from file dumb.schema: Undeclared actions: {"Action::\"read\""}
No response
No response
No response
Cedar validation features
The Cedar schema supports commonTypes
definitions to help avoid duplicating attribute types in entity types shapes and actions contexts, but commonTypes
cannot currently be used inside other common types definitions.
The Cedar schema should support commonTypes
defined in terms of other commonTypes
. It should however, not support recursive types.
The schema parser will construct a directed graph of the type definitions, with an edge from each type to the other types it depends on. It will then check that the graph is acyclic. This can be done using our existing functions for checking that the entity hierarchy is a DAG. We can safely inline common type definitions once we know the dependency graph does not have cycles.
If we depend on the order of commonTypes
being significant, we could require that a type is declared before it is referenced, making cycles impossible to create.
The order of entries in a JSON map is not generally significant, so we would either need to break from this convention by making the order significant, or use an association list of pairs instead. Depending on the order of the map is not acceptable because it is likely to cause issues if the a schema document is processed by standard JSON tools which may not preserve order. Using an association list would make common types use a different structure than the entity types and actions list.
No response
Cedar language features
We'd like to be able to grant permissions on all resources of a given type ("Cyrus can view all Photos").
A specific test for this would be ideal:
resource is Photo
It's possible to implement this today using attributes, but that leads to the possibility that an entity might be created with an attribute that doesn't actually match its type.
Syntaxes that treat the entity type like a pseudo-attribute would work too:
resource.type == "Photo"
resource.EntityType == "Photo"
resource.entity_type == "Photo"
However this might be confusing or collide with attribute names.
No response
Cedar validation features
The following schema fails with a warning (tested with the PlayGround2):
{
"Test::Namespace": {
"actions": {
"sampleAction": {
"attributes": {},
"appliesTo": {
"principalTypes": [],
"resourceTypes": [
"sampleResource"
],
"context": {}
}
}
},
"entityTypes": {
"sampleResource": {
"shape": {
"type": "Record",
"attributes": {
"orgname": {
"type": "String"
}
}
}
}
}
}
}
The error message is: JSON Schema file could not be parsed: data did not match any variant of untagged enum SchemaType at line 12 column 17
The problem here is that currently context
should either not be there or should be of type Record
, but the message is quite confusing. Plus empty context
seems reasonable...
Empty context
should be accepted and valid.
A better error message is displayed
No response
Cedar language features
A partial evaluator is an evaluator that evaluates an expression as far as possible in the presence of unknown values. The partial evaluator returns residual programs: the left over part of the program that was impossible to evaluate.
Consider the following policy:
permit(principal, action, resource) where {
if context.a {
context.b > 3
else {
context.c
};
Perhaps b
and c
are expensive to compute, or are geographically distributed and expensive to get. We could imagine setting them to unknown, as follows:
{
'a' : true,
'b' : unknown("b"),
'c' : unknown("c"),
}
Partially evaluating should result in the residual expression:
unknown("b") > 3
N/A
N/A
Adding this feature requires updating the Cedar core, Dafny definitional evaluator, and the differential and randomized tests (DRT).
Other
Currently, cedar-policy
uses the implicit ^
dependency for Core and Validator. This means that, e.g., cedar-policy
2.2 will accept Core and Validator 2.3 as compatible. Unfortunately, since we don't currently follow semver for Core and Validator (only for cedar-policy
), this could result in build problems or other breakage if Cargo actually tries to give Core/Validator 2.3 to cedar-policy
2.2 -- e.g., because someone tries to depend on cedar-policy
"=2.2"
in their Cargo.toml
. To prevent this, we should change the Cargo.toml
of cedar-policy
to use the =
constraint in its dependencies on Core and Validator. Probably also the same change in Validator's Cargo.toml
for its Core dependency.
Cedar language features
I would like to use cedar in Java
Cedar working in Java natively
I have tried nothing
No response
Cedar language features
We would like to be able to match entities based on patterns in their entity IDs. For example, we would like to be able to express conditions like "is a Photo with an entity ID matching VacationPhoto*.jpg".
We propose using the existing like
keyword, but allowing an entity pattern to appear on the RHS, not just a literal string. The entity pattern would look like a typical entity, but the ID string would be interpreted as like
matching currently is.
Sample policy:
permit(
principal == User::"alice",
action == Action::"update",
resource
)
when { resource like Photo::"VacationPhoto*.jpg" };
Alternative solutions:
Using a different keyword than like
would be fine.
Using an attribute check combined with a type check (see #94) would work, but would require duplicated information in the entity (the entity ID and the attribute must match). Eg.
when {
resource.filename like "VacationPhoto*.jpg"
&& resource is Photo
}
Using an attribute check, combined with a group membership check (see #94 (comment)) would work, but would require the parent to be set. Eg.
when {
resource.filename like "VacationPhoto*.jpg"
&& resource in ResourceGroup::"Photos"
}
Using two attribute checks, one for the type and another for the ID would work, but using string comparison for type comparisons seems suspect. Eg.
when {
resource.filename like "VacationPhoto*.jpg"
&& resource.type == "Photo"
}
Using an attribute check on an attribute which includes both the type and ID would work, but again uses string comparison for type comparisons:
when {
resource.typeAndFilename like "Photo::VacationPhoto*.jpg"
}
This was split out from #95
User level API changes
The Cedar language provides a general purpose annotation feature, allowing users to annotate policies w/ arbitrary key/value pairs, and consumers of policies can use these however they want.
The Cedar CLI uses this in a very nice way to let you assign policy IDs to policies via annotations:
@id("myid")
permit(principal, action, resource);
This is a nice feature, and we should make it easy for other consumers of the Cedar library to use, instead of needing to re-roll it themselves.
Take the function from Cedar CLI that renames policies according to @id
annotations, and move into the Cedar library and expose it.
The alternative is not doing this. We don't enforce any semantics over annotations, and we may not want privilege certain interpretations.
No response
User level API changes
I'd like to be able to make is_authorized_partial
requests where principal, action, and context are known but resource is unknown. The intent is to have a guard in front of list operations so I can short-circuit actually going through the list of resources if the principal isn't allowed to list anything.
From: @aaronjeline :
It looks like the public versions of
is_authorized
andis_authorized_partial
both take the sameRequest
object, which doesn't have an option for having theresource
be unknown.
I think my ideal solution would be if I could call
Request::new(Some(EntityUid), Some(EntityUid), None, Context)
or
Request::new(Some(EntityUid), Some(EntityUid), UnknownEntity, Context)
where UnknownEntity
is provided for the exact purpose of encapsulating an ast::EntityUIDEntry::Unknown
. Support seems to exist already in Request
for handling the ast::EntityUIDEntry::Unknown
case:
Lines 2055 to 2061 in d920116
I've tried constructing requests with None
and that didn't seem to work.
I've also tried accessing ast::EntityUIDEntry::Unknown
from my code but it's not exposed.
This may conflict with #72 depending on the implementation.
Cedar language features
Allow template policies to be grouped together using the CLI, so they can be linked all at once. Doing so ensures that the application writer cannot mistakenly link one policy in the group separately from all the policies.
Consider this pair of template policies:
@id("policy1")
permit(
principal == ?principal,
action,
resource in ?resource);
@id("policy2")
permit(
principal == ?principal,
action == Action::"viewDoc",
resource in Directory::"DivisionDocs");
This pair represents a role: the linked principal can access any resource in the linked group (policy1), or it can view any document in a particular collection. We want to make sure that both policies are always linked, together, and not just one or the other. Some grouping mechanism would help. For example:
@group("role1")
@id("policy1")
permit(
principal == ?principal,
action,
resource in ?resource);
@group("role1")
@id("policy2")
permit(
principal == ?principal,
action == Action::"viewDoc",
resource in Directory::"DivisionDocs");
Here we have labeled both policies with the same @group
; we could instantiate them together in an API that references the group, rather than individual policy.
We could achieve a similar effect combining both templates into a single one:
@id("bothpolicies")
permit(
principal == ?principal,
action,
resource)
when {
resource in ?resource ||
(action == Action::"viewDoc" && resource in Directory::"DivisionDocs")
};
This has the drawback that the combined policy is more complicated to understand. It also requires the template slot ?resource
to appear in the when
condition, rather than the scope, which is currently not supported. Finally, this policy will not index very well in Verified Permissions because of multiple constraints on the action and resource.
This feature request only applies to the CLI, using the annotation mechanism as shown. It should have no impact on core Cedar or its APIs.
Cedar validation features
When validation fails, we should list the (Principal,Action,Resource) for which it failed. This will make it easier to see why validation fails. E.g., suppose principal and action are unconstrained and all actions but one apply to type User
with attribute bar
, but that one action applies to an EntityType without bar
then:
permit(principal, action, resource in Foo) {
principal.bar == resource.baz
};
Will (correctly) fail validation, but the user needs to search for which action applies to some entity type other than User
. Listing which (P,A,R) failed would make this trivial.
When validation fails, we should list the (Principal,Action,Resource) for which it failed.
None
No response
Cedar language features
Parse errors currently return character numbers. It would be nice to have the line numbers as well, for editors that don't make it easy to jump to a character.
Current output
failed to parse policies from file roles.cedar:
Unrecognized token `resource` found at 901:909
Expected one of "!=", "%", "&&", "(", ")", "*", "+", ",", "-", ".", "/", ":", "<", "<=", "==", ">", ">=", "[", "]", "||", "}", ELSE, HAS, IN, LIKE or THEN
Unrecognized token `)` found at 910:911
Expected one of "("
Unrecognized token `{` found at 917:918
...
failed to parse policies from file roles.cedar:
Unrecognized token `resource` found at 901:909 on line 37
...
Changing editors :)
No response
Other
Currently, an EntityUID
stores a reference to its EntityType
, which can be either Concrete
or Unspecified
. We introduced the EntityType
type to support omitting entities in the input query. For example: when the "resource" of a query should have no impact on the authorization result, then users should not need to provide a resource entity when calling is_authorized
.
However, we never actually expect an EntityUID
to be "Unspecified", which leads to extra error handling code in several locations.
In CedarCore, the type EntityUID
should always be concrete (i.e., its EntityType
component should just be a Name
), and "Unspecified" entities should only be possible when constructing a Query
. This requires some refactoring of the code, but should introduce no breaking changes.
The current implementation works, but is more complicated than necessary.
No response
Cedar validation features
In this slack thread: https://cedar-policy.slack.com/archives/C0547KH7R19/p1684968294619939
A user found a confusing error when he had a namespaced schema but his entities file didn't use the namespaced type.
We should warn if types aren't declared in the schema and we should suggest a user likely meant a namespaced type if a matching namespaced type is declared in the schema.
We could keep the current behavior and update documentation to clarify behavior.
No response
Cedar validation features
In the validation code the upper bound of the record types {"foo" : Bool}
and {"foo" : Int}
is defined as {}
. This does not result in unsoundness, since the attribute "foo" can never be safely accessed from {}, but it is a little strange. Itβs (arguably) more natural for this to be defined as an error since the types Bool
and Int
are inconsistent.
Update the LUB computation in the validator so that {"foo" : Bool}
and {"foo" : Int}
do not have an upper bound. This will mean that some policies that previously validated will now fail to validate. The potential benefit is that this change may allow for more useful error messages. For example, consider a (contrived) expression like (if principal.is_user then {"foo" : true} else {"foo" : 2}).foo
. Validation will currently say that attribute foo
cannot be safely accessed, while the actual issue is that the two possibilities for foo
have incompatible types.
The alternative is to leave the definition as-is. This is also a viable option -- it just depends on which we find more useful in practice.
No response
Cedar validation features
The validator is sometimes able to decide that an ==
expression will always evaluate to true
of false
, but we are fairly conservative in this to avoid possible soundness bugs. We should expand the range of expressions this applies to. For example, 1 == "2"
is an equality between different primitive types, so it will always be false.
n/a
n/a
No response
A declarative, efficient, and flexible JavaScript library for building user interfaces.
π Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. πππ
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google β€οΈ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.