From a900d0ed8d5f7ba9b407e461eae315a6c0b4287d Mon Sep 17 00:00:00 2001 From: Christian Richter Date: Wed, 12 Apr 2023 15:40:18 +0200 Subject: [PATCH] Refactor caches Signed-off-by: Christian Richter --- services/proxy/pkg/command/server.go | 50 +++++++++++++--------- services/proxy/pkg/config/config.go | 1 + services/proxy/pkg/middleware/oidc_auth.go | 4 +- services/proxy/pkg/middleware/options.go | 19 +++++--- 4 files changed, 47 insertions(+), 27 deletions(-) diff --git a/services/proxy/pkg/command/server.go b/services/proxy/pkg/command/server.go index 83f653ee7a..42c9bfdae2 100644 --- a/services/proxy/pkg/command/server.go +++ b/services/proxy/pkg/command/server.go @@ -43,13 +43,13 @@ import ( ) type StaticRouteHandler struct { - prefix string - proxy http.Handler - sidCache microstore.Store - accessTokenCache microstore.Store - logger log.Logger - config config.Config - oidcClient oidc.OIDCProvider + prefix string + proxy http.Handler + userInfoCache microstore.Store + sessionLookupCache microstore.Store + logger log.Logger + config config.Config + oidcClient oidc.OIDCProvider } // Server is the entrypoint for the server command. @@ -62,7 +62,7 @@ func Server(cfg *config.Config) *cli.Command { return configlog.ReturnFatal(parser.ParseConfig(cfg)) }, Action: func(c *cli.Context) error { - cache := store.Create( + userInfoCache := store.Create( store.Store(cfg.OIDC.UserinfoCache.Store), store.TTL(cfg.OIDC.UserinfoCache.TTL), store.Size(cfg.OIDC.UserinfoCache.Size), @@ -71,6 +71,15 @@ func Server(cfg *config.Config) *cli.Command { microstore.Table(cfg.OIDC.UserinfoCache.Table), ) + sessionLookupCache := store.Create( + store.Store(cfg.OIDC.SessionLookupCache.Store), + store.TTL(cfg.OIDC.SessionLookupCache.TTL), + store.Size(cfg.OIDC.SessionLookupCache.Size), + microstore.Nodes(cfg.OIDC.SessionLookupCache.Nodes...), + microstore.Database(cfg.OIDC.SessionLookupCache.Database), + microstore.Table(cfg.OIDC.SessionLookupCache.Table), + ) + logger := logging.Configure(cfg.Service.Name, cfg.Log) err := tracing.Configure(cfg) if err != nil { @@ -122,20 +131,20 @@ func Server(cfg *config.Config) *cli.Command { ) lh := StaticRouteHandler{ - prefix: cfg.HTTP.Root, - sidCache: cache, // FIXME use correct cache - accessTokenCache: cache, // FIXME use correct cache - logger: logger, - config: *cfg, - oidcClient: oidcClient, - proxy: rp, + prefix: cfg.HTTP.Root, + userInfoCache: userInfoCache, + sessionLookupCache: sessionLookupCache, + logger: logger, + config: *cfg, + oidcClient: oidcClient, + proxy: rp, } if err != nil { return fmt.Errorf("failed to initialize reverse proxy: %w", err) } { - middlewares := loadMiddlewares(ctx, logger, cfg, cache) + middlewares := loadMiddlewares(ctx, logger, cfg, userInfoCache, sessionLookupCache) server, err := proxyHTTP.Server( proxyHTTP.Handler(lh.handler()), proxyHTTP.Logger(logger), @@ -222,14 +231,14 @@ func (h *StaticRouteHandler) backchannelLogout(w http.ResponseWriter, r *http.Re return } - records, err := h.sidCache.Read(logoutToken.SessionId) + records, err := h.userInfoCache.Read(logoutToken.SessionId) if errors.Is(err, microstore.ErrNotFound) || len(records) == 0 { render.Status(r, http.StatusOK) return } for _, record := range records { - err = h.accessTokenCache.Delete(string(record.Value)) + err = h.sessionLookupCache.Delete(string(record.Value)) if errors.Is(err, microstore.ErrNotFound) { render.Status(r, http.StatusOK) return @@ -239,7 +248,7 @@ func (h *StaticRouteHandler) backchannelLogout(w http.ResponseWriter, r *http.Re render.Status(r, http.StatusOK) } -func loadMiddlewares(ctx context.Context, logger log.Logger, cfg *config.Config, cache microstore.Store) alice.Chain { +func loadMiddlewares(ctx context.Context, logger log.Logger, cfg *config.Config, userInfoCache microstore.Store, sessionLookupCache microstore.Store) alice.Chain { rolesClient := settingssvc.NewRoleService("com.owncloud.api.settings", grpc.DefaultClient()) revaClient, err := pool.GetGatewayServiceClient(cfg.Reva.Address, cfg.Reva.GetRevaOptions()...) if err != nil { @@ -316,7 +325,8 @@ func loadMiddlewares(ctx context.Context, logger log.Logger, cfg *config.Config, authenticators = append(authenticators, middleware.NewOIDCAuthenticator( middleware.Logger(logger), - middleware.Cache(cache), + middleware.UserInfoCache(userInfoCache), + middleware.SessionLookupCache(sessionLookupCache), middleware.DefaultAccessTokenTTL(cfg.OIDC.UserinfoCache.TTL), middleware.HTTPClient(oidcHTTPClient), middleware.OIDCIss(cfg.OIDC.Issuer), diff --git a/services/proxy/pkg/config/config.go b/services/proxy/pkg/config/config.go index a2d6daed6f..c23cb56ed4 100644 --- a/services/proxy/pkg/config/config.go +++ b/services/proxy/pkg/config/config.go @@ -106,6 +106,7 @@ type OIDC struct { Insecure bool `yaml:"insecure" env:"OCIS_INSECURE;PROXY_OIDC_INSECURE" desc:"Disable TLS certificate validation for connections to the IDP. Note that this is not recommended for production environments."` AccessTokenVerifyMethod string `yaml:"access_token_verify_method" env:"PROXY_OIDC_ACCESS_TOKEN_VERIFY_METHOD" desc:"Sets how OIDC access tokens should be verified. Possible values are 'none' and 'jwt'. When using 'none', no special validation apart from using it for accessing the IPD's userinfo endpoint will be done. When using 'jwt', it tries to parse the access token as a jwt token and verifies the signature using the keys published on the IDP's 'jwks_uri'."` UserinfoCache *Cache `yaml:"user_info_cache"` + SessionLookupCache *Cache `yaml:"session_lookup_cache"` JWKS JWKS `yaml:"jwks"` RewriteWellKnown bool `yaml:"rewrite_well_known" env:"PROXY_OIDC_REWRITE_WELLKNOWN" desc:"Enables rewriting the /.well-known/openid-configuration to the configured OIDC issuer. Needed by the Desktop Client, Android Client and iOS Client to discover the OIDC provider."` } diff --git a/services/proxy/pkg/middleware/oidc_auth.go b/services/proxy/pkg/middleware/oidc_auth.go index 4341f537c1..61cdc25d15 100644 --- a/services/proxy/pkg/middleware/oidc_auth.go +++ b/services/proxy/pkg/middleware/oidc_auth.go @@ -30,8 +30,8 @@ func NewOIDCAuthenticator(opts ...Option) *OIDCAuthenticator { return &OIDCAuthenticator{ Logger: options.Logger, - userInfoCache: options.Cache, - sessionLookupCache: options.Cache, + userInfoCache: options.UserInfoCache, + sessionLookupCache: options.SessionLookupCache, DefaultTokenCacheTTL: options.DefaultAccessTokenTTL, HTTPClient: options.HTTPClient, OIDCIss: options.OIDCIss, diff --git a/services/proxy/pkg/middleware/options.go b/services/proxy/pkg/middleware/options.go index 2b144a9e7e..abbb66d751 100644 --- a/services/proxy/pkg/middleware/options.go +++ b/services/proxy/pkg/middleware/options.go @@ -54,8 +54,10 @@ type Options struct { EnableBasicAuth bool // DefaultAccessTokenTTL is used to calculate the expiration when an access token has no expiration set DefaultAccessTokenTTL time.Duration - // Cache sets the access token cache store - Cache store.Store + // UserInfoCache sets the access token cache store + UserInfoCache store.Store + // SessionLookupCache maps the session to a hashed jwt token + SessionLookupCache store.Store // CredentialsByUserAgent sets the auth challenges on a per user-agent basis CredentialsByUserAgent map[string]string // AccessTokenVerifyMethod configures how access_tokens should be verified but the oidc_auth middleware. @@ -191,10 +193,17 @@ func DefaultAccessTokenTTL(ttl time.Duration) Option { } } -// Cache provides a function to set the Cache -func Cache(val store.Store) Option { +// UserInfoCache provides a function to set the UserInfoCache +func UserInfoCache(val store.Store) Option { return func(o *Options) { - o.Cache = val + o.UserInfoCache = val + } +} + +// SessionLookupCache provides a function to set the SessionLookupCache +func SessionLookupCache(val store.Store) Option { + return func(o *Options) { + o.SessionLookupCache = val } }