From a5e9dc21cadb4b76775648ebd7c3e84cce6ebfb1 Mon Sep 17 00:00:00 2001 From: ben-toogood Date: Tue, 14 Jul 2020 10:27:15 +0100 Subject: [PATCH] util/wrapper: allow enforcing a specific namespace when verifying requests (#1832) * auth/jwt: add debugging * auth: more debugging * auth: more debugging * util/wrapper: don't use request context * util/wrapper: AuthHandlerNamespace * remove debugging --- service.go | 7 ++++++- util/wrapper/wrapper.go | 38 +++++++++++++++++++++++++++++++++----- 2 files changed, 39 insertions(+), 6 deletions(-) diff --git a/service.go b/service.go index c8fe4c76..e08b9f44 100644 --- a/service.go +++ b/service.go @@ -44,11 +44,16 @@ func newService(opts ...Option) Service { options.Client = wrapper.CacheClient(cacheFn, options.Client) options.Client = wrapper.AuthClient(authFn, options.Client) + // pass the services auth namespace to the auth handler so it + // uses this to verify requests, preventing the reliance on the + // unsecure Micro-Namespace header. + handlerNS := wrapper.AuthHandlerNamespace(options.Auth.Options().Issuer) + // wrap the server to provide handler stats options.Server.Init( server.WrapHandler(wrapper.HandlerStats(stats.DefaultStats)), server.WrapHandler(wrapper.TraceHandler(trace.DefaultTracer)), - server.WrapHandler(wrapper.AuthHandler(authFn)), + server.WrapHandler(wrapper.AuthHandler(authFn, handlerNS)), ) // set opts diff --git a/util/wrapper/wrapper.go b/util/wrapper/wrapper.go index e5d7895a..78e09664 100644 --- a/util/wrapper/wrapper.go +++ b/util/wrapper/wrapper.go @@ -187,10 +187,28 @@ func AuthClient(auth func() auth.Auth, c client.Client) client.Client { return &authWrapper{c, auth} } +func AuthHandlerNamespace(ns string) AuthHandlerOption { + return func(o *AuthHandlerOptions) { + o.Namespace = ns + } +} + +type AuthHandlerOption func(o *AuthHandlerOptions) + +type AuthHandlerOptions struct { + Namespace string +} + // AuthHandler wraps a server handler to perform auth -func AuthHandler(fn func() auth.Auth) server.HandlerWrapper { +func AuthHandler(fn func() auth.Auth, opts ...AuthHandlerOption) server.HandlerWrapper { return func(h server.HandlerFunc) server.HandlerFunc { return func(ctx context.Context, req server.Request, rsp interface{}) error { + // parse the options + options := AuthHandlerOptions{} + for _, o := range opts { + o(&options) + } + // get the auth.Auth interface a := fn() @@ -235,12 +253,22 @@ func AuthHandler(fn func() auth.Auth) server.HandlerWrapper { Endpoint: req.Endpoint(), } - // Verify the caller has access to the resource - err := a.Verify(account, res, auth.VerifyContext(ctx)) - if err != nil && account != nil { + // Normal services set the namespace to prevent it being overriden + // by setting the Namespace header, however this isn't the case for + // the proxy which uses the namespace header when routing requests + // to a specific network. + if len(options.Namespace) == 0 { + options.Namespace = ns + } + + // Verify the caller has access to the resource. + err := a.Verify(account, res, auth.VerifyNamespace(options.Namespace)) + if err == auth.ErrForbidden && account != nil { return errors.Forbidden(req.Service(), "Forbidden call made to %v:%v by %v", req.Service(), req.Endpoint(), account.ID) - } else if err != nil { + } else if err == auth.ErrForbidden { return errors.Unauthorized(req.Service(), "Unauthorized call made to %v:%v", req.Service(), req.Endpoint()) + } else if err != nil { + return errors.InternalServerError(req.Service(), "Error authorizing request: %v", err) } // There is an account, set it in the context