From 15b1699b0ad27c9fc3aa4498d4085b7338bec95a Mon Sep 17 00:00:00 2001 From: mo khan Date: Fri, 23 May 2025 16:08:15 -0600 Subject: feat: parse the body of the id token --- app/middleware/id_token_test.go | 1 - 1 file changed, 1 deletion(-) (limited to 'app') diff --git a/app/middleware/id_token_test.go b/app/middleware/id_token_test.go index 5487ada..9d8521a 100644 --- a/app/middleware/id_token_test.go +++ b/app/middleware/id_token_test.go @@ -23,7 +23,6 @@ func TestIDToken(t *testing.T) { t.Run("when an active id_token cookie is provided", func(t *testing.T) { t.Run("attaches the token to the request context", func(t *testing.T) { user := mockoidc.DefaultUser() - _, rawIDToken := srv.CreateTokensFor(user) server := middleware(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { -- cgit v1.2.3 From a8e47145f93f07740d751be37d450599b26b2fc8 Mon Sep 17 00:00:00 2001 From: mo khan Date: Sat, 24 May 2025 00:08:00 -0600 Subject: feat: create middleware to check if user has permission --- app/domain/entity.go | 3 +- app/domain/identifiable.go | 7 ++++ app/domain/sparkle.go | 4 +++ app/domain/user.go | 4 +++ app/middleware/permission.go | 24 +++++++++++++ app/middleware/require_permission.go | 33 ++++++++++++++++++ app/middleware/require_permission_test.go | 58 +++++++++++++++++++++++++++++++ 7 files changed, 131 insertions(+), 2 deletions(-) create mode 100644 app/domain/identifiable.go create mode 100644 app/middleware/permission.go create mode 100644 app/middleware/require_permission.go create mode 100644 app/middleware/require_permission_test.go (limited to 'app') diff --git a/app/domain/entity.go b/app/domain/entity.go index fb1cab8..0377c51 100644 --- a/app/domain/entity.go +++ b/app/domain/entity.go @@ -1,7 +1,6 @@ package domain type Entity interface { - GetID() ID - SetID(id ID) error + Identifiable Validate() error } diff --git a/app/domain/identifiable.go b/app/domain/identifiable.go new file mode 100644 index 0000000..8fbc1e4 --- /dev/null +++ b/app/domain/identifiable.go @@ -0,0 +1,7 @@ +package domain + +type Identifiable interface { + GetID() ID + SetID(id ID) error + ToGID() string +} diff --git a/app/domain/sparkle.go b/app/domain/sparkle.go index 68aed67..d4f70b2 100644 --- a/app/domain/sparkle.go +++ b/app/domain/sparkle.go @@ -49,6 +49,10 @@ func (s *Sparkle) SetID(id ID) error { return nil } +func (s *Sparkle) ToGID() string { + return "gid://sparkle/Sparkle/" + s.ID.String() +} + func (s *Sparkle) Validate() error { if s.Sparklee == "" { return SparkleeIsRequired diff --git a/app/domain/user.go b/app/domain/user.go index aae17f6..02ddd26 100644 --- a/app/domain/user.go +++ b/app/domain/user.go @@ -32,3 +32,7 @@ func (self *User) Sparkle(sparklee string, reason string) *Sparkle { Reason: reason, } } + +func (self *User) ToGID() string { + return "gid://sparkle/User/" + self.ID.String() +} diff --git a/app/middleware/permission.go b/app/middleware/permission.go new file mode 100644 index 0000000..03e7cf9 --- /dev/null +++ b/app/middleware/permission.go @@ -0,0 +1,24 @@ +package middleware + +import ( + "gitlab.com/gitlab-org/software-supply-chain-security/authorization/authzd.git/pkg/rpc" + "gitlab.com/gitlab-org/software-supply-chain-security/authorization/sparkled/app/domain" +) + +type Permission string + +func (p Permission) ToGID() string { + return "gid://sparkle/Permission/" + p.String() +} + +func (p Permission) RequestFor(user domain.Identifiable, resource domain.Identifiable) *rpc.AllowRequest { + return &rpc.AllowRequest{ + Subject: user.ToGID(), + Permission: p.ToGID(), + Resource: resource.ToGID(), + } +} + +func (p Permission) String() string { + return string(p) +} diff --git a/app/middleware/require_permission.go b/app/middleware/require_permission.go new file mode 100644 index 0000000..563278e --- /dev/null +++ b/app/middleware/require_permission.go @@ -0,0 +1,33 @@ +package middleware + +import ( + "net/http" + + "gitlab.com/gitlab-org/software-supply-chain-security/authorization/authzd.git/pkg/rpc" + "gitlab.com/gitlab-org/software-supply-chain-security/authorization/sparkled/app/cfg" + "gitlab.com/gitlab-org/software-supply-chain-security/authorization/sparkled/app/domain" + "gitlab.com/gitlab-org/software-supply-chain-security/authorization/sparkled/pkg/pls" +) + +func RequirePermission(permission Permission, ability rpc.Ability) func(http.Handler) http.Handler { + return func(next http.Handler) http.Handler { + return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + user := cfg.CurrentUser.From(r.Context()) + + reply, err := ability.Allowed(r.Context(), + permission.RequestFor(user, &domain.Sparkle{ID: "*"}), + ) + if err != nil { + pls.LogError(r.Context(), err) + w.WriteHeader(http.StatusForbidden) + return + } + + if reply.Result { + next.ServeHTTP(w, r) + } else { + w.WriteHeader(http.StatusForbidden) + } + }) + } +} diff --git a/app/middleware/require_permission_test.go b/app/middleware/require_permission_test.go new file mode 100644 index 0000000..34a04a7 --- /dev/null +++ b/app/middleware/require_permission_test.go @@ -0,0 +1,58 @@ +package middleware + +import ( + "context" + "net/http" + "testing" + + "github.com/stretchr/testify/require" + "github.com/xlgmokha/x/pkg/test" + "gitlab.com/gitlab-org/software-supply-chain-security/authorization/authzd.git/pkg/rpc" + "gitlab.com/gitlab-org/software-supply-chain-security/authorization/sparkled/app/cfg" + "gitlab.com/gitlab-org/software-supply-chain-security/authorization/sparkled/app/domain" +) + +type MockAbility func(context.Context, *rpc.AllowRequest) (*rpc.AllowReply, error) + +func (m MockAbility) Allowed(ctx context.Context, r *rpc.AllowRequest) (*rpc.AllowReply, error) { + return m(ctx, r) +} + +func TestRequirePermission(t *testing.T) { + user := &domain.User{ID: domain.ID("1")} + ctx := cfg.CurrentUser.With(t.Context(), user) + permission := Permission("read_sparkles") + + t.Run("when the permission is granted", func(t *testing.T) { + r, w := test.RequestResponse("GET", "/sparkles", test.WithContext(ctx)) + + middleware := RequirePermission(permission, MockAbility(func(ctx context.Context, r *rpc.AllowRequest) (*rpc.AllowReply, error) { + require.Equal(t, "gid://sparkle/User/"+user.ID.String(), r.Subject) + require.Equal(t, permission.ToGID(), r.Permission) + require.Equal(t, "gid://sparkle/Sparkle/*", r.Resource) + + return &rpc.AllowReply{Result: true}, nil + })) + server := middleware(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + w.WriteHeader(http.StatusTeapot) + })) + server.ServeHTTP(w, r) + + require.Equal(t, http.StatusTeapot, w.Code) + }) + + t.Run("when the permission is denied", func(t *testing.T) { + r, w := test.RequestResponse("GET", "/sparkles", test.WithContext(ctx)) + + middleware := RequirePermission(permission, MockAbility(func(ctx context.Context, r *rpc.AllowRequest) (*rpc.AllowReply, error) { + return &rpc.AllowReply{Result: false}, nil + })) + server := middleware(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + require.Fail(t, "unexpected call to handler") + })) + + server.ServeHTTP(w, r) + + require.Equal(t, http.StatusForbidden, w.Code) + }) +} -- cgit v1.2.3 From 23327d0ce3e641afd1316a112e1c7f9b443abe13 Mon Sep 17 00:00:00 2001 From: mo khan Date: Sat, 24 May 2025 00:16:14 -0600 Subject: refactor: decorate handler with access check middleware --- app/controllers/dashboard/controller.go | 7 +++++-- app/controllers/sparkles/controller.go | 8 +++++--- 2 files changed, 10 insertions(+), 5 deletions(-) (limited to 'app') diff --git a/app/controllers/dashboard/controller.go b/app/controllers/dashboard/controller.go index 097834f..04a7ed1 100644 --- a/app/controllers/dashboard/controller.go +++ b/app/controllers/dashboard/controller.go @@ -3,6 +3,7 @@ package dashboard import ( "net/http" + "github.com/xlgmokha/x/pkg/x" "gitlab.com/gitlab-org/software-supply-chain-security/authorization/sparkled/app/cfg" "gitlab.com/gitlab-org/software-supply-chain-security/authorization/sparkled/app/middleware" "gitlab.com/gitlab-org/software-supply-chain-security/authorization/sparkled/app/views" @@ -17,9 +18,11 @@ func New() *Controller { } func (c *Controller) MountTo(mux *http.ServeMux) { - requireUser := middleware.RequireUser() + mux.Handle("GET /dashboard", x.Middleware[http.Handler]( + http.HandlerFunc(c.Show), + middleware.RequireUser(), + )) - mux.Handle("GET /dashboard", requireUser(http.HandlerFunc(c.Show))) mux.Handle("GET /dashboard/nav", http.HandlerFunc(c.Navigation)) } diff --git a/app/controllers/sparkles/controller.go b/app/controllers/sparkles/controller.go index cd86cd2..bd7264e 100644 --- a/app/controllers/sparkles/controller.go +++ b/app/controllers/sparkles/controller.go @@ -21,10 +21,12 @@ func New(db domain.Repository[*domain.Sparkle]) *Controller { } func (c *Controller) MountTo(mux *http.ServeMux) { - requireUser := middleware.RequireUser() - mux.HandleFunc("GET /sparkles", c.Index) - mux.Handle("POST /sparkles", requireUser(http.HandlerFunc(c.Create))) + mux.Handle("POST /sparkles", x.Middleware[http.Handler]( + http.HandlerFunc(c.Create), + middleware.RequireUser(), + // middleware.RequirePermission("create_sparkle", nil), + )) // This is a temporary endpoint to restore a backup mux.HandleFunc("POST /sparkles/restore", c.Restore) -- cgit v1.2.3 From 245d770d914719f6fad496e98fb2d1ddfb029b96 Mon Sep 17 00:00:00 2001 From: mo khan Date: Sat, 24 May 2025 00:36:41 -0600 Subject: feat: connect rpc client to inversion of control container --- .runway/env-production.yml | 1 + .runway/env-staging.yml | 1 + app/controllers/sparkles/controller.go | 4 +++- app/init.go | 14 +++++++++++++- 4 files changed, 18 insertions(+), 2 deletions(-) (limited to 'app') diff --git a/.runway/env-production.yml b/.runway/env-production.yml index fd18897..75e1802 100644 --- a/.runway/env-production.yml +++ b/.runway/env-production.yml @@ -1,3 +1,4 @@ APP_ENV: "production" +AUTHZD_HOST: "https://authzd.runway.gitlab.net" OAUTH_CLIENT_ID: "75656280b7ca60223b060b57c4eb98a8a324878531efeccafc1d25709dbee5c9" OIDC_ISSUER: "https://gitlab.com" diff --git a/.runway/env-staging.yml b/.runway/env-staging.yml index 7a1192f..3ccc33e 100644 --- a/.runway/env-staging.yml +++ b/.runway/env-staging.yml @@ -1,3 +1,4 @@ APP_ENV: "production" +AUTHZD_HOST: "https://authzd.staging.runway.gitlab.net" OAUTH_CLIENT_ID: "786e37c8d2207d200f735379ad52579c452948222f9affc7a45e74bd7074ad3c" OIDC_ISSUER: "https://staging.gitlab.com" diff --git a/app/controllers/sparkles/controller.go b/app/controllers/sparkles/controller.go index bd7264e..ccf68b1 100644 --- a/app/controllers/sparkles/controller.go +++ b/app/controllers/sparkles/controller.go @@ -3,10 +3,12 @@ package sparkles import ( "net/http" + "github.com/xlgmokha/x/pkg/ioc" "github.com/xlgmokha/x/pkg/log" "github.com/xlgmokha/x/pkg/mapper" "github.com/xlgmokha/x/pkg/serde" "github.com/xlgmokha/x/pkg/x" + "gitlab.com/gitlab-org/software-supply-chain-security/authorization/authzd.git/pkg/rpc" "gitlab.com/gitlab-org/software-supply-chain-security/authorization/sparkled/app/domain" "gitlab.com/gitlab-org/software-supply-chain-security/authorization/sparkled/app/middleware" "gitlab.com/gitlab-org/software-supply-chain-security/authorization/sparkled/pkg/pls" @@ -25,7 +27,7 @@ func (c *Controller) MountTo(mux *http.ServeMux) { mux.Handle("POST /sparkles", x.Middleware[http.Handler]( http.HandlerFunc(c.Create), middleware.RequireUser(), - // middleware.RequirePermission("create_sparkle", nil), + middleware.RequirePermission("create_sparkle", ioc.MustResolve[rpc.Ability](ioc.Default)), )) // This is a temporary endpoint to restore a backup diff --git a/app/init.go b/app/init.go index d9ca3de..a88fa4f 100644 --- a/app/init.go +++ b/app/init.go @@ -7,8 +7,10 @@ import ( "github.com/coreos/go-oidc/v3/oidc" "github.com/rs/zerolog" + "github.com/xlgmokha/x/pkg/env" "github.com/xlgmokha/x/pkg/ioc" "github.com/xlgmokha/x/pkg/log" + "gitlab.com/gitlab-org/software-supply-chain-security/authorization/authzd.git/pkg/rpc" "gitlab.com/gitlab-org/software-supply-chain-security/authorization/sparkled/app/cfg" "gitlab.com/gitlab-org/software-supply-chain-security/authorization/sparkled/app/controllers/dashboard" "gitlab.com/gitlab-org/software-supply-chain-security/authorization/sparkled/app/controllers/sparkles" @@ -45,7 +47,11 @@ func init() { } }) ioc.Register[*oidc.Provider](ioc.Default, func() *oidc.Provider { - ctx := context.WithValue(context.Background(), oauth2.HTTPClient, ioc.MustResolve[*http.Client](ioc.Default)) + ctx := context.WithValue( + context.Background(), + oauth2.HTTPClient, + ioc.MustResolve[*http.Client](ioc.Default), + ) return web.NewOIDCProvider(ctx, cfg.OIDCIssuer, func(err error) { ioc.MustResolve[*zerolog.Logger](ioc.Default).Err(err).Send() }) @@ -55,6 +61,12 @@ func init() { ClientID: cfg.OAuthClientID, } }) + ioc.Register[rpc.Ability](ioc.Default, func() rpc.Ability { + return rpc.NewAbilityProtobufClient( + env.Fetch("AUTHZD_HOST", ""), + ioc.MustResolve[*http.Client](ioc.Default), + ) + }) http.DefaultClient = ioc.MustResolve[*http.Client](ioc.Default) } -- cgit v1.2.3 From 7b9c49c2481f8a5e62cb035f1ee7e5d254793f16 Mon Sep 17 00:00:00 2001 From: mo khan Date: Sat, 24 May 2025 00:38:29 -0600 Subject: fix: disable require permission middleware --- app/controllers/sparkles/controller.go | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'app') diff --git a/app/controllers/sparkles/controller.go b/app/controllers/sparkles/controller.go index ccf68b1..5167c2a 100644 --- a/app/controllers/sparkles/controller.go +++ b/app/controllers/sparkles/controller.go @@ -3,12 +3,10 @@ package sparkles import ( "net/http" - "github.com/xlgmokha/x/pkg/ioc" "github.com/xlgmokha/x/pkg/log" "github.com/xlgmokha/x/pkg/mapper" "github.com/xlgmokha/x/pkg/serde" "github.com/xlgmokha/x/pkg/x" - "gitlab.com/gitlab-org/software-supply-chain-security/authorization/authzd.git/pkg/rpc" "gitlab.com/gitlab-org/software-supply-chain-security/authorization/sparkled/app/domain" "gitlab.com/gitlab-org/software-supply-chain-security/authorization/sparkled/app/middleware" "gitlab.com/gitlab-org/software-supply-chain-security/authorization/sparkled/pkg/pls" @@ -27,7 +25,7 @@ func (c *Controller) MountTo(mux *http.ServeMux) { mux.Handle("POST /sparkles", x.Middleware[http.Handler]( http.HandlerFunc(c.Create), middleware.RequireUser(), - middleware.RequirePermission("create_sparkle", ioc.MustResolve[rpc.Ability](ioc.Default)), + // middleware.RequirePermission("create_sparkle", ioc.MustResolve[rpc.Ability](ioc.Default)), )) // This is a temporary endpoint to restore a backup -- cgit v1.2.3 From 9481fb347af85bd946408b902dcdd5310ee38dd9 Mon Sep 17 00:00:00 2001 From: mo khan Date: Sat, 24 May 2025 01:00:24 -0600 Subject: fix: register oidc provider once --- app/init.go | 2 +- cmd/sparkled/main.go | 10 ++++------ pkg/web/transport.go | 13 +++++-------- test/integration/container.go | 1 - 4 files changed, 10 insertions(+), 16 deletions(-) (limited to 'app') diff --git a/app/init.go b/app/init.go index a88fa4f..7b0c386 100644 --- a/app/init.go +++ b/app/init.go @@ -46,7 +46,7 @@ func init() { }, } }) - ioc.Register[*oidc.Provider](ioc.Default, func() *oidc.Provider { + ioc.RegisterSingleton[*oidc.Provider](ioc.Default, func() *oidc.Provider { ctx := context.WithValue( context.Background(), oauth2.HTTPClient, diff --git a/cmd/sparkled/main.go b/cmd/sparkled/main.go index 161e8c1..adc7ed1 100644 --- a/cmd/sparkled/main.go +++ b/cmd/sparkled/main.go @@ -1,21 +1,19 @@ package main import ( - "log" + "context" "net/http" "os" "github.com/xlgmokha/x/pkg/env" "github.com/xlgmokha/x/pkg/x" "gitlab.com/gitlab-org/software-supply-chain-security/authorization/sparkled/app" + "gitlab.com/gitlab-org/software-supply-chain-security/authorization/sparkled/pkg/pls" ) func main() { - bindAddr := env.Fetch("BIND_ADDR", ":8080") - log.Printf("Listening on %v\n", bindAddr) - - log.Fatal(http.ListenAndServe( - bindAddr, + pls.LogError(context.Background(), http.ListenAndServe( + env.Fetch("BIND_ADDR", ":8080"), app.New(x.Must(os.Getwd())), )) } diff --git a/pkg/web/transport.go b/pkg/web/transport.go index b8d728a..e3333f5 100644 --- a/pkg/web/transport.go +++ b/pkg/web/transport.go @@ -6,6 +6,7 @@ import ( "github.com/rs/zerolog" "github.com/xlgmokha/x/pkg/log" "github.com/xlgmokha/x/pkg/mapper" + "gitlab.com/gitlab-org/software-supply-chain-security/authorization/sparkled/pkg/pls" ) type Transport struct { @@ -14,20 +15,16 @@ type Transport struct { func (r *Transport) RoundTrip(request *http.Request) (*http.Response, error) { ctx := r.Logger.WithContext(request.Context()) + log.WithFields(ctx, mapper.MapFrom[*http.Request, log.Fields](request)) - defer func() { - log.WithFields(ctx, mapper.MapFrom[*http.Request, log.Fields](request)) - zerolog.Ctx(ctx).Print() - }() + defer pls.FlushLog(ctx) response, err := http.DefaultTransport.RoundTrip(request) if err != nil { - r.Logger.Err(err) + pls.LogError(ctx, err) return response, err } - log.WithFields(ctx, log.Fields{ - "status_code": response.StatusCode, - }) + log.WithFields(ctx, log.Fields{"status_code": response.StatusCode}) return response, nil } diff --git a/test/integration/container.go b/test/integration/container.go index 6c346a5..c8149b5 100644 --- a/test/integration/container.go +++ b/test/integration/container.go @@ -25,7 +25,6 @@ func NewContainer(t *testing.T, ctx context.Context, envVars map[string]string) testcontainers.WithLogConsumers(&Logger{TB: t}), testcontainers.WithLogger(log.TestLogger(t)), testcontainers.WithWaitStrategy( - wait.ForLog("Listening on"), wait.ForListeningPort(x.Must(nat.NewPort("tcp", "10000"))), wait.ForListeningPort(x.Must(nat.NewPort("tcp", "10003"))), wait.ForListeningPort(x.Must(nat.NewPort("tcp", "8080"))), -- cgit v1.2.3 From 3044fd1170a003380a558918605d32491f9b45a5 Mon Sep 17 00:00:00 2001 From: mo khan Date: Sat, 24 May 2025 01:32:31 -0600 Subject: chore: log x-request-id in sparkle and authzd --- app/init.go | 11 +++++++++++ pkg/authz/check_service.go | 13 +++++++------ 2 files changed, 18 insertions(+), 6 deletions(-) (limited to 'app') diff --git a/app/init.go b/app/init.go index 7b0c386..935c962 100644 --- a/app/init.go +++ b/app/init.go @@ -10,6 +10,7 @@ import ( "github.com/xlgmokha/x/pkg/env" "github.com/xlgmokha/x/pkg/ioc" "github.com/xlgmokha/x/pkg/log" + "github.com/xlgmokha/x/pkg/mapper" "gitlab.com/gitlab-org/software-supply-chain-security/authorization/authzd.git/pkg/rpc" "gitlab.com/gitlab-org/software-supply-chain-security/authorization/sparkled/app/cfg" "gitlab.com/gitlab-org/software-supply-chain-security/authorization/sparkled/app/controllers/dashboard" @@ -69,4 +70,14 @@ func init() { }) http.DefaultClient = ioc.MustResolve[*http.Client](ioc.Default) + + mapper.Register[*http.Request, log.Fields](func(r *http.Request) log.Fields { + return log.Fields{ + "host": r.URL.Host, + "method": r.Method, + "path": r.URL.Path, + "remote_host": r.RemoteAddr, + "request_id": r.Header.Get("x-request-id"), + } + }) } diff --git a/pkg/authz/check_service.go b/pkg/authz/check_service.go index bb2e960..55d075f 100644 --- a/pkg/authz/check_service.go +++ b/pkg/authz/check_service.go @@ -142,12 +142,13 @@ func (svc *CheckService) Denied(ctx context.Context) *auth.CheckResponse { func (svc *CheckService) fieldsFor(r *auth.CheckRequest) log.Fields { return log.Fields{ - "id": r.Attributes.Request.Http.Id, - "method": r.Attributes.Request.Http.Method, - "path": r.Attributes.Request.Http.Path, - "host": r.Attributes.Request.Http.Host, - "scheme": r.Attributes.Request.Http.Scheme, - "protocol": r.Attributes.Request.Http.Protocol, + "host": r.Attributes.Request.Http.Host, + "id": r.Attributes.Request.Http.Id, + "method": r.Attributes.Request.Http.Method, + "path": r.Attributes.Request.Http.Path, + "protocol": r.Attributes.Request.Http.Protocol, + "request_id": r.Attributes.Request.Http.Headers["x-request-id"], + "scheme": r.Attributes.Request.Http.Scheme, } } -- cgit v1.2.3 From 3724af53df29f7be507e9dc55adbc81e9b694cd6 Mon Sep 17 00:00:00 2001 From: mo khan Date: Sat, 24 May 2025 01:40:25 -0600 Subject: chore: log the sub claim from the envoy header --- app/middleware/user.go | 2 ++ 1 file changed, 2 insertions(+) (limited to 'app') diff --git a/app/middleware/user.go b/app/middleware/user.go index 6c018f4..2a6bf71 100644 --- a/app/middleware/user.go +++ b/app/middleware/user.go @@ -4,6 +4,7 @@ import ( "net/http" "github.com/coreos/go-oidc/v3/oidc" + "github.com/xlgmokha/x/pkg/log" "github.com/xlgmokha/x/pkg/mapper" "github.com/xlgmokha/x/pkg/x" "gitlab.com/gitlab-org/software-supply-chain-security/authorization/sparkled/app/cfg" @@ -15,6 +16,7 @@ func User(db domain.Repository[*domain.User]) func(http.Handler) http.Handler { return func(next http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { subject := r.Header.Get("x-jwt-claim-sub") + log.WithFields(r.Context(), log.Fields{"sub": subject}) user := db.Find(r.Context(), domain.ID(subject)) if !x.IsPresent(user) { -- cgit v1.2.3