diff options
| author | mo khan <mo@mokhan.ca> | 2025-03-28 17:49:09 -0600 |
|---|---|---|
| committer | mo khan <mo@mokhan.ca> | 2025-03-28 17:49:09 -0600 |
| commit | 30bbdad4ef99449f29f412d0b770e4b9f76ede42 (patch) | |
| tree | c295bb8b9020ba8a609d7a0a527a2a06fc5db342 /pkg | |
| parent | e47813ecaa942631945215a8c0c938a240c3894a (diff) | |
refactor: move authorizers into authz package
Diffstat (limited to 'pkg')
| -rw-r--r-- | pkg/app/app.go | 84 | ||||
| -rw-r--r-- | pkg/app/routes.go | 7 | ||||
| -rw-r--r-- | pkg/authz/casbin.go | 43 | ||||
| -rw-r--r-- | pkg/authz/cedar.go | 53 | ||||
| -rw-r--r-- | pkg/rpc/ability_handler.go | 20 | ||||
| -rw-r--r-- | pkg/rpc/server.go | 14 |
6 files changed, 135 insertions, 86 deletions
diff --git a/pkg/app/app.go b/pkg/app/app.go index c55ecce5..a8dedc10 100644 --- a/pkg/app/app.go +++ b/pkg/app/app.go @@ -1,95 +1,13 @@ package app import ( - "encoding/json" - "fmt" - "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" - xlog "gitlab.com/mokhax/spike/pkg/log" "gitlab.com/mokhax/spike/pkg/srv" ) -func WithCasbin() authz.Authorizer { - enforcer := x.Must(casbin.NewEnforcer("casbin.conf", "casbin.csv")) - - return authz.AuthorizerFunc(func(r *http.Request) bool { - host, _, err := net.SplitHostPort(r.Host) - if err != nil { - xlog.WithFields(r, xlog.Fields{"error": err}) - return false - } - - subject, found := authz.TokenFrom(r).Subject() - if !found { - subject = "*" - } - ok, err := enforcer.Enforce(subject, host, r.Method, r.URL.Path) - if err != nil { - xlog.WithFields(r, xlog.Fields{"error": err}) - return false - } - - fmt.Printf("%v: %v -> %v %v%v\n", ok, subject, r.Method, host, r.URL.Path) - xlog.WithFields(r, xlog.Fields{ - "ok": ok, - "subject": subject, - "action": r.Method, - "domain": host, - "object": r.URL.Path, - }) - return ok - }) -} - -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 { - xlog.Logger.Error("Error", "error", err) - return nil - } - - 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 { - mux := authz.HTTP(WithCasbin(), Routes()) + mux := authz.HTTP(authz.WithCasbin(), Routes()) return srv.Run(cfg.New( bindAddr, cfg.WithMux(mux), diff --git a/pkg/app/routes.go b/pkg/app/routes.go index 9cfa979b..ff1291c2 100644 --- a/pkg/app/routes.go +++ b/pkg/app/routes.go @@ -9,9 +9,10 @@ import ( func Routes() http.Handler { mux := http.NewServeMux() mux.Handle("/", prxy.New(map[string]string{ - "idp.example.com": "http://localhost:8282", - "ui.example.com": "http://localhost:8283", - "api.example.com": "http://localhost:8284", + "api.example.com": "http://localhost:8284", + "authzd.example.com": "http://localhost:50051", + "idp.example.com": "http://localhost:8282", + "ui.example.com": "http://localhost:8283", })) return mux } diff --git a/pkg/authz/casbin.go b/pkg/authz/casbin.go new file mode 100644 index 00000000..99dcc8ec --- /dev/null +++ b/pkg/authz/casbin.go @@ -0,0 +1,43 @@ +package authz + +import ( + "fmt" + "net" + "net/http" + + "github.com/casbin/casbin/v3" + "github.com/xlgmokha/x/pkg/x" + xlog "gitlab.com/mokhax/spike/pkg/log" +) + +func WithCasbin() Authorizer { + enforcer := x.Must(casbin.NewEnforcer("casbin.conf", "casbin.csv")) + + return AuthorizerFunc(func(r *http.Request) bool { + host, _, err := net.SplitHostPort(r.Host) + if err != nil { + xlog.WithFields(r, xlog.Fields{"error": err}) + return false + } + + subject, found := TokenFrom(r).Subject() + if !found { + subject = "*" + } + ok, err := enforcer.Enforce(subject, host, r.Method, r.URL.Path) + if err != nil { + xlog.WithFields(r, xlog.Fields{"error": err}) + return false + } + + fmt.Printf("%v: %v -> %v %v%v\n", ok, subject, r.Method, host, r.URL.Path) + xlog.WithFields(r, xlog.Fields{ + "ok": ok, + "subject": subject, + "action": r.Method, + "domain": host, + "object": r.URL.Path, + }) + return ok + }) +} diff --git a/pkg/authz/cedar.go b/pkg/authz/cedar.go new file mode 100644 index 00000000..1d952651 --- /dev/null +++ b/pkg/authz/cedar.go @@ -0,0 +1,53 @@ +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" +) + +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{ + 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 + }) +} diff --git a/pkg/rpc/ability_handler.go b/pkg/rpc/ability_handler.go new file mode 100644 index 00000000..a881b41b --- /dev/null +++ b/pkg/rpc/ability_handler.go @@ -0,0 +1,20 @@ +package rpc + +import ( + context "context" + "net/http" + + "github.com/xlgmokha/x/pkg/x" + "gitlab.com/mokhax/spike/pkg/authz" +) + +type AbilityHandler struct { + authorizer authz.Authorizer + UnimplementedAbilityServer +} + +func (h *AbilityHandler) Allowed(ctx context.Context, req *AllowRequest) (*AllowReply, error) { + // TODO:: Replace http.Request with authz.Request + request := x.Must(http.NewRequestWithContext(ctx, req.Permission, req.Resource, nil)) + return &AllowReply{Result: h.authorizer.Authorize(request)}, nil +} diff --git a/pkg/rpc/server.go b/pkg/rpc/server.go new file mode 100644 index 00000000..ba96b610 --- /dev/null +++ b/pkg/rpc/server.go @@ -0,0 +1,14 @@ +package rpc + +import ( + "gitlab.com/mokhax/spike/pkg/authz" + grpc "google.golang.org/grpc" +) + +func New(authorizer authz.Authorizer, options ...grpc.ServerOption) *grpc.Server { + server := grpc.NewServer(options...) + RegisterAbilityServer(server, &AbilityHandler{ + authorizer: authorizer, + }) + return server +} |
