Skip to content
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

prevent re-using refresh token in Boilerplate (#9335) #9336

Conversation

ysmoradi
Copy link
Member

@ysmoradi ysmoradi commented Nov 26, 2024

This closes #9335

Summary by CodeRabbit

  • New Features

    • Updated database selection options to exclude "Cosmos," simplifying choices to SqlServer, PostgreSQL, MySQL, and Other.
    • Enhanced UI display for session information, including device info and last seen time.
  • Bug Fixes

    • Improved session management and validation logic in the IdentityController.
  • Chores

    • Removed references and configurations related to Cosmos DB across various files, streamlining database support.
  • Documentation

    • Updated comments and documentation to reflect changes in database configurations and session management.

@ysmoradi ysmoradi requested a review from msynk November 26, 2024 12:58
Copy link

coderabbitai bot commented Nov 26, 2024

Important

Review skipped

Auto incremental reviews are disabled on this repository.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Walkthrough

The changes in this pull request focus on removing support for the Cosmos database across various components of the Bit platform CI and its associated templates. This includes the elimination of Cosmos-related test steps, configuration options, and references in multiple files. The modifications streamline the database options to SqlServer, Sqlite, PostgreSQL, and MySQL, while enhancing session management and security features in the identity controller. Additionally, several UI components and configuration files have been updated to reflect these changes, ensuring consistency throughout the application.

Changes

File Change Summary
.github/workflows/bit.full.ci.yml Removed PostgreSQL and Cosmos test steps; updated sample configuration tests to use SqlServer instead of Cosmos.
src/Templates/Boilerplate/Bit.Boilerplate/.template.config/template.json Removed "Cosmos" option from database choices; excluded HubConnectionExtensions.cs if SignalR is not enabled.
src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Components/Pages/Authorized/Settings/ProfileSection.razor.cs Removed SignalR-related directives and logic from ProfileSection class.
src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Components/Pages/Authorized/Settings/SessionsSection.razor Updated BitPersona components to enhance session information display.
src/Templates/Boilerplate/Bit.Boilerplate/src/Server/Boilerplate.Server.Api/Controllers/Identity/IdentityController.cs Added SESSION_STAMP claim; streamlined session management logic in SignIn and Refresh methods.
src/Templates/Boilerplate/Bit.Boilerplate/src/Server/Boilerplate.Server.Api/Data/AppDbContext.cs Removed Cosmos DB support from AppDbContext; simplified database configuration logic.
src/Templates/Boilerplate/Bit.Boilerplate/src/Server/Boilerplate.Server.Api/Data/Migrations/20241126123435_InitialMigration.cs Created initial migration without Cosmos-specific annotations; modified foreign key behavior for UserSession.
src/Templates/Boilerplate/Bit.Boilerplate/src/Server/Boilerplate.Server.Api/appsettings.json Removed CosmosConnectionString from configuration.
src/Websites/Platform/src/Bit.Websites.Platform.Client/Pages/Templates/Templates05CreateProjectPage.razor Removed "Cosmos" from the database selection dropdown; updated explanatory text for SQLite.
src/Websites/Platform/src/Bit.Websites.Platform.Client/Pages/Templates/Templates05CreateProjectPage.razor.cs Removed "Cosmos" from the database parameter options.

Assessment against linked issues

Objective Addressed Explanation
Prevent re-using refresh tokens (#9335)
Ensure the removal of Cosmos DB references and support

🐰 In the land of code, where changes bloom,
The Cosmos fades, making room.
With SqlServer and MySql in sight,
Our templates shine, oh so bright!
Refresh tokens now secure and tight,
A hop towards clarity, what a delight! 🌟


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?

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Generate unit testing code for this file.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai generate unit testing code for this file.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and generate unit testing code.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

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)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 8

🧹 Outside diff range and nitpick comments (11)
src/Templates/Boilerplate/Bit.Boilerplate/src/Shared/Services/AuthPolicies.cs (1)

43-48: Consider adding rate limiting for refresh token attempts

While the session stamp effectively prevents token reuse, consider enhancing security further by implementing rate limiting for refresh token attempts to prevent brute force attacks.

Would you like me to provide an example implementation of rate limiting for refresh token endpoints?

src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Components/Pages/Authorized/Settings/SessionsSection.razor (2)

23-29: Consider adding tooltips for privilege indicators

The visual indicators (✓/✘) for privileged sessions are good, but might benefit from tooltips to explain their meaning to users.

Consider adding a tooltip attribute:

-ImageInitials="@(currentSession.Privileged ? "✓" : "✘")"
+ImageInitials="@(currentSession.Privileged ? "✓" : "✘")"
+Tooltip="@(currentSession.Privileged ? Localizer[nameof(AppStrings.PrivilegedSession)] : Localizer[nameof(AppStrings.StandardSession)])"

Line range hint 1-67: Review security considerations for session management

While the UI improvements enhance visibility of session information, please ensure:

  1. The component is only accessible to authenticated users with appropriate permissions
  2. Consider masking sensitive information (e.g., partial IP addresses) for security
  3. Implement rate limiting for session revocation to prevent abuse
  4. Add confirmation dialog before session revocation to prevent accidental termination

Consider implementing these security enhancements:

  • Add rate limiting middleware for session management endpoints
  • Implement audit logging for session revocation events
  • Use secure session storage mechanisms
src/Templates/Boilerplate/Bit.Boilerplate/src/Server/Boilerplate.Server.Api/Data/AppDbContext.cs (2)

Line range hint 48-63: Enhance error handling for refresh token operations

While the current concurrency exception handling is good, consider adding specific handling for refresh token operations to provide clearer error messages and proper audit logging.

 public override async Task<int> SaveChangesAsync(bool acceptAllChangesOnSuccess, CancellationToken cancellationToken = new CancellationToken())
 {
     try
     {
         return await base.SaveChangesAsync(acceptAllChangesOnSuccess, cancellationToken);
     }
     catch (DbUpdateConcurrencyException exception)
     {
+        // Check if the concurrency exception is related to refresh token
+        if (exception.Entries.Any(e => e.Entity is UserSession))
+        {
+            throw new ConflictException(nameof(AppStrings.RefreshTokenAlreadyUsed), exception);
+        }
         throw new ConflictException(nameof(AppStrings.UpdateConcurrencyException), exception);
     }
 }

Line range hint 1-171: Consider implementing a dedicated refresh token service

To better handle refresh token security across different database providers, consider extracting token management logic into a dedicated service that can:

  1. Implement consistent token invalidation across all database providers
  2. Provide proper audit logging for security events
  3. Handle token cleanup and expiration
  4. Implement rate limiting for token refresh attempts

This would help ensure consistent security regardless of the underlying database provider.

Would you like me to provide a detailed design for this service?

src/Templates/Boilerplate/Bit.Boilerplate/src/Server/Boilerplate.Server.Api/Controllers/Identity/UserController.cs (3)

Line range hint 66-82: Prevent race conditions in session termination

The current implementation might allow refresh token reuse during the brief window between token validation and session removal. Consider marking the session as used first, then removing it.

Here's a suggested implementation using a transaction:

 [HttpPost]
 public async Task SignOut(CancellationToken cancellationToken)
 {
     var currentSessionId = User.GetSessionId();
+    await using var transaction = await DbContext.Database.BeginTransactionAsync(cancellationToken);
     var userSession = await DbContext.UserSessions
-        .FirstOrDefaultAsync(us => us.Id == currentSessionId, cancellationToken) ?? throw new ResourceNotFoundException();
+        .FirstOrDefaultAsync(us => us.Id == currentSessionId && !us.IsUsed, cancellationToken) 
+        ?? throw new ResourceNotFoundException("Session not found or already terminated");
+    
+    userSession.IsUsed = true;
+    await DbContext.SaveChangesAsync(cancellationToken);
 
     DbContext.UserSessions.Remove(userSession);
     await DbContext.SaveChangesAsync(cancellationToken);
+    await transaction.CommitAsync(cancellationToken);
 
     SignOut();
 }

Line range hint 397-398: Enhance elevated access token security

The comment indicates that elevated access token claims are added during refresh token requests, but there's no mechanism to prevent replay attacks or ensure the refresh token hasn't been reused.

Consider implementing the following security measures:

  1. Add a nonce to the elevated access token claim
  2. Store the nonce in the UserSession record
  3. Validate the nonce during token refresh
  4. Invalidate the nonce after successful validation

This ensures that even if a refresh token is somehow reused, the elevated access token claim cannot be replayed.


Line range hint 1-1: Summary of Required Security Improvements

To fully prevent refresh token reuse as per PR objectives, the following changes are needed:

  1. Add IsUsed flag to UserSessions table
  2. Implement token rotation or single-use mechanism
  3. Use transactions for atomic session updates
  4. Add nonce validation for elevated access tokens

Would you like assistance in implementing these security improvements?

src/Templates/Boilerplate/Bit.Boilerplate/src/Server/Boilerplate.Server.Api/Data/Migrations/20241126123435_InitialMigration.Designer.cs (1)

744-745: Security enhancement: Proper cleanup of push notification subscriptions

The change to OnDelete(DeleteBehavior.SetNull) for the UserSession-PushNotificationSubscription relationship is a good security practice. When a user session ends, the push notification subscription is not immediately deleted but rather unlinked, which:

  1. Prevents orphaned push notification channels
  2. Maintains audit trail
  3. Allows for proper cleanup of notification tokens

Consider implementing a background job to clean up unused push notification subscriptions after a certain period to prevent accumulation of stale records.

src/Templates/Boilerplate/Bit.Boilerplate/src/Server/Boilerplate.Server.Api/Controllers/Identity/IdentityController.cs (2)

Line range hint 284-288: Avoid possible race conditions in SendOtp method

The resendDelay calculation may result in negative values if OtpRequestedOn is in the future or null. Additionally, there is a potential for race conditions if multiple requests are made simultaneously. Implement proper checks to handle these scenarios and ensure thread safety.

Consider updating the code as follows:

-var resendDelay = (DateTimeOffset.Now - user.OtpRequestedOn) - AppSettings.Identity.OtpTokenLifetime;
+var timeSinceLastRequest = DateTimeOffset.Now - (user.OtpRequestedOn ?? DateTimeOffset.MinValue);
+var resendDelay = AppSettings.Identity.OtpTokenLifetime - timeSinceLastRequest;

-if (resendDelay < TimeSpan.Zero)
+if (resendDelay > TimeSpan.Zero)
    throw new TooManyRequestsExceptions(Localizer[nameof(AppStrings.WaitForOtpRequestResendDelay), resendDelay.Humanize(culture: CultureInfo.CurrentUICulture)]);

Line range hint 327-331: Correct the logic for resendDelay calculation in SendTwoFactorToken

Similar to the SendOtp method, the calculation of resendDelay may produce incorrect results if TwoFactorTokenRequestedOn is null. Adjust the logic to handle null values and ensure accurate delay calculation.

Update the code to handle null values:

-var resendDelay = (DateTimeOffset.Now - user.TwoFactorTokenRequestedOn) - AppSettings.Identity.TwoFactorTokenLifetime;
+var timeSinceLastRequest = DateTimeOffset.Now - (user.TwoFactorTokenRequestedOn ?? DateTimeOffset.MinValue);
+var resendDelay = AppSettings.Identity.TwoFactorTokenLifetime - timeSinceLastRequest;

-if (resendDelay < TimeSpan.Zero)
+if (resendDelay > TimeSpan.Zero)
    throw new TooManyRequestsExceptions(Localizer[nameof(AppStrings.WaitForTwoFactorTokenRequestResendDelay), resendDelay.Humanize(culture: CultureInfo.CurrentUICulture)]);
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Reviewing files that changed from the base of the PR and between 45f2f71 and 3263aba.

📒 Files selected for processing (26)
  • .github/workflows/bit.full.ci.yml (2 hunks)
  • src/Templates/Boilerplate/Bit.Boilerplate/.template.config/template.json (0 hunks)
  • src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Components/Pages/Authorized/Settings/ProfileSection.razor.cs (0 hunks)
  • src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Components/Pages/Authorized/Settings/SessionsSection.razor (2 hunks)
  • src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Extensions/HubConnectionExtensions.cs (0 hunks)
  • src/Templates/Boilerplate/Bit.Boilerplate/src/Directory.Packages.props (0 hunks)
  • src/Templates/Boilerplate/Bit.Boilerplate/src/Directory.Packages8.props (0 hunks)
  • src/Templates/Boilerplate/Bit.Boilerplate/src/Server/Boilerplate.Server.Api/Boilerplate.Server.Api.csproj (0 hunks)
  • src/Templates/Boilerplate/Bit.Boilerplate/src/Server/Boilerplate.Server.Api/Controllers/Identity/IdentityController.cs (4 hunks)
  • src/Templates/Boilerplate/Bit.Boilerplate/src/Server/Boilerplate.Server.Api/Controllers/Identity/UserController.cs (1 hunks)
  • src/Templates/Boilerplate/Bit.Boilerplate/src/Server/Boilerplate.Server.Api/Data/AppDbContext.cs (2 hunks)
  • src/Templates/Boilerplate/Bit.Boilerplate/src/Server/Boilerplate.Server.Api/Data/Configurations/Identity/RoleConfiguration.cs (0 hunks)
  • src/Templates/Boilerplate/Bit.Boilerplate/src/Server/Boilerplate.Server.Api/Data/Configurations/Identity/UserConfiguration.cs (0 hunks)
  • src/Templates/Boilerplate/Bit.Boilerplate/src/Server/Boilerplate.Server.Api/Data/Configurations/PushNotification/PushNotificationSubscriptionConfiguration.cs (1 hunks)
  • src/Templates/Boilerplate/Bit.Boilerplate/src/Server/Boilerplate.Server.Api/Data/Migrations/20241126123435_InitialMigration.Designer.cs (4 hunks)
  • src/Templates/Boilerplate/Bit.Boilerplate/src/Server/Boilerplate.Server.Api/Data/Migrations/20241126123435_InitialMigration.cs (4 hunks)
  • src/Templates/Boilerplate/Bit.Boilerplate/src/Server/Boilerplate.Server.Api/Data/Migrations/AppDbContextModelSnapshot.cs (3 hunks)
  • src/Templates/Boilerplate/Bit.Boilerplate/src/Server/Boilerplate.Server.Api/Program.Services.cs (0 hunks)
  • src/Templates/Boilerplate/Bit.Boilerplate/src/Server/Boilerplate.Server.Api/SignalR/AppHub.cs (0 hunks)
  • src/Templates/Boilerplate/Bit.Boilerplate/src/Server/Boilerplate.Server.Api/appsettings.json (0 hunks)
  • src/Templates/Boilerplate/Bit.Boilerplate/src/Server/Boilerplate.Server.Web/appsettings.json (0 hunks)
  • src/Templates/Boilerplate/Bit.Boilerplate/src/Shared/Dtos/Identity/UserSessionDto.cs (0 hunks)
  • src/Templates/Boilerplate/Bit.Boilerplate/src/Shared/Services/AuthPolicies.cs (1 hunks)
  • src/Templates/Boilerplate/Bit.Boilerplate/src/Shared/Services/SharedPubSubMessages.cs (0 hunks)
  • src/Websites/Platform/src/Bit.Websites.Platform.Client/Pages/Templates/Templates05CreateProjectPage.razor (1 hunks)
  • src/Websites/Platform/src/Bit.Websites.Platform.Client/Pages/Templates/Templates05CreateProjectPage.razor.cs (0 hunks)
💤 Files with no reviewable changes (15)
  • src/Templates/Boilerplate/Bit.Boilerplate/.template.config/template.json
  • src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Components/Pages/Authorized/Settings/ProfileSection.razor.cs
  • src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Extensions/HubConnectionExtensions.cs
  • src/Templates/Boilerplate/Bit.Boilerplate/src/Directory.Packages.props
  • src/Templates/Boilerplate/Bit.Boilerplate/src/Directory.Packages8.props
  • src/Templates/Boilerplate/Bit.Boilerplate/src/Server/Boilerplate.Server.Api/Boilerplate.Server.Api.csproj
  • src/Templates/Boilerplate/Bit.Boilerplate/src/Server/Boilerplate.Server.Api/Data/Configurations/Identity/RoleConfiguration.cs
  • src/Templates/Boilerplate/Bit.Boilerplate/src/Server/Boilerplate.Server.Api/Data/Configurations/Identity/UserConfiguration.cs
  • src/Templates/Boilerplate/Bit.Boilerplate/src/Server/Boilerplate.Server.Api/Program.Services.cs
  • src/Templates/Boilerplate/Bit.Boilerplate/src/Server/Boilerplate.Server.Api/SignalR/AppHub.cs
  • src/Templates/Boilerplate/Bit.Boilerplate/src/Server/Boilerplate.Server.Api/appsettings.json
  • src/Templates/Boilerplate/Bit.Boilerplate/src/Server/Boilerplate.Server.Web/appsettings.json
  • src/Templates/Boilerplate/Bit.Boilerplate/src/Shared/Dtos/Identity/UserSessionDto.cs
  • src/Templates/Boilerplate/Bit.Boilerplate/src/Shared/Services/SharedPubSubMessages.cs
  • src/Websites/Platform/src/Bit.Websites.Platform.Client/Pages/Templates/Templates05CreateProjectPage.razor.cs
🔇 Additional comments (16)
src/Templates/Boilerplate/Bit.Boilerplate/src/Server/Boilerplate.Server.Api/Data/Configurations/PushNotification/PushNotificationSubscriptionConfiguration.cs (2)

13-13: LGTM! Improved security through automatic FK nullification

The change from ClientSetNull to SetNull enhances security by ensuring database-level cleanup of push notification subscriptions when user sessions are invalidated, which aligns with the goal of preventing refresh token reuse.


13-13: Verify session invalidation behavior

Let's ensure this change doesn't affect the session invalidation logic elsewhere in the codebase.

✅ Verification successful

Setting UserSession to null is safe for session invalidation

The change to use DeleteBehavior.SetNull for the PushNotificationSubscription's UserSession relationship is safe and consistent with the session invalidation logic in the codebase. Here's why:

  • The UserSession deletion is properly handled in the UserController where sessions are explicitly removed using DbContext.UserSessions.Remove() during sign-out and session revocation.
  • The SetNull behavior only affects the PushNotificationSubscription table by nulling the UserSessionId foreign key when the associated session is deleted, which is the desired behavior.
  • The session invalidation flow remains intact as the UserSession entity itself is still deleted with Cascade behavior from its parent User entity.
  • Push notification subscriptions are designed to outlive sessions, as evidenced by the nullable UserSessionId and SetNull delete behavior.
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Check for session invalidation logic that might be affected

# Look for session invalidation patterns
rg -A 5 "InvalidateSession|DeleteSession|RemoveSession" 

# Check for UserSession deletion handling
ast-grep --pattern 'UserSession.Delete$$$' 

# Look for refresh token invalidation logic
rg -A 5 "RefreshToken.*invalid|invalid.*RefreshToken"

Length of output: 5548


Script:

#!/bin/bash
# Let's check for session and token related configurations and handlers

# Check for session and token related configurations
ast-grep --pattern 'class $_Configuration : IEntityTypeConfiguration<$_> {
  $$$
}'

# Look for session deletion or token invalidation in controllers/services
rg -A 10 "UserSession|RefreshToken" --type cs

# Check for cascade delete configurations
rg -A 5 "DeleteBehavior" --type cs

Length of output: 101019

src/Templates/Boilerplate/Bit.Boilerplate/src/Shared/Services/AuthPolicies.cs (1)

43-48: Implementation effectively prevents refresh token reuse!

The addition of SESSION_STAMP claim type with its concurrency stamp mechanism is a robust approach to prevent refresh token reuse. This implementation aligns well with security best practices by ensuring tokens are single-use and tied to specific sessions.

Let's verify the complete implementation of this security measure:

✅ Verification successful

SESSION_STAMP is properly implemented to prevent refresh token reuse

The verification confirms that SESSION_STAMP is correctly integrated into the authentication flow:

  • During sign-in: A new session stamp is created using the session's start time
  • During refresh: The system validates the session stamp from the refresh token against the stored session timestamp (RenewedOn or StartedOn)
  • If timestamps don't match, the system throws UnauthorizedException, effectively preventing token reuse
  • The session stamp is updated (RenewedOn) after successful refresh, ensuring single-use tokens
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Verify the SESSION_STAMP is properly integrated in the authentication flow
# Expected: Find usage in SignIn/Refresh methods of IdentityController

# Check for SESSION_STAMP usage in authentication-related files
rg -l "SESSION_STAMP" --type cs

# Look for refresh token handling in IdentityController
ast-grep --pattern 'class IdentityController {
  $$$
  Refresh($$$) {
    $$$
  }
  $$$
}'

Length of output: 437


Script:

#!/bin/bash
# Let's examine the implementation details in IdentityController
rg "SESSION_STAMP" -B 5 -A 10 src/Templates/Boilerplate/Bit.Boilerplate/src/Server/Boilerplate.Server.Api/Controllers/Identity/IdentityController.cs

# Also check for refresh token related methods
ast-grep --pattern 'RefreshToken($$$) {
  $$$
}'

Length of output: 3012

src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Components/Pages/Authorized/Settings/SessionsSection.razor (1)

46-52: Verify session revocation implementation

While the UI changes for displaying sessions look good, it's crucial to ensure that the session revocation functionality (triggered by the delete button) properly invalidates the refresh token to prevent reuse.

Let's verify the session revocation implementation:

✅ Verification successful

Let's gather more specific information about the session revocation implementation.


Let's search for more details about the session handling and token invalidation:


Based on the gathered information, I can now generate the final response:

Session revocation implementation is properly secured

The session revocation implementation is well-designed with multiple security measures in place:

  • Server-side validation prevents revoking the current session (must use SignOut instead)
  • Session revocation triggers client-side token cleanup via PubSub notifications
  • Refresh tokens are protected and validated with security stamps
  • Client properly handles token cleanup during SignOut
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Search for the RevokeSession implementation and related token invalidation logic
ast-grep --pattern 'RevokeSession($$$) {
  $$$
}'

# Look for refresh token handling in the codebase
rg -l 'refresh.*token|token.*refresh' --type cs

Length of output: 1276


Script:

#!/bin/bash
# Check UserController for session revocation endpoint
rg -A 10 "RevokeSession|RevokeSessions?" "src/Templates/Boilerplate/Bit.Boilerplate/src/Server/Boilerplate.Server.Api/Controllers/Identity/UserController.cs"

# Check AuthManager for client-side session handling
rg -A 10 "RevokeSession|RevokeSessions?" "src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Services/AuthManager.cs"

# Look for refresh token invalidation in IdentityController
rg -A 10 "InvalidateRefreshToken|RevokeToken" "src/Templates/Boilerplate/Bit.Boilerplate/src/Server/Boilerplate.Server.Api/Controllers/Identity/IdentityController.cs"

Length of output: 1316


Script:

#!/bin/bash
# Check UserSessions table structure and handling
rg -A 10 "class UserSession" src/Templates/Boilerplate/Bit.Boilerplate/src/Server/Boilerplate.Server.Api/Models/Identity/

# Look for refresh token handling in IdentityController
rg -A 10 "RefreshToken|SignOut" src/Templates/Boilerplate/Bit.Boilerplate/src/Server/Boilerplate.Server.Api/Controllers/Identity/IdentityController.cs

# Check for token validation/invalidation in AuthManager
rg -A 10 "SignOut|InvalidateToken" src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Services/AuthManager.cs

Length of output: 3664

src/Templates/Boilerplate/Bit.Boilerplate/src/Server/Boilerplate.Server.Api/Data/AppDbContext.cs (1)

Line range hint 19-19: Verify UserSession entity configuration for refresh token security

Given the PR's objective to prevent refresh token reuse, ensure that the UserSession entity has proper configuration in the Configurations folder to enforce token invalidation constraints.

✅ Verification successful

Let me gather more information about the UserSession model and its configuration.


Let me check the IdentityController implementation to understand how refresh tokens are handled with UserSessions.


Based on the code review, I can now provide the final response:

Refresh token reuse prevention is properly implemented

The UserSession entity and refresh token handling in IdentityController.cs effectively prevents refresh token reuse through:

  • Session stamp validation: Each refresh token contains a session stamp that must match the current session's RenewedOn/StartedOn timestamp
  • Session invalidation: If a refresh token is reused, the session stamp validation will fail and the session is deleted
  • Automatic session renewal: RenewedOn timestamp is updated with each successful refresh, invalidating previous refresh tokens
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Search for UserSession configuration
ast-grep --pattern 'class UserSessionConfiguration : IEntityTypeConfiguration<UserSession>
{
  $$$
}'

# Check for any existing refresh token handling
rg -l "RefreshToken|UserSession" src/

Length of output: 4090


Script:

#!/bin/bash
# Check UserSession model
cat src/Templates/Boilerplate/Bit.Boilerplate/src/Server/Boilerplate.Server.Api/Models/Identity/UserSession.cs

# Check migrations for UserSession table configuration
cat src/Templates/Boilerplate/Bit.Boilerplate/src/Server/Boilerplate.Server.Api/Data/Migrations/20241126123435_InitialMigration.cs

# Check if there's any specific configuration in Data/Configurations
fd -e cs -p "UserSessionConfiguration.cs" src/Templates/Boilerplate/Bit.Boilerplate/src/Server/Boilerplate.Server.Api/Data/Configurations/Identity/

# Check IdentityController for refresh token handling
rg -A 5 "RefreshToken" src/Templates/Boilerplate/Bit.Boilerplate/src/Server/Boilerplate.Server.Api/Controllers/Identity/IdentityController.cs

Length of output: 26557


Script:

#!/bin/bash
# Check IdentityController for sign-in and refresh token handling
cat src/Templates/Boilerplate/Bit.Boilerplate/src/Server/Boilerplate.Server.Api/Controllers/Identity/IdentityController.cs

# Check if there are any other files handling refresh tokens
rg -l "RefreshToken.*UserSession" src/Templates/Boilerplate/Bit.Boilerplate/src/Server/Boilerplate.Server.Api/

Length of output: 20735

.github/workflows/bit.full.ci.yml (1)

141-141: LGTM: Database options test step updated correctly

The test step has been updated to remove Cosmos DB tests while maintaining coverage for PostgreSQL, MySql, and Other database options. This aligns with the architectural changes to streamline database support.

Let's verify the database options are consistently defined across the codebase:

✅ Verification successful

Database support changes verified successfully

Based on the codebase analysis, the removal of Cosmos DB and streamlining of database options to PostgreSQL, MySQL, SQLite, and SQL Server is consistently implemented. The search results confirm:

  1. No remaining Cosmos DB or DocumentDB references in configuration files or code
  2. Database providers are properly configured in Program.Services.cs for:
    • SQLite
    • SQL Server
    • PostgreSQL
    • MySQL
  3. Connection strings in appsettings.json are updated accordingly for the supported databases
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Search for any remaining Cosmos DB references in configuration files
rg -i 'cosmos|documentdb' --type json

Length of output: 39


Script:

#!/bin/bash
# Let's try a broader search for database configurations and providers
rg -i "UseCosmos|UseDocumentDb|CosmosDb|DocumentDb" -g "*.{cs,json,yml}"

# Also search for database provider enums or configurations
ast-grep --pattern 'enum $_ {
  $$$
  Cosmos
  $$$
}'

# Check for database connection strings or configurations
rg -i "database.*provider|connection.*string" -g "*.{json,cs,yml}" -A 2 -B 2

Length of output: 33292

src/Websites/Platform/src/Bit.Websites.Platform.Client/Pages/Templates/Templates05CreateProjectPage.razor (1)

250-250: LGTM with a note about documentation consistency

The updated database options text correctly reflects the supported databases after removing Cosmos DB support.

Let's verify the consistency of database options across documentation:

✅ Verification successful

Database options text update is consistent with codebase changes

The verification shows no remaining references to Cosmos DB in the codebase, and the only database-related text found is unrelated to the supported database options. This confirms that the updated text in Templates05CreateProjectPage.razor correctly reflects the current state of supported databases.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Search for any remaining references to Cosmos DB in documentation
rg -i "cosmos" "*.md" "*.mdx" "*.razor" "*.html"

# Search for database options listings to ensure consistency
rg -i "supported.*database|database.*option" "*.md" "*.mdx" "*.razor" "*.html"

Length of output: 501


Script:

#!/bin/bash
# Search for any remaining references to Cosmos DB in documentation and code
rg -i "cosmos"

# Search for database options listings to ensure consistency
rg -i "supported.*database|database.*option"

Length of output: 186

src/Templates/Boilerplate/Bit.Boilerplate/src/Server/Boilerplate.Server.Api/Controllers/Identity/UserController.cs (1)

51-62: ⚠️ Potential issue

Session filtering doesn't prevent refresh token reuse

While the code filters expired sessions, it doesn't implement a mechanism to prevent refresh token reuse. Consider adding a IsUsed flag or implementing token rotation to invalidate refresh tokens after they've been used once.

Here's a suggested implementation:

 return (await DbContext.UserSessions
     .Where(us => us.UserId == userId)
+    .Where(us => !us.IsUsed) // Add IsUsed column to UserSessions table
     .ToArrayAsync(cancellationToken))
     .Select(us =>
     {
         var dto = us.Map();
         dto.RenewedOn = us.RenewedOn ?? us.StartedOn;
         return dto;
     })
     .Where(dto => DateTimeOffset.UtcNow - dto.RenewedOn < AppSettings.Identity.RefreshTokenExpiration)
     .OrderByDescending(us => us.RenewedOn)
     .ToList();

Let's verify if the UserSessions table has the necessary column:

src/Templates/Boilerplate/Bit.Boilerplate/src/Server/Boilerplate.Server.Api/Data/Migrations/20241126123435_InitialMigration.cs (2)

48-48: Consider implications of changing ConcurrencyStamp type

The ConcurrencyStamp columns in both Roles and Users tables are defined as TEXT type without rowVersion attribute. This might affect optimistic concurrency control.

Consider using a dedicated version column or timestamp for better concurrency control.

Also applies to: 77-77


286-287: Review cascade delete behavior for UserSessions

Setting onDelete: ReferentialAction.SetNull for UserSessions foreign key could lead to orphaned PushNotificationSubscriptions records. Consider if this aligns with the business requirements for handling inactive sessions.

Consider implementing a cleanup job to handle orphaned notification subscriptions or use CASCADE delete if the subscriptions should be removed when the session ends.

src/Templates/Boilerplate/Bit.Boilerplate/src/Server/Boilerplate.Server.Api/Data/Migrations/AppDbContextModelSnapshot.cs (1)

84-84: LGTM: Removed Cosmos DB specific configurations

The removal of ValueGeneratedOnAddOrUpdate() from ConcurrencyStamp properties is consistent with the migration away from Cosmos DB.

Also applies to: 117-117

src/Templates/Boilerplate/Bit.Boilerplate/src/Server/Boilerplate.Server.Api/Data/Migrations/20241126123435_InitialMigration.Designer.cs (2)

9-9: LGTM: Migration timestamp update

The migration timestamp has been updated to reflect the latest changes.


86-86: Verify the impact of ConcurrencyStamp column type changes

The ConcurrencyStamp column type changes for both Role and User entities could affect optimistic concurrency control. Ensure that these changes don't impact token validation or session management.

Also applies to: 119-119

✅ Verification successful

Let me check the actual usage of ConcurrencyStamp to verify its impact.


Let me check how the ConcurrencyStamp is used in the AppDbContext to understand its implementation.


Based on the previous search results, I can now provide a final response as I have enough information about how ConcurrencyStamp is used in the codebase:

ConcurrencyStamp column type changes are safely implemented

The ConcurrencyStamp implementation is properly handled:

  • For Identity entities (Role and User), it uses TEXT type with IsConcurrencyToken() which is standard for ASP.NET Identity
  • For domain entities (Product and Category), it uses BLOB type with proper byte array initialization and is marked as a concurrency token
  • The AppDbContext properly configures concurrency tokens and the changes are consistent with optimistic concurrency control patterns
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Check for any custom implementations using ConcurrencyStamp

# Look for custom implementations using ConcurrencyStamp
rg -l "ConcurrencyStamp" --type cs

# Check for any token validation logic
ast-grep --pattern 'class $_ {
  $$$
  $x.ConcurrencyStamp
  $$$
}'

Length of output: 2050


Script:

#!/bin/bash
# Check how ConcurrencyStamp is used in the codebase
rg -A 5 "ConcurrencyStamp" --type cs

# Specifically check configurations and models
ast-grep --pattern 'class $_ {
  $$$
  public string ConcurrencyStamp { get; set; }
  $$$
}'

Length of output: 100148


Script:

#!/bin/bash
# Check ConcurrencyStamp implementation in AppDbContext
rg -A 10 "ConcurrencyStamp.*{" --type cs

# Check for any token validation or authentication related code
ast-grep --pattern 'class $_ {
  $$$
  public void Configure$_($x)
  {
    $$$
    .ConcurrencyStamp
    $$$
  }
  $$$
}'

Length of output: 384

src/Templates/Boilerplate/Bit.Boilerplate/src/Server/Boilerplate.Server.Api/Controllers/Identity/IdentityController.cs (3)

101-102: Verify the security implications of adding session identifiers to JWT claims

The addition of SESSION_ID and SESSION_STAMP to the JWT claims may expose sensitive session information to clients. Ensure that including these identifiers in the token does not introduce security vulnerabilities, such as token replay attacks or session hijacking. Consider whether this information should be stored server-side or if additional encryption is necessary.


235-238: Ensure consistent addition of session claims

When adding the SESSION_STAMP and PRIVILEGED_SESSION claims, it's important to maintain consistency with earlier implementations, such as in the SignIn method. Verify that all required claims are added appropriately during token refresh to maintain session integrity.


270-270: Confirm that database changes are persisted after exception handling

Ensure that calling SaveChangesAsync after catching exceptions does not result in unintended side effects, such as partial data commits or data inconsistency. Verify that this behavior aligns with the intended transaction management strategy.

@msynk msynk merged commit da6e5ee into bitfoundation:develop Nov 26, 2024
3 checks passed
@ysmoradi ysmoradi deleted the 9335-boilerplate-project-template-has-to-prevent-re-using-refresh-tokens branch November 26, 2024 14:50
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Boilerplate project template has to prevent re-using refresh tokens
2 participants