@@ -17,18 +17,16 @@ import (
1717 "github.com/google/go-querystring/query"
1818)
1919
20- type RequestType int
20+ type AuthModuleType int
2121
2222const (
23- AuthRequest RequestType = iota
23+ AuthRequest AuthModuleType = iota
2424 ExtAuthz
2525 ForwardAuth
2626)
2727
2828var BrowserUserAgentRegex = regexp .MustCompile ("Chrome|Gecko|AppleWebKit|Opera|Edge" )
2929
30- var SupportedProxies = []string {"nginx" , "traefik" , "caddy" , "envoy" }
31-
3230type Proxy struct {
3331 Proxy string `uri:"proxy" binding:"required"`
3432}
@@ -38,7 +36,11 @@ type ProxyContext struct {
3836 Proto string
3937 Path string
4038 Method string
39+ << << << < HEAD
4140 Type RequestType
41+ == == == =
42+ Type AuthModuleType
43+ >> >> >> > main
4244 IsBrowser bool
4345}
4446
@@ -339,12 +341,10 @@ func (controller *ProxyController) getForwardAuthContext(c *gin.Context) (ProxyC
339341 return ProxyContext {}, errors .New ("x-forwarded-proto not found" )
340342 }
341343
344+ // Normally we should only allow GET for forward auth but since it's a fallback
345+ // for envoy we should allow everything, not a big deal
342346 method := c .Request .Method
343347
344- if method != http .MethodGet {
345- return ProxyContext {}, errors .New ("method not allowed" )
346- }
347-
348348 return ProxyContext {
349349 Host : host ,
350350 Proto : proto ,
@@ -368,14 +368,20 @@ func (controller *ProxyController) getAuthRequestContext(c *gin.Context) (ProxyC
368368 }
369369
370370 host := url .Host
371+
372+ if strings .TrimSpace (host ) == "" {
373+ return ProxyContext {}, errors .New ("host not found" )
374+ }
375+
371376 proto := url .Scheme
372- path := url .Path
373- method := c .Request .Method
374377
375- if method != http . MethodGet {
376- return ProxyContext {}, errors .New ("method not allowed " )
378+ if strings . TrimSpace ( proto ) == "" {
379+ return ProxyContext {}, errors .New ("proto not found " )
377380 }
378381
382+ path := url .Path
383+ method := c .Request .Method
384+
379385 return ProxyContext {
380386 Host : host ,
381387 Proto : proto ,
@@ -386,31 +392,72 @@ func (controller *ProxyController) getAuthRequestContext(c *gin.Context) (ProxyC
386392}
387393
388394func (controller * ProxyController ) getExtAuthzContext (c * gin.Context ) (ProxyContext , error ) {
395+ // We hope for the someone to set the x-forwarded-proto header
389396 proto , ok := controller .getHeader (c , "x-forwarded-proto" )
390397
391398 if ! ok {
392399 return ProxyContext {}, errors .New ("x-forwarded-proto not found" )
393400 }
394401
395- host , ok := controller .getHeader (c , "host" )
402+ // It sets the host to the original host, not the forwarded host
403+ host := c .Request .Host
396404
397- if ! ok {
405+ if strings . TrimSpace ( host ) == "" {
398406 return ProxyContext {}, errors .New ("host not found" )
399407 }
400408
401- // Seems like we can't get the path?
409+ // We get the path from the query string
410+ path := c .Query ("path" )
402411
403412 // For envoy we need to support every method
404413 method := c .Request .Method
405414
406415 return ProxyContext {
407416 Host : host ,
408417 Proto : proto ,
418+ Path : path ,
409419 Method : method ,
410420 Type : ExtAuthz ,
411421 }, nil
412422}
413423
424+ func (controller * ProxyController ) determineAuthModules (proxy string ) []AuthModuleType {
425+ switch proxy {
426+ case "traefik" , "caddy" :
427+ return []AuthModuleType {ForwardAuth }
428+ case "envoy" :
429+ return []AuthModuleType {ExtAuthz , ForwardAuth }
430+ case "nginx" :
431+ return []AuthModuleType {AuthRequest , ForwardAuth }
432+ default :
433+ return []AuthModuleType {}
434+ }
435+ }
436+
437+ func (controller * ProxyController ) getContextFromAuthModule (c * gin.Context , module AuthModuleType ) (ProxyContext , error ) {
438+ switch module {
439+ case ForwardAuth :
440+ ctx , err := controller .getForwardAuthContext (c )
441+ if err != nil {
442+ return ProxyContext {}, err
443+ }
444+ return ctx , nil
445+ case ExtAuthz :
446+ ctx , err := controller .getExtAuthzContext (c )
447+ if err != nil {
448+ return ProxyContext {}, err
449+ }
450+ return ctx , nil
451+ case AuthRequest :
452+ ctx , err := controller .getAuthRequestContext (c )
453+ if err != nil {
454+ return ProxyContext {}, err
455+ }
456+ return ctx , nil
457+ }
458+ return ProxyContext {}, fmt .Errorf ("unsupported auth module: %v" , module )
459+ }
460+
414461func (controller * ProxyController ) getProxyContext (c * gin.Context ) (ProxyContext , error ) {
415462 var req Proxy
416463
@@ -419,54 +466,38 @@ func (controller *ProxyController) getProxyContext(c *gin.Context) (ProxyContext
419466 return ProxyContext {}, err
420467 }
421468
469+ tlog .App .Debug ().Msgf ("Proxy: %v" , req .Proxy )
470+
471+ authModules := controller .determineAuthModules (req .Proxy )
472+
473+ if len (authModules ) == 0 {
474+ return ProxyContext {}, fmt .Errorf ("no auth modules supported for proxy: %v" , req .Proxy )
475+ }
476+
422477 var ctx ProxyContext
423478
424- switch req .Proxy {
425- // For nginx we need to handle both forward_auth and auth_request extraction since it can be
426- // used either with something line nginx proxy manager with advanced config or with
427- // the kubernetes ingress controller
428- case "nginx" :
429- tlog .App .Debug ().Str ("proxy" , req .Proxy ).Msg ("Attempting forward_auth compatible extraction" )
430- forwardAuthCtx , err := controller .getForwardAuthContext (c )
479+ for _ , module := range authModules {
480+ tlog .App .Debug ().Msgf ("Trying auth module: %v" , module )
481+ ctx , err = controller .getContextFromAuthModule (c , module )
431482 if err == nil {
432- tlog .App .Debug ().Str ("proxy" , req .Proxy ).Msg ("Extractions success using forward_auth" )
433- ctx = forwardAuthCtx
434- } else {
435- tlog .App .Debug ().Str ("proxy" , req .Proxy ).Msg ("Extractions failed using forward_auth trying with auth_request" )
436- authRequestCtx , err := controller .getAuthRequestContext (c )
437- if err != nil {
438- tlog .App .Warn ().Str ("proxy" , req .Proxy ).Msg ("Failed to determine required module for header extraction" )
439- return ProxyContext {}, err
440- }
441- ctx = authRequestCtx
483+ tlog .App .Debug ().Msgf ("Auth module %v succeeded" , module )
484+ break
442485 }
443- case "envoy" :
444- tlog .App .Debug ().Str ("proxy" , req .Proxy ).Msg ("Attempting ext_authz compatible extraction" )
445- extAuthzCtx , err := controller .getExtAuthzContext (c )
446- if err != nil {
447- tlog .App .Warn ().Str ("proxy" , req .Proxy ).Msg ("Failed to determine required module for header extraction" )
448- return ProxyContext {}, err
449- }
450- ctx = extAuthzCtx
451- // By default we fallback to the forward_auth module which supports most proxies like traefik or caddy
452- default :
453- tlog .App .Debug ().Str ("proxy" , req .Proxy ).Msg ("Attempting forward_auth compatible extraction" )
454- forwardAuthCtx , err := controller .getForwardAuthContext (c )
455- if err != nil {
456- tlog .App .Warn ().Str ("proxy" , req .Proxy ).Msg ("Failed to determine required module for header extraction" )
457- return ProxyContext {}, err
458- }
459- ctx = forwardAuthCtx
486+ tlog .App .Debug ().Err (err ).Msgf ("Auth module %v failed" , module )
487+ }
488+
489+ if err != nil {
490+ return ProxyContext {}, err
460491 }
461492
462493 // We don't care if the header is empty, we will just assume it's not a browser
463494 userAgent , _ := controller .getHeader (c , "user-agent" )
464495 isBrowser := BrowserUserAgentRegex .MatchString (userAgent )
465496
466497 if isBrowser {
467- tlog .App .Debug ().Msg ("Request identified as (most likely) coming from a browser" )
498+ tlog .App .Debug ().Msg ("Request identified as coming from a browser" )
468499 } else {
469- tlog .App .Debug ().Msg ("Request identified as (most likely) coming from a non-browser client" )
500+ tlog .App .Debug ().Msg ("Request identified as coming from a non-browser client" )
470501 }
471502
472503 ctx .IsBrowser = isBrowser
0 commit comments