TykTechnologies / tyk

Tyk Open Source API Gateway written in Go, supporting REST, GraphQL, TCP and gRPC protocols
Other
9.68k stars 1.08k forks source link

[TT-13359] move upstream basic auth to ee package #6669

Closed jeffy-mathew closed 1 day ago

jeffy-mathew commented 3 days ago

User description

Description

This PR moves upstream basic auth implementations to ee package

Related Issue

Parent: https://tyktech.atlassian.net/browse/TT-13359 Subtask: https://tyktech.atlassian.net/browse/TT-13389

Motivation and Context

How This Has Been Tested

Screenshots (if appropriate)

Types of changes

Checklist


PR Type

Enhancement, Other


Description


Changes walkthrough 📝

Relevant files
Enhancement
8 files
api_definitions.go
Refactor UpstreamBasicAuth to use AuthSource struct           

apidef/api_definitions.go
  • Changed HeaderName to Header in UpstreamBasicAuth.
  • Introduced AuthSource struct for auth configurations.
  • Added methods IsEnabled and AuthKeyName to AuthSource.
  • +24/-2   
    upstream.go
    Update UpstreamBasicAuth to use AuthSource in OAS               

    apidef/oas/upstream.go
  • Changed HeaderName to Header in UpstreamBasicAuth.
  • Updated Fill and ExtractTo methods to handle AuthSource.
  • +18/-5   
    middleware.go
    Implement Upstream Basic Auth Middleware                                 

    ee/middleware/upstreambasicauth/middleware.go
  • Added new middleware for upstream basic authentication.
  • Implemented methods for middleware lifecycle and request processing.
  • +76/-0   
    model.go
    Define Middleware Model and APISpec Structures                     

    ee/middleware/upstreambasicauth/model.go
  • Defined interfaces and structures for middleware dependencies.
  • Added APISpec struct for middleware configuration.
  • +48/-0   
    provider.go
    Implement Provider for Upstream Authentication                     

    ee/middleware/upstreambasicauth/provider.go
  • Implemented Provider for upstream authentication.
  • Added method to set request headers for authentication.
  • +26/-0   
    api_loader.go
    Integrate Upstream Basic Auth Middleware in API Loader     

    gateway/api_loader.go - Integrated new upstream basic auth middleware into API processing.
    +4/-1     
    mw_upstream_basic_auth.go
    Replace UpstreamBasicAuth with Noop for Non-EE Builds       

    gateway/mw_upstream_basic_auth.go
  • Replaced UpstreamBasicAuth with noopUpstreamBasicAuth.
  • Added build constraints for non-EE and non-dev environments.
  • +14/-54 
    mw_upstream_basic_auth_ee.go
    Add EE-Specific Upstream Basic Auth Middleware                     

    gateway/mw_upstream_basic_auth_ee.go
  • Added EE-specific implementation for upstream basic auth middleware.
  • +14/-0   
    Tests
    1 files
    mw_upstream_basic_auth_test.go
    Update Test Build Constraints for EE Middleware                   

    gateway/mw_upstream_basic_auth_test.go - Added build constraints for EE and dev environments.
    +2/-0     

    💡 PR-Agent usage: Comment /help "your question" on any pull request to receive relevant information

    buger commented 3 days ago

    :broken_heart: The detected issue is not in one of the allowed statuses :broken_heart:

    Detected Status Open :x:
    Allowed Statuses In Dev,In Code Review,Ready for Testing,In Test,In Progress,In Review :heavy_check_mark:

    Please ensure your jira story is in one of the allowed statuses

    github-actions[bot] commented 3 days ago

    API Changes

    --- prev.txt    2024-10-25 14:26:59.613540649 +0000
    +++ current.txt 2024-10-25 14:26:52.941483202 +0000
    @@ -2416,9 +2416,9 @@
        Username string `bson:"username" json:"username"`
        // Password is the password to be used for upstream basic authentication.
        Password string `bson:"password" json:"password"`
    -   // HeaderName is the custom header name to be used for upstream basic authentication.
    +   // Header holds the configuration for custom header name to be used for upstream basic authentication.
        // Defaults to `Authorization`.
    -   HeaderName string `bson:"header_name" json:"header_name"`
    +   Header AuthSource `bson:"header" json:"header"`
     }
         UpstreamBasicAuth holds upstream basic authentication configuration.
    
    @@ -5252,9 +5252,8 @@
     type UpstreamBasicAuth struct {
        // Enabled enables upstream basic authentication.
        Enabled bool `bson:"enabled" json:"enabled"`
    -   // HeaderName is the custom header name to be used for upstream basic authentication.
    -   // Defaults to `Authorization`.
    -   HeaderName string `bson:"headerName" json:"headerName"`
    +   // Header contains configurations for the header value.
    +   Header *AuthSource `bson:"header,omitempty" json:"header,omitempty"`
        // Username is the username to be used for upstream basic authentication.
        Username string `bson:"username" json:"username"`
        // Password is the password to be used for upstream basic authentication.
    @@ -8184,6 +8183,87 @@
     }
         StreamsConfig represents a stream configuration.
    
    +# Package: ./ee/middleware/upstreambasicauth
    +
    +package upstreambasicauth // import "github.com/TykTechnologies/tyk/ee/middleware/upstreambasicauth"
    +
    +
    +CONSTANTS
    +
    +const (
    +   // ExtensionTykStreaming is the OAS extension for Tyk streaming.
    +   ExtensionTykStreaming = "x-tyk-streaming"
    +   StreamGCInterval      = 1 * time.Minute
    +)
    +
    +TYPES
    +
    +type APISpec struct {
    +   APIID string
    +   Name  string
    +   IsOAS bool
    +   OAS   oas.OAS
    +
    +   UpstreamAuth apidef.UpstreamAuth
    +}
    +    APISpec is a subset of gateway.APISpec for the values the middleware
    +    consumes.
    +
    +func NewAPISpec(id string, name string, isOasDef bool, oasDef oas.OAS, upstreamAuth apidef.UpstreamAuth) *APISpec
    +    NewAPISpec creates a new APISpec object based on the required inputs.
    +    The resulting object is a subset of `*gateway.APISpec`.
    +
    +type BaseMiddleware interface {
    +   model.LoggerProvider
    +}
    +    BaseMiddleware is the subset of BaseMiddleware APIs that the middleware
    +    uses.
    +
    +type Gateway interface {
    +   model.ConfigProvider
    +   model.ReplaceTykVariables
    +}
    +    Gateway is the subset of Gateway APIs that the middleware uses.
    +
    +type Middleware struct {
    +   Spec *APISpec
    +   Gw   Gateway
    +
    +   // Has unexported fields.
    +}
    +    Middleware implements upstream basic auth middleware.
    +
    +func NewMiddleware(gw Gateway, mw BaseMiddleware, spec *APISpec) *Middleware
    +    NewMiddleware returns a new instance of Middleware.
    +
    +func (m *Middleware) EnabledForSpec() bool
    +    EnabledForSpec checks if streaming is enabled on the config.
    +
    +func (m *Middleware) Init()
    +    Init initializes the middleware.
    +
    +func (m *Middleware) Logger() *logrus.Entry
    +    Logger returns a logger with middleware filled out.
    +
    +func (m *Middleware) Name() string
    +    Name returns the name for the middleware.
    +
    +func (m *Middleware) ProcessRequest(_ http.ResponseWriter, r *http.Request, _ interface{}) (error, int)
    +    ProcessRequest will handle upstream basic auth.
    +
    +type Provider struct {
    +   // Logger is the logger to be used.
    +   Logger *logrus.Entry
    +   // HeaderName is the header name to be used to fill upstream auth with.
    +   HeaderName string
    +   // AuthValue is the value of auth header.
    +   AuthValue string
    +}
    +    Provider implements upstream auth provider.
    +
    +func (u Provider) Fill(r *http.Request)
    +    Fill sets the request's HeaderName with AuthValue
    +
     # Package: ./gateway
    
     package gateway // import "github.com/TykTechnologies/tyk/gateway"
    @@ -11443,34 +11523,6 @@
         Enums representing the various statuses for a VersionInfo Path match during
         a proxy request
    
    -type UpstreamBasicAuth struct {
    -   *BaseMiddleware
    -}
    -    UpstreamBasicAuth is a middleware that will do basic authentication for
    -    upstream connections. UpstreamBasicAuth middleware is only supported in Tyk
    -    OAS API definitions.
    -
    -func (t *UpstreamBasicAuth) EnabledForSpec() bool
    -    EnabledForSpec returns true if the middleware is enabled based on API Spec.
    -
    -func (t *UpstreamBasicAuth) Name() string
    -    Name returns the name of middleware.
    -
    -func (t *UpstreamBasicAuth) ProcessRequest(_ http.ResponseWriter, r *http.Request, _ interface{}) (error, int)
    -    ProcessRequest will inject basic auth info into request context so that it
    -    can be used during reverse proxy.
    -
    -type UpstreamBasicAuthProvider struct {
    -   // HeaderName is the header name to be used to fill upstream auth with.
    -   HeaderName string
    -   // AuthValue is the value of auth header.
    -   AuthValue string
    -}
    -    UpstreamBasicAuthProvider implements upstream auth provider.
    -
    -func (u UpstreamBasicAuthProvider) Fill(r *http.Request)
    -    Fill sets the request's HeaderName with AuthValue
    -
     type UpstreamOAuth struct {
        *BaseMiddleware
     }
    github-actions[bot] commented 3 days ago

    PR Reviewer Guide 🔍

    Here are some key observations to aid the review process:

    ⏱️ Estimated effort to review: 3 🔵🔵🔵⚪⚪
    🧪 No relevant tests
    🔒 No security concerns identified
    ⚡ Recommended focus areas for review

    Code Duplication
    The methods `IsEnabled` and `AuthKeyName` in the `AuthSource` struct seem to be duplicated across different files. Consider creating a shared package or file to define these methods in one place to adhere to the DRY principle. Error Handling
    The `Fill` and `ExtractTo` methods in `UpstreamBasicAuth` struct do not handle potential nil pointer dereferences when accessing properties of `api.Header`. It's important to add nil checks before accessing these properties to prevent runtime panics. Logging Level
    The use of `Info` level for logging potential sensitive operations such as overwriting headers in `Provider.Fill` method might not be appropriate. Consider using `Warning` or `Error` level to highlight the importance of this action.
    github-actions[bot] commented 3 days ago

    PR Code Suggestions ✨

    Explore these optional code suggestions:

    CategorySuggestion                                                                                                                                    Score
    Possible bug
    Prevent potential nil pointer dereference by checking if Header is nil ___ **Consider checking if Header is nil before accessing its methods to prevent potential
    nil pointer dereference.** [apidef/api_definitions.go [820-821]](https://github.com/TykTechnologies/tyk/pull/6669/files#diff-9961ccc89a48d32db5b47ba3006315ef52f6e5007fb4b09f8c5d6d299c669d67R820-R821) ```diff -if !a.IsEnabled() { +if a == nil || !a.IsEnabled() { return "" } ```
    Suggestion importance[1-10]: 8 Why: The suggestion addresses a potential nil pointer dereference, which is a critical issue that can cause runtime errors. By adding a nil check, the code becomes more robust and prevents unexpected crashes.
    8
    Add null check for api.Header to avoid nil pointer dereference ___ **Ensure that Header is properly initialized before calling Fill to avoid nil pointer
    dereference.** [apidef/oas/upstream.go [624-627]](https://github.com/TykTechnologies/tyk/pull/6669/files#diff-7b0941c7f37fe5a2a23047e0822a65519ca11c371660f36555b59a60f000e3f4R624-R627) ```diff if u.Header == nil { u.Header = &AuthSource{} } -u.Header.Fill(api.Header.Enabled, api.Header.Name) +if api.Header != nil { + u.Header.Fill(api.Header.Enabled, api.Header.Name) +} ```
    Suggestion importance[1-10]: 8 Why: This suggestion prevents a potential nil pointer dereference by ensuring `api.Header` is not nil before calling its methods. This is crucial for preventing runtime errors and improving code stability.
    8
    Enhancement
    Prevent setting empty authentication headers ___ **Add a check to ensure AuthValue is not empty before setting the header, to avoid
    setting empty authentication headers.** [ee/middleware/upstreambasicauth/provider.go [25]](https://github.com/TykTechnologies/tyk/pull/6669/files#diff-16e7043ed331108c72617c42eb50870a76523593a477bebb197fae04c22943a4R25-R25) ```diff -r.Header.Set(u.HeaderName, u.AuthValue) +if u.AuthValue != "" { + r.Header.Set(u.HeaderName, u.AuthValue) +} ```
    Suggestion importance[1-10]: 7 Why: The suggestion enhances the code by ensuring that empty authentication headers are not set, which can prevent potential security issues or misconfigurations.
    7
    Improve error handling by logging when UpstreamBasicAuth is not supported ___ **Log an error message when UpstreamBasicAuth is not supported instead of just
    returning false, to provide clearer debugging information.** [gateway/mw_upstream_basic_auth.go [22-24]](https://github.com/TykTechnologies/tyk/pull/6669/files#diff-ba603a8b249fdf72522258e825b7f9c64064203129c167795b206d66e9ebcda7R22-R24) ```diff if d.Spec.UpstreamAuth.BasicAuth.Enabled { d.Logger().Error("Upstream basic auth is supported only in Tyk Enterprise Edition") + return false } ```
    Suggestion importance[1-10]: 6 Why: The suggestion improves error handling by ensuring that an error message is logged when `UpstreamBasicAuth` is not supported. This provides clearer debugging information, although it does not address a critical issue.
    6
    sonarcloud[bot] commented 3 days ago

    Quality Gate Failed Quality Gate failed

    Failed conditions
    0.0% Coverage on New Code (required ≥ 80%)
    C Reliability Rating on New Code (required ≥ A)

    See analysis details on SonarCloud

    Catch issues before they fail your Quality Gate with our IDE extension SonarLint