diff options
| author | mo khan <mo@mokhan.ca> | 2025-04-02 11:23:47 -0600 |
|---|---|---|
| committer | mo khan <mo@mokhan.ca> | 2025-04-02 11:23:47 -0600 |
| commit | 3f54e2fc59f21029813863491b37e39bb6015115 (patch) | |
| tree | 423d1d427e4d340d8030d3c9d98794084c0d5edb | |
| parent | e8708d505dfbe6c3ecbf41afb9732b73b6f1f156 (diff) | |
refactor: move policies and entities in policies package
| -rw-r--r-- | cedar.conf | 5 | ||||
| -rw-r--r-- | cedar.json | 24 | ||||
| -rw-r--r-- | pkg/authz/cedar.go | 35 | ||||
| -rw-r--r-- | pkg/policies/entities.json | 47 | ||||
| -rw-r--r-- | pkg/policies/init.go | 54 | ||||
| -rw-r--r-- | pkg/policies/rest.cedar | 41 | ||||
| -rw-r--r-- | pkg/rpc/ability_service.go (renamed from pkg/rpc/ability_handler.go) | 0 | ||||
| -rw-r--r-- | pkg/rpc/server_test.go | 12 |
8 files changed, 130 insertions, 88 deletions
diff --git a/cedar.conf b/cedar.conf deleted file mode 100644 index 0d032bc..0000000 --- a/cedar.conf +++ /dev/null @@ -1,5 +0,0 @@ -permit ( - principal == Subject::"*", - action == Action::"GET", - resource in Path::"/projects.json" -); diff --git a/cedar.json b/cedar.json deleted file mode 100644 index c170a3b..0000000 --- a/cedar.json +++ /dev/null @@ -1,24 +0,0 @@ -[ - { - "uid": { - "type": "User", - "id": "*" - } - }, - { - "uid": { - "type": "Project", - "id": "3" - }, - "parents": [ - { - "type": "Group", - "id": "3" - }, - { - "type": "Path", - "id": "/projects.json" - } - ] - } -] diff --git a/pkg/authz/cedar.go b/pkg/authz/cedar.go index 1d95265..7a92f8e 100644 --- a/pkg/authz/cedar.go +++ b/pkg/authz/cedar.go @@ -1,53 +1,26 @@ package authz import ( - "encoding/json" - "fmt" - "net" "net/http" - "os" cedar "github.com/cedar-policy/cedar-go" - "github.com/cedar-policy/cedar-go/types" - "github.com/xlgmokha/x/pkg/x" - xlog "gitlab.com/mokhax/spike/pkg/log" + "gitlab.com/mokhax/spike/pkg/policies" ) func WithCedar() Authorizer { - var policy cedar.Policy - x.Check(policy.UnmarshalCedar(x.Must(os.ReadFile("cedar.conf")))) - - policies := cedar.NewPolicySet() - policies.Add("cedar.conf", &policy) - - var entities cedar.EntityMap - if err := json.Unmarshal(x.Must(os.ReadFile("cedar.json")), &entities); err != nil { - xlog.Logger.Error("Error", "error", err) - return nil - } - return AuthorizerFunc(func(r *http.Request) bool { - host, _, err := net.SplitHostPort(r.Host) - if err != nil { - return false - } - subject, found := TokenFrom(r).Subject() if !found { subject = "*" } - req := cedar.Request{ + return policies.Allowed(cedar.Request{ Principal: cedar.NewEntityUID("Subject", cedar.String(subject)), Action: cedar.NewEntityUID("Action", cedar.String(r.Method)), Resource: cedar.NewEntityUID("Path", cedar.String(r.URL.Path)), Context: cedar.NewRecord(cedar.RecordMap{ - "Host": cedar.String(host), + "Host": cedar.String(r.Host), }), - } - - ok, diagnostic := policies.IsAuthorized(entities, req) - fmt.Printf("%v: %v -> %v %v%v %v\n", ok, subject, r.Method, host, r.URL.Path, diagnostic.Reasons) - return ok == types.Allow + }) }) } diff --git a/pkg/policies/entities.json b/pkg/policies/entities.json new file mode 100644 index 0000000..e6d4145 --- /dev/null +++ b/pkg/policies/entities.json @@ -0,0 +1,47 @@ +[ + { + "uid": { + "type": "User", + "id": "alice" + }, + "attrs": { + "age": 18 + }, + "parents": [] + }, + { + "uid": { + "type": "Photo", + "id": "VacationPhoto94.jpg" + }, + "attrs": {}, + "parents": [ + { + "type": "Album", + "id": "jane_vacation" + } + ] + }, + { + "uid": { + "type": "User", + "id": "1" + } + }, + { + "uid": { + "type": "Project", + "id": "3" + }, + "parents": [ + { + "type": "Group", + "id": "3" + }, + { + "type": "Path", + "id": "/projects.json" + } + ] + } +] diff --git a/pkg/policies/init.go b/pkg/policies/init.go index d455cb8..cabfbec 100644 --- a/pkg/policies/init.go +++ b/pkg/policies/init.go @@ -3,33 +3,21 @@ package policies import ( "embed" _ "embed" - "encoding/json" + "fmt" "io/fs" "log" + "strings" "github.com/cedar-policy/cedar-go" "github.com/cedar-policy/cedar-go/types" - "github.com/xlgmokha/x/pkg/x" xlog "gitlab.com/mokhax/spike/pkg/log" ) -//go:embed *.cedar +//go:embed *.cedar *.json var files embed.FS var All *cedar.PolicySet = cedar.NewPolicySet() - -const entitiesJSON = `[ - { - "uid": { "type": "User", "id": "alice" }, - "attrs": { "age": 18 }, - "parents": [] - }, - { - "uid": { "type": "Photo", "id": "VacationPhoto94.jpg" }, - "attrs": {}, - "parents": [{ "type": "Album", "id": "jane_vacation" }] - } -]` +var Entities cedar.EntityMap = cedar.EntityMap{} func init() { err := fs.WalkDir(files, ".", func(path string, d fs.DirEntry, err error) error { @@ -41,17 +29,30 @@ func init() { return nil } - content, err := fs.ReadFile(files, path) - if err != nil { - return err - } + if strings.HasSuffix(path, ".cedar") { + content, err := fs.ReadFile(files, path) + if err != nil { + return err + } - var policy cedar.Policy - if err := policy.UnmarshalCedar(content); err != nil { - return err + policy := cedar.Policy{} + if err := policy.UnmarshalCedar(content); err != nil { + return err + } + policy.SetFilename(path) + + All.Add(cedar.PolicyID(path), &policy) + } else if strings.HasSuffix(path, ".json") { + content, err := fs.ReadFile(files, path) + if err != nil { + return err + } + + if err := Entities.UnmarshalJSON(content); err != nil { + return err + } } - All.Add(cedar.PolicyID(path), &policy) return nil }) @@ -61,10 +62,9 @@ func init() { } func Allowed(request cedar.Request) bool { - var entities cedar.EntityMap - x.Check(json.Unmarshal([]byte(entitiesJSON), &entities)) + ok, diagnostic := All.IsAuthorized(Entities, request) + fmt.Printf("%v: %v -> %v %v%v\n", ok, request.Principal, request.Action, request.Context.Map(), request.Resource) - ok, diagnostic := All.IsAuthorized(entities, request) if len(diagnostic.Errors) > 0 { for err := range diagnostic.Errors { xlog.Default.Printf("%v\n", err) diff --git a/pkg/policies/rest.cedar b/pkg/policies/rest.cedar new file mode 100644 index 0000000..a889684 --- /dev/null +++ b/pkg/policies/rest.cedar @@ -0,0 +1,41 @@ +permit ( + principal == Subject::"*", + action == Action::"GET", + resource in Path::"/projects.json" +); + +permit ( + principal == Subject::"gid://User/1", + action == Action::"GET", + resource in Path::"/*.json" +); + +permit ( + principal == Subject::"gid://User/1", + action == Action::"POST", + resource in Path::"/*.json" +); + +permit ( + principal == Subject::"gid://User/1", + action == Action::"PUT", + resource in Path::"/*.json" +); + +permit ( + principal == Subject::"gid://User/1", + action == Action::"PATCH", + resource in Path::"/*.json" +); + +permit ( + principal == Subject::"gid://User/1", + action == Action::"DELETE", + resource in Path::"/*.json" +); + +permit ( + principal == Subject::"gid://User/1", + action == Action::"HEAD", + resource in Path::"/*.json" +); diff --git a/pkg/rpc/ability_handler.go b/pkg/rpc/ability_service.go index bf299da..bf299da 100644 --- a/pkg/rpc/ability_handler.go +++ b/pkg/rpc/ability_service.go diff --git a/pkg/rpc/server_test.go b/pkg/rpc/server_test.go index 266f143..8f333a5 100644 --- a/pkg/rpc/server_test.go +++ b/pkg/rpc/server_test.go @@ -41,7 +41,7 @@ func TestServer(t *testing.T) { assert.False(t, reply.Result) }) - t.Run("returns true", func(t *testing.T) { + t.Run("returns true for alice:view:jane_vacation", func(t *testing.T) { reply, err := client.Allowed(t.Context(), &AllowRequest{ Subject: "alice", Permission: "view", @@ -50,4 +50,14 @@ func TestServer(t *testing.T) { require.NoError(t, err) assert.True(t, reply.Result) }) + + t.Run("returns gid://User/1:read_projects:gid://Organization/1", func(t *testing.T) { + reply, err := client.Allowed(t.Context(), &AllowRequest{ + Subject: "gid://User/1", + Permission: "read_projects", + Resource: "gid://Organization/1", + }) + require.NoError(t, err) + assert.True(t, reply.Result) + }) } |
