Skip to content

Commit

Permalink
chore: Use Expr for Cedar caveats (#14)
Browse files Browse the repository at this point in the history
Caveats are AND'd together into a `forbid unless` policy.
  • Loading branch information
dnys1 committed Jul 30, 2024
1 parent cbaa51d commit 49ea053
Show file tree
Hide file tree
Showing 13 changed files with 155 additions and 129 deletions.
11 changes: 4 additions & 7 deletions dart/lib/src/cedar_cork.dart
Original file line number Diff line number Diff line change
Expand Up @@ -30,11 +30,8 @@ extension type CedarCorkBuilder(CorkBuilder _builder) implements CorkBuilder {
}

@redeclare
void addCaveat(cedar.CedarPolicy policy) {
if (policy.effect != cedar.CedarPolicyEffect.forbid) {
throw ArgumentError('Only forbid policies are allowed as caveats.');
}
_builder.addCaveat(policy.toProto());
void addCaveat(cedar.JsonExpr caveat) {
_builder.addCaveat(caveat.toProto());
}
}

Expand Down Expand Up @@ -81,8 +78,8 @@ extension type CedarCork(Cork _cork) implements Cork {
}

@redeclare
List<cedar.CedarPolicy> get caveats => UnmodifiableListView([
List<cedar.JsonExpr> get caveats => UnmodifiableListView([
for (final caveat in _cork.caveats)
proto.Policy().unpackAny(caveat).fromProto(),
proto.Expr().unpackAny(caveat).fromProto(),
]);
}
23 changes: 12 additions & 11 deletions dart/lib/src/proto/cedar/v3/cork.pb.dart
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,9 @@ import 'dart:core' as $core;

import 'package:protobuf/protobuf.dart' as $pb;

import 'entity.pb.dart' as $4;
import 'entity.pb.dart' as $3;
import 'entity_id.pb.dart' as $0;
import 'policy.pb.dart' as $5;
import 'expr.pb.dart' as $4;

/// A bearer token that can be used to make claims about an entity for the purpose
/// of authorization and authentication w/ Cedar.
Expand All @@ -25,8 +25,8 @@ class Cork extends $pb.GeneratedMessage {
$0.EntityId? issuer,
$0.EntityId? bearer,
$0.EntityId? audience,
$4.Entity? claims,
$core.Iterable<$5.Policy>? caveats,
$3.Entity? claims,
$core.Iterable<$4.Expr>? caveats,
$core.List<$core.int>? signature,
}) {
final $result = create();
Expand Down Expand Up @@ -62,8 +62,8 @@ class Cork extends $pb.GeneratedMessage {
..aOM<$0.EntityId>(2, _omitFieldNames ? '' : 'issuer', subBuilder: $0.EntityId.create)
..aOM<$0.EntityId>(3, _omitFieldNames ? '' : 'bearer', subBuilder: $0.EntityId.create)
..aOM<$0.EntityId>(4, _omitFieldNames ? '' : 'audience', subBuilder: $0.EntityId.create)
..aOM<$4.Entity>(5, _omitFieldNames ? '' : 'claims', subBuilder: $4.Entity.create)
..pc<$5.Policy>(6, _omitFieldNames ? '' : 'caveats', $pb.PbFieldType.PM, subBuilder: $5.Policy.create)
..aOM<$3.Entity>(5, _omitFieldNames ? '' : 'claims', subBuilder: $3.Entity.create)
..pc<$4.Expr>(6, _omitFieldNames ? '' : 'caveats', $pb.PbFieldType.PM, subBuilder: $4.Expr.create)
..a<$core.List<$core.int>>(999, _omitFieldNames ? '' : 'signature', $pb.PbFieldType.OY)
..hasRequiredFields = false
;
Expand Down Expand Up @@ -137,23 +137,24 @@ class Cork extends $pb.GeneratedMessage {

/// Claims made about the [bearer] of the cork.
@$pb.TagNumber(5)
$4.Entity get claims => $_getN(4);
$3.Entity get claims => $_getN(4);
@$pb.TagNumber(5)
set claims($4.Entity v) { setField(5, v); }
set claims($3.Entity v) { setField(5, v); }
@$pb.TagNumber(5)
$core.bool hasClaims() => $_has(4);
@$pb.TagNumber(5)
void clearClaims() => clearField(5);
@$pb.TagNumber(5)
$4.Entity ensureClaims() => $_ensure(4);
$3.Entity ensureClaims() => $_ensure(4);

/// The caveats to this cork's validity and usage.
///
///
/// Caveats are structured conditions which must be met for the cork to be considered
/// valid and for its claims to be considered true.
///
/// Effectively, these form the body of a `forbid unless` policy AND'd together.
@$pb.TagNumber(6)
$core.List<$5.Policy> get caveats => $_getList(5);
$core.List<$4.Expr> get caveats => $_getList(5);

/// The final signature of the cork.
@$pb.TagNumber(999)
Expand Down
8 changes: 4 additions & 4 deletions dart/lib/src/proto/cedar/v3/cork.pbjson.dart
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ const Cork$json = {
{'1': 'bearer', '3': 3, '4': 1, '5': 11, '6': '.cedar.v3.EntityId', '10': 'bearer'},
{'1': 'audience', '3': 4, '4': 1, '5': 11, '6': '.cedar.v3.EntityId', '9': 0, '10': 'audience', '17': true},
{'1': 'claims', '3': 5, '4': 1, '5': 11, '6': '.cedar.v3.Entity', '9': 1, '10': 'claims', '17': true},
{'1': 'caveats', '3': 6, '4': 3, '5': 11, '6': '.cedar.v3.Policy', '10': 'caveats'},
{'1': 'caveats', '3': 6, '4': 3, '5': 11, '6': '.cedar.v3.Expr', '10': 'caveats'},
{'1': 'signature', '3': 999, '4': 1, '5': 12, '10': 'signature'},
],
'8': [
Expand All @@ -36,7 +36,7 @@ final $typed_data.Uint8List corkDescriptor = $convert.base64Decode(
'CgRDb3JrEg4KAmlkGAEgASgMUgJpZBIqCgZpc3N1ZXIYAiABKAsyEi5jZWRhci52My5FbnRpdH'
'lJZFIGaXNzdWVyEioKBmJlYXJlchgDIAEoCzISLmNlZGFyLnYzLkVudGl0eUlkUgZiZWFyZXIS'
'MwoIYXVkaWVuY2UYBCABKAsyEi5jZWRhci52My5FbnRpdHlJZEgAUghhdWRpZW5jZYgBARItCg'
'ZjbGFpbXMYBSABKAsyEC5jZWRhci52My5FbnRpdHlIAVIGY2xhaW1ziAEBEioKB2NhdmVhdHMY'
'BiADKAsyEC5jZWRhci52My5Qb2xpY3lSB2NhdmVhdHMSHQoJc2lnbmF0dXJlGOcHIAEoDFIJc2'
'lnbmF0dXJlQgsKCV9hdWRpZW5jZUIJCgdfY2xhaW1z');
'ZjbGFpbXMYBSABKAsyEC5jZWRhci52My5FbnRpdHlIAVIGY2xhaW1ziAEBEigKB2NhdmVhdHMY'
'BiADKAsyDi5jZWRhci52My5FeHByUgdjYXZlYXRzEh0KCXNpZ25hdHVyZRjnByABKAxSCXNpZ2'
'5hdHVyZUILCglfYXVkaWVuY2VCCQoHX2NsYWltcw==');

12 changes: 6 additions & 6 deletions dart/lib/src/proto/cedar/v3/policy.pb.dart
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import 'dart:core' as $core;
import 'package:protobuf/protobuf.dart' as $pb;

import 'entity_id.pb.dart' as $0;
import 'expr.pb.dart' as $3;
import 'expr.pb.dart' as $4;
import 'policy.pbenum.dart';

export 'policy.pbenum.dart';
Expand Down Expand Up @@ -428,7 +428,7 @@ class PolicyResource extends $pb.GeneratedMessage {
class PolicyCondition extends $pb.GeneratedMessage {
factory PolicyCondition({
PolicyConditionKind? kind,
$3.Expr? body,
$4.Expr? body,
}) {
final $result = create();
if (kind != null) {
Expand All @@ -445,7 +445,7 @@ class PolicyCondition extends $pb.GeneratedMessage {

static final $pb.BuilderInfo _i = $pb.BuilderInfo(_omitMessageNames ? '' : 'PolicyCondition', package: const $pb.PackageName(_omitMessageNames ? '' : 'cedar.v3'), createEmptyInstance: create)
..e<PolicyConditionKind>(1, _omitFieldNames ? '' : 'kind', $pb.PbFieldType.OE, defaultOrMaker: PolicyConditionKind.POLICY_CONDITION_KIND_UNSPECIFIED, valueOf: PolicyConditionKind.valueOf, enumValues: PolicyConditionKind.values)
..aOM<$3.Expr>(2, _omitFieldNames ? '' : 'body', subBuilder: $3.Expr.create)
..aOM<$4.Expr>(2, _omitFieldNames ? '' : 'body', subBuilder: $4.Expr.create)
..hasRequiredFields = false
;

Expand Down Expand Up @@ -480,15 +480,15 @@ class PolicyCondition extends $pb.GeneratedMessage {
void clearKind() => clearField(1);

@$pb.TagNumber(2)
$3.Expr get body => $_getN(1);
$4.Expr get body => $_getN(1);
@$pb.TagNumber(2)
set body($3.Expr v) { setField(2, v); }
set body($4.Expr v) { setField(2, v); }
@$pb.TagNumber(2)
$core.bool hasBody() => $_has(1);
@$pb.TagNumber(2)
void clearBody() => clearField(2);
@$pb.TagNumber(2)
$3.Expr ensureBody() => $_ensure(1);
$4.Expr ensureBody() => $_ensure(1);
}


Expand Down
48 changes: 24 additions & 24 deletions dart/lib/src/proto/corks/v1/cork.pb.dart
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import 'dart:core' as $core;

import 'package:protobuf/protobuf.dart' as $pb;

import '../../google/protobuf/any.pb.dart' as $6;
import '../../google/protobuf/any.pb.dart' as $5;

/// Encodes a cork's metadata and its signature.
///
Expand All @@ -25,11 +25,11 @@ import '../../google/protobuf/any.pb.dart' as $6;
class Cork extends $pb.GeneratedMessage {
factory Cork({
$core.List<$core.int>? id,
$6.Any? issuer,
$6.Any? bearer,
$6.Any? audience,
$6.Any? claims,
$core.Iterable<$6.Any>? caveats,
$5.Any? issuer,
$5.Any? bearer,
$5.Any? audience,
$5.Any? claims,
$core.Iterable<$5.Any>? caveats,
$core.List<$core.int>? signature,
}) {
final $result = create();
Expand Down Expand Up @@ -62,11 +62,11 @@ class Cork extends $pb.GeneratedMessage {

static final $pb.BuilderInfo _i = $pb.BuilderInfo(_omitMessageNames ? '' : 'Cork', package: const $pb.PackageName(_omitMessageNames ? '' : 'corks.v1'), createEmptyInstance: create)
..a<$core.List<$core.int>>(1, _omitFieldNames ? '' : 'id', $pb.PbFieldType.OY)
..aOM<$6.Any>(2, _omitFieldNames ? '' : 'issuer', subBuilder: $6.Any.create)
..aOM<$6.Any>(3, _omitFieldNames ? '' : 'bearer', subBuilder: $6.Any.create)
..aOM<$6.Any>(4, _omitFieldNames ? '' : 'audience', subBuilder: $6.Any.create)
..aOM<$6.Any>(5, _omitFieldNames ? '' : 'claims', subBuilder: $6.Any.create)
..pc<$6.Any>(6, _omitFieldNames ? '' : 'caveats', $pb.PbFieldType.PM, subBuilder: $6.Any.create)
..aOM<$5.Any>(2, _omitFieldNames ? '' : 'issuer', subBuilder: $5.Any.create)
..aOM<$5.Any>(3, _omitFieldNames ? '' : 'bearer', subBuilder: $5.Any.create)
..aOM<$5.Any>(4, _omitFieldNames ? '' : 'audience', subBuilder: $5.Any.create)
..aOM<$5.Any>(5, _omitFieldNames ? '' : 'claims', subBuilder: $5.Any.create)
..pc<$5.Any>(6, _omitFieldNames ? '' : 'caveats', $pb.PbFieldType.PM, subBuilder: $5.Any.create)
..a<$core.List<$core.int>>(999, _omitFieldNames ? '' : 'signature', $pb.PbFieldType.OY)
..hasRequiredFields = false
;
Expand Down Expand Up @@ -104,55 +104,55 @@ class Cork extends $pb.GeneratedMessage {

/// The encoded issuer of the cork.
@$pb.TagNumber(2)
$6.Any get issuer => $_getN(1);
$5.Any get issuer => $_getN(1);
@$pb.TagNumber(2)
set issuer($6.Any v) { setField(2, v); }
set issuer($5.Any v) { setField(2, v); }
@$pb.TagNumber(2)
$core.bool hasIssuer() => $_has(1);
@$pb.TagNumber(2)
void clearIssuer() => clearField(2);
@$pb.TagNumber(2)
$6.Any ensureIssuer() => $_ensure(1);
$5.Any ensureIssuer() => $_ensure(1);

/// The encoded bearer of the cork.
@$pb.TagNumber(3)
$6.Any get bearer => $_getN(2);
$5.Any get bearer => $_getN(2);
@$pb.TagNumber(3)
set bearer($6.Any v) { setField(3, v); }
set bearer($5.Any v) { setField(3, v); }
@$pb.TagNumber(3)
$core.bool hasBearer() => $_has(2);
@$pb.TagNumber(3)
void clearBearer() => clearField(3);
@$pb.TagNumber(3)
$6.Any ensureBearer() => $_ensure(2);
$5.Any ensureBearer() => $_ensure(2);

/// The encoded audience of the cork.
@$pb.TagNumber(4)
$6.Any get audience => $_getN(3);
$5.Any get audience => $_getN(3);
@$pb.TagNumber(4)
set audience($6.Any v) { setField(4, v); }
set audience($5.Any v) { setField(4, v); }
@$pb.TagNumber(4)
$core.bool hasAudience() => $_has(3);
@$pb.TagNumber(4)
void clearAudience() => clearField(4);
@$pb.TagNumber(4)
$6.Any ensureAudience() => $_ensure(3);
$5.Any ensureAudience() => $_ensure(3);

/// The encoded claims of the cork.
@$pb.TagNumber(5)
$6.Any get claims => $_getN(4);
$5.Any get claims => $_getN(4);
@$pb.TagNumber(5)
set claims($6.Any v) { setField(5, v); }
set claims($5.Any v) { setField(5, v); }
@$pb.TagNumber(5)
$core.bool hasClaims() => $_has(4);
@$pb.TagNumber(5)
void clearClaims() => clearField(5);
@$pb.TagNumber(5)
$6.Any ensureClaims() => $_ensure(4);
$5.Any ensureClaims() => $_ensure(4);

/// The encoded caveats of the cork.
@$pb.TagNumber(6)
$core.List<$6.Any> get caveats => $_getList(5);
$core.List<$5.Any> get caveats => $_getList(5);

/// The final signature of the cork.
@$pb.TagNumber(999)
Expand Down
28 changes: 7 additions & 21 deletions dart/test/cedar_cork_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -32,28 +32,14 @@ final bKey = secretKey;
final issuer = CedarEntityId('Organization', 'acme-corp');
final bearer = CedarEntityId('User', 'alice');

final _caveat = CedarPolicy(
effect: CedarPolicyEffect.forbid,
principal: CedarPolicyPrincipal(
op: CedarPolicyOp.equals,
entity: bearer,
final _caveat = JsonExpr.equals(
JsonExpr.getAttribute(
JsonExpr.variable(CedarVariable.principal),
'name',
),
JsonExpr.value(
CedarValueJson.string('Alice'),
),
action: CedarPolicyAction(op: CedarPolicyOp.all),
resource: CedarPolicyResource(op: CedarPolicyOp.all),
conditions: [
CedarPolicyCondition(
kind: CedarPolicyConditionKind.unless,
body: JsonExpr.equals(
JsonExpr.getAttribute(
JsonExpr.variable(CedarVariable.principal),
'name',
),
JsonExpr.value(
CedarValueJson.string('Alice'),
),
),
),
],
);

final _tests = <_TestCase>[
Expand Down
10 changes: 9 additions & 1 deletion go/cedar/expr/expr.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,15 @@ package cedarexpr

import cedarv3 "github.com/celest-dev/corks/go/proto/cedar/v3"

type Expr = cedarv3.Expr
type Expr cedarv3.Expr

func (e *Expr) Raw() *cedarv3.Expr {
if e == nil {
return nil
}
return (*cedarv3.Expr)(e)
}

type Value = cedarv3.Expr_Value
type Var = cedarv3.Expr_Var
type Slot = cedarv3.Expr_Slot
Expand Down
2 changes: 1 addition & 1 deletion go/cedar/policy.go
Original file line number Diff line number Diff line change
Expand Up @@ -139,7 +139,7 @@ func (c *PolicyCondition) Raw() *cedarv3.PolicyCondition {
}
return &cedarv3.PolicyCondition{
Kind: c.Kind.Raw(),
Body: c.Body,
Body: c.Body.Raw(),
}
}

Expand Down
29 changes: 18 additions & 11 deletions go/cedarcork/cedarcork.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import (

corks "github.com/celest-dev/corks/go"
"github.com/celest-dev/corks/go/cedar"
cedarexpr "github.com/celest-dev/corks/go/cedar/expr"
cedarv3 "github.com/celest-dev/corks/go/proto/cedar/v3"
)

Expand Down Expand Up @@ -77,21 +78,27 @@ func (c *Cork) Claims() *cedarv3.Entity {
return entity
}

func (c *Cork) Caveats() []*cedarv3.Policy {
func (c *Cork) Caveats() []*cedarv3.Expr {
if c == nil {
return nil
}
caveats := c.Cork.Caveats()
policies := make([]*cedarv3.Policy, len(caveats))
expressions := make([]*cedarv3.Expr, len(caveats))
for i, caveat := range caveats {
policy := new(cedarv3.Policy)
err := caveat.UnmarshalTo(policy)
expression := new(cedarv3.Expr)
err := caveat.UnmarshalTo(expression)
if err != nil {
return nil
}
policies[i] = policy
expressions[i] = expression
}
return policies
return expressions
}

// Rebuild returns a new builder with the cork's data.
func (c *Cork) Rebuild() *builder {
b := &builder{Builder: c.Cork.Rebuild()}
return b
}

type builder struct {
Expand Down Expand Up @@ -129,12 +136,12 @@ func (b *builder) Claims(claims *cedar.Entity) *builder {
}

// Caveat adds a caveat to the cork.
func (b *builder) Caveat(caveat *cedar.Policy) *builder {
if caveat.Effect != cedar.EffectForbid {
b.errors = append(b.errors, errors.New("only forbid policies are allowed"))
} else {
b.Builder.Caveat(caveat.Raw())
func (b *builder) Caveat(caveat *cedarexpr.Expr) *builder {
if caveat == nil {
b.errors = append(b.errors, fmt.Errorf("%w: caveat is nil", corks.ErrInvalidCork))
return b
}
b.Builder.Caveat(caveat.Raw())
return b
}

Expand Down
Loading

0 comments on commit 49ea053

Please sign in to comment.