From 6318a8b497f9122e626771915488fc33cb567d51 Mon Sep 17 00:00:00 2001 From: William Petit Date: Wed, 20 Sep 2023 10:02:59 -0600 Subject: [PATCH] feat(auth): automatically create session for anonymous users ref https://forge.cadoles.com/arcad/edge-menu/issues/86 --- go.mod | 2 +- go.sum | 4 +- internal/agent/controller/app/app_handler.go | 8 +++ internal/agent/controller/app/auth_module.go | 73 ++++++++++++++++++++ internal/agent/controller/app/server.go | 3 +- 5 files changed, 85 insertions(+), 5 deletions(-) diff --git a/go.mod b/go.mod index 3e8ae71..f9f7df8 100644 --- a/go.mod +++ b/go.mod @@ -3,7 +3,7 @@ module forge.cadoles.com/Cadoles/emissary go 1.19 require ( - forge.cadoles.com/arcad/edge v0.0.0-20230426135323-17808d14c978 + forge.cadoles.com/arcad/edge v0.0.0-20230920152353-c3535a4a9b7f github.com/Masterminds/sprig/v3 v3.2.3 github.com/alecthomas/participle/v2 v2.0.0-beta.5 github.com/andreyvit/diff v0.0.0-20170406064948-c7f18ee00883 diff --git a/go.sum b/go.sum index 8fd6a3b..3d13daa 100644 --- a/go.sum +++ b/go.sum @@ -54,8 +54,8 @@ cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohl cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs= cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0= dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= -forge.cadoles.com/arcad/edge v0.0.0-20230426135323-17808d14c978 h1:fekSRSb8gYcVx8C0B9K6B7+KiFHVixIwvPUkxcnRFp4= -forge.cadoles.com/arcad/edge v0.0.0-20230426135323-17808d14c978/go.mod h1:uv3wBa+UbcEUb7IiJCj1T96Xo3cmx1BwNxbBYRZhln8= +forge.cadoles.com/arcad/edge v0.0.0-20230920152353-c3535a4a9b7f h1:3DcH1hDBRjTaBJTlxzSJ0zf9G5/y0AUtyU11DiDhCwI= +forge.cadoles.com/arcad/edge v0.0.0-20230920152353-c3535a4a9b7f/go.mod h1:uv3wBa+UbcEUb7IiJCj1T96Xo3cmx1BwNxbBYRZhln8= gioui.org v0.0.0-20210308172011-57750fc8a0a6/go.mod h1:RSH6KIUZ0p2xy5zHDxgAM4zumjgTw83q2ge/PI+yyw8= github.com/AdaLogics/go-fuzz-headers v0.0.0-20210715213245-6c3934b029d8/go.mod h1:CzsSbkDixRphAF5hS6wbMKq0eI6ccJRb7/A0M6JBnwg= github.com/Azure/azure-pipeline-go v0.2.3/go.mod h1:x841ezTBIMG6O3lAcl8ATHnsOPVl2bqk7S3ta6S6u4k= diff --git a/internal/agent/controller/app/app_handler.go b/internal/agent/controller/app/app_handler.go index 61cd8e7..dac70b9 100644 --- a/internal/agent/controller/app/app_handler.go +++ b/internal/agent/controller/app/app_handler.go @@ -90,10 +90,18 @@ func (c *Controller) getHandlerOptions(ctx context.Context, appKey string, specs modules := c.getAppModules(deps) + anonymousUserMiddleware, err := getAnonymousUserMiddleware(specs.Config.Auth) + if err != nil { + return nil, errors.Wrap(err, "could not get anonymous user middleware") + } + options := []edgeHTTP.HandlerOptionFunc{ edgeHTTP.WithBus(deps.Bus), edgeHTTP.WithServerModules(modules...), edgeHTTP.WithHTTPMounts(mounts...), + edgeHTTP.WithHTTPMiddlewares( + anonymousUserMiddleware, + ), } return options, nil diff --git a/internal/agent/controller/app/auth_module.go b/internal/agent/controller/app/auth_module.go index 855bebf..3097bd8 100644 --- a/internal/agent/controller/app/auth_module.go +++ b/internal/agent/controller/app/auth_module.go @@ -1,15 +1,19 @@ package app import ( + "net/http" "time" "forge.cadoles.com/Cadoles/emissary/internal/agent/controller/app/spec" + appSpec "forge.cadoles.com/Cadoles/emissary/internal/agent/controller/app/spec" "forge.cadoles.com/Cadoles/emissary/internal/jwk" "forge.cadoles.com/arcad/edge/pkg/app" "forge.cadoles.com/arcad/edge/pkg/module" "forge.cadoles.com/arcad/edge/pkg/module/auth" authModule "forge.cadoles.com/arcad/edge/pkg/module/auth" authHTTP "forge.cadoles.com/arcad/edge/pkg/module/auth/http" + authModuleMiddleware "forge.cadoles.com/arcad/edge/pkg/module/auth/middleware" + "github.com/dop251/goja" "github.com/lestrrat-go/jwx/v2/jwa" "github.com/pkg/errors" @@ -91,3 +95,72 @@ func getAuthMount(auth *spec.Auth, keySet jwk.Set) (auth.MountFunc, error) { return nil, nil } } + +func getAnonymousUserMiddleware(auth *appSpec.Auth) (func(http.Handler) http.Handler, error) { + anonymousUserSigningKey, err := getAnonymousUserSigningKey(auth) + if err != nil { + return nil, errors.Wrap(err, "could not get anonymous user signing key") + } + + cookieDuration := defaultCookieDuration + if auth.Local.CookieDuration != "" { + cookieDuration, err = time.ParseDuration(auth.Local.CookieDuration) + if err != nil { + return nil, errors.WithStack(err) + } + } + + middleware := authModuleMiddleware.AnonymousUser( + anonymousUserSigningKey.Algorithm(), + anonymousUserSigningKey, + authModuleMiddleware.WithCookieOptions(getCookieDomain, cookieDuration), + ) + + return middleware, nil +} + +func getAnonymousUserSigningKey(auth *appSpec.Auth) (jwk.Key, error) { + var ( + key jwk.Key + err error + ) + + generateNewKey := func() (jwk.Key, error) { + key, err := jwk.Generate(2048) + if err != nil { + return nil, errors.WithStack(err) + } + + return key, nil + } + + switch { + default: + fallthrough + case auth == nil: + key, err = generateNewKey() + if err != nil { + return nil, errors.Wrap(err, "could not generate anonymous user signing key") + } + + return key, nil + + case auth.Local != nil: + switch typedKey := auth.Local.Key.(type) { + case string: + key, err = jwk.FromRaw([]byte(typedKey)) + if err != nil { + return nil, errors.Wrap(err, "could not parse local auth key") + } + + if err := key.Set(jwk.AlgorithmKey, jwa.HS256); err != nil { + return nil, errors.WithStack(err) + } + + default: + return nil, errors.Errorf("unexpected key type '%T'", auth.Local.Key) + } + } + + return key, nil +} diff --git a/internal/agent/controller/app/server.go b/internal/agent/controller/app/server.go index f7cfde7..22d1cae 100644 --- a/internal/agent/controller/app/server.go +++ b/internal/agent/controller/app/server.go @@ -8,7 +8,6 @@ import ( "sync" "time" - "forge.cadoles.com/Cadoles/emissary/internal/agent/controller/app/spec" appSpec "forge.cadoles.com/Cadoles/emissary/internal/agent/controller/app/spec" "forge.cadoles.com/Cadoles/emissary/internal/proxy/wildcard" edgeHTTP "forge.cadoles.com/arcad/edge/pkg/http" @@ -128,7 +127,7 @@ func (s *Server) Stop() error { return nil } -func NewServer(bundle bundle.Bundle, config *spec.Config, handlerOptions ...edgeHTTP.HandlerOptionFunc) *Server { +func NewServer(bundle bundle.Bundle, config *appSpec.Config, handlerOptions ...edgeHTTP.HandlerOptionFunc) *Server { return &Server{ bundle: bundle, config: config,