Commit 96f7120
Changed files (3)
pkg
gid
policies
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("", "")
+}
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"
-};
+);
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))
})
}