From 1323a554bcf1c46ed85d86c01735000194e77b35 Mon Sep 17 00:00:00 2001 From: Christian Richter Date: Wed, 28 Feb 2024 11:59:53 +0100 Subject: [PATCH] move static routes to seperate package Signed-off-by: Christian Richter --- services/proxy/pkg/command/server.go | 108 ++---------------- .../pkg/staticroutes/backchannellogout.go | 63 ++++++++++ .../proxy/pkg/staticroutes/staticroutes.go | 43 +++++++ 3 files changed, 115 insertions(+), 99 deletions(-) create mode 100644 services/proxy/pkg/staticroutes/backchannellogout.go create mode 100644 services/proxy/pkg/staticroutes/staticroutes.go diff --git a/services/proxy/pkg/command/server.go b/services/proxy/pkg/command/server.go index a3739163e9..254170a58f 100644 --- a/services/proxy/pkg/command/server.go +++ b/services/proxy/pkg/command/server.go @@ -3,15 +3,13 @@ package command import ( "context" "crypto/tls" - "errors" "fmt" + "github.com/owncloud/ocis/v2/services/proxy/pkg/staticroutes" "net/http" "os" "time" - "github.com/go-chi/chi/v5" chimiddleware "github.com/go-chi/chi/v5/middleware" - "github.com/go-chi/render" "github.com/justinas/alice" "github.com/oklog/run" "github.com/urfave/cli/v2" @@ -135,13 +133,13 @@ func Server(cfg *config.Config) *cli.Command { proxy.Config(cfg), ) - lh := StaticRouteHandler{ - prefix: cfg.HTTP.Root, - userInfoCache: userInfoCache, - logger: logger, - config: *cfg, - oidcClient: oidcClient, - proxy: rp, + lh := staticroutes.StaticRouteHandler{ + Prefix: cfg.HTTP.Root, + UserInfoCache: userInfoCache, + Logger: logger, + Config: *cfg, + OidcClient: oidcClient, + Proxy: rp, } if err != nil { return fmt.Errorf("failed to initialize reverse proxy: %w", err) @@ -150,7 +148,7 @@ func Server(cfg *config.Config) *cli.Command { { middlewares := loadMiddlewares(ctx, logger, cfg, userInfoCache, signingKeyStore, traceProvider, *m) server, err := proxyHTTP.Server( - proxyHTTP.Handler(lh.handler()), + proxyHTTP.Handler(lh.Handler()), proxyHTTP.Logger(logger), proxyHTTP.Context(ctx), proxyHTTP.Config(cfg), @@ -201,94 +199,6 @@ func Server(cfg *config.Config) *cli.Command { } } -// StaticRouteHandler defines a Route Handler for static routes -type StaticRouteHandler struct { - prefix string - proxy http.Handler - userInfoCache microstore.Store - logger log.Logger - config config.Config - oidcClient oidc.OIDCClient -} - -func (h *StaticRouteHandler) handler() http.Handler { - m := chi.NewMux() - m.Route(h.prefix, func(r chi.Router) { - // Wrapper for backchannel logout - r.Post("/backchannel_logout", h.backchannelLogout) - - // TODO: migrate oidc well knowns here in a second wrapper - - // Send all requests to the proxy handler - r.HandleFunc("/*", h.proxy.ServeHTTP) - }) - - // Also send requests for methods unknown to chi to the proxy handler as well - m.MethodNotAllowed(h.proxy.ServeHTTP) - - return m -} - -type jse struct { - Error string `json:"error"` - ErrorDescription string `json:"error_description"` -} - -// handle backchannel logout requests as per https://openid.net/specs/openid-connect-backchannel-1_0.html#BCRequest -func (h *StaticRouteHandler) backchannelLogout(w http.ResponseWriter, r *http.Request) { - // parse the application/x-www-form-urlencoded POST request - logger := h.logger.SubloggerWithRequestID(r.Context()) - if err := r.ParseForm(); err != nil { - logger.Warn().Err(err).Msg("ParseForm failed") - render.Status(r, http.StatusBadRequest) - render.JSON(w, r, jse{Error: "invalid_request", ErrorDescription: err.Error()}) - return - } - - logoutToken, err := h.oidcClient.VerifyLogoutToken(r.Context(), r.PostFormValue("logout_token")) - if err != nil { - logger.Warn().Err(err).Msg("VerifyLogoutToken failed") - render.Status(r, http.StatusBadRequest) - render.JSON(w, r, jse{Error: "invalid_request", ErrorDescription: err.Error()}) - return - } - - records, err := h.userInfoCache.Read(logoutToken.SessionId) - if errors.Is(err, microstore.ErrNotFound) || len(records) == 0 { - render.Status(r, http.StatusOK) - render.JSON(w, r, nil) - return - } - - if err != nil { - logger.Error().Err(err).Msg("Error reading userinfo cache") - render.Status(r, http.StatusBadRequest) - render.JSON(w, r, jse{Error: "invalid_request", ErrorDescription: err.Error()}) - return - } - - for _, record := range records { - err = h.userInfoCache.Delete(string(record.Value)) - if err != nil && !errors.Is(err, microstore.ErrNotFound) { - // Spec requires us to return a 400 BadRequest when the session could not be destroyed - logger.Err(err).Msg("could not delete user info from cache") - render.Status(r, http.StatusBadRequest) - render.JSON(w, r, jse{Error: "invalid_request", ErrorDescription: err.Error()}) - return - } - logger.Debug().Msg("Deleted userinfo from cache") - } - - // we can ignore errors when cleaning up the lookup table - err = h.userInfoCache.Delete(logoutToken.SessionId) - if err != nil { - logger.Debug().Err(err).Msg("Failed to cleanup sessionid lookup entry") - } - - render.Status(r, http.StatusOK) - render.JSON(w, r, nil) -} - func loadMiddlewares(ctx context.Context, logger log.Logger, cfg *config.Config, userInfoCache, signingKeyStore microstore.Store, traceProvider trace.TracerProvider, metrics metrics.Metrics) alice.Chain { rolesClient := settingssvc.NewRoleService("com.owncloud.api.settings", cfg.GrpcClient) policiesProviderClient := policiessvc.NewPoliciesProviderService("com.owncloud.api.policies", cfg.GrpcClient) diff --git a/services/proxy/pkg/staticroutes/backchannellogout.go b/services/proxy/pkg/staticroutes/backchannellogout.go new file mode 100644 index 0000000000..a3cece55d3 --- /dev/null +++ b/services/proxy/pkg/staticroutes/backchannellogout.go @@ -0,0 +1,63 @@ +package staticroutes + +import ( + "github.com/go-chi/render" + "github.com/pkg/errors" + microstore "go-micro.dev/v4/store" + "net/http" +) + +// handle backchannel logout requests as per https://openid.net/specs/openid-connect-backchannel-1_0.html#BCRequest +func (s *StaticRouteHandler) backchannelLogout(w http.ResponseWriter, r *http.Request) { + // parse the application/x-www-form-urlencoded POST request + logger := s.Logger.SubloggerWithRequestID(r.Context()) + if err := r.ParseForm(); err != nil { + logger.Warn().Err(err).Msg("ParseForm failed") + render.Status(r, http.StatusBadRequest) + render.JSON(w, r, jse{Error: "invalid_request", ErrorDescription: err.Error()}) + return + } + + logoutToken, err := s.OidcClient.VerifyLogoutToken(r.Context(), r.PostFormValue("logout_token")) + if err != nil { + logger.Warn().Err(err).Msg("VerifyLogoutToken failed") + render.Status(r, http.StatusBadRequest) + render.JSON(w, r, jse{Error: "invalid_request", ErrorDescription: err.Error()}) + return + } + + records, err := s.UserInfoCache.Read(logoutToken.SessionId) + if errors.Is(err, microstore.ErrNotFound) || len(records) == 0 { + render.Status(r, http.StatusOK) + render.JSON(w, r, nil) + return + } + + if err != nil { + logger.Error().Err(err).Msg("Error reading userinfo cache") + render.Status(r, http.StatusBadRequest) + render.JSON(w, r, jse{Error: "invalid_request", ErrorDescription: err.Error()}) + return + } + + for _, record := range records { + err = s.UserInfoCache.Delete(string(record.Value)) + if err != nil && !errors.Is(err, microstore.ErrNotFound) { + // Spec requires us to return a 400 BadRequest when the session could not be destroyed + logger.Err(err).Msg("could not delete user info from cache") + render.Status(r, http.StatusBadRequest) + render.JSON(w, r, jse{Error: "invalid_request", ErrorDescription: err.Error()}) + return + } + logger.Debug().Msg("Deleted userinfo from cache") + } + + // we can ignore errors when cleaning up the lookup table + err = s.UserInfoCache.Delete(logoutToken.SessionId) + if err != nil { + logger.Debug().Err(err).Msg("Failed to cleanup sessionid lookup entry") + } + + render.Status(r, http.StatusOK) + render.JSON(w, r, nil) +} diff --git a/services/proxy/pkg/staticroutes/staticroutes.go b/services/proxy/pkg/staticroutes/staticroutes.go new file mode 100644 index 0000000000..88b8914ea6 --- /dev/null +++ b/services/proxy/pkg/staticroutes/staticroutes.go @@ -0,0 +1,43 @@ +package staticroutes + +import ( + "github.com/go-chi/chi/v5" + "github.com/owncloud/ocis/v2/ocis-pkg/log" + "github.com/owncloud/ocis/v2/ocis-pkg/oidc" + "github.com/owncloud/ocis/v2/services/proxy/pkg/config" + microstore "go-micro.dev/v4/store" + "net/http" +) + +// StaticRouteHandler defines a Route Handler for static routes +type StaticRouteHandler struct { + Prefix string + Proxy http.Handler + UserInfoCache microstore.Store + Logger log.Logger + Config config.Config + OidcClient oidc.OIDCClient +} + +type jse struct { + Error string `json:"error"` + ErrorDescription string `json:"error_description"` +} + +func (s *StaticRouteHandler) Handler() http.Handler { + m := chi.NewMux() + m.Route(s.Prefix, func(r chi.Router) { + // Wrapper for backchannel logout + r.Post("/backchannel_logout", s.backchannelLogout) + + // TODO: migrate oidc well knowns here in a second wrapper + + // Send all requests to the proxy handler + r.HandleFunc("/*", s.Proxy.ServeHTTP) + }) + + // Also send requests for methods unknown to chi to the proxy handler as well + m.MethodNotAllowed(s.Proxy.ServeHTTP) + + return m +}