diff options
| author | mo khan <mo@mokhan.ca> | 2025-04-02 18:13:52 -0600 |
|---|---|---|
| committer | mo khan <mo@mokhan.ca> | 2025-04-02 18:13:52 -0600 |
| commit | 96f7120703a46bcd26bf0bf140d7127adc1ade4a (patch) | |
| tree | da51b52747e8e1b946a75b02479e96bb8ed36b7f | |
| parent | d8bb19101c155adddd942e3fa908ebec5b5ae7c1 (diff) | |
refactor: update gtwy cedar policy
| -rw-r--r-- | pkg/gid/gid.go | 4 | ||||
| -rw-r--r-- | pkg/policies/gtwy.cedar | 18 | ||||
| -rw-r--r-- | pkg/policies/policies_test.go | 131 |
3 files changed, 104 insertions, 49 deletions
diff --git a/pkg/gid/gid.go b/pkg/gid/gid.go index 3b9b29b..7d1ea97 100644 --- a/pkg/gid/gid.go +++ b/pkg/gid/gid.go @@ -30,3 +30,7 @@ func NewEntityUID(globalID string) cedar.EntityUID { func DefaultEntityUID(id string) cedar.EntityUID { return cedar.NewEntityUID("User", cedar.String(id)) } + +func ZeroEntityUID() cedar.EntityUID { + return cedar.NewEntityUID("", "") +} diff --git a/pkg/policies/gtwy.cedar b/pkg/policies/gtwy.cedar index 763ab5f..a236e08 100644 --- a/pkg/policies/gtwy.cedar +++ b/pkg/policies/gtwy.cedar @@ -1,16 +1,12 @@ -permit ( - principal == User::"1", +permit( + principal is User, action in [ + HttpMethod::"DELETE", HttpMethod::"GET", - HttpMethod::"POST", - HttpMethod::"PUT", + HttpMethod::"HEAD", HttpMethod::"PATCH", - HttpMethod::"DELETE", - HttpMethod::"HEAD" + HttpMethod::"POST", + HttpMethod::"PUT" ], resource -) when { - context.host == "api.example.com" || - context.host == "idp.example.com" || - context.host == "ui.example.com" -}; +); diff --git a/pkg/policies/policies_test.go b/pkg/policies/policies_test.go index 67179a7..24ef6c6 100644 --- a/pkg/policies/policies_test.go +++ b/pkg/policies/policies_test.go @@ -11,80 +11,135 @@ import ( func build(f func(*cedar.Request)) *cedar.Request { request := &cedar.Request{ - Principal: gid.NewEntityUID("gid://User/1"), - Action: cedar.NewEntityUID("HttpMethod", cedar.String("GET")), - Resource: cedar.NewEntityUID("HttpPath", cedar.String("/projects.json")), - Context: cedar.NewRecord(cedar.RecordMap{"host": cedar.String("api.example.com")}), - } - if f != nil { - f(request) + Principal: gid.NewEntityUID("gid://example/User/1"), + Action: cedar.NewEntityUID("HttpMethod", "GET"), + Resource: cedar.NewEntityUID("HttpPath", "/"), + Context: cedar.NewRecord(cedar.RecordMap{ + "host": cedar.String("idp.example.com"), + }), } + f(request) return request } func TestAllowed(t *testing.T) { allowed := []*cedar.Request{ build(func(r *cedar.Request) {}), - build(func(r *cedar.Request) { r.Action = cedar.NewEntityUID("HttpMethod", cedar.String("POST")) }), - build(func(r *cedar.Request) { r.Action = cedar.NewEntityUID("HttpMethod", cedar.String("PUT")) }), - build(func(r *cedar.Request) { r.Action = cedar.NewEntityUID("HttpMethod", cedar.String("PATCH")) }), - build(func(r *cedar.Request) { r.Action = cedar.NewEntityUID("HttpMethod", cedar.String("DELETE")) }), - build(func(r *cedar.Request) { r.Action = cedar.NewEntityUID("HttpMethod", cedar.String("HEAD")) }), build(func(r *cedar.Request) { - r.Resource = cedar.NewEntityUID("HttpPath", cedar.String("/organizations.json")) + r.Principal = gid.NewEntityUID("gid://example/User/1") + r.Action = cedar.NewEntityUID("HttpMethod", "POST") }), - build(func(r *cedar.Request) { r.Resource = cedar.NewEntityUID("HttpPath", cedar.String("/groups.json")) }), build(func(r *cedar.Request) { - r.Resource = cedar.NewEntityUID("HttpPath", cedar.String("/.well-known/openid-configuration")) - r.Context = cedar.NewRecord(cedar.RecordMap{"host": cedar.String("idp.example.com")}) + r.Principal = gid.NewEntityUID("gid://example/User/1") + r.Action = cedar.NewEntityUID("HttpMethod", "PUT") }), build(func(r *cedar.Request) { - r.Resource = cedar.NewEntityUID("HttpPath", cedar.String("/.well-known/oauth-authorization-server")) - r.Context = cedar.NewRecord(cedar.RecordMap{"host": cedar.String("idp.example.com")}) + r.Principal = gid.NewEntityUID("gid://example/User/1") + r.Action = cedar.NewEntityUID("HttpMethod", "PATCH") }), - // build(func(r *cedar.Request) { - // r.Principal = gid.NewEntityUID("gid://User/*") - // r.Resource = cedar.NewEntityUID("HttpPath", cedar.String("/.well-known/openid-configuration")) - // r.Context = cedar.NewRecord(cedar.RecordMap{"host": cedar.String("idp.example.com")}) - // }), - // build(func(r *cedar.Request) { - // r.Principal = gid.NewEntityUID("gid://User/*") - // r.Resource = cedar.NewEntityUID("HttpPath", cedar.String("/.well-known/oauth-authorization-server")) - // r.Context = cedar.NewRecord(cedar.RecordMap{"host": cedar.String("idp.example.com")}) - // }), build(func(r *cedar.Request) { - r.Action = cedar.NewEntityUID("HttpMethod", cedar.String("POST")) - r.Resource = cedar.NewEntityUID("HttpPath", cedar.String("/twirp/authx.rpc.Ability/Allowed")) - r.Context = cedar.NewRecord(cedar.RecordMap{"host": cedar.String("idp.example.com")}) + r.Principal = gid.NewEntityUID("gid://example/User/1") + r.Action = cedar.NewEntityUID("HttpMethod", "DELETE") + }), + build(func(r *cedar.Request) { + r.Principal = gid.NewEntityUID("gid://example/User/1") + r.Action = cedar.NewEntityUID("HttpMethod", "HEAD") + }), + build(func(r *cedar.Request) { + r.Principal = gid.NewEntityUID("gid://example/User/1") + r.Resource = cedar.NewEntityUID("HttpPath", "/organizations.json") + r.Context = cedar.NewRecord(cedar.RecordMap{ + "host": cedar.String("api.example.com"), + }) + }), + build(func(r *cedar.Request) { + r.Principal = gid.NewEntityUID("gid://example/User/1") + r.Resource = cedar.NewEntityUID("HttpPath", "/groups.json") + r.Context = cedar.NewRecord(cedar.RecordMap{ + "host": cedar.String("api.example.com"), + }) + }), + build(func(r *cedar.Request) { + r.Principal = gid.NewEntityUID("gid://example/User/1") + r.Resource = cedar.NewEntityUID("HttpPath", "/.well-known/openid-configuration") + r.Context = cedar.NewRecord(cedar.RecordMap{ + "host": cedar.String("idp.example.com"), + }) + }), + build(func(r *cedar.Request) { + r.Principal = gid.NewEntityUID("gid://example/User/1") + r.Resource = cedar.NewEntityUID("HttpPath", "/.well-known/oauth-authorization-server") + r.Context = cedar.NewRecord(cedar.RecordMap{ + "host": cedar.String("idp.example.com"), + }) }), build(func(r *cedar.Request) { - r.Action = cedar.NewEntityUID("HttpMethod", cedar.String("GET")) - r.Resource = cedar.NewEntityUID("HttpPath", cedar.String("/index.html")) - r.Context = cedar.NewRecord(cedar.RecordMap{"host": cedar.String("ui.example.com")}) + r.Principal = gid.NewEntityUID("gid://example/User/*") + r.Resource = cedar.NewEntityUID("HttpPath", "/.well-known/openid-configuration") + r.Context = cedar.NewRecord(cedar.RecordMap{ + "host": cedar.String("idp.example.com"), + }) + }), + build(func(r *cedar.Request) { + r.Principal = gid.NewEntityUID("gid://example/User/*") + r.Resource = cedar.NewEntityUID("HttpPath", "/.well-known/oauth-authorization-server") + r.Context = cedar.NewRecord(cedar.RecordMap{ + "host": cedar.String("idp.example.com"), + }) + }), + build(func(r *cedar.Request) { + r.Principal = gid.NewEntityUID("gid://example/User/1") + r.Action = cedar.NewEntityUID("HttpMethod", "POST") + r.Resource = cedar.NewEntityUID("HttpPath", "/twirp/authx.rpc.Ability/Allowed") + r.Context = cedar.NewRecord(cedar.RecordMap{ + "host": cedar.String("idp.example.com"), + }) + }), + build(func(r *cedar.Request) { + r.Principal = gid.NewEntityUID("gid://example/User/1") + r.Action = cedar.NewEntityUID("HttpMethod", "GET") + r.Resource = cedar.NewEntityUID("HttpPath", "/index.html") + r.Context = cedar.NewRecord(cedar.RecordMap{ + "host": cedar.String("ui.example.com"), + }) }), } for _, tt := range allowed { - t.Run(fmt.Sprintf("allows: %v %v %v %v", tt.Principal, tt.Action, tt.Resource, tt.Context), func(t *testing.T) { + t.Run(fmt.Sprintf("allows: %v/%v %v %v%v", tt.Principal.Type, tt.Principal.ID, tt.Action.ID, tt.Context.Map()["host"], tt.Resource.ID), func(t *testing.T) { assert.True(t, Allowed(*tt)) }) } denied := []*cedar.Request{ build(func(r *cedar.Request) { - r.Principal = gid.NewEntityUID("gid://User/*") + r.Principal = gid.ZeroEntityUID() r.Action = cedar.NewEntityUID("HttpMethod", cedar.String("POST")) }), build(func(r *cedar.Request) { - r.Context = cedar.NewRecord(cedar.RecordMap{"host": cedar.String("unknown.example.com")}) + r.Principal = gid.ZeroEntityUID() + r.Action = cedar.NewEntityUID("HttpMethod", cedar.String("PUT")) + }), + build(func(r *cedar.Request) { + r.Principal = gid.ZeroEntityUID() + r.Action = cedar.NewEntityUID("HttpMethod", cedar.String("PATCH")) + }), + build(func(r *cedar.Request) { + r.Principal = gid.ZeroEntityUID() + r.Action = cedar.NewEntityUID("HttpMethod", cedar.String("DELETE")) + }), + build(func(r *cedar.Request) { + r.Principal = gid.ZeroEntityUID() + r.Action = cedar.NewEntityUID("HttpMethod", cedar.String("HEAD")) }), build(func(r *cedar.Request) { + r.Principal = gid.ZeroEntityUID() r.Action = cedar.NewEntityUID("HttpMethod", cedar.String("TRACE")) }), } for _, tt := range denied { - t.Run(fmt.Sprintf("denies: %v %v %v %v", tt.Principal, tt.Action, tt.Resource, tt.Context), func(t *testing.T) { + t.Run(fmt.Sprintf("denies: %v/%v %v %v%v", tt.Principal.Type, tt.Principal.ID, tt.Action.ID, tt.Context.Map()["host"], tt.Resource.ID), func(t *testing.T) { assert.False(t, Allowed(*tt)) }) } |
