forked from cedar-policy/cedar-go
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request cedar-policy#34 from strongdm/idx-46/performance
General performance improvements and experimental batch mode
- Loading branch information
Showing
23 changed files
with
4,702 additions
and
485 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,2 +1,3 @@ | ||
.idea/ | ||
tmp/ | ||
tmp/ | ||
.DS_Store |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,116 +1,61 @@ | ||
package cedar | ||
|
||
import ( | ||
"fmt" | ||
|
||
"github.com/cedar-policy/cedar-go/internal/eval" | ||
"github.com/cedar-policy/cedar-go/types" | ||
) | ||
|
||
// A Decision is the result of the authorization. | ||
type Decision bool | ||
type Request = types.Request | ||
type Decision = types.Decision | ||
type Diagnostic = types.Diagnostic | ||
type DiagnosticReason = types.DiagnosticReason | ||
type DiagnosticError = types.DiagnosticError | ||
|
||
// Each authorization results in one of these Decisions. | ||
const ( | ||
Allow = Decision(true) | ||
Deny = Decision(false) | ||
Allow = types.Allow | ||
Deny = types.Deny | ||
) | ||
|
||
func (a Decision) String() string { | ||
if a { | ||
return "allow" | ||
} | ||
return "deny" | ||
} | ||
|
||
func (a Decision) MarshalJSON() ([]byte, error) { return []byte(`"` + a.String() + `"`), nil } | ||
|
||
func (a *Decision) UnmarshalJSON(b []byte) error { | ||
*a = string(b) == `"allow"` | ||
return nil | ||
} | ||
|
||
// A Diagnostic details the errors and reasons for an authorization decision. | ||
type Diagnostic struct { | ||
Reasons []Reason `json:"reasons,omitempty"` | ||
Errors []Error `json:"errors,omitempty"` | ||
} | ||
|
||
// An Error details the Policy index within a PolicySet, the Position within the | ||
// text document, and the resulting error message. | ||
type Error struct { | ||
PolicyID PolicyID `json:"policy"` | ||
Position Position `json:"position"` | ||
Message string `json:"message"` | ||
} | ||
|
||
func (e Error) String() string { | ||
return fmt.Sprintf("while evaluating policy `%v`: %v", e.PolicyID, e.Message) | ||
} | ||
|
||
// A Reason details the Policy index within a PolicySet, and the Position within | ||
// the text document. | ||
type Reason struct { | ||
PolicyID PolicyID `json:"policy"` | ||
Position Position `json:"position"` | ||
} | ||
|
||
// A Request is the Principal, Action, Resource, and Context portion of an | ||
// authorization request. | ||
type Request struct { | ||
Principal types.EntityUID `json:"principal"` | ||
Action types.EntityUID `json:"action"` | ||
Resource types.EntityUID `json:"resource"` | ||
Context types.Record `json:"context"` | ||
} | ||
|
||
// IsAuthorized uses the combination of the PolicySet and Entities to determine | ||
// if the given Request to determine Decision and Diagnostic. | ||
func (p PolicySet) IsAuthorized(entityMap types.Entities, req Request) (Decision, Diagnostic) { | ||
c := &eval.Context{ | ||
c := eval.InitEnv(&eval.Env{ | ||
Entities: entityMap, | ||
Principal: req.Principal, | ||
Action: req.Action, | ||
Resource: req.Resource, | ||
Context: req.Context, | ||
} | ||
}) | ||
var diag Diagnostic | ||
var gotForbid bool | ||
var forbidReasons []Reason | ||
var gotPermit bool | ||
var permitReasons []Reason | ||
var forbids []DiagnosticReason | ||
var permits []DiagnosticReason | ||
// Don't try to short circuit this. | ||
// - Even though single forbid means forbid | ||
// - All policy should be run to collect errors | ||
// - For permit, all permits must be run to collect annotations | ||
// - For forbid, forbids must be run to collect annotations | ||
for id, po := range p.policies { | ||
v, err := po.eval.Eval(c) | ||
result, err := po.eval.Eval(c) | ||
if err != nil { | ||
diag.Errors = append(diag.Errors, Error{PolicyID: id, Position: po.Position(), Message: err.Error()}) | ||
diag.Errors = append(diag.Errors, DiagnosticError{PolicyID: id, Position: po.Position(), Message: err.Error()}) | ||
continue | ||
} | ||
vb, err := eval.ValueToBool(v) | ||
if err != nil { | ||
// should never happen, maybe remove this case | ||
diag.Errors = append(diag.Errors, Error{PolicyID: id, Position: po.Position(), Message: err.Error()}) | ||
continue | ||
} | ||
if !vb { | ||
if !result { | ||
continue | ||
} | ||
if po.Effect() == Forbid { | ||
forbidReasons = append(forbidReasons, Reason{PolicyID: id, Position: po.Position()}) | ||
gotForbid = true | ||
forbids = append(forbids, DiagnosticReason{PolicyID: id, Position: po.Position()}) | ||
} else { | ||
permitReasons = append(permitReasons, Reason{PolicyID: id, Position: po.Position()}) | ||
gotPermit = true | ||
permits = append(permits, DiagnosticReason{PolicyID: id, Position: po.Position()}) | ||
} | ||
} | ||
if gotForbid { | ||
diag.Reasons = forbidReasons | ||
} else if gotPermit { | ||
diag.Reasons = permitReasons | ||
if len(forbids) > 0 { | ||
diag.Reasons = forbids | ||
return Deny, diag | ||
} | ||
if len(permits) > 0 { | ||
diag.Reasons = permits | ||
return Allow, diag | ||
} | ||
return Decision(gotPermit && !gotForbid), diag | ||
return Deny, diag | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.