From 1b117279f2c683c271a931a7a6718f50dfa3131a Mon Sep 17 00:00:00 2001 From: Aayushi Jain Date: Thu, 13 Mar 2025 13:08:08 -0700 Subject: [PATCH 01/32] feat(proxyd): add external authentication support and refactor auth handling --- proxyd/example.config.toml | 2 ++ proxyd/proxyd.go | 30 ++++++++++++++------ proxyd/server.go | 56 ++++++++++++++++++++++++++++++++++---- 3 files changed, 73 insertions(+), 15 deletions(-) diff --git a/proxyd/example.config.toml b/proxyd/example.config.toml index 14355afe..d74d3a75 100644 --- a/proxyd/example.config.toml +++ b/proxyd/example.config.toml @@ -117,6 +117,8 @@ backends = ["alchemy"] # is provided. Note that you will need to quote the environment variable # in order for it to be value TOML, e.g. "$FOO_AUTH_KEY" = "foo_alias". secret = "test" +# URL for external authentication service (optional) +auth_url = "https://api.developer.coinbase.com/rpc/v1/base" # Mapping of methods to backend groups. [rpc_method_mappings] diff --git a/proxyd/proxyd.go b/proxyd/proxyd.go index 6ce7edb0..f5058c30 100644 --- a/proxyd/proxyd.go +++ b/proxyd/proxyd.go @@ -33,9 +33,11 @@ func Start(config *Config) (*Server, func(), error) { return nil, nil, errors.New("must define at least one RPC method mapping") } - for authKey := range config.Authentication { - if authKey == "none" { - return nil, nil, errors.New("cannot use none as an auth key") + if config.Authentication != nil { + if secret, ok := config.Authentication["secret"]; ok { + if secret == "none" { + return nil, nil, errors.New("cannot use none as an auth key") + } } } @@ -193,7 +195,6 @@ func Start(config *Config) (*Server, func(), error) { opts = append(opts, WithStrippedTrailingXFF()) } opts = append(opts, WithProxydIP(os.Getenv("PROXYD_IP"))) - opts = append(opts, WithSkipIsSyncingCheck(cfg.SkipIsSyncingCheck)) opts = append(opts, WithConsensusSkipPeerCountCheck(cfg.ConsensusSkipPeerCountCheck)) opts = append(opts, WithConsensusForcedCandidate(cfg.ConsensusForcedCandidate)) opts = append(opts, WithWeight(cfg.Weight)) @@ -285,16 +286,26 @@ func Start(config *Config) (*Server, func(), error) { } } - var resolvedAuth map[string]string + var authenticatedPaths map[string]string + var authURL string if config.Authentication != nil { - resolvedAuth = make(map[string]string) - for secret, alias := range config.Authentication { + // Check if auth_url is specified in the authentication map + if urlVal, ok := config.Authentication["auth_url"]; ok { + authURL = urlVal + } + + // Check for traditional secret-based auth + if secret, ok := config.Authentication["secret"]; ok { + if authURL != "" { + return nil, nil, errors.New("cannot specify both auth_url and secrets") + } + authenticatedPaths = make(map[string]string) resolvedSecret, err := ReadFromEnvOrConfig(secret) if err != nil { return nil, nil, err } - resolvedAuth[resolvedSecret] = alias + authenticatedPaths[resolvedSecret] = "default" } } @@ -343,7 +354,7 @@ func Start(config *Config) (*Server, func(), error) { NewStringSetFromStrings(config.WSMethodWhitelist), config.RPCMethodMappings, config.Server.MaxBodySizeBytes, - resolvedAuth, + authenticatedPaths, secondsToDuration(config.Server.TimeoutSeconds), config.Server.MaxUpstreamBatchSize, config.Server.EnableXServedByHeader, @@ -354,6 +365,7 @@ func Start(config *Config) (*Server, func(), error) { config.Server.MaxRequestBodyLogLen, config.BatchConfig.MaxSize, limiterFactory, + authURL, ) if err != nil { return nil, nil, fmt.Errorf("error creating server: %w", err) diff --git a/proxyd/server.go b/proxyd/server.go index 60cfa3dc..8091d65c 100644 --- a/proxyd/server.go +++ b/proxyd/server.go @@ -50,6 +50,13 @@ const ( var emptyArrayResponse = json.RawMessage("[]") +type AuthCallbackRequest struct { + Headers map[string][]string `json:"headers"` + Path string `json:"path"` + Body string `json:"body"` + RemoteAddr string `json:"remote_addr"` +} + type Server struct { BackendGroups map[string]*BackendGroup wsBackendGroup *BackendGroup @@ -76,6 +83,7 @@ type Server struct { cache RPCCache srvMu sync.Mutex rateLimitHeader string + authURL string } type limiterFunc func(method string) bool @@ -99,6 +107,7 @@ func NewServer( maxRequestBodyLogLen int, maxBatchSize int, limiterFactory limiterFactoryFunc, + authURL string, ) (*Server, error) { if cache == nil { cache = &NoopRPCCache{} @@ -191,6 +200,7 @@ func NewServer( limExemptOrigins: limExemptOrigins, limExemptUserAgents: limExemptUserAgents, rateLimitHeader: rateLimitHeader, + authURL: authURL, }, nil } @@ -628,7 +638,17 @@ func (s *Server) populateContext(w http.ResponseWriter, r *http.Request) context ctx = context.WithValue(ctx, ContextKeyOpTxProxyAuth, opTxProxyAuth) // nolint:staticcheck } - if len(s.authenticatedPaths) > 0 { + if s.authURL != "" { + // Use external authentication service + alias, err := s.performAuthCallback(r, authorization) + if err != nil { + log.Error("auth callback failed", "err", err) + w.WriteHeader(http.StatusUnauthorized) + return nil + } + ctx = context.WithValue(ctx, ContextKeyAuth, alias) // nolint:staticcheck + } else if len(s.authenticatedPaths) > 0 { + // Fallback to traditional auth if authorization == "" || s.authenticatedPaths[authorization] == "" { log.Info("blocked unauthorized request", "authorization", authorization) httpResponseCodesTotal.WithLabelValues("401").Inc() @@ -638,12 +658,36 @@ func (s *Server) populateContext(w http.ResponseWriter, r *http.Request) context ctx = context.WithValue(ctx, ContextKeyAuth, s.authenticatedPaths[authorization]) // nolint:staticcheck } + return context.WithValue(ctx, ContextKeyReqID, randStr(10)) +} - return context.WithValue( - ctx, - ContextKeyReqID, // nolint:staticcheck - randStr(10), - ) +func (s *Server) performAuthCallback(r *http.Request, apiKey string) (string, error) { + if s.authURL == "" { + return "", fmt.Errorf("no auth URL configured") + } + + // Create auth request with API key in path + authURL := fmt.Sprintf("%s/%s", s.authURL, apiKey) + req, err := http.NewRequestWithContext(r.Context(), "POST", authURL, r.Body) + if err != nil { + return "", err + } + + // Forward headers + req.Header.Set("Content-Type", "application/json") + + client := &http.Client{Timeout: 5 * time.Second} + resp, err := client.Do(req) + if err != nil { + return "", fmt.Errorf("auth callback failed: %w", err) + } + defer resp.Body.Close() + + if resp.StatusCode != http.StatusOK { + return "", fmt.Errorf("auth callback failed with status: %d", resp.StatusCode) + } + + return apiKey, nil } func randStr(l int) string { From 23186fb5e58e23765342bfe29b9f872af8c0f66a Mon Sep 17 00:00:00 2001 From: Aayushi Jain Date: Thu, 13 Mar 2025 13:19:30 -0700 Subject: [PATCH 02/32] fix(proxyd): add staticcheck directive to suppress lint warning for context value assignment --- proxyd/server.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/proxyd/server.go b/proxyd/server.go index 8091d65c..5436781d 100644 --- a/proxyd/server.go +++ b/proxyd/server.go @@ -658,7 +658,7 @@ func (s *Server) populateContext(w http.ResponseWriter, r *http.Request) context ctx = context.WithValue(ctx, ContextKeyAuth, s.authenticatedPaths[authorization]) // nolint:staticcheck } - return context.WithValue(ctx, ContextKeyReqID, randStr(10)) + return context.WithValue(ctx, ContextKeyReqID, randStr(10)) // nolint:staticcheck } func (s *Server) performAuthCallback(r *http.Request, apiKey string) (string, error) { From 532924c07a077115d28acab3ef0679a37eac25bd Mon Sep 17 00:00:00 2001 From: Aayushi Jain Date: Fri, 14 Mar 2025 12:16:38 -0700 Subject: [PATCH 03/32] feat(proxyd): implement stub authentication for testing purposes --- proxyd/server.go | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/proxyd/server.go b/proxyd/server.go index 5436781d..dbae4016 100644 --- a/proxyd/server.go +++ b/proxyd/server.go @@ -662,6 +662,23 @@ func (s *Server) populateContext(w http.ResponseWriter, r *http.Request) context } func (s *Server) performAuthCallback(r *http.Request, apiKey string) (string, error) { + // Stub authentication for testing + validKeys := []string{ + "aayushi-key", + "v1KtFv89SKPFJhKcTlMWybsPAsfIVX3j", + } + + // Check if apiKey matches any valid key + for _, validKey := range validKeys { + if apiKey == validKey { + return apiKey, nil + } + } + + // Return unauthorized for any other key + return "", fmt.Errorf("unauthorized") + + /* Original HTTP request logic commented out for now if s.authURL == "" { return "", fmt.Errorf("no auth URL configured") } @@ -688,6 +705,7 @@ func (s *Server) performAuthCallback(r *http.Request, apiKey string) (string, er } return apiKey, nil + */ } func randStr(l int) string { From cc9cff451bc4e3461234ce60965fb65531d86680 Mon Sep 17 00:00:00 2001 From: Aayushi Jain Date: Mon, 17 Mar 2025 09:11:00 -0700 Subject: [PATCH 04/32] feat(proxyd): enhance logging for authentication processes and change log level to debug --- proxyd/example.config.toml | 2 +- proxyd/server.go | 40 ++++++++++++++++++++++++++++++++++---- 2 files changed, 37 insertions(+), 5 deletions(-) diff --git a/proxyd/example.config.toml b/proxyd/example.config.toml index d74d3a75..3475e969 100644 --- a/proxyd/example.config.toml +++ b/proxyd/example.config.toml @@ -21,7 +21,7 @@ ws_port = 8085 max_body_size_bytes = 10485760 max_concurrent_rpcs = 1000 # Server log level -log_level = "info" +log_level = "debug" [redis] # URL to a Redis instance. diff --git a/proxyd/server.go b/proxyd/server.go index dbae4016..a9edb186 100644 --- a/proxyd/server.go +++ b/proxyd/server.go @@ -624,6 +624,13 @@ func (s *Server) populateContext(w http.ResponseWriter, r *http.Request) context vars := mux.Vars(r) authorization := vars["authorization"] xff := r.Header.Get(s.rateLimitHeader) + + log.Debug("received request", + "path", r.URL.Path, + "auth_key", authorization, + "auth_url_configured", s.authURL != "", + "authenticated_paths_configured", len(s.authenticatedPaths) > 0) + if xff == "" { ipPort := strings.Split(r.RemoteAddr, ":") if len(ipPort) == 2 { @@ -639,29 +646,49 @@ func (s *Server) populateContext(w http.ResponseWriter, r *http.Request) context } if s.authURL != "" { + log.Debug("using external auth service", + "auth_url", s.authURL, + "auth_key", authorization) + // Use external authentication service alias, err := s.performAuthCallback(r, authorization) if err != nil { - log.Error("auth callback failed", "err", err) + log.Error("auth callback failed", + "err", err, + "auth_key", authorization) w.WriteHeader(http.StatusUnauthorized) return nil } + log.Debug("external auth succeeded", + "auth_key", authorization, + "alias", alias) ctx = context.WithValue(ctx, ContextKeyAuth, alias) // nolint:staticcheck } else if len(s.authenticatedPaths) > 0 { + log.Debug("using traditional auth", + "auth_key", authorization, + "valid_keys", len(s.authenticatedPaths)) + // Fallback to traditional auth if authorization == "" || s.authenticatedPaths[authorization] == "" { - log.Info("blocked unauthorized request", "authorization", authorization) + log.Info("blocked unauthorized request", + "auth_key", authorization, + "valid_keys_count", len(s.authenticatedPaths)) httpResponseCodesTotal.WithLabelValues("401").Inc() w.WriteHeader(401) return nil } - + log.Debug("traditional auth succeeded", + "auth_key", authorization, + "alias", s.authenticatedPaths[authorization]) ctx = context.WithValue(ctx, ContextKeyAuth, s.authenticatedPaths[authorization]) // nolint:staticcheck } return context.WithValue(ctx, ContextKeyReqID, randStr(10)) // nolint:staticcheck } func (s *Server) performAuthCallback(r *http.Request, apiKey string) (string, error) { + log.Debug("performing auth callback", + "api_key", apiKey) + // Stub authentication for testing validKeys := []string{ "aayushi-key", @@ -671,11 +698,15 @@ func (s *Server) performAuthCallback(r *http.Request, apiKey string) (string, er // Check if apiKey matches any valid key for _, validKey := range validKeys { if apiKey == validKey { + log.Debug("auth callback succeeded", + "api_key", apiKey) return apiKey, nil } } - // Return unauthorized for any other key + log.Debug("auth callback failed", + "api_key", apiKey, + "reason", "key not in valid keys list") return "", fmt.Errorf("unauthorized") /* Original HTTP request logic commented out for now @@ -706,6 +737,7 @@ func (s *Server) performAuthCallback(r *http.Request, apiKey string) (string, er return apiKey, nil */ + } func randStr(l int) string { From 0ca4f1abfc51de0f8ad5094139e5cea643aba2ae Mon Sep 17 00:00:00 2001 From: Aayushi Jain Date: Mon, 17 Mar 2025 09:39:44 -0700 Subject: [PATCH 05/32] refactor(proxyd): change log level to info and update logging statements for request handling --- proxyd/example.config.toml | 2 +- proxyd/server.go | 31 +++++++++++-------------------- 2 files changed, 12 insertions(+), 21 deletions(-) diff --git a/proxyd/example.config.toml b/proxyd/example.config.toml index 3475e969..d74d3a75 100644 --- a/proxyd/example.config.toml +++ b/proxyd/example.config.toml @@ -21,7 +21,7 @@ ws_port = 8085 max_body_size_bytes = 10485760 max_concurrent_rpcs = 1000 # Server log level -log_level = "debug" +log_level = "info" [redis] # URL to a Redis instance. diff --git a/proxyd/server.go b/proxyd/server.go index a9edb186..524548b4 100644 --- a/proxyd/server.go +++ b/proxyd/server.go @@ -625,7 +625,7 @@ func (s *Server) populateContext(w http.ResponseWriter, r *http.Request) context authorization := vars["authorization"] xff := r.Header.Get(s.rateLimitHeader) - log.Debug("received request", + log.Info("received request", "path", r.URL.Path, "auth_key", authorization, "auth_url_configured", s.authURL != "", @@ -646,7 +646,7 @@ func (s *Server) populateContext(w http.ResponseWriter, r *http.Request) context } if s.authURL != "" { - log.Debug("using external auth service", + log.Info("using external auth service", "auth_url", s.authURL, "auth_key", authorization) @@ -659,12 +659,12 @@ func (s *Server) populateContext(w http.ResponseWriter, r *http.Request) context w.WriteHeader(http.StatusUnauthorized) return nil } - log.Debug("external auth succeeded", + log.Info("external auth succeeded", "auth_key", authorization, "alias", alias) ctx = context.WithValue(ctx, ContextKeyAuth, alias) // nolint:staticcheck } else if len(s.authenticatedPaths) > 0 { - log.Debug("using traditional auth", + log.Info("using traditional auth", "auth_key", authorization, "valid_keys", len(s.authenticatedPaths)) @@ -677,7 +677,7 @@ func (s *Server) populateContext(w http.ResponseWriter, r *http.Request) context w.WriteHeader(401) return nil } - log.Debug("traditional auth succeeded", + log.Info("traditional auth succeeded", "auth_key", authorization, "alias", s.authenticatedPaths[authorization]) ctx = context.WithValue(ctx, ContextKeyAuth, s.authenticatedPaths[authorization]) // nolint:staticcheck @@ -686,25 +686,16 @@ func (s *Server) populateContext(w http.ResponseWriter, r *http.Request) context } func (s *Server) performAuthCallback(r *http.Request, apiKey string) (string, error) { - log.Debug("performing auth callback", + log.Info("performing auth callback", "api_key", apiKey) - // Stub authentication for testing - validKeys := []string{ - "aayushi-key", - "v1KtFv89SKPFJhKcTlMWybsPAsfIVX3j", + if apiKey == "aayushi-key" { + log.Info("auth callback succeeded", + "api_key", apiKey) + return apiKey, nil } - // Check if apiKey matches any valid key - for _, validKey := range validKeys { - if apiKey == validKey { - log.Debug("auth callback succeeded", - "api_key", apiKey) - return apiKey, nil - } - } - - log.Debug("auth callback failed", + log.Info("auth callback failed", "api_key", apiKey, "reason", "key not in valid keys list") return "", fmt.Errorf("unauthorized") From 728028e3a21a62916feedf5e4266df076e5913bc Mon Sep 17 00:00:00 2001 From: Aayushi Jain Date: Mon, 17 Mar 2025 10:30:01 -0700 Subject: [PATCH 06/32] refactor(proxyd): improve logging statements for context population and authentication callback --- proxyd/server.go | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/proxyd/server.go b/proxyd/server.go index 524548b4..600699b9 100644 --- a/proxyd/server.go +++ b/proxyd/server.go @@ -625,7 +625,7 @@ func (s *Server) populateContext(w http.ResponseWriter, r *http.Request) context authorization := vars["authorization"] xff := r.Header.Get(s.rateLimitHeader) - log.Info("received request", + log.Info("populateContext received request", "path", r.URL.Path, "auth_key", authorization, "auth_url_configured", s.authURL != "", @@ -686,7 +686,7 @@ func (s *Server) populateContext(w http.ResponseWriter, r *http.Request) context } func (s *Server) performAuthCallback(r *http.Request, apiKey string) (string, error) { - log.Info("performing auth callback", + log.Info("performAuthCallback performing auth callback", "api_key", apiKey) if apiKey == "aayushi-key" { @@ -886,11 +886,16 @@ func instrumentedHdlr(h http.Handler) http.HandlerFunc { } func GetAuthCtx(ctx context.Context) string { + if ctx == nil { + log.Info("GetAuthCtx called with nil context") + return "none" + } authUser, ok := ctx.Value(ContextKeyAuth).(string) if !ok { + log.Info("GetAuthCtx No auth value found in context") return "none" } - + log.Info("GetAuthCtx Auth value found in context", "auth", authUser) return authUser } From 03f63b65e8bdc2c3a3fbda16c6075664b6eb3044 Mon Sep 17 00:00:00 2001 From: Aayushi Jain Date: Mon, 17 Mar 2025 11:25:27 -0700 Subject: [PATCH 07/32] refactor(proxyd): streamline authentication handling and improve logging for auth_url resolution --- proxyd/proxyd.go | 35 +++++++++++++++++++---------------- proxyd/server.go | 17 +++++++---------- 2 files changed, 26 insertions(+), 26 deletions(-) diff --git a/proxyd/proxyd.go b/proxyd/proxyd.go index f5058c30..7bba2421 100644 --- a/proxyd/proxyd.go +++ b/proxyd/proxyd.go @@ -286,26 +286,30 @@ func Start(config *Config) (*Server, func(), error) { } } - var authenticatedPaths map[string]string - var authURL string + var resolvedAuth map[string]string if config.Authentication != nil { - // Check if auth_url is specified in the authentication map - if urlVal, ok := config.Authentication["auth_url"]; ok { - authURL = urlVal - } + resolvedAuth = make(map[string]string) - // Check for traditional secret-based auth - if secret, ok := config.Authentication["secret"]; ok { - if authURL != "" { - return nil, nil, errors.New("cannot specify both auth_url and secrets") - } - authenticatedPaths = make(map[string]string) - resolvedSecret, err := ReadFromEnvOrConfig(secret) + // First check for auth_url + if urlVal, ok := config.Authentication["auth_url"]; ok { + resolvedURL, err := ReadFromEnvOrConfig(urlVal) if err != nil { return nil, nil, err } - authenticatedPaths[resolvedSecret] = "default" + resolvedAuth["auth_url"] = resolvedURL + log.Info("Start proxyd with configured external auth service", "url", resolvedURL) + } else { + // If no auth_url, process secrets as before + for secret, alias := range config.Authentication { + if secret != "auth_url" { // Skip auth_url key + resolvedSecret, err := ReadFromEnvOrConfig(secret) + if err != nil { + return nil, nil, err + } + resolvedAuth[resolvedSecret] = alias + } + } } } @@ -354,7 +358,7 @@ func Start(config *Config) (*Server, func(), error) { NewStringSetFromStrings(config.WSMethodWhitelist), config.RPCMethodMappings, config.Server.MaxBodySizeBytes, - authenticatedPaths, + resolvedAuth, secondsToDuration(config.Server.TimeoutSeconds), config.Server.MaxUpstreamBatchSize, config.Server.EnableXServedByHeader, @@ -365,7 +369,6 @@ func Start(config *Config) (*Server, func(), error) { config.Server.MaxRequestBodyLogLen, config.BatchConfig.MaxSize, limiterFactory, - authURL, ) if err != nil { return nil, nil, fmt.Errorf("error creating server: %w", err) diff --git a/proxyd/server.go b/proxyd/server.go index 600699b9..6a04d44c 100644 --- a/proxyd/server.go +++ b/proxyd/server.go @@ -83,7 +83,6 @@ type Server struct { cache RPCCache srvMu sync.Mutex rateLimitHeader string - authURL string } type limiterFunc func(method string) bool @@ -107,7 +106,6 @@ func NewServer( maxRequestBodyLogLen int, maxBatchSize int, limiterFactory limiterFactoryFunc, - authURL string, ) (*Server, error) { if cache == nil { cache = &NoopRPCCache{} @@ -200,7 +198,6 @@ func NewServer( limExemptOrigins: limExemptOrigins, limExemptUserAgents: limExemptUserAgents, rateLimitHeader: rateLimitHeader, - authURL: authURL, }, nil } @@ -628,7 +625,7 @@ func (s *Server) populateContext(w http.ResponseWriter, r *http.Request) context log.Info("populateContext received request", "path", r.URL.Path, "auth_key", authorization, - "auth_url_configured", s.authURL != "", + "auth_url_configured", s.authenticatedPaths["auth_url"] != "", "authenticated_paths_configured", len(s.authenticatedPaths) > 0) if xff == "" { @@ -645,15 +642,15 @@ func (s *Server) populateContext(w http.ResponseWriter, r *http.Request) context ctx = context.WithValue(ctx, ContextKeyOpTxProxyAuth, opTxProxyAuth) // nolint:staticcheck } - if s.authURL != "" { - log.Info("using external auth service", - "auth_url", s.authURL, + if s.authenticatedPaths["auth_url"] != "" { + log.Info("populateContext using external auth service", + "auth_url", s.authenticatedPaths["auth_url"], "auth_key", authorization) // Use external authentication service alias, err := s.performAuthCallback(r, authorization) if err != nil { - log.Error("auth callback failed", + log.Error("populateContext auth callback failed", "err", err, "auth_key", authorization) w.WriteHeader(http.StatusUnauthorized) @@ -690,12 +687,12 @@ func (s *Server) performAuthCallback(r *http.Request, apiKey string) (string, er "api_key", apiKey) if apiKey == "aayushi-key" { - log.Info("auth callback succeeded", + log.Info("performAuthCallback auth callback succeeded", "api_key", apiKey) return apiKey, nil } - log.Info("auth callback failed", + log.Info("performAuthCallback auth callback failed", "api_key", apiKey, "reason", "key not in valid keys list") return "", fmt.Errorf("unauthorized") From 3a626d87434c193b6e83d027bedd0e4b9f5c22e9 Mon Sep 17 00:00:00 2001 From: Aayushi Jain Date: Mon, 17 Mar 2025 12:32:52 -0700 Subject: [PATCH 08/32] refactor(proxyd): enhance authentication logging and streamline auth_url processing --- proxyd/proxyd.go | 35 ++++++++++++++++++++--------------- proxyd/server.go | 26 +++++++++++++------------- 2 files changed, 33 insertions(+), 28 deletions(-) diff --git a/proxyd/proxyd.go b/proxyd/proxyd.go index 7bba2421..3adc3097 100644 --- a/proxyd/proxyd.go +++ b/proxyd/proxyd.go @@ -287,29 +287,34 @@ func Start(config *Config) (*Server, func(), error) { } var resolvedAuth map[string]string - if config.Authentication != nil { + log.Info("Startfunction Processing authentication config") resolvedAuth = make(map[string]string) - // First check for auth_url - if urlVal, ok := config.Authentication["auth_url"]; ok { - resolvedURL, err := ReadFromEnvOrConfig(urlVal) + // First, check and process the auth_url if present + if authURL, ok := config.Authentication["auth_url"]; ok { + log.Info("Startfunction Found auth_url config", "url", authURL) + resolvedURL, err := ReadFromEnvOrConfig(authURL) if err != nil { return nil, nil, err } + // Store the auth_url with a special key that we'll check for later resolvedAuth["auth_url"] = resolvedURL - log.Info("Start proxyd with configured external auth service", "url", resolvedURL) - } else { - // If no auth_url, process secrets as before - for secret, alias := range config.Authentication { - if secret != "auth_url" { // Skip auth_url key - resolvedSecret, err := ReadFromEnvOrConfig(secret) - if err != nil { - return nil, nil, err - } - resolvedAuth[resolvedSecret] = alias - } + log.Info("Startfunction Configured external auth service", "url", resolvedURL) + } + // Then process any remaining keys as traditional auth keys + for key, alias := range config.Authentication { + // Skip auth_url as we've already processed it + if key == "auth_url" { + continue + } + + resolvedKey, err := ReadFromEnvOrConfig(key) + if err != nil { + return nil, nil, err } + resolvedAuth[resolvedKey] = alias + log.Info("Startfunction Configured traditional auth", "key", resolvedKey, "alias", alias) } } diff --git a/proxyd/server.go b/proxyd/server.go index 6a04d44c..913b62c1 100644 --- a/proxyd/server.go +++ b/proxyd/server.go @@ -625,8 +625,7 @@ func (s *Server) populateContext(w http.ResponseWriter, r *http.Request) context log.Info("populateContext received request", "path", r.URL.Path, "auth_key", authorization, - "auth_url_configured", s.authenticatedPaths["auth_url"] != "", - "authenticated_paths_configured", len(s.authenticatedPaths) > 0) + "auth_url_configured", s.authenticatedPaths["auth_url"] != "") if xff == "" { ipPort := strings.Split(r.RemoteAddr, ":") @@ -642,39 +641,40 @@ func (s *Server) populateContext(w http.ResponseWriter, r *http.Request) context ctx = context.WithValue(ctx, ContextKeyOpTxProxyAuth, opTxProxyAuth) // nolint:staticcheck } - if s.authenticatedPaths["auth_url"] != "" { - log.Info("populateContext using external auth service", - "auth_url", s.authenticatedPaths["auth_url"], + // Check if we have an external auth URL configured + authURL, hasExternalAuth := s.authenticatedPaths["auth_url"] + if hasExternalAuth && authURL != "" { + log.Info("populateContext Using external auth service", + "auth_url", authURL, "auth_key", authorization) // Use external authentication service alias, err := s.performAuthCallback(r, authorization) if err != nil { - log.Error("populateContext auth callback failed", + log.Error("Auth callback failed", "err", err, "auth_key", authorization) w.WriteHeader(http.StatusUnauthorized) return nil } - log.Info("external auth succeeded", - "auth_key", authorization, - "alias", alias) + + log.Info("populateContext External auth succeeded", "auth_key", authorization, "alias", alias) ctx = context.WithValue(ctx, ContextKeyAuth, alias) // nolint:staticcheck - } else if len(s.authenticatedPaths) > 0 { - log.Info("using traditional auth", + } else { + log.Info("populateContext using traditional auth", "auth_key", authorization, "valid_keys", len(s.authenticatedPaths)) // Fallback to traditional auth if authorization == "" || s.authenticatedPaths[authorization] == "" { - log.Info("blocked unauthorized request", + log.Info("populateContext blocked unauthorized request", "auth_key", authorization, "valid_keys_count", len(s.authenticatedPaths)) httpResponseCodesTotal.WithLabelValues("401").Inc() w.WriteHeader(401) return nil } - log.Info("traditional auth succeeded", + log.Info("populateContext traditional auth succeeded", "auth_key", authorization, "alias", s.authenticatedPaths[authorization]) ctx = context.WithValue(ctx, ContextKeyAuth, s.authenticatedPaths[authorization]) // nolint:staticcheck From 5423883cc21163326789b606c087f675edd1ed17 Mon Sep 17 00:00:00 2001 From: Aayushi Jain Date: Mon, 17 Mar 2025 13:44:07 -0700 Subject: [PATCH 09/32] refactor: add more debugging logs --- proxyd/proxyd.go | 19 ++++++++++++++----- proxyd/server.go | 8 ++++++++ 2 files changed, 22 insertions(+), 5 deletions(-) diff --git a/proxyd/proxyd.go b/proxyd/proxyd.go index 3adc3097..d8614537 100644 --- a/proxyd/proxyd.go +++ b/proxyd/proxyd.go @@ -288,19 +288,24 @@ func Start(config *Config) (*Server, func(), error) { var resolvedAuth map[string]string if config.Authentication != nil { - log.Info("Startfunction Processing authentication config") + log.Info("Authentication config contents", + "raw_config", config.Authentication, + "auth_url_value", config.Authentication["auth_url"], + "secret_value", config.Authentication["secret"]) + resolvedAuth = make(map[string]string) // First, check and process the auth_url if present if authURL, ok := config.Authentication["auth_url"]; ok { - log.Info("Startfunction Found auth_url config", "url", authURL) + log.Info("Found auth_url in config", "auth_url", authURL) resolvedURL, err := ReadFromEnvOrConfig(authURL) if err != nil { return nil, nil, err } - // Store the auth_url with a special key that we'll check for later resolvedAuth["auth_url"] = resolvedURL - log.Info("Startfunction Configured external auth service", "url", resolvedURL) + log.Info("Configured external auth service", + "original_url", authURL, + "resolved_url", resolvedURL) } // Then process any remaining keys as traditional auth keys for key, alias := range config.Authentication { @@ -314,7 +319,7 @@ func Start(config *Config) (*Server, func(), error) { return nil, nil, err } resolvedAuth[resolvedKey] = alias - log.Info("Startfunction Configured traditional auth", "key", resolvedKey, "alias", alias) + log.Info("Configured traditional auth", "key", resolvedKey, "alias", alias) } } @@ -357,6 +362,10 @@ func Start(config *Config) (*Server, func(), error) { return NewMemoryFrontendRateLimit(dur, max) } + log.Info("Creating server", + "resolvedAuth", resolvedAuth, + "has_auth_url", resolvedAuth["auth_url"] != "") + srv, err := NewServer( backendGroups, wsBackendGroup, diff --git a/proxyd/server.go b/proxyd/server.go index 913b62c1..0fab908b 100644 --- a/proxyd/server.go +++ b/proxyd/server.go @@ -107,6 +107,10 @@ func NewServer( maxBatchSize int, limiterFactory limiterFactoryFunc, ) (*Server, error) { + log.Info("NewServer called", + "authenticatedPaths", authenticatedPaths, + "has_auth_url", authenticatedPaths["auth_url"] != "") + if cache == nil { cache = &NoopRPCCache{} } @@ -618,6 +622,10 @@ func (s *Server) HandleWS(w http.ResponseWriter, r *http.Request) { } func (s *Server) populateContext(w http.ResponseWriter, r *http.Request) context.Context { + log.Info("populateContext authenticatedPaths", + "paths", s.authenticatedPaths, + "has_auth_url", s.authenticatedPaths["auth_url"] != "") + vars := mux.Vars(r) authorization := vars["authorization"] xff := r.Header.Get(s.rateLimitHeader) From befee13b73435a1800aa678247fdce226e98b4e7 Mon Sep 17 00:00:00 2001 From: Aayushi Jain Date: Mon, 17 Mar 2025 13:45:53 -0700 Subject: [PATCH 10/32] minor log change --- proxyd/proxyd.go | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/proxyd/proxyd.go b/proxyd/proxyd.go index d8614537..1671301f 100644 --- a/proxyd/proxyd.go +++ b/proxyd/proxyd.go @@ -288,7 +288,7 @@ func Start(config *Config) (*Server, func(), error) { var resolvedAuth map[string]string if config.Authentication != nil { - log.Info("Authentication config contents", + log.Info("Startfunction Authentication config contents", "raw_config", config.Authentication, "auth_url_value", config.Authentication["auth_url"], "secret_value", config.Authentication["secret"]) @@ -297,13 +297,13 @@ func Start(config *Config) (*Server, func(), error) { // First, check and process the auth_url if present if authURL, ok := config.Authentication["auth_url"]; ok { - log.Info("Found auth_url in config", "auth_url", authURL) + log.Info("Startfunction Found auth_url in config", "auth_url", authURL) resolvedURL, err := ReadFromEnvOrConfig(authURL) if err != nil { return nil, nil, err } resolvedAuth["auth_url"] = resolvedURL - log.Info("Configured external auth service", + log.Info("Startfunction Configured external auth service", "original_url", authURL, "resolved_url", resolvedURL) } @@ -311,6 +311,7 @@ func Start(config *Config) (*Server, func(), error) { for key, alias := range config.Authentication { // Skip auth_url as we've already processed it if key == "auth_url" { + log.Info("Startfunction Skipping auth_url", "key", key) continue } @@ -319,7 +320,7 @@ func Start(config *Config) (*Server, func(), error) { return nil, nil, err } resolvedAuth[resolvedKey] = alias - log.Info("Configured traditional auth", "key", resolvedKey, "alias", alias) + log.Info("Startfunction Configured traditional auth", "key", resolvedKey, "alias", alias) } } From 1053ebb8fb25602f9001d09f872024da28a34394 Mon Sep 17 00:00:00 2001 From: Aayushi Jain Date: Mon, 17 Mar 2025 14:02:16 -0700 Subject: [PATCH 11/32] feat(proxyd): change legacy authentication checks to fail open --- proxyd/proxyd.go | 8 -------- proxyd/server.go | 13 ------------- 2 files changed, 21 deletions(-) diff --git a/proxyd/proxyd.go b/proxyd/proxyd.go index 1671301f..79a5dbf3 100644 --- a/proxyd/proxyd.go +++ b/proxyd/proxyd.go @@ -33,14 +33,6 @@ func Start(config *Config) (*Server, func(), error) { return nil, nil, errors.New("must define at least one RPC method mapping") } - if config.Authentication != nil { - if secret, ok := config.Authentication["secret"]; ok { - if secret == "none" { - return nil, nil, errors.New("cannot use none as an auth key") - } - } - } - // redis primary client var redisClient redis.UniversalClient if config.Redis.URL != "" { diff --git a/proxyd/server.go b/proxyd/server.go index 0fab908b..784d5cdd 100644 --- a/proxyd/server.go +++ b/proxyd/server.go @@ -672,19 +672,6 @@ func (s *Server) populateContext(w http.ResponseWriter, r *http.Request) context log.Info("populateContext using traditional auth", "auth_key", authorization, "valid_keys", len(s.authenticatedPaths)) - - // Fallback to traditional auth - if authorization == "" || s.authenticatedPaths[authorization] == "" { - log.Info("populateContext blocked unauthorized request", - "auth_key", authorization, - "valid_keys_count", len(s.authenticatedPaths)) - httpResponseCodesTotal.WithLabelValues("401").Inc() - w.WriteHeader(401) - return nil - } - log.Info("populateContext traditional auth succeeded", - "auth_key", authorization, - "alias", s.authenticatedPaths[authorization]) ctx = context.WithValue(ctx, ContextKeyAuth, s.authenticatedPaths[authorization]) // nolint:staticcheck } return context.WithValue(ctx, ContextKeyReqID, randStr(10)) // nolint:staticcheck From bdd2e05e79dfa2dbe2d9d156364bd14a99ee5ad0 Mon Sep 17 00:00:00 2001 From: Aayushi Jain Date: Mon, 17 Mar 2025 15:28:05 -0700 Subject: [PATCH 12/32] simplify resolvedAuth map logic --- proxyd/example.config.toml | 2 -- proxyd/proxyd.go | 10 ++-------- 2 files changed, 2 insertions(+), 10 deletions(-) diff --git a/proxyd/example.config.toml b/proxyd/example.config.toml index d74d3a75..14355afe 100644 --- a/proxyd/example.config.toml +++ b/proxyd/example.config.toml @@ -117,8 +117,6 @@ backends = ["alchemy"] # is provided. Note that you will need to quote the environment variable # in order for it to be value TOML, e.g. "$FOO_AUTH_KEY" = "foo_alias". secret = "test" -# URL for external authentication service (optional) -auth_url = "https://api.developer.coinbase.com/rpc/v1/base" # Mapping of methods to backend groups. [rpc_method_mappings] diff --git a/proxyd/proxyd.go b/proxyd/proxyd.go index 79a5dbf3..d4e90d25 100644 --- a/proxyd/proxyd.go +++ b/proxyd/proxyd.go @@ -289,15 +289,9 @@ func Start(config *Config) (*Server, func(), error) { // First, check and process the auth_url if present if authURL, ok := config.Authentication["auth_url"]; ok { - log.Info("Startfunction Found auth_url in config", "auth_url", authURL) - resolvedURL, err := ReadFromEnvOrConfig(authURL) - if err != nil { - return nil, nil, err - } - resolvedAuth["auth_url"] = resolvedURL + resolvedAuth["auth_url"] = authURL log.Info("Startfunction Configured external auth service", - "original_url", authURL, - "resolved_url", resolvedURL) + "auth_url", authURL) } // Then process any remaining keys as traditional auth keys for key, alias := range config.Authentication { From 84892c1cfc7c622d2368527f039fe0953778c09f Mon Sep 17 00:00:00 2001 From: Aayushi Jain Date: Mon, 17 Mar 2025 17:10:28 -0700 Subject: [PATCH 13/32] refactor(proxyd): enhance logging in populateContext for better debugging and add helper function to retrieve map keys --- proxyd/server.go | 21 ++++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/proxyd/server.go b/proxyd/server.go index 784d5cdd..2c7fab5e 100644 --- a/proxyd/server.go +++ b/proxyd/server.go @@ -622,9 +622,12 @@ func (s *Server) HandleWS(w http.ResponseWriter, r *http.Request) { } func (s *Server) populateContext(w http.ResponseWriter, r *http.Request) context.Context { - log.Info("populateContext authenticatedPaths", - "paths", s.authenticatedPaths, - "has_auth_url", s.authenticatedPaths["auth_url"] != "") + log.Info("populateContext detailed inspection", + "s ", s, + "auth_paths_nil", s.authenticatedPaths == nil, + "auth_paths_len", len(s.authenticatedPaths), + "all_keys", getMapKeys(s.authenticatedPaths), + "auth_url_exists", s.authenticatedPaths != nil && s.authenticatedPaths["auth_url"] != "") vars := mux.Vars(r) authorization := vars["authorization"] @@ -960,3 +963,15 @@ func createBatchRequest(elems []batchElem) []*RPCReq { } return batch } + +// Helper function to get map keys +func getMapKeys(m map[string]string) []string { + if m == nil { + return nil + } + keys := make([]string, 0, len(m)) + for k := range m { + keys = append(keys, k) + } + return keys +} From 37533912bb01091745930ddc86727cc5f0f591b1 Mon Sep 17 00:00:00 2001 From: Aayushi Jain Date: Mon, 17 Mar 2025 18:00:32 -0700 Subject: [PATCH 14/32] refactor(proxyd): initialize resolvedAuth map and improve logging for server creation and context population --- proxyd/proxyd.go | 11 +++++------ proxyd/server.go | 22 ++++++++++------------ 2 files changed, 15 insertions(+), 18 deletions(-) diff --git a/proxyd/proxyd.go b/proxyd/proxyd.go index d4e90d25..c4ef0ed2 100644 --- a/proxyd/proxyd.go +++ b/proxyd/proxyd.go @@ -278,15 +278,14 @@ func Start(config *Config) (*Server, func(), error) { } } - var resolvedAuth map[string]string + var resolvedAuth map[string]string = make(map[string]string) // Initialize map first + if config.Authentication != nil { log.Info("Startfunction Authentication config contents", "raw_config", config.Authentication, "auth_url_value", config.Authentication["auth_url"], "secret_value", config.Authentication["secret"]) - resolvedAuth = make(map[string]string) - // First, check and process the auth_url if present if authURL, ok := config.Authentication["auth_url"]; ok { resolvedAuth["auth_url"] = authURL @@ -349,9 +348,9 @@ func Start(config *Config) (*Server, func(), error) { return NewMemoryFrontendRateLimit(dur, max) } - log.Info("Creating server", - "resolvedAuth", resolvedAuth, - "has_auth_url", resolvedAuth["auth_url"] != "") + log.Info("StartFunction Creating server with auth paths", + "resolvedAuth_nil", resolvedAuth == nil, + "config_auth_nil", config.Authentication == nil) srv, err := NewServer( backendGroups, diff --git a/proxyd/server.go b/proxyd/server.go index 2c7fab5e..6aba8e98 100644 --- a/proxyd/server.go +++ b/proxyd/server.go @@ -108,8 +108,7 @@ func NewServer( limiterFactory limiterFactoryFunc, ) (*Server, error) { log.Info("NewServer called", - "authenticatedPaths", authenticatedPaths, - "has_auth_url", authenticatedPaths["auth_url"] != "") + "authenticatedPaths", authenticatedPaths) if cache == nil { cache = &NoopRPCCache{} @@ -622,6 +621,13 @@ func (s *Server) HandleWS(w http.ResponseWriter, r *http.Request) { } func (s *Server) populateContext(w http.ResponseWriter, r *http.Request) context.Context { + s.srvMu.Lock() + defer s.srvMu.Unlock() + + vars := mux.Vars(r) + authorization := vars["authorization"] + xff := r.Header.Get(s.rateLimitHeader) + log.Info("populateContext detailed inspection", "s ", s, "auth_paths_nil", s.authenticatedPaths == nil, @@ -629,15 +635,6 @@ func (s *Server) populateContext(w http.ResponseWriter, r *http.Request) context "all_keys", getMapKeys(s.authenticatedPaths), "auth_url_exists", s.authenticatedPaths != nil && s.authenticatedPaths["auth_url"] != "") - vars := mux.Vars(r) - authorization := vars["authorization"] - xff := r.Header.Get(s.rateLimitHeader) - - log.Info("populateContext received request", - "path", r.URL.Path, - "auth_key", authorization, - "auth_url_configured", s.authenticatedPaths["auth_url"] != "") - if xff == "" { ipPort := strings.Split(r.RemoteAddr, ":") if len(ipPort) == 2 { @@ -654,7 +651,8 @@ func (s *Server) populateContext(w http.ResponseWriter, r *http.Request) context // Check if we have an external auth URL configured authURL, hasExternalAuth := s.authenticatedPaths["auth_url"] - if hasExternalAuth && authURL != "" { + log.Info("populateContext hasExternalAuth", "hasExternalAuth", hasExternalAuth, "authURL", authURL) + if hasExternalAuth && authURL != "" { // nolint:staticcheck log.Info("populateContext Using external auth service", "auth_url", authURL, "auth_key", authorization) From 75404f9d6cf8038b90be10e50c690aab1944678d Mon Sep 17 00:00:00 2001 From: Aayushi Jain Date: Tue, 18 Mar 2025 11:48:45 -0700 Subject: [PATCH 15/32] feat(proxyd): add callback to performAuthCallback --- proxyd/server.go | 80 ++++++++++++++++++++++++++++++++++-------------- 1 file changed, 57 insertions(+), 23 deletions(-) diff --git a/proxyd/server.go b/proxyd/server.go index 6aba8e98..f84bd51c 100644 --- a/proxyd/server.go +++ b/proxyd/server.go @@ -1,6 +1,7 @@ package proxyd import ( + "bytes" "context" "crypto/rand" "encoding/hex" @@ -658,7 +659,7 @@ func (s *Server) populateContext(w http.ResponseWriter, r *http.Request) context "auth_key", authorization) // Use external authentication service - alias, err := s.performAuthCallback(r, authorization) + alias, err := s.performAuthCallback(r, authorization, authURL) if err != nil { log.Error("Auth callback failed", "err", err, @@ -678,50 +679,83 @@ func (s *Server) populateContext(w http.ResponseWriter, r *http.Request) context return context.WithValue(ctx, ContextKeyReqID, randStr(10)) // nolint:staticcheck } -func (s *Server) performAuthCallback(r *http.Request, apiKey string) (string, error) { - log.Info("performAuthCallback performing auth callback", - "api_key", apiKey) +func (s *Server) performAuthCallback(r *http.Request, apiKey string, authURL string) (string, error) { + log.Info("performAuthCallback starting", + "api_key", apiKey, + "auth_url", authURL, + "request_path", r.URL.Path) - if apiKey == "aayushi-key" { - log.Info("performAuthCallback auth callback succeeded", - "api_key", apiKey) - return apiKey, nil + // Create auth callback request body + authReq := &AuthCallbackRequest{ + Headers: r.Header, + Path: r.URL.Path, + Body: "", // We'll read the body below + RemoteAddr: r.RemoteAddr, } - log.Info("performAuthCallback auth callback failed", - "api_key", apiKey, - "reason", "key not in valid keys list") - return "", fmt.Errorf("unauthorized") + // Read and restore the request body since it's a stream + if r.Body != nil { + log.Info("performAuthCallback reading request body") + bodyBytes, err := io.ReadAll(r.Body) + if err != nil { + log.Error("performAuthCallback failed to read body", "err", err) + return "", fmt.Errorf("failed to read request body: %w", err) + } + // Restore the body for later use + r.Body = io.NopCloser(bytes.NewBuffer(bodyBytes)) + authReq.Body = string(bodyBytes) + log.Info("performAuthCallback read body successfully", + "body_length", len(bodyBytes)) + } - /* Original HTTP request logic commented out for now - if s.authURL == "" { - return "", fmt.Errorf("no auth URL configured") + // Marshal the auth request to JSON + authReqBody, err := json.Marshal(authReq) + if err != nil { + log.Error("performAuthCallback failed to marshal request", "err", err) + return "", fmt.Errorf("failed to marshal auth request: %w", err) } + log.Info("performAuthCallback marshaled request body", + "body_length", len(authReqBody)) - // Create auth request with API key in path - authURL := fmt.Sprintf("%s/%s", s.authURL, apiKey) - req, err := http.NewRequestWithContext(r.Context(), "POST", authURL, r.Body) + // Create the auth callback request + req, err := http.NewRequestWithContext(r.Context(), "POST", authURL, bytes.NewBuffer(authReqBody)) if err != nil { - return "", err + log.Error("performAuthCallback failed to create request", "err", err) + return "", fmt.Errorf("failed to create auth request: %w", err) } - // Forward headers + // Set headers req.Header.Set("Content-Type", "application/json") + req.Header.Set("Authorization", apiKey) + log.Info("performAuthCallback created request with headers", + "content_type", req.Header.Get("Content-Type"), + "auth_key", apiKey) + // Make the request client := &http.Client{Timeout: 5 * time.Second} + log.Info("performAuthCallback sending request to auth service") resp, err := client.Do(req) if err != nil { + log.Error("performAuthCallback request failed", "err", err) return "", fmt.Errorf("auth callback failed: %w", err) } defer resp.Body.Close() + // Check response status + log.Info("performAuthCallback received response", + "status_code", resp.StatusCode) + if resp.StatusCode != http.StatusOK { - return "", fmt.Errorf("auth callback failed with status: %d", resp.StatusCode) + body, _ := io.ReadAll(resp.Body) + log.Info("performAuthCallback request rejected", + "status_code", resp.StatusCode, + "response_body", string(body)) + return "", fmt.Errorf("auth callback failed with status %d: %s", resp.StatusCode, string(body)) } + log.Info("performAuthCallback succeeded", + "api_key", apiKey) return apiKey, nil - */ - } func randStr(l int) string { From ab4b5c649bdb6787fa2430cb9e65bf61dcddf656 Mon Sep 17 00:00:00 2001 From: Aayushi Jain Date: Tue, 18 Mar 2025 13:21:02 -0700 Subject: [PATCH 16/32] refactor(proxyd): update authorization header format in performAuthCallback --- proxyd/server.go | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/proxyd/server.go b/proxyd/server.go index f84bd51c..fa39edfd 100644 --- a/proxyd/server.go +++ b/proxyd/server.go @@ -681,7 +681,6 @@ func (s *Server) populateContext(w http.ResponseWriter, r *http.Request) context func (s *Server) performAuthCallback(r *http.Request, apiKey string, authURL string) (string, error) { log.Info("performAuthCallback starting", - "api_key", apiKey, "auth_url", authURL, "request_path", r.URL.Path) @@ -714,8 +713,6 @@ func (s *Server) performAuthCallback(r *http.Request, apiKey string, authURL str log.Error("performAuthCallback failed to marshal request", "err", err) return "", fmt.Errorf("failed to marshal auth request: %w", err) } - log.Info("performAuthCallback marshaled request body", - "body_length", len(authReqBody)) // Create the auth callback request req, err := http.NewRequestWithContext(r.Context(), "POST", authURL, bytes.NewBuffer(authReqBody)) @@ -724,12 +721,15 @@ func (s *Server) performAuthCallback(r *http.Request, apiKey string, authURL str return "", fmt.Errorf("failed to create auth request: %w", err) } - // Set headers + // Set headers with Bearer token format req.Header.Set("Content-Type", "application/json") - req.Header.Set("Authorization", apiKey) + req.Header.Set("Authorization", fmt.Sprintf("Bearer %s", apiKey)) log.Info("performAuthCallback created request with headers", "content_type", req.Header.Get("Content-Type"), - "auth_key", apiKey) + "auth_key", apiKey, + "request_body", authReq.Body, + "auth_header", req.Header.Get("Authorization"), + ) // Make the request client := &http.Client{Timeout: 5 * time.Second} @@ -739,10 +739,14 @@ func (s *Server) performAuthCallback(r *http.Request, apiKey string, authURL str log.Error("performAuthCallback request failed", "err", err) return "", fmt.Errorf("auth callback failed: %w", err) } + if resp == nil { + log.Error("performAuthCallback received nil response") + return "", fmt.Errorf("auth callback failed: nil response") + } defer resp.Body.Close() // Check response status - log.Info("performAuthCallback received response", + log.Info("performAuthCallback received response", "resp", resp, "status_code", resp.StatusCode) if resp.StatusCode != http.StatusOK { @@ -753,8 +757,7 @@ func (s *Server) performAuthCallback(r *http.Request, apiKey string, authURL str return "", fmt.Errorf("auth callback failed with status %d: %s", resp.StatusCode, string(body)) } - log.Info("performAuthCallback succeeded", - "api_key", apiKey) + log.Info("performAuthCallback succeeded") return apiKey, nil } From ebb40bb65748cc22b601a50fef85b1ac538b101c Mon Sep 17 00:00:00 2001 From: Aayushi Jain Date: Mon, 24 Mar 2025 16:01:33 -0700 Subject: [PATCH 17/32] refactor(proxyd): performAuthCallback sends request to middleware --- proxyd/server.go | 55 ++++++++++++++++++++---------------------------- 1 file changed, 23 insertions(+), 32 deletions(-) diff --git a/proxyd/server.go b/proxyd/server.go index fa39edfd..e7463918 100644 --- a/proxyd/server.go +++ b/proxyd/server.go @@ -680,56 +680,33 @@ func (s *Server) populateContext(w http.ResponseWriter, r *http.Request) context } func (s *Server) performAuthCallback(r *http.Request, apiKey string, authURL string) (string, error) { - log.Info("performAuthCallback starting", - "auth_url", authURL, - "request_path", r.URL.Path) - - // Create auth callback request body - authReq := &AuthCallbackRequest{ - Headers: r.Header, - Path: r.URL.Path, - Body: "", // We'll read the body below - RemoteAddr: r.RemoteAddr, - } - - // Read and restore the request body since it's a stream - if r.Body != nil { - log.Info("performAuthCallback reading request body") - bodyBytes, err := io.ReadAll(r.Body) - if err != nil { - log.Error("performAuthCallback failed to read body", "err", err) - return "", fmt.Errorf("failed to read request body: %w", err) - } - // Restore the body for later use - r.Body = io.NopCloser(bytes.NewBuffer(bodyBytes)) - authReq.Body = string(bodyBytes) - log.Info("performAuthCallback read body successfully", - "body_length", len(bodyBytes)) + log.Info("performAuthCallback starting", "auth_url", authURL) + + // Create auth request body with the API key + authReqBody := map[string]string{ + "id": apiKey, } // Marshal the auth request to JSON - authReqBody, err := json.Marshal(authReq) + jsonBody, err := json.Marshal(authReqBody) if err != nil { log.Error("performAuthCallback failed to marshal request", "err", err) return "", fmt.Errorf("failed to marshal auth request: %w", err) } // Create the auth callback request - req, err := http.NewRequestWithContext(r.Context(), "POST", authURL, bytes.NewBuffer(authReqBody)) + req, err := http.NewRequestWithContext(r.Context(), "POST", authURL, bytes.NewBuffer(jsonBody)) if err != nil { log.Error("performAuthCallback failed to create request", "err", err) return "", fmt.Errorf("failed to create auth request: %w", err) } - // Set headers with Bearer token format + // Set headers req.Header.Set("Content-Type", "application/json") - req.Header.Set("Authorization", fmt.Sprintf("Bearer %s", apiKey)) log.Info("performAuthCallback created request with headers", "content_type", req.Header.Get("Content-Type"), "auth_key", apiKey, - "request_body", authReq.Body, - "auth_header", req.Header.Get("Authorization"), - ) + "request_body", string(jsonBody)) // Make the request client := &http.Client{Timeout: 5 * time.Second} @@ -757,6 +734,20 @@ func (s *Server) performAuthCallback(r *http.Request, apiKey string, authURL str return "", fmt.Errorf("auth callback failed with status %d: %s", resp.StatusCode, string(body)) } + // Parse response to check authenticated status + var authResponse struct { + Authenticated bool `json:"authenticated"` + } + if err := json.NewDecoder(resp.Body).Decode(&authResponse); err != nil { + log.Error("performAuthCallback failed to decode response", "err", err) + return "", fmt.Errorf("failed to decode auth response: %w", err) + } + + if !authResponse.Authenticated { + log.Info("performAuthCallback authentication failed") + return "", fmt.Errorf("authentication failed") + } + log.Info("performAuthCallback succeeded") return apiKey, nil } From 9d00e37cc8ec1792a3fd666457a8edcf2a286c98 Mon Sep 17 00:00:00 2001 From: Aayushi Jain Date: Tue, 25 Mar 2025 12:20:03 -0700 Subject: [PATCH 18/32] refactor(proxyd): streamline logging in Start and populateContext functions, fix error handling in performAuthCallback for failed auth --- proxyd/proxyd.go | 18 +-------------- proxyd/server.go | 59 ++++++++++++++++++------------------------------ 2 files changed, 23 insertions(+), 54 deletions(-) diff --git a/proxyd/proxyd.go b/proxyd/proxyd.go index c4ef0ed2..c354bd2b 100644 --- a/proxyd/proxyd.go +++ b/proxyd/proxyd.go @@ -278,25 +278,14 @@ func Start(config *Config) (*Server, func(), error) { } } - var resolvedAuth map[string]string = make(map[string]string) // Initialize map first + var resolvedAuth map[string]string = make(map[string]string) if config.Authentication != nil { - log.Info("Startfunction Authentication config contents", - "raw_config", config.Authentication, - "auth_url_value", config.Authentication["auth_url"], - "secret_value", config.Authentication["secret"]) - - // First, check and process the auth_url if present if authURL, ok := config.Authentication["auth_url"]; ok { resolvedAuth["auth_url"] = authURL - log.Info("Startfunction Configured external auth service", - "auth_url", authURL) } - // Then process any remaining keys as traditional auth keys for key, alias := range config.Authentication { - // Skip auth_url as we've already processed it if key == "auth_url" { - log.Info("Startfunction Skipping auth_url", "key", key) continue } @@ -305,7 +294,6 @@ func Start(config *Config) (*Server, func(), error) { return nil, nil, err } resolvedAuth[resolvedKey] = alias - log.Info("Startfunction Configured traditional auth", "key", resolvedKey, "alias", alias) } } @@ -348,10 +336,6 @@ func Start(config *Config) (*Server, func(), error) { return NewMemoryFrontendRateLimit(dur, max) } - log.Info("StartFunction Creating server with auth paths", - "resolvedAuth_nil", resolvedAuth == nil, - "config_auth_nil", config.Authentication == nil) - srv, err := NewServer( backendGroups, wsBackendGroup, diff --git a/proxyd/server.go b/proxyd/server.go index e7463918..29ba4933 100644 --- a/proxyd/server.go +++ b/proxyd/server.go @@ -108,8 +108,6 @@ func NewServer( maxBatchSize int, limiterFactory limiterFactoryFunc, ) (*Server, error) { - log.Info("NewServer called", - "authenticatedPaths", authenticatedPaths) if cache == nil { cache = &NoopRPCCache{} @@ -629,13 +627,6 @@ func (s *Server) populateContext(w http.ResponseWriter, r *http.Request) context authorization := vars["authorization"] xff := r.Header.Get(s.rateLimitHeader) - log.Info("populateContext detailed inspection", - "s ", s, - "auth_paths_nil", s.authenticatedPaths == nil, - "auth_paths_len", len(s.authenticatedPaths), - "all_keys", getMapKeys(s.authenticatedPaths), - "auth_url_exists", s.authenticatedPaths != nil && s.authenticatedPaths["auth_url"] != "") - if xff == "" { ipPort := strings.Split(r.RemoteAddr, ":") if len(ipPort) == 2 { @@ -652,37 +643,26 @@ func (s *Server) populateContext(w http.ResponseWriter, r *http.Request) context // Check if we have an external auth URL configured authURL, hasExternalAuth := s.authenticatedPaths["auth_url"] - log.Info("populateContext hasExternalAuth", "hasExternalAuth", hasExternalAuth, "authURL", authURL) if hasExternalAuth && authURL != "" { // nolint:staticcheck - log.Info("populateContext Using external auth service", - "auth_url", authURL, - "auth_key", authorization) - // Use external authentication service alias, err := s.performAuthCallback(r, authorization, authURL) - if err != nil { + if err != nil || alias == "" { // Check both error and empty alias log.Error("Auth callback failed", "err", err, - "auth_key", authorization) + "auth_key", authorization, + "alias", alias) w.WriteHeader(http.StatusUnauthorized) return nil } - log.Info("populateContext External auth succeeded", "auth_key", authorization, "alias", alias) ctx = context.WithValue(ctx, ContextKeyAuth, alias) // nolint:staticcheck } else { - log.Info("populateContext using traditional auth", - "auth_key", authorization, - "valid_keys", len(s.authenticatedPaths)) ctx = context.WithValue(ctx, ContextKeyAuth, s.authenticatedPaths[authorization]) // nolint:staticcheck } return context.WithValue(ctx, ContextKeyReqID, randStr(10)) // nolint:staticcheck } func (s *Server) performAuthCallback(r *http.Request, apiKey string, authURL string) (string, error) { - log.Info("performAuthCallback starting", "auth_url", authURL) - - // Create auth request body with the API key authReqBody := map[string]string{ "id": apiKey, } @@ -703,14 +683,9 @@ func (s *Server) performAuthCallback(r *http.Request, apiKey string, authURL str // Set headers req.Header.Set("Content-Type", "application/json") - log.Info("performAuthCallback created request with headers", - "content_type", req.Header.Get("Content-Type"), - "auth_key", apiKey, - "request_body", string(jsonBody)) // Make the request client := &http.Client{Timeout: 5 * time.Second} - log.Info("performAuthCallback sending request to auth service") resp, err := client.Do(req) if err != nil { log.Error("performAuthCallback request failed", "err", err) @@ -722,33 +697,43 @@ func (s *Server) performAuthCallback(r *http.Request, apiKey string, authURL str } defer resp.Body.Close() - // Check response status - log.Info("performAuthCallback received response", "resp", resp, - "status_code", resp.StatusCode) - if resp.StatusCode != http.StatusOK { body, _ := io.ReadAll(resp.Body) - log.Info("performAuthCallback request rejected", + log.Error("performAuthCallback non-200 status", "status_code", resp.StatusCode, "response_body", string(body)) return "", fmt.Errorf("auth callback failed with status %d: %s", resp.StatusCode, string(body)) } + // Read response body for logging + body, err := io.ReadAll(resp.Body) + if err != nil { + log.Error("performAuthCallback failed to read response body", "err", err) + return "", fmt.Errorf("failed to read auth response: %w", err) + } + log.Info("performAuthCallback received response body", "body", string(body)) + // Parse response to check authenticated status var authResponse struct { Authenticated bool `json:"authenticated"` } - if err := json.NewDecoder(resp.Body).Decode(&authResponse); err != nil { - log.Error("performAuthCallback failed to decode response", "err", err) + if err := json.Unmarshal(body, &authResponse); err != nil { + log.Error("performAuthCallback failed to decode response", + "err", err, + "body", string(body)) return "", fmt.Errorf("failed to decode auth response: %w", err) } + log.Info("performAuthCallback parsed response", + "authenticated", authResponse.Authenticated, + "auth_response", authResponse) + if !authResponse.Authenticated { - log.Info("performAuthCallback authentication failed") + log.Error("performAuthCallback authentication failed", + "auth_response", authResponse) return "", fmt.Errorf("authentication failed") } - log.Info("performAuthCallback succeeded") return apiKey, nil } From af6a8c6b390d8560df9d8e26b8adc09617377ceb Mon Sep 17 00:00:00 2001 From: Aayushi Jain Date: Tue, 25 Mar 2025 13:26:05 -0700 Subject: [PATCH 19/32] logging --- proxyd/server.go | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/proxyd/server.go b/proxyd/server.go index 29ba4933..583a798d 100644 --- a/proxyd/server.go +++ b/proxyd/server.go @@ -643,17 +643,20 @@ func (s *Server) populateContext(w http.ResponseWriter, r *http.Request) context // Check if we have an external auth URL configured authURL, hasExternalAuth := s.authenticatedPaths["auth_url"] + log.Info("populateContext Auth configuration", "hasExternalAuth", hasExternalAuth, "authURL", authURL) if hasExternalAuth && authURL != "" { // nolint:staticcheck // Use external authentication service + log.Info("populateContext Using external authentication service", "authURL", authURL) alias, err := s.performAuthCallback(r, authorization, authURL) if err != nil || alias == "" { // Check both error and empty alias - log.Error("Auth callback failed", + log.Error("populateContext Auth callback failed", "err", err, "auth_key", authorization, "alias", alias) w.WriteHeader(http.StatusUnauthorized) return nil } + log.Info("populateContext Auth callback successful", "alias", alias) ctx = context.WithValue(ctx, ContextKeyAuth, alias) // nolint:staticcheck } else { @@ -663,6 +666,8 @@ func (s *Server) populateContext(w http.ResponseWriter, r *http.Request) context } func (s *Server) performAuthCallback(r *http.Request, apiKey string, authURL string) (string, error) { + log.Info("Attempting performAuthCallback", "apiKey", apiKey, "authURL", authURL) + authReqBody := map[string]string{ "id": apiKey, } @@ -675,6 +680,7 @@ func (s *Server) performAuthCallback(r *http.Request, apiKey string, authURL str } // Create the auth callback request + log.Info("performAuthCallback Creating request", "authURL", authURL) req, err := http.NewRequestWithContext(r.Context(), "POST", authURL, bytes.NewBuffer(jsonBody)) if err != nil { log.Error("performAuthCallback failed to create request", "err", err) From d14dd265b73f56dcc0203d251024623e3c3c8c54 Mon Sep 17 00:00:00 2001 From: Aayushi Jain Date: Tue, 25 Mar 2025 16:16:31 -0700 Subject: [PATCH 20/32] remove logs --- proxyd/server.go | 24 ++++-------------------- 1 file changed, 4 insertions(+), 20 deletions(-) diff --git a/proxyd/server.go b/proxyd/server.go index 583a798d..eeaaf7ea 100644 --- a/proxyd/server.go +++ b/proxyd/server.go @@ -643,20 +643,15 @@ func (s *Server) populateContext(w http.ResponseWriter, r *http.Request) context // Check if we have an external auth URL configured authURL, hasExternalAuth := s.authenticatedPaths["auth_url"] - log.Info("populateContext Auth configuration", "hasExternalAuth", hasExternalAuth, "authURL", authURL) if hasExternalAuth && authURL != "" { // nolint:staticcheck // Use external authentication service - log.Info("populateContext Using external authentication service", "authURL", authURL) alias, err := s.performAuthCallback(r, authorization, authURL) if err != nil || alias == "" { // Check both error and empty alias log.Error("populateContext Auth callback failed", - "err", err, - "auth_key", authorization, - "alias", alias) + "err", err) w.WriteHeader(http.StatusUnauthorized) return nil } - log.Info("populateContext Auth callback successful", "alias", alias) ctx = context.WithValue(ctx, ContextKeyAuth, alias) // nolint:staticcheck } else { @@ -666,8 +661,6 @@ func (s *Server) populateContext(w http.ResponseWriter, r *http.Request) context } func (s *Server) performAuthCallback(r *http.Request, apiKey string, authURL string) (string, error) { - log.Info("Attempting performAuthCallback", "apiKey", apiKey, "authURL", authURL) - authReqBody := map[string]string{ "id": apiKey, } @@ -680,7 +673,6 @@ func (s *Server) performAuthCallback(r *http.Request, apiKey string, authURL str } // Create the auth callback request - log.Info("performAuthCallback Creating request", "authURL", authURL) req, err := http.NewRequestWithContext(r.Context(), "POST", authURL, bytes.NewBuffer(jsonBody)) if err != nil { log.Error("performAuthCallback failed to create request", "err", err) @@ -706,8 +698,7 @@ func (s *Server) performAuthCallback(r *http.Request, apiKey string, authURL str if resp.StatusCode != http.StatusOK { body, _ := io.ReadAll(resp.Body) log.Error("performAuthCallback non-200 status", - "status_code", resp.StatusCode, - "response_body", string(body)) + "status_code", resp.StatusCode) return "", fmt.Errorf("auth callback failed with status %d: %s", resp.StatusCode, string(body)) } @@ -717,7 +708,6 @@ func (s *Server) performAuthCallback(r *http.Request, apiKey string, authURL str log.Error("performAuthCallback failed to read response body", "err", err) return "", fmt.Errorf("failed to read auth response: %w", err) } - log.Info("performAuthCallback received response body", "body", string(body)) // Parse response to check authenticated status var authResponse struct { @@ -725,18 +715,12 @@ func (s *Server) performAuthCallback(r *http.Request, apiKey string, authURL str } if err := json.Unmarshal(body, &authResponse); err != nil { log.Error("performAuthCallback failed to decode response", - "err", err, - "body", string(body)) + "err", err) return "", fmt.Errorf("failed to decode auth response: %w", err) } - log.Info("performAuthCallback parsed response", - "authenticated", authResponse.Authenticated, - "auth_response", authResponse) - if !authResponse.Authenticated { - log.Error("performAuthCallback authentication failed", - "auth_response", authResponse) + log.Error("performAuthCallback authentication failed") return "", fmt.Errorf("authentication failed") } From 32e55579e16389b56d70090f04729fdb204e64a0 Mon Sep 17 00:00:00 2001 From: Aayushi Jain Date: Wed, 26 Mar 2025 00:30:02 -1000 Subject: [PATCH 21/32] generalize performAuthCallback --- proxyd/server.go | 67 +++++++++--------------------------------------- 1 file changed, 12 insertions(+), 55 deletions(-) diff --git a/proxyd/server.go b/proxyd/server.go index eeaaf7ea..3b106b86 100644 --- a/proxyd/server.go +++ b/proxyd/server.go @@ -1,7 +1,6 @@ package proxyd import ( - "bytes" "context" "crypto/rand" "encoding/hex" @@ -620,9 +619,6 @@ func (s *Server) HandleWS(w http.ResponseWriter, r *http.Request) { } func (s *Server) populateContext(w http.ResponseWriter, r *http.Request) context.Context { - s.srvMu.Lock() - defer s.srvMu.Unlock() - vars := mux.Vars(r) authorization := vars["authorization"] xff := r.Header.Get(s.rateLimitHeader) @@ -645,10 +641,9 @@ func (s *Server) populateContext(w http.ResponseWriter, r *http.Request) context authURL, hasExternalAuth := s.authenticatedPaths["auth_url"] if hasExternalAuth && authURL != "" { // nolint:staticcheck // Use external authentication service - alias, err := s.performAuthCallback(r, authorization, authURL) + alias, err := s.performAuthCallback(r, authURL) if err != nil || alias == "" { // Check both error and empty alias - log.Error("populateContext Auth callback failed", - "err", err) + log.Error("populateContext Auth callback failed", "err", err) w.WriteHeader(http.StatusUnauthorized) return nil } @@ -660,27 +655,16 @@ func (s *Server) populateContext(w http.ResponseWriter, r *http.Request) context return context.WithValue(ctx, ContextKeyReqID, randStr(10)) // nolint:staticcheck } -func (s *Server) performAuthCallback(r *http.Request, apiKey string, authURL string) (string, error) { - authReqBody := map[string]string{ - "id": apiKey, - } - - // Marshal the auth request to JSON - jsonBody, err := json.Marshal(authReqBody) - if err != nil { - log.Error("performAuthCallback failed to marshal request", "err", err) - return "", fmt.Errorf("failed to marshal auth request: %w", err) - } - - // Create the auth callback request - req, err := http.NewRequestWithContext(r.Context(), "POST", authURL, bytes.NewBuffer(jsonBody)) +func (s *Server) performAuthCallback(r *http.Request, authURL string) (string, error) { + // Create new request to auth URL with same method, headers and body + req, err := http.NewRequestWithContext(r.Context(), r.Method, authURL, r.Body) if err != nil { log.Error("performAuthCallback failed to create request", "err", err) return "", fmt.Errorf("failed to create auth request: %w", err) } - // Set headers - req.Header.Set("Content-Type", "application/json") + // Copy original headers + req.Header = r.Header // Make the request client := &http.Client{Timeout: 5 * time.Second} @@ -689,42 +673,15 @@ func (s *Server) performAuthCallback(r *http.Request, apiKey string, authURL str log.Error("performAuthCallback request failed", "err", err) return "", fmt.Errorf("auth callback failed: %w", err) } - if resp == nil { - log.Error("performAuthCallback received nil response") - return "", fmt.Errorf("auth callback failed: nil response") - } defer resp.Body.Close() - if resp.StatusCode != http.StatusOK { - body, _ := io.ReadAll(resp.Body) - log.Error("performAuthCallback non-200 status", - "status_code", resp.StatusCode) - return "", fmt.Errorf("auth callback failed with status %d: %s", resp.StatusCode, string(body)) - } - - // Read response body for logging - body, err := io.ReadAll(resp.Body) - if err != nil { - log.Error("performAuthCallback failed to read response body", "err", err) - return "", fmt.Errorf("failed to read auth response: %w", err) - } - - // Parse response to check authenticated status - var authResponse struct { - Authenticated bool `json:"authenticated"` - } - if err := json.Unmarshal(body, &authResponse); err != nil { - log.Error("performAuthCallback failed to decode response", - "err", err) - return "", fmt.Errorf("failed to decode auth response: %w", err) - } - - if !authResponse.Authenticated { - log.Error("performAuthCallback authentication failed") - return "", fmt.Errorf("authentication failed") + // Only reject if we get a 401 + if resp.StatusCode == http.StatusUnauthorized { + return "", fmt.Errorf("unauthorized") } - return apiKey, nil + // Return the authorization value from the request + return mux.Vars(r)["authorization"], nil } func randStr(l int) string { From 9ee8d62eb90041fd9a860843d38c535ea4543546 Mon Sep 17 00:00:00 2001 From: Aayushi Jain Date: Wed, 26 Mar 2025 00:58:27 -1000 Subject: [PATCH 22/32] add debugging logs --- proxyd/server.go | 1 + 1 file changed, 1 insertion(+) diff --git a/proxyd/server.go b/proxyd/server.go index 3b106b86..eed0ba9a 100644 --- a/proxyd/server.go +++ b/proxyd/server.go @@ -668,6 +668,7 @@ func (s *Server) performAuthCallback(r *http.Request, authURL string) (string, e // Make the request client := &http.Client{Timeout: 5 * time.Second} + log.Info("performAuthCallback making request", "authURL", authURL, "req", req) resp, err := client.Do(req) if err != nil { log.Error("performAuthCallback request failed", "err", err) From 0c782e38481ea117f09032f03d0840ab70d482d4 Mon Sep 17 00:00:00 2001 From: Aayushi Jain Date: Wed, 26 Mar 2025 06:29:57 -1000 Subject: [PATCH 23/32] log --- proxyd/server.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/proxyd/server.go b/proxyd/server.go index eed0ba9a..39c02f26 100644 --- a/proxyd/server.go +++ b/proxyd/server.go @@ -668,7 +668,7 @@ func (s *Server) performAuthCallback(r *http.Request, authURL string) (string, e // Make the request client := &http.Client{Timeout: 5 * time.Second} - log.Info("performAuthCallback making request", "authURL", authURL, "req", req) + log.Info("performAuthCallback making request", "authURL", authURL, "req URL Path", req.URL.Path) resp, err := client.Do(req) if err != nil { log.Error("performAuthCallback request failed", "err", err) From 9daebd921c7518b719a31be054364587973ed4ac Mon Sep 17 00:00:00 2001 From: Aayushi Jain Date: Wed, 26 Mar 2025 07:09:48 -1000 Subject: [PATCH 24/32] fix authurl to add token --- proxyd/server.go | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/proxyd/server.go b/proxyd/server.go index 39c02f26..4ae4358f 100644 --- a/proxyd/server.go +++ b/proxyd/server.go @@ -656,8 +656,19 @@ func (s *Server) populateContext(w http.ResponseWriter, r *http.Request) context } func (s *Server) performAuthCallback(r *http.Request, authURL string) (string, error) { + // Get the authorization token from the request + authorization := mux.Vars(r)["authorization"] + if authorization == "" { + return "", fmt.Errorf("missing authorization token") + } + + // Append the token to the auth URL path + authURLWithToken := fmt.Sprintf("%s/%s", + strings.TrimRight(authURL, "/"), // Remove any trailing slash + authorization) + // Create new request to auth URL with same method, headers and body - req, err := http.NewRequestWithContext(r.Context(), r.Method, authURL, r.Body) + req, err := http.NewRequestWithContext(r.Context(), r.Method, authURLWithToken, r.Body) if err != nil { log.Error("performAuthCallback failed to create request", "err", err) return "", fmt.Errorf("failed to create auth request: %w", err) @@ -668,7 +679,9 @@ func (s *Server) performAuthCallback(r *http.Request, authURL string) (string, e // Make the request client := &http.Client{Timeout: 5 * time.Second} - log.Info("performAuthCallback making request", "authURL", authURL, "req URL Path", req.URL.Path) + log.Info("performAuthCallback making request", + "authURL", authURLWithToken, + "token", authorization) resp, err := client.Do(req) if err != nil { log.Error("performAuthCallback request failed", "err", err) @@ -681,8 +694,7 @@ func (s *Server) performAuthCallback(r *http.Request, authURL string) (string, e return "", fmt.Errorf("unauthorized") } - // Return the authorization value from the request - return mux.Vars(r)["authorization"], nil + return authorization, nil } func randStr(l int) string { From 57f3093ac9fb63049dfba38af66e3ecbad953ddc Mon Sep 17 00:00:00 2001 From: Aayushi Jain Date: Wed, 26 Mar 2025 07:50:00 -1000 Subject: [PATCH 25/32] debugging --- proxyd/server.go | 21 +++++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) diff --git a/proxyd/server.go b/proxyd/server.go index 4ae4358f..1ee76672 100644 --- a/proxyd/server.go +++ b/proxyd/server.go @@ -1,6 +1,7 @@ package proxyd import ( + "bytes" "context" "crypto/rand" "encoding/hex" @@ -647,7 +648,7 @@ func (s *Server) populateContext(w http.ResponseWriter, r *http.Request) context w.WriteHeader(http.StatusUnauthorized) return nil } - + log.Info("populateContext Auth callback successful", "alias", alias) ctx = context.WithValue(ctx, ContextKeyAuth, alias) // nolint:staticcheck } else { ctx = context.WithValue(ctx, ContextKeyAuth, s.authenticatedPaths[authorization]) // nolint:staticcheck @@ -662,13 +663,25 @@ func (s *Server) performAuthCallback(r *http.Request, authURL string) (string, e return "", fmt.Errorf("missing authorization token") } + // Read the body first + bodyBytes, err := io.ReadAll(r.Body) + if err != nil { + log.Error("performAuthCallback failed to read request body", "err", err) + return "", fmt.Errorf("failed to read request body: %w", err) + } + r.Body.Close() + + // Create new body for original request + r.Body = io.NopCloser(bytes.NewBuffer(bodyBytes)) + // Append the token to the auth URL path authURLWithToken := fmt.Sprintf("%s/%s", - strings.TrimRight(authURL, "/"), // Remove any trailing slash + strings.TrimRight(authURL, "/"), authorization) - // Create new request to auth URL with same method, headers and body - req, err := http.NewRequestWithContext(r.Context(), r.Method, authURLWithToken, r.Body) + // Create new request to auth URL with same method, headers and new body copy + req, err := http.NewRequestWithContext(r.Context(), r.Method, authURLWithToken, + bytes.NewBuffer(bodyBytes)) if err != nil { log.Error("performAuthCallback failed to create request", "err", err) return "", fmt.Errorf("failed to create auth request: %w", err) From 158c5fb6ae1baef1e27bb04e89fb38ce06bfc170 Mon Sep 17 00:00:00 2001 From: Aayushi Jain Date: Wed, 26 Mar 2025 09:51:30 -1000 Subject: [PATCH 26/32] remove logs --- proxyd/server.go | 5 ----- 1 file changed, 5 deletions(-) diff --git a/proxyd/server.go b/proxyd/server.go index 1ee76672..e68226d9 100644 --- a/proxyd/server.go +++ b/proxyd/server.go @@ -644,11 +644,9 @@ func (s *Server) populateContext(w http.ResponseWriter, r *http.Request) context // Use external authentication service alias, err := s.performAuthCallback(r, authURL) if err != nil || alias == "" { // Check both error and empty alias - log.Error("populateContext Auth callback failed", "err", err) w.WriteHeader(http.StatusUnauthorized) return nil } - log.Info("populateContext Auth callback successful", "alias", alias) ctx = context.WithValue(ctx, ContextKeyAuth, alias) // nolint:staticcheck } else { ctx = context.WithValue(ctx, ContextKeyAuth, s.authenticatedPaths[authorization]) // nolint:staticcheck @@ -692,9 +690,6 @@ func (s *Server) performAuthCallback(r *http.Request, authURL string) (string, e // Make the request client := &http.Client{Timeout: 5 * time.Second} - log.Info("performAuthCallback making request", - "authURL", authURLWithToken, - "token", authorization) resp, err := client.Do(req) if err != nil { log.Error("performAuthCallback request failed", "err", err) From bd71e881f21705c35bea2343769457290db2c58e Mon Sep 17 00:00:00 2001 From: Aayushi Jain Date: Wed, 26 Mar 2025 12:25:33 -1000 Subject: [PATCH 27/32] add http client --- proxyd/server.go | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/proxyd/server.go b/proxyd/server.go index e68226d9..449bb6fc 100644 --- a/proxyd/server.go +++ b/proxyd/server.go @@ -51,6 +51,11 @@ const ( var emptyArrayResponse = json.RawMessage("[]") +var ( + // Shared HTTP client for auth callbacks with 5 second timeout + authHTTPClient = &http.Client{Timeout: 5 * time.Second} +) + type AuthCallbackRequest struct { Headers map[string][]string `json:"headers"` Path string `json:"path"` @@ -667,7 +672,7 @@ func (s *Server) performAuthCallback(r *http.Request, authURL string) (string, e log.Error("performAuthCallback failed to read request body", "err", err) return "", fmt.Errorf("failed to read request body: %w", err) } - r.Body.Close() + defer r.Body.Close() // Create new body for original request r.Body = io.NopCloser(bytes.NewBuffer(bodyBytes)) @@ -686,11 +691,10 @@ func (s *Server) performAuthCallback(r *http.Request, authURL string) (string, e } // Copy original headers - req.Header = r.Header + req.Header = r.Header.Clone() - // Make the request - client := &http.Client{Timeout: 5 * time.Second} - resp, err := client.Do(req) + // Use the shared client + resp, err := authHTTPClient.Do(req) if err != nil { log.Error("performAuthCallback request failed", "err", err) return "", fmt.Errorf("auth callback failed: %w", err) From 2f188839c74b64587600c25c989323ef8a32de31 Mon Sep 17 00:00:00 2001 From: Aayushi Jain Date: Wed, 26 Mar 2025 12:28:01 -1000 Subject: [PATCH 28/32] remove logs --- proxyd/server.go | 6 ------ 1 file changed, 6 deletions(-) diff --git a/proxyd/server.go b/proxyd/server.go index 449bb6fc..581b8fd7 100644 --- a/proxyd/server.go +++ b/proxyd/server.go @@ -864,16 +864,10 @@ func instrumentedHdlr(h http.Handler) http.HandlerFunc { } func GetAuthCtx(ctx context.Context) string { - if ctx == nil { - log.Info("GetAuthCtx called with nil context") - return "none" - } authUser, ok := ctx.Value(ContextKeyAuth).(string) if !ok { - log.Info("GetAuthCtx No auth value found in context") return "none" } - log.Info("GetAuthCtx Auth value found in context", "auth", authUser) return authUser } From 69b1dda2b0d6182f7482de702c2957ec77477466 Mon Sep 17 00:00:00 2001 From: Aayushi Jain Date: Wed, 26 Mar 2025 12:30:49 -1000 Subject: [PATCH 29/32] add httpclient to server --- proxyd/server.go | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/proxyd/server.go b/proxyd/server.go index 581b8fd7..d0fab97f 100644 --- a/proxyd/server.go +++ b/proxyd/server.go @@ -89,6 +89,7 @@ type Server struct { cache RPCCache srvMu sync.Mutex rateLimitHeader string + authClient *http.Client } type limiterFunc func(method string) bool @@ -205,6 +206,9 @@ func NewServer( limExemptOrigins: limExemptOrigins, limExemptUserAgents: limExemptUserAgents, rateLimitHeader: rateLimitHeader, + authClient: &http.Client{ + Timeout: 5 * time.Second, + }, }, nil } @@ -693,8 +697,8 @@ func (s *Server) performAuthCallback(r *http.Request, authURL string) (string, e // Copy original headers req.Header = r.Header.Clone() - // Use the shared client - resp, err := authHTTPClient.Do(req) + // Use the server's auth client + resp, err := s.authClient.Do(req) if err != nil { log.Error("performAuthCallback request failed", "err", err) return "", fmt.Errorf("auth callback failed: %w", err) From df4b9290529577e25b698f49e392d4e7cfb918d0 Mon Sep 17 00:00:00 2001 From: Aayushi Jain Date: Wed, 26 Mar 2025 12:32:49 -1000 Subject: [PATCH 30/32] remove other client --- proxyd/server.go | 5 ----- 1 file changed, 5 deletions(-) diff --git a/proxyd/server.go b/proxyd/server.go index d0fab97f..2598646c 100644 --- a/proxyd/server.go +++ b/proxyd/server.go @@ -51,11 +51,6 @@ const ( var emptyArrayResponse = json.RawMessage("[]") -var ( - // Shared HTTP client for auth callbacks with 5 second timeout - authHTTPClient = &http.Client{Timeout: 5 * time.Second} -) - type AuthCallbackRequest struct { Headers map[string][]string `json:"headers"` Path string `json:"path"` From d6a1393aca01430132d9c706369b7a554b46c712 Mon Sep 17 00:00:00 2001 From: Aayushi Jain Date: Wed, 26 Mar 2025 12:59:58 -1000 Subject: [PATCH 31/32] remove fn --- proxyd/server.go | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/proxyd/server.go b/proxyd/server.go index 2598646c..7e69a539 100644 --- a/proxyd/server.go +++ b/proxyd/server.go @@ -939,15 +939,3 @@ func createBatchRequest(elems []batchElem) []*RPCReq { } return batch } - -// Helper function to get map keys -func getMapKeys(m map[string]string) []string { - if m == nil { - return nil - } - keys := make([]string, 0, len(m)) - for k := range m { - keys = append(keys, k) - } - return keys -} From 243f165348b21e5670e9b23e7ba53b1f7a3fce17 Mon Sep 17 00:00:00 2001 From: Aayushi Jain Date: Tue, 1 Apr 2025 12:00:24 -1000 Subject: [PATCH 32/32] jsonrpc error --- proxyd/server.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/proxyd/server.go b/proxyd/server.go index 7e69a539..f241e9d4 100644 --- a/proxyd/server.go +++ b/proxyd/server.go @@ -648,7 +648,7 @@ func (s *Server) populateContext(w http.ResponseWriter, r *http.Request) context // Use external authentication service alias, err := s.performAuthCallback(r, authURL) if err != nil || alias == "" { // Check both error and empty alias - w.WriteHeader(http.StatusUnauthorized) + writeRPCError(ctx, w, nil, &RPCErr{Code: -32001, Message: "unauthorized"}) return nil } ctx = context.WithValue(ctx, ContextKeyAuth, alias) // nolint:staticcheck