providers/proxy: fix panic, keep session storages open (#11439)

* fix panic when redis connection fails

Signed-off-by: Jens Langhammer <jens@goauthentik.io>

* re-use session when refreshing apps

Signed-off-by: Jens Langhammer <jens@goauthentik.io>

---------

Signed-off-by: Jens Langhammer <jens@goauthentik.io>
This commit is contained in:
Jens L.
2024-09-19 23:05:58 +02:00
committed by GitHub
parent 20f555ebb6
commit ad3820c11c
4 changed files with 29 additions and 12 deletions

View File

@ -65,8 +65,11 @@ type Server interface {
CryptoStore() *ak.CryptoStore CryptoStore() *ak.CryptoStore
} }
func NewApplication(p api.ProxyOutpostConfig, c *http.Client, server Server) (*Application, error) { func init() {
gob.Register(Claims{}) gob.Register(Claims{})
}
func NewApplication(p api.ProxyOutpostConfig, c *http.Client, server Server, oldApp *Application) (*Application, error) {
muxLogger := log.WithField("logger", "authentik.outpost.proxyv2.application").WithField("name", p.Name) muxLogger := log.WithField("logger", "authentik.outpost.proxyv2.application").WithField("name", p.Name)
externalHost, err := url.Parse(p.ExternalHost) externalHost, err := url.Parse(p.ExternalHost)
@ -137,7 +140,15 @@ func NewApplication(p api.ProxyOutpostConfig, c *http.Client, server Server) (*A
isEmbedded: isEmbedded, isEmbedded: isEmbedded,
} }
go a.authHeaderCache.Start() go a.authHeaderCache.Start()
a.sessions = a.getStore(p, externalHost) if oldApp != nil && oldApp.sessions != nil {
a.sessions = oldApp.sessions
} else {
sess, err := a.getStore(p, externalHost)
if err != nil {
return nil, err
}
a.sessions = sess
}
mux.Use(web.NewLoggingHandler(muxLogger, func(l *log.Entry, r *http.Request) *log.Entry { mux.Use(web.NewLoggingHandler(muxLogger, func(l *log.Entry, r *http.Request) *log.Entry {
c := a.getClaimsFromSession(r) c := a.getClaimsFromSession(r)
if c == nil { if c == nil {
@ -235,9 +246,8 @@ func NewApplication(p api.ProxyOutpostConfig, c *http.Client, server Server) (*A
// TODO: maybe create event for this? // TODO: maybe create event for this?
a.log.WithError(err).Warning("failed to compile SkipPathRegex") a.log.WithError(err).Warning("failed to compile SkipPathRegex")
continue continue
} else {
a.UnauthenticatedRegex = append(a.UnauthenticatedRegex, re)
} }
a.UnauthenticatedRegex = append(a.UnauthenticatedRegex, re)
} }
} }
return a, nil return a, nil

View File

@ -26,7 +26,7 @@ import (
const RedisKeyPrefix = "authentik_proxy_session_" const RedisKeyPrefix = "authentik_proxy_session_"
func (a *Application) getStore(p api.ProxyOutpostConfig, externalHost *url.URL) sessions.Store { func (a *Application) getStore(p api.ProxyOutpostConfig, externalHost *url.URL) (sessions.Store, error) {
maxAge := 0 maxAge := 0
if p.AccessTokenValidity.IsSet() { if p.AccessTokenValidity.IsSet() {
t := p.AccessTokenValidity.Get() t := p.AccessTokenValidity.Get()
@ -73,7 +73,7 @@ func (a *Application) getStore(p api.ProxyOutpostConfig, externalHost *url.URL)
// New default RedisStore // New default RedisStore
rs, err := redisstore.NewRedisStore(context.Background(), client) rs, err := redisstore.NewRedisStore(context.Background(), client)
if err != nil { if err != nil {
a.log.WithError(err).Panic("failed to connect to redis") return nil, err
} }
rs.KeyPrefix(RedisKeyPrefix) rs.KeyPrefix(RedisKeyPrefix)
@ -87,7 +87,7 @@ func (a *Application) getStore(p api.ProxyOutpostConfig, externalHost *url.URL)
}) })
a.log.Trace("using redis session backend") a.log.Trace("using redis session backend")
return rs return rs, nil
} }
dir := os.TempDir() dir := os.TempDir()
cs := sessions.NewFilesystemStore(dir) cs := sessions.NewFilesystemStore(dir)
@ -106,7 +106,7 @@ func (a *Application) getStore(p api.ProxyOutpostConfig, externalHost *url.URL)
cs.Options.MaxAge = maxAge cs.Options.MaxAge = maxAge
cs.Options.Path = "/" cs.Options.Path = "/"
a.log.WithField("dir", dir).Trace("using filesystem session backend") a.log.WithField("dir", dir).Trace("using filesystem session backend")
return cs return cs, nil
} }
func (a *Application) SessionName() string { func (a *Application) SessionName() string {

View File

@ -66,6 +66,7 @@ func newTestApplication() *Application {
}, },
http.DefaultClient, http.DefaultClient,
ts, ts,
nil,
) )
ts.apps = append(ts.apps, a) ts.apps = append(ts.apps, a)
return a return a

View File

@ -4,6 +4,7 @@ import (
"context" "context"
"fmt" "fmt"
"net/http" "net/http"
"net/url"
"github.com/getsentry/sentry-go" "github.com/getsentry/sentry-go"
"goauthentik.io/internal/constants" "goauthentik.io/internal/constants"
@ -37,16 +38,21 @@ func (ps *ProxyServer) Refresh() error {
), ),
), ),
} }
a, err := application.NewApplication(provider, hc, ps) externalHost, err := url.Parse(provider.ExternalHost)
existing, ok := ps.apps[a.Host] if err != nil {
ps.log.WithError(err).Warning("failed to parse URL, skipping provider")
continue
}
existing, ok := ps.apps[externalHost.Host]
a, err := application.NewApplication(provider, hc, ps, existing)
if ok { if ok {
existing.Stop() existing.Stop()
} }
if err != nil { if err != nil {
ps.log.WithError(err).Warning("failed to setup application") ps.log.WithError(err).Warning("failed to setup application")
} else { continue
apps[a.Host] = a
} }
apps[externalHost.Host] = a
} }
ps.apps = apps ps.apps = apps
ps.log.Debug("Swapped maps") ps.log.Debug("Swapped maps")