From fc0738269e16bd4ff429c4dbe49a557bc0e7e611 Mon Sep 17 00:00:00 2001 From: mo khan Date: Thu, 20 Mar 2025 10:49:23 -0600 Subject: feat: add a cedar policy --- cedar.conf | 5 +++++ cedar.json | 24 ++++++++++++++++++++++++ go.mod | 2 ++ go.sum | 4 ++++ pkg/app/app.go | 43 +++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 78 insertions(+) create mode 100644 cedar.conf create mode 100644 cedar.json diff --git a/cedar.conf b/cedar.conf new file mode 100644 index 0000000..0d032bc --- /dev/null +++ b/cedar.conf @@ -0,0 +1,5 @@ +permit ( + principal == Subject::"*", + action == Action::"GET", + resource in Path::"/projects.json" +); diff --git a/cedar.json b/cedar.json new file mode 100644 index 0000000..c170a3b --- /dev/null +++ b/cedar.json @@ -0,0 +1,24 @@ +[ + { + "uid": { + "type": "User", + "id": "*" + } + }, + { + "uid": { + "type": "Project", + "id": "3" + }, + "parents": [ + { + "type": "Group", + "id": "3" + }, + { + "type": "Path", + "id": "/projects.json" + } + ] + } +] diff --git a/go.mod b/go.mod index 75eeac7..a6849a7 100644 --- a/go.mod +++ b/go.mod @@ -4,6 +4,7 @@ go 1.24.0 require ( github.com/casbin/casbin/v3 v3.0.0-beta.7 + github.com/cedar-policy/cedar-go v1.1.1 github.com/lestrrat-go/jwx/v3 v3.0.0-alpha3 github.com/magefile/mage v1.15.0 github.com/playwright-community/playwright-go v0.5001.0 @@ -32,6 +33,7 @@ require ( github.com/pmezard/go-difflib v1.0.0 // indirect github.com/segmentio/asm v1.2.0 // indirect golang.org/x/crypto v0.36.0 // indirect + golang.org/x/exp v0.0.0-20240222234643-814bf88cf225 // indirect golang.org/x/sys v0.31.0 // indirect google.golang.org/protobuf v1.28.1 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect diff --git a/go.sum b/go.sum index 93f55df..7b93d7e 100644 --- a/go.sum +++ b/go.sum @@ -4,6 +4,8 @@ github.com/arthurnn/twirp-ruby v1.13.0 h1:j0T7I5oxe2niKFdfjiiCmkiydwYeegrbwVMs+G github.com/arthurnn/twirp-ruby v1.13.0/go.mod h1:1fVOQuSLzwXoPi9/ejlDYG3roilJIPAZN2sw+A3o48o= github.com/casbin/casbin/v3 v3.0.0-beta.7 h1:siS3e6cRtuyFlshUgJfw0wnWuK3z3U/ald0C8Jtof24= github.com/casbin/casbin/v3 v3.0.0-beta.7/go.mod h1:69HoI+h4yMUTydUMxT7VQh7FgGpoJsB/ZskkVGcvasQ= +github.com/cedar-policy/cedar-go v1.1.1 h1:yXCEaYQCXC+BxbOx/8TDHQu4dfuWVLs8irGrGjqClu0= +github.com/cedar-policy/cedar-go v1.1.1/go.mod h1:pEgiK479O5dJfzXnTguOMm+bCplzy5rEEFPGdZKPWz4= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= @@ -68,6 +70,8 @@ golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5y golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU= golang.org/x/crypto v0.36.0 h1:AnAEvhDddvBdpY+uR+MyHmuZzzNqXSe/GvuDeob5L34= golang.org/x/crypto v0.36.0/go.mod h1:Y4J0ReaxCR1IMaabaSMugxJES1EpwhBHhv2bDHklZvc= +golang.org/x/exp v0.0.0-20240222234643-814bf88cf225 h1:LfspQV/FYTatPTr/3HzIcmiUFH7PGP+OQ6mgDYo3yuQ= +golang.org/x/exp v0.0.0-20240222234643-814bf88cf225/go.mod h1:CxmFvTBINI24O/j8iY7H1xHzx2i4OsyguNBmN/uPtqc= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= diff --git a/pkg/app/app.go b/pkg/app/app.go index fd6a3f1..6e50dad 100644 --- a/pkg/app/app.go +++ b/pkg/app/app.go @@ -1,11 +1,16 @@ package app import ( + "encoding/json" "fmt" + "log" "net" "net/http" + "os" "github.com/casbin/casbin/v3" + cedar "github.com/cedar-policy/cedar-go" + "github.com/cedar-policy/cedar-go/types" "github.com/xlgmokha/x/pkg/x" "gitlab.com/mokhax/spike/pkg/authz" "gitlab.com/mokhax/spike/pkg/cfg" @@ -36,9 +41,47 @@ func WithCasbin() authz.Authorizer { }) } +func WithCedar() authz.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 { + log.Fatal(err) + } + return authz.AuthorizerFunc(func(r *http.Request) bool { + host, _, err := net.SplitHostPort(r.Host) + if err != nil { + return false + } + + subject, found := authz.TokenFrom(r).Subject() + if !found { + subject = "*" + } + + req := 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), + }), + } + + 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 + }) +} + func Start(bindAddr string) error { return srv.Run(cfg.New( bindAddr, + // cfg.WithMux(authz.HTTP(WithCedar(), Routes())), cfg.WithMux(authz.HTTP(WithCasbin(), Routes())), )) } -- cgit v1.2.3