-
-
Notifications
You must be signed in to change notification settings - Fork 1.6k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat!(middleware/session): re-write session middleware with handler #3016
base: main
Are you sure you want to change the base?
Conversation
Important Review skippedDraft detected. Please check the settings in the CodeRabbit UI or the You can disable this status message by setting the WalkthroughThe recent changes address inconsistencies in session and CSRF middleware handling by aligning with NIST guidelines on timeout and expiration. Key modifications include refactoring session handling to use Changes
Sequence Diagram(s) (Beta)sequenceDiagram
participant Client
participant FiberApp
participant Middleware
participant SessionStore
Client->>FiberApp: HTTP Request
FiberApp->>Middleware: Process Request
Middleware->>SessionStore: Retrieve Session (session.FromContext(c))
SessionStore-->>Middleware: Session Data
Middleware->>FiberApp: Continue Processing
FiberApp-->>Client: HTTP Response
Assessment against linked issues
Poem
Thank you for using CodeRabbit. We offer it for free to the OSS community and would appreciate your support in helping us grow. If you find it useful, would you consider giving us a shout-out on your favorite social media? TipsChatThere are 3 ways to chat with CodeRabbit:
Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments. CodeRabbit Commands (Invoked using PR comments)
Other keywords and placeholders
CodeRabbit Configuration File (
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 2
Outside diff range and nitpick comments (3)
middleware/csrf/session_manager.go (1)
74-84
: Consider adding logging for error scenarios in session deletion.if err != nil { log.Errorf("Failed to retrieve session for deletion: %v", err) }middleware/session/middleware.go (1)
51-94
: Add detailed documentation for the middleware lifecycle.// NewMiddleware creates and manages the lifecycle of session middleware. // It retrieves a middleware instance from the pool, attaches it to the context, // and ensures it is properly released after the request is processed.middleware/session/session.go (1)
Line range hint
170-192
: Improve error handling in theSave
method to handle potential encoding failures more gracefully.if err != nil { log.Errorf("Session encoding failed: %v", err) return err }
Review Details
Configuration used: CodeRabbit UI
Review profile: CHILL
Files selected for processing (4)
- middleware/csrf/session_manager.go (3 hunks)
- middleware/session/config.go (3 hunks)
- middleware/session/middleware.go (1 hunks)
- middleware/session/session.go (7 hunks)
Additional comments not posted (4)
middleware/csrf/session_manager.go (1)
57-68
: Ensure thread safety when setting session tokens.Verification successful
The
Set
method implementations found in the codebase indicate that thread safety measures are in place. Specifically:
- In
middleware/session/middleware.go
, theSet
method uses a mutex (m.mu.Lock()
andm.mu.Unlock()
) to ensure thread safety.- In
middleware/session/data.go
, theSet
method also uses a lock (d.Lock()
andd.Unlock()
) to ensure thread safety.These implementations confirm that the session management operations are thread-safe.
Scripts Executed
The following scripts were executed for the analysis:
Script:
#!/bin/bash # Description: Check for potential data races when setting session tokens. # Command: Run your Go data race detector tool on this section.Length of output: 0
Script:
#!/bin/bash # Description: Check if the session management library used in the codebase provides thread-safe operations. # Command: Search for the session management library and inspect its documentation or implementation for thread safety. # Find the session management library used in the codebase session_lib=$(rg --files-with-matches 'session.FromContext' | head -n 1) # Check if the session management library provides thread-safe operations if [ -n "$session_lib" ]; then rg 'thread-safe' "$session_lib" else echo "Session management library not found." fiLength of output: 208
Script:
#!/bin/bash # Description: Extract and inspect the implementation of the `Set` method in the session management library to verify thread safety. # Find the implementation of the `Set` method in the session management library ast-grep --lang go --pattern 'func ($_ $_) Set($_, $_) $_' middleware/csrf/session_manager.goLength of output: 95
Script:
#!/bin/bash # Description: Search the entire codebase for the implementation of the `Set` method to verify thread safety. # Find the implementation of the `Set` method in the entire codebase ast-grep --lang go --pattern 'func ($_ $_) Set($_, $_) $_'Length of output: 1417
middleware/session/config.go (1)
13-15
: RenamingExpiration
toIdleTimeout
clarifies the purpose and aligns with best practices.middleware/session/middleware.go (1)
31-37
: Well-structuredMiddleware
struct with appropriate use of synchronization for thread safety.middleware/session/session.go (1)
16-22
: The addition ofidleTimeout
in theSession
struct is a positive change for better session management.
sess := session.FromContext(c) | ||
var token Token | ||
var ok bool | ||
|
||
if sess != nil { | ||
token, ok = sess.Get(m.key).(Token) | ||
} else { | ||
// Try to get the session from the store | ||
storeSess, err := m.session.Get(c) | ||
if err != nil { | ||
// Handle error | ||
return nil | ||
} | ||
token, ok = storeSess.Get(m.key).(Token) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Refactor to improve error handling in session retrieval.
if err != nil {
// Log the error or handle it according to your error handling policy
return nil
}
if int(cfg.IdleTimeout.Seconds()) <= 0 { | ||
cfg.IdleTimeout = ConfigDefault.IdleTimeout |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Enhance error handling for configuration validation.
if len(selectors) != numSelectors {
log.Errorf("[session] KeyLookup format is incorrect: %s", cfg.KeyLookup)
return ConfigDefault // Return default config or handle error appropriately
}
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
TODO: There should probably be a way to allow for not having an idle timeout.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@sixcolors, to accommodate the possibility of not having an idle timeout, we can introduce a specific value for IdleTimeout
that, when set, indicates the session should not expire based on time. For example, setting IdleTimeout
to -1
could be used to represent no timeout.
Here's a proposed change to the configDefault
function in middleware/session/config.go
to support this:
func configDefault(config ...Config) Config {
if len(config) < 1 {
return ConfigDefault
}
cfg := config[0]
// Set default values
if cfg.IdleTimeout == -1 {
// -1 means no idle timeout
cfg.IdleTimeout = 0 // 0 could internally represent no timeout
} else if int(cfg.IdleTimeout.Seconds()) <= 0 {
cfg.IdleTimeout = ConfigDefault.IdleTimeout
}
// Existing code for setting other defaults
if cfg.KeyLookup == "" {
cfg.KeyLookup = ConfigDefault.KeyLookup
}
if cfg.KeyGenerator == nil {
cfg.KeyGenerator = ConfigDefault.KeyGenerator
}
// Existing code for validating KeyLookup
selectors := strings.Split(cfg.KeyLookup, ":")
const numSelectors = 2
if len(selectors) != numSelectors {
panic("[session] KeyLookup must in the form of <source>:<name>")
}
switch Source(selectors[0]) {
case SourceCookie:
cfg.source = SourceCookie
case SourceHeader:
cfg.source = SourceHeader
case SourceURLQuery:
cfg.source = SourceURLQuery
default:
panic("[session] source is not supported")
}
cfg.sessionName = selectors[1]
return cfg
}
This modification allows setting IdleTimeout
to -1
to disable the timeout, while maintaining the default behavior when a non-negative timeout is specified. If this approach aligns with your expectations, it could be implemented to enhance the flexibility of session management.
Known IssuesStorage Adapter UPSERT BehaviorThere is an issue with the way Fiber's storage adapters handle setting keys. The current operation for setting a key is an UPSERT, which means it will insert a new key if it does not exist or update it if it does. This can lead to issues in scenarios with simultaneous requests altering the same session. For example:
If the session destruction completes first, the inconsequential change could recreate the session, potentially preventing actions like logging out and posing security risks. Since this PR changes the session behavior to save and update on every request, it amplifies the problem if not addressed. |
See: https://github.com/gofiber/recipes/tree/v3-csrf-with-session-PR-3016-update/csrf-with-session for usage example of this PR in current state. |
Those new sequence diagrams are awesome |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Wow, you've been doing a good job. I commented on a few details. Thanks for contributing here.
Co-authored-by: Renan Bastos <[email protected]>
Codecov ReportAttention: Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## main #3016 +/- ##
==========================================
+ Coverage 80.19% 80.29% +0.10%
==========================================
Files 117 118 +1
Lines 9048 9192 +144
==========================================
+ Hits 7256 7381 +125
- Misses 1360 1370 +10
- Partials 432 441 +9
Flags with carried forward coverage won't be shown. Click here to find out more. ☔ View full report in Codecov by Sentry. |
@sixcolors looks very good |
Which tasks are still open? |
ok, there was a task list above^^ |
- Refactor session tests to improve readability and maintainability. - Add a new test case to ensure proper session release functionality. - Update session.md
Feature: Re-write Session Middleware with Handler
Summary
This pull request introduces significant changes to the session middleware, enhancing its functionality and improving its robustness. The primary focus is on the re-write of the session middleware with a new handler.
Status
session.New()
returns middleware handler)Changelog
Middleware Changes
middleware/session/middleware.go
to define the session middleware and its configuration.CSRF Session Manager Changes
getRaw
,setRaw
, anddelRaw
methods to use the session from the context first before falling back to the store.log
) from the session manager.Configuration Changes
Expiration
toIdleTimeout
to better reflect the session idle duration.Session Struct Changes
exp
is nowidleTimeout
to indicate the idle timeout duration for sessions.idleTimeout
instead ofexp
.Save
method to handle idle timeout correctly.Future Work On This PR
This is an initial commit for the new middleware approach. If the new middleware handler proves to be more effective, further changes will be made to:
session.New
to return theMiddleware
handler instead of the oldsession.Store
struct.Session
toRawSession
, preferring the new style of session management.A suggested standard use for the session might look something like this after these modifications:
Testing
Notes
Please review the changes and provide feedback or approval for merging.
Fixes #2741