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

feat(websocket): Add jwt support to ws connection #474

Open
wants to merge 8 commits into
base: main
Choose a base branch
from

Conversation

kasugamirai
Copy link
Contributor

@kasugamirai kasugamirai commented Sep 5, 2024

Overview

What I've done

What I haven't done

How I tested

Screenshot

Which point I want you to review particularly

Memo

Summary by CodeRabbit

  • New Features

    • Added a new API endpoint for token validation at /validate-token, allowing clients to validate tokens directly.
    • Introduced a dedicated function to check user authentication status, responding with a JSON object.
    • Updated the project to ignore IDE-specific configuration files by adding the .idea directory to .gitignore.
    • Enhanced the Axum web server with authentication middleware and dynamic configuration loading.
    • Implemented a JWT verification mechanism and an AuthServiceClient for communication with an authentication service.
  • Bug Fixes

    • Improved error handling with additional logging for server binding and address retrieval failures.
  • Documentation

    • Enhanced comments and structure in the authentication module for better clarity and maintainability.

@kasugamirai kasugamirai requested a review from a team as a code owner September 5, 2024 18:16
Copy link
Contributor

coderabbitai bot commented Sep 5, 2024

Walkthrough

The changes involve updating the .gitignore file to exclude the .idea directory, adding a new API endpoint for token validation in the Echo framework, and introducing a new function for handling token validation responses. Additionally, modifications to the Axum web server enhance authentication handling and configuration management. New dependencies are added to Rust workspace files, and a structured approach to JWT verification and error handling is established. These updates collectively improve the functionality and organization of the codebase.

Changes

File Path Change Summary
.gitignore Added .idea to ignore IDE-specific configuration files.
api/internal/app/app.go Added a new API endpoint /validate-token for token validation.
api/internal/app/public.go Introduced ValidateToken function to respond with authentication status.
websocket/Cargo.toml Added multiple dependencies for enhanced functionality, including jsonwebtoken and reqwest.
websocket/crates/common/Cargo.toml Created a new Cargo.toml for the "common" package with dotenv as a dependency.
websocket/crates/common/src/config.rs Introduced Config struct for managing server configuration with environment variable support.
websocket/crates/common/src/lib.rs Added a new config module for configuration management.
websocket/crates/infra/Cargo.toml Added local dependencies for services and common, along with several workspace dependencies.
websocket/crates/infra/src/auth/error.rs Defined JwtError enum for JWT-related error handling with HTTP response integration.
websocket/crates/infra/src/auth/jwt.rs Implemented JwtValidator struct for JWT verification with caching and testing capabilities.
websocket/crates/infra/src/auth/middleware.rs Developed authentication middleware for Axum, verifying JWTs from requests.
websocket/crates/services/Cargo.toml Created a new Cargo.toml for the services package with essential dependencies.
websocket/crates/services/src/auth.rs Introduced AuthServiceClient struct for HTTP communication with an authentication service.
websocket/crates/services/src/lib.rs Added auth module for authentication functionalities, exposing AuthServiceClient.
websocket/crates/infra/src/main.rs Enhanced Axum server with authentication middleware, dynamic configuration loading, and JWT validation.

Possibly related PRs

  • feat(websocket): implement socket #318: This PR introduces WebSocket functionality, which is relevant to the main PR's changes that enhance API capabilities, including token validation, potentially used in conjunction with WebSocket communication.
  • ci: add websocket support and refactor #504: This PR adds WebSocket support and refactors the codebase, aligning with the main PR's focus on enhancing API functionality, including the new token validation endpoint that could be utilized in WebSocket interactions.

Suggested labels

worker, cicd

Suggested reviewers

  • pyshx

Poem

🐇
In the meadow, changes bloom,
New paths for tokens chase away gloom.
With validation now in sight,
Our code hops with pure delight!
A cleaner space, a joyful band,
Together we thrive, paw in hand!
🌼


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.

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

netlify bot commented Sep 5, 2024

Deploy Preview for reearth-flow ready!

Name Link
🔨 Latest commit 126f2a0
🔍 Latest deploy log https://app.netlify.com/sites/reearth-flow/deploys/66f2762a0b99730008fd1481
😎 Deploy Preview https://deploy-preview-474--reearth-flow.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.

To edit notification comments on pull requests, go to your Netlify site configuration.

Copy link
Contributor

@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: 3

Review details

Configuration used: .coderabbit.yaml
Review profile: CHILL

Commits

Files that changed from the base of the PR and between 154df00 and 35eab96.

Files ignored due to path filters (1)
  • websocket/Cargo.lock is excluded by !**/*.lock, !**/*.lock
Files selected for processing (9)
  • websocket/Cargo.toml (2 hunks)
  • websocket/crates/domain/src/project.rs (2 hunks)
  • websocket/crates/domain/src/utils.rs (1 hunks)
  • websocket/crates/infra/Cargo.toml (1 hunks)
  • websocket/crates/infra/src/auth/error.rs (1 hunks)
  • websocket/crates/infra/src/auth/jwt.rs (1 hunks)
  • websocket/crates/infra/src/auth/mod.rs (1 hunks)
  • websocket/crates/infra/src/auth/types.rs (1 hunks)
  • websocket/crates/infra/src/lib.rs (1 hunks)
Files skipped from review due to trivial changes (2)
  • websocket/Cargo.toml
  • websocket/crates/domain/src/utils.rs
Additional comments not posted (15)
websocket/crates/infra/src/lib.rs (1)

1-1: Approve the addition of the auth module.

The addition of the auth module aligns with the PR's objective to enhance security through JWT integration. Ensure that the implementation within this module adheres to security best practices and integrates seamlessly with the existing modules.

Run the following script to verify the integration of the auth module:

websocket/crates/infra/src/auth/mod.rs (1)

1-3: Module Declarations Approved

The module declarations for error, jwt, and types are correctly structured and follow Rust's standard module declaration format.

websocket/crates/infra/src/auth/types.rs (3)

3-14: Well-structured JWT Claims representation.

The Claims struct is well-defined and appropriately uses Option for fields that may not always be present, adhering to best practices for JWT claims.


16-25: Well-structured JSON Web Key representation.

The Jwk struct is well-defined and appropriately uses Option for fields that may not always be present. The naming of use_ as use_ is a clever workaround for Rust's reserved keywords, ensuring clarity and avoiding syntax issues.


27-30: Simple and effective JSON Web Keys set representation.

The Jwks struct is straightforward and effectively wraps a vector of Jwk, serving its purpose without unnecessary complexity.

websocket/crates/infra/src/auth/error.rs (3)

1-2: Imports are appropriate for the functionality.

The use of reqwest::StatusCode and thiserror::Error is appropriate for handling HTTP-related errors and structuring custom errors in Rust.


4-29: Well-structured error enumeration for JWT authentication.

The AuthError enum is well-defined with specific error cases for JWT authentication processes:

  • InvalidTokenHeader for invalid token headers.
  • NoKidInTokenHeader for missing kid in the token header.
  • NoMatchingJwk for no matching JSON Web Key found.
  • InvalidJwkKey for invalid JSON Web Key.
  • TokenValidationFailed for general token validation failures.
  • FailedToFetchJwks for failures in fetching JSON Web Key Sets.
  • HttpRequestFailed for HTTP request failures, appropriately using StatusCode.
  • Unexpected for any unexpected errors.

This structure not only makes the error handling more robust but also improves the readability and maintainability of the code.


31-31: Standard Rust practice for error handling.

The definition of the Result type alias using the AuthError enum is a standard Rust practice that simplifies error handling across the module. This approach is clean and reduces complexity in error propagation.

websocket/crates/domain/src/project.rs (2)

53-53: Refactor: Improve variable naming for clarity.

The renaming of _latest_snapshot_state to latest_snapshot_state improves code readability by removing the underscore prefix, which typically indicates a private or unused variable in many programming languages. This change suggests that the variable is indeed used and should be clearly identified as such.


113-113: Verify: Check the usage of merged_state in snapshot creation.

The assignment of the result from self.merge_updates().await? to merged_state suggests that this merged state is important for the snapshot creation process. It's crucial to verify how this variable is used subsequently in the function or if it affects the snapshot's state, as this could have significant implications for the functionality.

Run the following script to verify the usage of merged_state:

Verification successful

No impact of merged_state on snapshot creation.

The merged_state variable is assigned the result of self.merge_updates().await? but is not used within the create_snapshot_internal function. This indicates that it currently has no impact on the snapshot creation process. It might be intended for future use or other purposes.

  • Location: websocket/crates/domain/src/project.rs, function create_snapshot_internal.
Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Verify the usage of `merged_state` in the snapshot creation process.

# Test: Search for the usage of `merged_state` in the function. Expect: Usage that affects the snapshot's state.
rg --type rust -A 5 $'merged_state'

Length of output: 2978


Script:

#!/bin/bash
# Description: Search for the complete definition of the `create_snapshot_internal` function to verify the usage of `merged_state`.

# Test: Extract the complete function definition to check for any usage of `merged_state`.
ast-grep --lang rust --pattern $'fn create_snapshot_internal($$$) {
  $$$
}' --debug

Length of output: 303


Script:

#!/bin/bash
# Description: Search for the complete definition of the `create_snapshot_internal` function to verify the usage of `merged_state`.

# Test: Extract the complete function definition to check for any usage of `merged_state`.
ast-grep --lang rust --pattern $'fn create_snapshot_internal($$$) {
  $$$
}'

Length of output: 77


Script:

#!/bin/bash
# Description: Search for the definition of the `create_snapshot_internal` function using `rg`.

# Test: Locate the function definition to verify the usage of `merged_state`.
rg --type rust 'fn create_snapshot_internal'

Length of output: 124


Script:

#!/bin/bash
# Description: Extract the full function body of `create_snapshot_internal` to verify the usage of `merged_state`.

# Test: Extract lines around the function definition to capture its full body.
rg --type rust -A 50 'async fn create_snapshot_internal' websocket/crates/domain/src/project.rs

Length of output: 1646

websocket/crates/infra/src/auth/jwt.rs (5)

1-7: Review of Imports and Basic Setup

The imports and basic setup using Arc, RwLock, and reqwest::Client are appropriate for the asynchronous and network-bound nature of JWT operations. The use of Arc and RwLock suggests that the JWT keys might be shared and modified across multiple tasks, which is a common pattern in asynchronous Rust applications to handle shared state safely.


9-16: JWTProvider Structure Review

The JWTProvider struct is well-defined with fields necessary for JWT operations such as issuer (iss), JWKS URI (jwks_uri), audience (aud), algorithm (alg), and token time-to-live (ttl). This setup is typical for JWT providers and covers all the basic requirements for token validation.


18-27: Constructor Method for JWTProvider

The constructor method new is straightforward and correctly initializes the JWTProvider with the provided parameters. This method enhances the maintainability of the code by encapsulating the creation logic within the struct itself.


51-80: JWT Validation Method Review

The validate_jwt method is comprehensive, covering all critical steps in JWT validation, including decoding the header, extracting the key ID, fetching the corresponding JWK, and validating the token against expected claims and issuer. The method uses asynchronous locks appropriately and handles potential errors at each step, which is crucial for security-sensitive operations.


83-177: Unit Tests for JWT Validation

The unit tests provided are robust, covering the generation of a JWT, mocking the JWKS endpoint, and validating the token. The use of MockServer from the wiremock crate is appropriate for simulating the JWKS endpoint. The tests check various aspects of the JWT, such as the issuer, audience, and custom claims, which is essential for ensuring the JWT implementation works as expected.

pub mod error;
pub mod jwt;
pub mod types;
//todo: add auth module to ws connection
Copy link
Contributor

Choose a reason for hiding this comment

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

Reminder: Integrate Auth Module with WebSocket Connection

The TODO comment indicates that the auth module needs to be integrated with the WebSocket connection. It's crucial to track this task in your project management tool to ensure it doesn't get overlooked.

Would you like me to help by creating a task in your project management tool or by providing a code snippet for this integration?

Comment on lines 33 to 42
thiserror.workspace = true
reqwest.workspace = true
jsonwebtoken.workspace = true
wiremock.workspace = true
rsa.workspace = true
rand.workspace = true
base64.workspace = true
Copy link
Contributor

Choose a reason for hiding this comment

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

Review of new dependencies in Cargo.toml

The addition of new dependencies is crucial for the JWT integration in WebSocket connections. Here's a breakdown of each dependency and its potential use:

  • thiserror (line 33): Typically used for custom error types in Rust. This is essential for robust error handling in the new authentication features.
  • reqwest (line 34): A popular HTTP client for Rust. This might be used for external API interactions, possibly related to authentication processes.
  • jsonwebtoken (line 35): Directly related to handling JWTs. This is central to the PR's goal of integrating JWT into WebSocket connections.
  • wiremock (line 36): Used for mocking HTTP requests in tests. This suggests that testing the new features involves external HTTP interactions.
  • rsa (line 37): A library for RSA encryption, likely used for cryptographic operations in JWT processing.
  • rand (line 38): Utilized for generating random numbers, possibly for cryptographic purposes in token generation or processing.
  • base64 (line 39): Often used in encoding and decoding JWTs which are base64 URL encoded.

Concerns:

  • The use of .workspace = true for each dependency is unusual and likely incorrect. This syntax is not standard in Cargo.toml files and may be an error. Typically, dependencies are listed with versions, not with .workspace = true.

Recommendation:

  • Verify the intended use of .workspace = true and correct it to specify actual version numbers or paths as needed. This is crucial for the correct functioning of the dependency management in Cargo.

Please replace .workspace = true with appropriate version numbers or paths for each dependency to ensure proper dependency resolution and project build.

Comment on lines 28 to 81
async fn fetch_jwks(&self) -> Result<HashMap<String, Jwk>> {
let response = Client::new()
.get(&self.jwks_uri)
.send()
.await
.map_err(|e| AuthError::FailedToFetchJwks(e.to_string()))?;

if !response.status().is_success() {
return Err(AuthError::HttpRequestFailed(response.status()));
}

let jwks: Jwks = response
.json()
.await
.map_err(|e| AuthError::FailedToFetchJwks(e.to_string()))?;

Ok(jwks
.keys
.into_iter()
.map(|key| (key.kid.clone(), key))
.collect())
}
Copy link
Contributor

Choose a reason for hiding this comment

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

Asynchronous JWKS Fetching Method

The method fetch_jwks is responsible for fetching the JSON Web Key Set (JWKS) from a specified URI. It handles HTTP errors and JSON parsing errors effectively by converting them into AuthError. However, the use of Client::new() on each call could be optimized by reusing a client instance across calls to reduce overhead.

Consider reusing a reqwest::Client instance across multiple calls to improve performance. Here's a suggested change:

- let response = Client::new()
+ let client = Client::new(); // This should ideally be stored in JWTProvider and reused
+ let response = client

Committable suggestion was skipped due to low confidence.

Copy link
Contributor

@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: 0

Review details

Configuration used: .coderabbit.yaml
Review profile: CHILL

Commits

Files that changed from the base of the PR and between 35eab96 and 6d1d3df.

Files ignored due to path filters (1)
  • websocket/Cargo.lock is excluded by !**/*.lock, !**/*.lock
Files selected for processing (9)
  • websocket/Cargo.toml (2 hunks)
  • websocket/crates/domain/src/project.rs (2 hunks)
  • websocket/crates/domain/src/utils.rs (1 hunks)
  • websocket/crates/infra/Cargo.toml (1 hunks)
  • websocket/crates/infra/src/auth/error.rs (1 hunks)
  • websocket/crates/infra/src/auth/jwt.rs (1 hunks)
  • websocket/crates/infra/src/auth/mod.rs (1 hunks)
  • websocket/crates/infra/src/auth/types.rs (1 hunks)
  • websocket/crates/infra/src/lib.rs (1 hunks)
Files skipped from review due to trivial changes (3)
  • websocket/Cargo.toml
  • websocket/crates/domain/src/utils.rs
  • websocket/crates/infra/Cargo.toml
Files skipped from review as they are similar to previous changes (4)
  • websocket/crates/domain/src/project.rs
  • websocket/crates/infra/src/auth/error.rs
  • websocket/crates/infra/src/auth/jwt.rs
  • websocket/crates/infra/src/auth/types.rs
Additional comments not posted (3)
websocket/crates/infra/src/lib.rs (1)

1-1: Approved: Addition of the auth module.

The declaration of the auth module is correct and enhances the application's architecture by potentially improving security protocols.

websocket/crates/infra/src/auth/mod.rs (2)

1-3: Approved: Module declarations for authentication functionalities.

The structure with separate modules for error, jwt, and types is well-organized and suitable for handling different aspects of authentication.


4-4: Reminder: Integrate Auth Module with WebSocket Connection

The TODO comment indicates that the auth module needs to be integrated with the WebSocket connection. It's crucial to track this task in your project management tool to ensure it doesn't get overlooked.

Would you like me to help by creating a task in your project management tool or by providing a code snippet for this integration?

@kasugamirai kasugamirai force-pushed the feat/websocket-auth branch 2 times, most recently from 6074b01 to 731d5b5 Compare September 6, 2024 07:01
Copy link
Contributor

@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: 0

Review details

Configuration used: .coderabbit.yaml
Review profile: CHILL

Commits

Files that changed from the base of the PR and between 6d1d3df and 731d5b5.

Files ignored due to path filters (1)
  • websocket/Cargo.lock is excluded by !**/*.lock, !**/*.lock
Files selected for processing (9)
  • websocket/Cargo.toml (2 hunks)
  • websocket/crates/domain/src/project.rs (2 hunks)
  • websocket/crates/domain/src/utils.rs (1 hunks)
  • websocket/crates/infra/Cargo.toml (1 hunks)
  • websocket/crates/infra/src/auth/error.rs (1 hunks)
  • websocket/crates/infra/src/auth/jwt.rs (1 hunks)
  • websocket/crates/infra/src/auth/mod.rs (1 hunks)
  • websocket/crates/infra/src/auth/types.rs (1 hunks)
  • websocket/crates/infra/src/lib.rs (1 hunks)
Files skipped from review due to trivial changes (4)
  • websocket/Cargo.toml
  • websocket/crates/domain/src/project.rs
  • websocket/crates/domain/src/utils.rs
  • websocket/crates/infra/Cargo.toml
Files skipped from review as they are similar to previous changes (4)
  • websocket/crates/infra/src/auth/error.rs
  • websocket/crates/infra/src/auth/jwt.rs
  • websocket/crates/infra/src/auth/types.rs
  • websocket/crates/infra/src/lib.rs
Additional comments not posted (1)
websocket/crates/infra/src/auth/mod.rs (1)

4-4: Skip: Existing comment still valid.

The previous comment on this TODO is still applicable and addresses the necessary action.

Copy link
Contributor

@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: 1

Review details

Configuration used: .coderabbit.yaml
Review profile: CHILL

Commits

Files that changed from the base of the PR and between 731d5b5 and b926d40.

Files ignored due to path filters (1)
  • websocket/Cargo.lock is excluded by !**/*.lock, !**/*.lock
Files selected for processing (10)
  • websocket/Cargo.toml (2 hunks)
  • websocket/crates/domain/src/project.rs (2 hunks)
  • websocket/crates/domain/src/utils.rs (1 hunks)
  • websocket/crates/infra/Cargo.toml (1 hunks)
  • websocket/crates/infra/src/auth/error.rs (1 hunks)
  • websocket/crates/infra/src/auth/jwt.rs (1 hunks)
  • websocket/crates/infra/src/auth/jwt_validator.rs (1 hunks)
  • websocket/crates/infra/src/auth/mod.rs (1 hunks)
  • websocket/crates/infra/src/auth/types.rs (1 hunks)
  • websocket/crates/infra/src/lib.rs (1 hunks)
Files skipped from review due to trivial changes (4)
  • websocket/Cargo.toml
  • websocket/crates/domain/src/project.rs
  • websocket/crates/domain/src/utils.rs
  • websocket/crates/infra/Cargo.toml
Files skipped from review as they are similar to previous changes (4)
  • websocket/crates/infra/src/auth/error.rs
  • websocket/crates/infra/src/auth/jwt.rs
  • websocket/crates/infra/src/auth/types.rs
  • websocket/crates/infra/src/lib.rs
Additional comments not posted (3)
websocket/crates/infra/src/auth/mod.rs (2)

1-4: Module Declarations Approved

The structure and organization of the modules are appropriate and follow Rust's modular code organization best practices.


5-5: Skip: Duplicate Comment

This TODO comment has been previously addressed and is still valid.

websocket/crates/infra/src/auth/jwt_validator.rs (1)

15-29: Constructor Implementation Approved

The constructor is well-implemented, using appropriate Rust practices for handling concurrency with Arc<RwLock<>>. This setup ensures thread safety for the JWKs, which might be accessed or updated concurrently.

Comment on lines 31 to 62
// Validate the JWT token
pub async fn validate_token(&self, token: &str) -> Result<TokenData<Claims>> {
let header =
decode_header(token).map_err(|e| AuthError::InvalidTokenHeader(e.to_string()))?;
let kid = header.kid.ok_or(AuthError::NoKidInTokenHeader)?;

// Get JWK from the cache
let jwks = self.jwks.read().await;
let jwk = jwks
.get(&kid)
.ok_or_else(|| AuthError::NoMatchingJwk(kid.clone()))?;

// Create the decoding key
let decoding_key = DecodingKey::from_rsa_components(&jwk.n, &jwk.e)
.map_err(|e| AuthError::InvalidJwkKey(e.to_string()))?;

// Create validation object
let mut validation = Validation::new(self.alg);
validation.set_audience(&self.aud);
validation.set_issuer(&[&self.iss]);

// Validate the token
decode::<Claims>(token, &decoding_key, &validation)
.map_err(|err| AuthError::TokenValidationFailed(err.to_string()))
}
Copy link
Contributor

Choose a reason for hiding this comment

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

Token Validation Method Approved with Suggestion

The method for validating JWT tokens is robust, covering various aspects of JWT validation comprehensively. The asynchronous handling of JWK retrieval and the detailed error handling enhance the security and reliability of the method.

Suggestion:
Consider adding more detailed logging at key steps in the token validation process, especially before raising errors, to aid in debugging and monitoring the authentication flow.

Copy link
Contributor

@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: 0

Review details

Configuration used: .coderabbit.yaml
Review profile: CHILL

Commits

Files that changed from the base of the PR and between b926d40 and df1d031.

Files ignored due to path filters (1)
  • websocket/Cargo.lock is excluded by !**/*.lock, !**/*.lock
Files selected for processing (10)
  • websocket/Cargo.toml (2 hunks)
  • websocket/crates/domain/src/project.rs (2 hunks)
  • websocket/crates/domain/src/utils.rs (1 hunks)
  • websocket/crates/infra/Cargo.toml (1 hunks)
  • websocket/crates/infra/src/auth/error.rs (1 hunks)
  • websocket/crates/infra/src/auth/jwt.rs (1 hunks)
  • websocket/crates/infra/src/auth/jwt_validator.rs (1 hunks)
  • websocket/crates/infra/src/auth/mod.rs (1 hunks)
  • websocket/crates/infra/src/auth/types.rs (1 hunks)
  • websocket/crates/infra/src/lib.rs (1 hunks)
Files skipped from review due to trivial changes (5)
  • websocket/Cargo.toml
  • websocket/crates/domain/src/project.rs
  • websocket/crates/domain/src/utils.rs
  • websocket/crates/infra/Cargo.toml
  • websocket/crates/infra/src/auth/mod.rs
Files skipped from review as they are similar to previous changes (5)
  • websocket/crates/infra/src/auth/error.rs
  • websocket/crates/infra/src/auth/jwt.rs
  • websocket/crates/infra/src/auth/jwt_validator.rs
  • websocket/crates/infra/src/auth/types.rs
  • websocket/crates/infra/src/lib.rs

Copy link
Contributor

@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: 0

Outside diff range, codebase verification and nitpick comments (2)
websocket/crates/infra/src/middleware/error.rs (1)

4-29: Approved: Comprehensive error handling for JWT authentication.

The error definitions using thiserror are well-implemented, covering a broad spectrum of JWT-related issues. Each error type is clearly defined with specific messages, enhancing the robustness of the authentication module.

Suggestion: Add documentation comments.

Consider adding documentation comments to each error type to provide further context and improve maintainability.

websocket/crates/infra/src/middleware/types.rs (1)

3-35: Approved: Well-defined data structures for JWT processing.

The data structures for handling JWT claims and keys are appropriately defined, utilizing serde for serialization and deserialization. This setup is essential for effective JWT processing and aligns with standard practices.

Suggestion: Add documentation comments.

Consider adding documentation comments to each structure to provide further context and improve maintainability.

Review details

Configuration used: .coderabbit.yaml
Review profile: CHILL

Commits

Files that changed from the base of the PR and between df1d031 and ec20535.

Files ignored due to path filters (1)
  • websocket/Cargo.lock is excluded by !**/*.lock, !**/*.lock
Files selected for processing (10)
  • websocket/Cargo.toml (2 hunks)
  • websocket/crates/domain/src/project.rs (2 hunks)
  • websocket/crates/domain/src/utils.rs (1 hunks)
  • websocket/crates/infra/Cargo.toml (1 hunks)
  • websocket/crates/infra/src/lib.rs (1 hunks)
  • websocket/crates/infra/src/middleware/error.rs (1 hunks)
  • websocket/crates/infra/src/middleware/jwt.rs (1 hunks)
  • websocket/crates/infra/src/middleware/jwt_validator.rs (1 hunks)
  • websocket/crates/infra/src/middleware/mod.rs (1 hunks)
  • websocket/crates/infra/src/middleware/types.rs (1 hunks)
Files skipped from review due to trivial changes (3)
  • websocket/crates/domain/src/project.rs
  • websocket/crates/domain/src/utils.rs
  • websocket/crates/infra/Cargo.toml
Files skipped from review as they are similar to previous changes (1)
  • websocket/Cargo.toml
Additional comments not posted (6)
websocket/crates/infra/src/lib.rs (1)

1-1: Approved: New module declaration for middleware.

The addition of the middleware module is a straightforward enhancement to the application's architecture, focusing on expanding middleware functionalities. This change is approved as it does not interfere with the existing modules.

websocket/crates/infra/src/middleware/jwt_validator.rs (2)

13-33: Review: JWTValidator struct and constructor

The JWTValidator struct is well-defined with appropriate fields for JWT validation. The constructor is correctly implemented to initialize these fields. This setup ensures that all necessary parameters are encapsulated within the validator, promoting good encapsulation practices.


36-62: Review: validate_token method

The validate_token method is comprehensive and robust. It includes:

  • Decoding the JWT header and handling errors.
  • Retrieving the JWK from a cache based on the kid from the token header.
  • Constructing a decoding key from the JWK.
  • Setting up validation criteria based on the issuer and audience.
  • Finally, decoding the token with the constructed key and validation settings.

Each step includes error handling that transforms various errors into an AuthError, which is a good practice for maintaining consistency in how errors are reported and handled within the application.

websocket/crates/infra/src/middleware/mod.rs (2)

24-48: Review: jwt_auth_middleware function

The jwt_auth_middleware function is well-structured and performs several critical operations:

  • It extracts the JWT from the request.
  • Fetches JWKS using the JWTProvider.
  • Validates the token.
  • Constructs an AuthenticatedInfo object and inserts it into the request.

This function effectively integrates JWT authentication into the request handling pipeline of the application. Error handling using HTTP status codes is appropriate and ensures that the middleware responds correctly to different authentication errors.


50-57: Review: extract_token function

The extract_token function is a utility that simplifies the process of extracting the bearer token from the request headers. It is concise and correctly handles the extraction by checking the Authorization header and stripping the "Bearer " prefix. This function aids in maintaining the cleanliness and modularity of the code by separating concerns.

websocket/crates/infra/src/middleware/jwt.rs (1)

11-38: Review: JWTProvider struct and its methods

The JWTProvider struct is well-designed to handle JWT operations with fields for issuer, audience, algorithm, JWKS URI, and a cache for JWKS. The methods new, fetch_jwks, and get_validator are well-implemented:

  • new initializes the provider with the necessary configuration.
  • fetch_jwks handles the fetching and caching of JWKS, including error handling and cache expiration checks.
  • get_validator creates a JWTValidator instance using the cached keys.

This setup ensures that JWT operations are centralized and managed efficiently, promoting good software architecture practices.

Copy link
Contributor

@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: 0

Review details

Configuration used: .coderabbit.yaml
Review profile: CHILL

Commits

Files that changed from the base of the PR and between ec20535 and 410cd5c.

Files ignored due to path filters (1)
  • websocket/Cargo.lock is excluded by !**/*.lock, !**/*.lock
Files selected for processing (10)
  • websocket/Cargo.toml (2 hunks)
  • websocket/crates/domain/src/project.rs (2 hunks)
  • websocket/crates/domain/src/utils.rs (1 hunks)
  • websocket/crates/infra/Cargo.toml (1 hunks)
  • websocket/crates/infra/src/lib.rs (1 hunks)
  • websocket/crates/infra/src/middleware/error.rs (1 hunks)
  • websocket/crates/infra/src/middleware/jwt.rs (1 hunks)
  • websocket/crates/infra/src/middleware/jwt_validator.rs (1 hunks)
  • websocket/crates/infra/src/middleware/mod.rs (1 hunks)
  • websocket/crates/infra/src/middleware/types.rs (1 hunks)
Files skipped from review due to trivial changes (5)
  • websocket/Cargo.toml
  • websocket/crates/domain/src/project.rs
  • websocket/crates/domain/src/utils.rs
  • websocket/crates/infra/Cargo.toml
  • websocket/crates/infra/src/middleware/error.rs
Files skipped from review as they are similar to previous changes (5)
  • websocket/crates/infra/src/lib.rs
  • websocket/crates/infra/src/middleware/jwt.rs
  • websocket/crates/infra/src/middleware/jwt_validator.rs
  • websocket/crates/infra/src/middleware/mod.rs
  • websocket/crates/infra/src/middleware/types.rs

Copy link
Contributor

@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: 1

Outside diff range, codebase verification and nitpick comments (3)
websocket/crates/infra/src/mw/services.rs (1)

6-27: Nicely done, just a minor suggestion regarding error handling.

The forward_request_to_auth_service function is well-structured and follows a clear logic for forwarding requests to the auth service.

One small improvement suggestion:
Instead of ignoring the actual error and always returning MwError::InternalServer at line 24, consider propagating the actual error. This will make debugging easier if something goes wrong.

You can change it to something like:

.map_err(MwError::RequestForwardFailed)?;

This way, the actual error will be wrapped in MwError::RequestForwardFailed and can be handled appropriately.

Other than that, the function looks good to me!

websocket/crates/infra/src/mw/mod.rs (2)

18-53: Improve error handling and logging.

The function can be improved by adding more detailed error handling and logging.

Apply this diff to improve error handling and logging:

 pub async fn auth_middleware(
     request: Request<Body>,
     next: Next,
 ) -> Result<Response<Body>, MwError> {
     let method = request.method().clone();
     let headers = request.headers().clone();
     let body_bytes = axum::body::to_bytes(request.into_body(), usize::MAX)
         .await
-        .map_err(|_| MwError::InternalServer)?;
+        .map_err(|e| {
+            tracing::error!("Failed to read request body: {}", e);
+            MwError::InternalServer
+        })?;
     let body_string = String::from_utf8_lossy(&body_bytes).to_string();
     let mut request = Request::new(Body::from(body_bytes));
     *request.method_mut() = method.clone();
     *request.headers_mut() = headers.clone();
 
     let auth_response =
         forward_request_to_auth_service(&AUTH_SERVICE_URL, method, &headers, body_string).await?;
 
     if auth_response.status().is_success() {
         Ok(next.run(request).await)
     } else {
+        tracing::warn!("Authentication failed with status code: {}", auth_response.status());
         let status = auth_response.status();
         let headers = auth_response.headers().clone();
         let body = auth_response
             .bytes()
             .await
-            .map_err(|_| MwError::InternalServer)?;
+            .map_err(|e| {
+                tracing::error!("Failed to read auth service response body: {}", e);
+                MwError::InternalServer
+            })?;
 
         let mut response_builder = Response::builder().status(status);
         for (name, value) in headers.iter() {
             response_builder = response_builder.header(name, value);
         }
         Ok(response_builder
             .body(Body::from(body))
-            .map_err(|_| MwError::InternalServer)?)
+            .map_err(|e| {
+                tracing::error!("Failed to build response: {}", e);
+                MwError::InternalServer
+            })?)
     }
 }

55-141: Improve tests by adding more test cases and using a more realistic mock server.

The tests can be improved by adding more test cases and using a more realistic mock server.

Consider the following suggestions:

  • Add test cases for different HTTP methods and headers.
  • Add test cases for different auth service response status codes and bodies.
  • Use a more realistic mock server that simulates the actual auth service API.
  • Use a separate mock server for each test case to avoid interference between tests.
Review details

Configuration used: .coderabbit.yaml
Review profile: CHILL

Commits

Files that changed from the base of the PR and between 410cd5c and 251d6e1.

Files ignored due to path filters (1)
  • websocket/Cargo.lock is excluded by !**/*.lock, !**/*.lock
Files selected for processing (17)
  • .gitignore (1 hunks)
  • api/internal/app/app.go (1 hunks)
  • api/internal/app/public.go (1 hunks)
  • websocket/Cargo.toml (2 hunks)
  • websocket/crates/domain/src/project.rs (2 hunks)
  • websocket/crates/domain/src/utils.rs (1 hunks)
  • websocket/crates/infra/Cargo.toml (1 hunks)
  • websocket/crates/infra/src/lib.rs (1 hunks)
  • websocket/crates/infra/src/main.rs (2 hunks)
  • websocket/crates/infra/src/middleware/error.rs (1 hunks)
  • websocket/crates/infra/src/middleware/jwt.rs (1 hunks)
  • websocket/crates/infra/src/middleware/jwt_validator.rs (1 hunks)
  • websocket/crates/infra/src/middleware/mod.rs (1 hunks)
  • websocket/crates/infra/src/middleware/types.rs (1 hunks)
  • websocket/crates/infra/src/mw/error.rs (1 hunks)
  • websocket/crates/infra/src/mw/mod.rs (1 hunks)
  • websocket/crates/infra/src/mw/services.rs (1 hunks)
Files skipped from review due to trivial changes (5)
  • .gitignore
  • websocket/Cargo.toml
  • websocket/crates/domain/src/project.rs
  • websocket/crates/domain/src/utils.rs
  • websocket/crates/infra/src/middleware/types.rs
Files skipped from review as they are similar to previous changes (5)
  • websocket/crates/infra/src/lib.rs
  • websocket/crates/infra/src/middleware/error.rs
  • websocket/crates/infra/src/middleware/jwt.rs
  • websocket/crates/infra/src/middleware/jwt_validator.rs
  • websocket/crates/infra/src/middleware/mod.rs
Additional comments not posted (6)
websocket/crates/infra/src/mw/error.rs (2)

5-11: The custom error type MwError looks good!

  • It covers the necessary error cases with RequestForwardFailed and InternalServer variants.
  • Deriving Error and Debug traits is a good practice for error types.
  • The error messages are appropriate and descriptive.

Good job defining this custom error type!


13-26: The IntoResponse implementation for MwError is well-done!

  • It matches on the error variant and sets the appropriate HTTP status code and error message.
  • Returning a JSON response with the error message is a good practice for API error responses.
  • The implementation is straightforward and easy to understand.

Great job implementing the IntoResponse trait for MwError!

websocket/crates/infra/Cargo.toml (1)

40-42: Review of new dependencies in Cargo.toml

The addition of hyper, http-body-util, and once_cell dependencies seems relevant for the HTTP-related functionality in the project.

Here's a breakdown of each dependency and its potential use:

  • hyper: An HTTP library for Rust. This might be used for low-level HTTP interactions in the project.
  • http-body-util: Provides utilities for working with HTTP bodies. This could be helpful in handling request/response bodies.
  • once_cell: Provides types for single assignment cells, which are useful for global configuration or caches.

Recommendation:
As mentioned in the previous comments, the use of .workspace = true for these dependencies is likely incorrect. It's recommended to verify the intended use of .workspace = true and correct it to specify actual version numbers or paths as needed. This is crucial for the correct functioning of the dependency management in Cargo.

Please replace .workspace = true with appropriate version numbers or paths for each dependency to ensure proper dependency resolution and project build.

websocket/crates/infra/src/main.rs (2)

3-4: LGTM!

The code changes are approved.


25-32: LGTM, but verify the middleware application.

The changes are approved.

However, ensure that the commented out line applying the auth_middleware to the router is uncommented and thoroughly tested to confirm that it behaves as expected.

Run the following script to verify the middleware application:

api/internal/app/app.go (1)

94-94: LGTM!

The addition of the /validate-token endpoint for token validation aligns with the PR objective of integrating JWT for enhanced security. The endpoint is correctly added to the existing group of API routes without altering the behavior of the previously defined routes.

Comment on lines +106 to +112
func ValidateToken() echo.HandlerFunc {
return func(c echo.Context) error {
return c.JSON(http.StatusOK, map[string]interface{}{
"status": "authenticated",
})
}
}
Copy link
Contributor

Choose a reason for hiding this comment

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

Implement token validation logic.

The function can be improved by actually validating the token instead of always returning "authenticated".

Apply this diff to implement token validation logic:

 func ValidateToken() echo.HandlerFunc {
 	return func(c echo.Context) error {
+		// Get the token from the request header
+		token := c.Request().Header.Get("Authorization")
+		if token == "" {
+			return c.JSON(http.StatusUnauthorized, map[string]interface{}{
+				"status": "unauthenticated",
+			})
+		}
+
+		// Validate the token
+		claims, err := validateToken(token)
+		if err != nil {
+			return c.JSON(http.StatusUnauthorized, map[string]interface{}{
+				"status": "unauthenticated",
+			})
+		}
+
 		return c.JSON(http.StatusOK, map[string]interface{}{
-			"status": "authenticated",
+			"status":  "authenticated",
+			"user_id": claims.UserID,
 		})
 	}
 }

Committable suggestion was skipped due to low confidence.

@kasugamirai kasugamirai force-pushed the feat/websocket-auth branch 3 times, most recently from c8d54d2 to 313daac Compare September 12, 2024 17:58
Copy link
Contributor

@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: 0

Outside diff range and nitpick comments (1)
websocket/crates/services/src/auth.rs (1)

13-22: Consider making the timeout configurable.

The AuthServiceClient::new method looks good overall. It correctly handles the case where the provided URI string is invalid and sets a default timeout of 5 seconds.

However, consider making the timeout configurable by accepting it as an optional parameter with a default value. This would allow users of the AuthServiceClient to adjust the timeout based on their specific requirements.

Review details

Configuration used: .coderabbit.yaml
Review profile: CHILL

Commits

Files that changed from the base of the PR and between 3893ba9 and 313daac.

Files ignored due to path filters (1)
  • websocket/Cargo.lock is excluded by !**/*.lock, !**/*.lock
Files selected for processing (19)
  • .gitignore (1 hunks)
  • api/internal/app/app.go (1 hunks)
  • api/internal/app/public.go (1 hunks)
  • websocket/Cargo.toml (2 hunks)
  • websocket/crates/common/Cargo.toml (1 hunks)
  • websocket/crates/common/src/config.rs (1 hunks)
  • websocket/crates/common/src/lib.rs (1 hunks)
  • websocket/crates/domain/src/project.rs (2 hunks)
  • websocket/crates/domain/src/utils.rs (1 hunks)
  • websocket/crates/infra/Cargo.toml (2 hunks)
  • websocket/crates/infra/src/auth/error.rs (1 hunks)
  • websocket/crates/infra/src/auth/jwt.rs (1 hunks)
  • websocket/crates/infra/src/auth/middleware.rs (1 hunks)
  • websocket/crates/infra/src/auth/mod.rs (1 hunks)
  • websocket/crates/infra/src/lib.rs (1 hunks)
  • websocket/crates/infra/src/main.rs (3 hunks)
  • websocket/crates/services/Cargo.toml (1 hunks)
  • websocket/crates/services/src/auth.rs (1 hunks)
  • websocket/crates/services/src/lib.rs (1 hunks)
Files skipped from review due to trivial changes (2)
  • .gitignore
  • websocket/crates/domain/src/utils.rs
Files skipped from review as they are similar to previous changes (7)
  • api/internal/app/app.go
  • api/internal/app/public.go
  • websocket/Cargo.toml
  • websocket/crates/domain/src/project.rs
  • websocket/crates/infra/Cargo.toml
  • websocket/crates/infra/src/auth/mod.rs
  • websocket/crates/infra/src/lib.rs
Additional comments not posted (26)
websocket/crates/common/src/lib.rs (1)

1-2: LGTM!

The code follows Rust's module system conventions:

  • The mod config; statement declares a module named config.
  • The pub use config::Config; statement re-exports the Config struct from the config module, making it publicly accessible from this module.

The changes are minimal and look good to me.

websocket/crates/services/src/lib.rs (1)

1-2: LGTM!

The addition of the auth module and re-exporting the AuthServiceClient struct aligns with the PR objectives of integrating a JWT module for the WebSocket connection. This change enhances the authentication capabilities of the project and follows good practices of modularity and separation of concerns.

websocket/crates/common/Cargo.toml (2)

1-13: LGTM! The package configuration and workspace setup look good.

The package metadata and dependency inheritance from the workspace promote consistency and maintainability across the monorepo. The use of a workspace-level "dotenv" dependency is a good practice.


5-5: Verify the package exclusion from the workspace build.

The exclude.workspace = true setting indicates that this package is excluded from the workspace build. Please ensure this exclusion is intentional and aligns with the package's purpose and build requirements.

websocket/crates/services/Cargo.toml (1)

1-19: Effective use of workspace inheritance for package configuration.

The Cargo.toml file for the "services" package effectively utilizes workspace inheritance for package metadata and dependencies. This approach offers several benefits:

  1. Consistency: By inheriting common configuration from the workspace, it ensures consistency across multiple packages within the workspace.

  2. Reduced Duplication: Workspace inheritance eliminates the need to duplicate package metadata and dependency declarations in each package's Cargo.toml file, reducing redundancy and making the configuration more maintainable.

  3. Centralized Management: With workspace inheritance, changes to common configuration can be made in a single place (the workspace's Cargo.toml), propagating to all packages that inherit from it.

The chosen dependencies, such as tokio, axum, reqwest, http, thiserror, wiremock, and tower, are commonly used and well-maintained crates in the Rust ecosystem, indicating a solid foundation for the "services" package.

Overall, the configuration in this Cargo.toml file demonstrates a well-structured and organized approach to package management within a workspace.

websocket/crates/common/src/config.rs (1)

1-19: LGTM!

The code follows best practices for configuration management:

  • It uses the dotenv crate to load environment variables from a file.
  • It defines a Config struct to centralize configuration values.
  • The from_env method provides a convenient way to create a Config instance from environment variables.
  • It uses the Result type to handle potential errors during environment variable loading.
  • It provides default values for configuration fields, ensuring a fallback if the corresponding environment variables are not set.

The code is well-structured, readable, and maintainable. Great job!

websocket/crates/infra/src/auth/error.rs (3)

1-5: Imports look good!

The code segment correctly imports the necessary dependencies from axum, reqwest, and thiserror crates, which are required for defining the custom error type and implementing the IntoResponse trait.


6-19: The custom error type is well-defined!

The code segment defines a custom error type JwtError using the thiserror crate, covering various error scenarios related to JWT handling. The use of #[allow(dead_code)] attribute is acceptable for unused variants, and the #[from] attribute is correctly used for automatic error conversion.


20-55: The IntoResponse trait implementation is comprehensive and robust!

The code segment implements the IntoResponse trait for the JwtError type, handling all variants and constructing appropriate HTTP responses. The response construction is well-structured, with proper status codes and error messages. The error handling is robust, ensuring a fallback response is returned in case of critical errors during response construction.

websocket/crates/infra/src/main.rs (5)

3-4: LGTM!

The imports are necessary for the authentication middleware functionality and look good.


10-11: LGTM!

The imports are necessary for loading configuration and creating an auth client. They look good.


29-32: LGTM!

Loading configuration from environment variables and creating an auth client are good practices and necessary for the authentication middleware functionality. The code changes look good.


38-41: LGTM!

Adding an authentication middleware layer is a good practice for securing the application. The middleware is applied globally, which is appropriate. The code changes look good.


56-56: LGTM!

Binding the listener to the server address loaded from the configuration is a good practice for flexibility and avoiding hardcoded values. The code changes look good.

websocket/crates/infra/src/auth/jwt.rs (3)

5-8: LGTM!

The Jwt struct is well-defined with appropriate field types.


10-23: LGTM!

The impl block for Jwt is well-structured and the verify method correctly handles the verification process and error cases.


25-71: Great job with the tests!

The test module provides good coverage for the Jwt struct and verify method, correctly testing the success and failure paths using wiremock to mock the AuthServiceClient responses. The test assertions are also correct.

websocket/crates/services/src/auth.rs (6)

5-10: LGTM!

The AuthServiceClient struct is well-defined with appropriate fields and types.


24-34: LGTM!

The AuthServiceClient::forward_request method is implemented correctly. It sets the Authorization header with the provided token, uses the configured URI and timeout, and returns the response from the server or a reqwest::Error if the request fails.


43-48: LGTM!

The test_new_client test correctly verifies the construction of a new AuthServiceClient instance by checking that the URI and timeout are set correctly.


50-64: LGTM!

The test_authenticate test correctly verifies the successful forwarding of a request with a valid token by using a mock server to simulate the authentication service and checking that the response status is 200 OK.


66-80: LGTM!

The test_authenticate_unauthorized test correctly verifies the handling of a request with an invalid token by using a mock server to simulate the authentication service and checking that the response status is 401 Unauthorized.


82-97: LGTM!

The test_authenticate_timeout test correctly verifies the handling of a request that times out by using a mock server to simulate the authentication service with a delay longer than the configured timeout and checking that the request returns an error.

websocket/crates/infra/src/auth/middleware.rs (3)

11-20: LGTM!

The auth_middleware function is implemented correctly. It handles the following cases appropriately:

  • When the token is not found, it returns a JwtError with a StatusCode::UNAUTHORIZED.
  • When the token is valid, it passes the request to the next middleware.
  • When the token verification fails, it returns a JwtError.

22-28: LGTM!

The extract_token function is implemented correctly. It handles the following cases appropriately:

  • When the "Authorization" header is not present or does not start with "Bearer ", it returns None.
  • When the "Authorization" header is present and starts with "Bearer ", it returns the token as a String.

30-143: LGTM!

The unit tests and integration tests are implemented correctly.

The unit tests for the extract_token function cover all the possible cases:

  • When the "Authorization" header is present and starts with "Bearer ", it returns the token as a String.
  • When the "Authorization" header is not present, it returns None.
  • When the "Authorization" header is present but does not start with "Bearer ", it returns None.

The integration tests for the auth_middleware function cover the happy path and the error path:

  • When the token is valid, it returns a StatusCode::OK and the response body is "Protected".
  • When the token is invalid, it returns a StatusCode::UNAUTHORIZED.

The integration tests use a mock server to simulate the AuthServiceClient and test the auth_middleware function in isolation, which is a good practice.

Copy link
Contributor

@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: 1

Review details

Configuration used: .coderabbit.yaml
Review profile: CHILL

Commits

Files that changed from the base of the PR and between 313daac and 6b7d7fa.

Files ignored due to path filters (1)
  • websocket/Cargo.lock is excluded by !**/*.lock, !**/*.lock
Files selected for processing (20)
  • .gitignore (1 hunks)
  • api/internal/app/app.go (1 hunks)
  • api/internal/app/public.go (1 hunks)
  • websocket/Cargo.toml (2 hunks)
  • websocket/crates/common/Cargo.toml (1 hunks)
  • websocket/crates/common/src/config.rs (1 hunks)
  • websocket/crates/common/src/lib.rs (1 hunks)
  • websocket/crates/domain/src/project.rs (2 hunks)
  • websocket/crates/domain/src/utils.rs (1 hunks)
  • websocket/crates/infra/Cargo.toml (2 hunks)
  • websocket/crates/infra/src/auth/error.rs (1 hunks)
  • websocket/crates/infra/src/auth/jwt.rs (1 hunks)
  • websocket/crates/infra/src/auth/middleware.rs (1 hunks)
  • websocket/crates/infra/src/auth/mod.rs (1 hunks)
  • websocket/crates/infra/src/lib.rs (1 hunks)
  • websocket/crates/infra/src/main.rs (3 hunks)
  • websocket/crates/infra/src/socket/handler.rs (1 hunks)
  • websocket/crates/services/Cargo.toml (1 hunks)
  • websocket/crates/services/src/auth.rs (1 hunks)
  • websocket/crates/services/src/lib.rs (1 hunks)
Files skipped from review due to trivial changes (4)
  • .gitignore
  • websocket/crates/common/Cargo.toml
  • websocket/crates/domain/src/utils.rs
  • websocket/crates/services/Cargo.toml
Files skipped from review as they are similar to previous changes (13)
  • api/internal/app/app.go
  • api/internal/app/public.go
  • websocket/Cargo.toml
  • websocket/crates/common/src/config.rs
  • websocket/crates/common/src/lib.rs
  • websocket/crates/domain/src/project.rs
  • websocket/crates/infra/Cargo.toml
  • websocket/crates/infra/src/auth/error.rs
  • websocket/crates/infra/src/auth/middleware.rs
  • websocket/crates/infra/src/auth/mod.rs
  • websocket/crates/infra/src/lib.rs
  • websocket/crates/services/src/auth.rs
  • websocket/crates/services/src/lib.rs
Additional comments not posted (9)
websocket/crates/infra/src/main.rs (6)

3-4: LGTM!

The imports are correctly specified and necessary for the changes made in the file.


10-11: LGTM!

The imports are correctly specified and necessary for the changes made in the file.


29-32: LGTM!

  • Loading the configuration from environment variables is a good practice for managing the application configuration.
  • The expect calls are used to handle the errors that may occur while loading the configuration and creating the AuthServiceClient instance.
  • The error messages are descriptive and help in identifying the cause of the error.

38-41: LGTM!

  • The middleware layer is added to the router to handle the authentication of the requests.
  • The auth_middleware is called with the auth_client and the request to perform the authentication.
  • The auth_client is cloned to avoid moving it into the closure.

45-45: LGTM!

  • The state_err is passed to the handle_error function to handle the errors that may occur while processing the requests.
  • The state_err is cloned to avoid moving it into the closure.

56-56: LGTM!

Binding the listener to the server address loaded from the configuration is a good practice for managing the application configuration.

websocket/crates/infra/src/auth/jwt.rs (3)

5-8: LGTM!

The Jwt struct is well-defined with appropriate fields to store the token and the AuthServiceClient.


10-23: LGTM!

The impl block for Jwt is correctly implemented with a constructor and a verify method. The verify method sends a request to the auth service to verify the token and handles the response status code appropriately. It returns a Result with a boolean indicating the verification status or a JwtError.


25-71: LGTM!

The test module is correctly implemented with two test functions covering the success and failure cases of the verify method. The tests use wiremock effectively to mock the auth service responses and make appropriate assertions on the results of the verify method.

Comment on lines 68 to 70
//if token != "nyaan" {
// return;
//}
Copy link
Contributor

Choose a reason for hiding this comment

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

Security Risk: Commented out authentication check exposes the WebSocket server to unauthorized access.

Removing the authentication check allows any client to connect to the WebSocket server without proper authentication. This is a significant security vulnerability that needs to be addressed immediately.

Recommendations:

  1. Implement a robust authentication mechanism using JSON Web Tokens (JWT) instead of hardcoded token values.
  2. Validate the JWT on the server-side to ensure the client is authenticated and authorized to access the WebSocket server.
  3. Store and transmit the JWT securely to prevent unauthorized access.
  4. Consider implementing additional security measures such as rate limiting and IP restrictions to further protect the WebSocket server.

Copy link
Contributor

@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: 0

Outside diff range and nitpick comments (1)
websocket/crates/infra/src/socket/handler.rs (1)

77-98: The authentication process using AuthServiceClient is a significant improvement!

The new authentication mechanism using AuthServiceClient is a robust and secure approach compared to the previous hardcoded token check. The error handling for the authentication request is appropriate, logging errors and terminating the connection if the authentication fails.

Consider handling the case where the AuthServiceClient returns a non-success status code other than an error. In such cases, log an appropriate message and terminate the connection. For example:

        Ok(response) => {
            if response.status().is_success() {
                debug!("Authentication successful");
            } else {
                error!("Authentication failed: Status code {}", response.status());
+               socket.close().await;
                return;
            }
        }
Review details

Configuration used: .coderabbit.yaml
Review profile: CHILL

Commits

Files that changed from the base of the PR and between 6b7d7fa and 4f6d20b.

Files ignored due to path filters (1)
  • websocket/Cargo.lock is excluded by !**/*.lock, !**/*.lock
Files selected for processing (20)
  • .gitignore (1 hunks)
  • api/internal/app/app.go (1 hunks)
  • api/internal/app/public.go (1 hunks)
  • websocket/Cargo.toml (2 hunks)
  • websocket/crates/common/Cargo.toml (1 hunks)
  • websocket/crates/common/src/config.rs (1 hunks)
  • websocket/crates/common/src/lib.rs (1 hunks)
  • websocket/crates/domain/src/project.rs (2 hunks)
  • websocket/crates/domain/src/utils.rs (1 hunks)
  • websocket/crates/infra/Cargo.toml (2 hunks)
  • websocket/crates/infra/src/auth/error.rs (1 hunks)
  • websocket/crates/infra/src/auth/jwt.rs (1 hunks)
  • websocket/crates/infra/src/auth/middleware.rs (1 hunks)
  • websocket/crates/infra/src/auth/mod.rs (1 hunks)
  • websocket/crates/infra/src/lib.rs (1 hunks)
  • websocket/crates/infra/src/main.rs (3 hunks)
  • websocket/crates/infra/src/socket/handler.rs (5 hunks)
  • websocket/crates/services/Cargo.toml (1 hunks)
  • websocket/crates/services/src/auth.rs (1 hunks)
  • websocket/crates/services/src/lib.rs (1 hunks)
Files skipped from review due to trivial changes (5)
  • .gitignore
  • websocket/crates/common/Cargo.toml
  • websocket/crates/domain/src/utils.rs
  • websocket/crates/infra/src/auth/error.rs
  • websocket/crates/services/Cargo.toml
Files skipped from review as they are similar to previous changes (13)
  • api/internal/app/app.go
  • api/internal/app/public.go
  • websocket/Cargo.toml
  • websocket/crates/common/src/config.rs
  • websocket/crates/common/src/lib.rs
  • websocket/crates/domain/src/project.rs
  • websocket/crates/infra/Cargo.toml
  • websocket/crates/infra/src/auth/jwt.rs
  • websocket/crates/infra/src/auth/middleware.rs
  • websocket/crates/infra/src/auth/mod.rs
  • websocket/crates/infra/src/lib.rs
  • websocket/crates/services/src/auth.rs
  • websocket/crates/services/src/lib.rs
Additional comments not posted (11)
websocket/crates/infra/src/main.rs (7)

3-3: LGTM!

The import of from_fn from the axum library is necessary for adding middleware to the Axum router.


4-4: LGTM!

The import of auth_middleware from the infra module is necessary for integrating authentication middleware into the Axum router.


10-10: LGTM!

The import of Config from the common module is necessary for loading configuration from environment variables.


11-11: LGTM!

The import of AuthServiceClient from the services module is necessary for creating an authentication service client.


29-32: LGTM!

  • Loading configuration from environment variables using Config::from_env() is a good practice for managing application settings.
  • Creating an authentication service client using AuthServiceClient::new() is necessary for integrating authentication functionality into the application.

38-41: LGTM!

  • Adding a middleware layer to the Axum router using from_fn() is necessary for implementing authentication handling.
  • Integrating the auth_middleware into the routing logic is necessary for applying authentication to the relevant routes.

56-56: LGTM!

Binding the server to the address specified in the configuration using tokio::net::TcpListener::bind(&config.server_addr) is a good practice for managing the server's network settings.

websocket/crates/infra/src/socket/handler.rs (4)

15-15: LGTM!

The import statement for AuthServiceClient is necessary to use the authentication service.


39-39: LGTM!

The addition of the auth_server_url field to the WebSocketQuery struct is necessary to pass the authentication server URL to the handle_socket function.


51-58: LGTM!

The modification of the handle_socket function to accept an auth_server_url parameter is necessary to create an instance of AuthServiceClient for authentication.


209-215: LGTM!

The modifications to the join method of AppState are good improvements:

  • Using try_lock instead of lock when accessing the rooms field helps avoid potential deadlocks.
  • Returning a Result type allows proper error handling.

Copy link
Contributor

@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: 1

Review details

Configuration used: .coderabbit.yaml
Review profile: CHILL

Commits

Files that changed from the base of the PR and between 4f6d20b and b2484e9.

Files ignored due to path filters (1)
  • websocket/Cargo.lock is excluded by !**/*.lock, !**/*.lock
Files selected for processing (20)
  • .gitignore (1 hunks)
  • api/internal/app/app.go (1 hunks)
  • api/internal/app/public.go (1 hunks)
  • websocket/Cargo.toml (2 hunks)
  • websocket/crates/common/Cargo.toml (1 hunks)
  • websocket/crates/common/src/config.rs (1 hunks)
  • websocket/crates/common/src/lib.rs (1 hunks)
  • websocket/crates/domain/src/project.rs (2 hunks)
  • websocket/crates/domain/src/utils.rs (1 hunks)
  • websocket/crates/infra/Cargo.toml (2 hunks)
  • websocket/crates/infra/src/auth/error.rs (1 hunks)
  • websocket/crates/infra/src/auth/jwt.rs (1 hunks)
  • websocket/crates/infra/src/auth/middleware.rs (1 hunks)
  • websocket/crates/infra/src/auth/mod.rs (1 hunks)
  • websocket/crates/infra/src/lib.rs (1 hunks)
  • websocket/crates/infra/src/main.rs (3 hunks)
  • websocket/crates/infra/src/socket/handler.rs (3 hunks)
  • websocket/crates/services/Cargo.toml (1 hunks)
  • websocket/crates/services/src/auth.rs (1 hunks)
  • websocket/crates/services/src/lib.rs (1 hunks)
Files skipped from review due to trivial changes (3)
  • .gitignore
  • websocket/crates/common/Cargo.toml
  • websocket/crates/services/Cargo.toml
Files skipped from review as they are similar to previous changes (14)
  • api/internal/app/app.go
  • api/internal/app/public.go
  • websocket/Cargo.toml
  • websocket/crates/common/src/config.rs
  • websocket/crates/common/src/lib.rs
  • websocket/crates/domain/src/project.rs
  • websocket/crates/infra/Cargo.toml
  • websocket/crates/infra/src/auth/error.rs
  • websocket/crates/infra/src/auth/jwt.rs
  • websocket/crates/infra/src/auth/middleware.rs
  • websocket/crates/infra/src/auth/mod.rs
  • websocket/crates/infra/src/lib.rs
  • websocket/crates/infra/src/socket/handler.rs
  • websocket/crates/services/src/auth.rs
Additional comments not posted (6)
websocket/crates/services/src/lib.rs (1)

1-3: LGTM!

The changes in this file are creating a new auth module and re-exporting two items from it: AuthServiceClient and AuthServiceError. This is consistent with the PR objective of integrating a JWT module for WebSocket connections.

The file does not contain any logic or implementation details, so there are no correctness, performance, or security issues to review.

websocket/crates/infra/src/main.rs (5)

3-4: LGTM!

The imports are correctly added to enable the integration of the authentication middleware into the Axum router.


10-11: LGTM!

The imports are correctly added to enable loading the configuration from environment variables and creating an instance of the AuthServiceClient.


29-32: LGTM!

Loading the configuration from environment variables is a good practice for managing application settings. Creating an instance of the AuthServiceClient is necessary for making authentication requests to the auth service.


38-41: LGTM!

Adding the authentication middleware to the Axum router is crucial for handling authentication and authorization of incoming requests. The auth_middleware closure captures the auth_client instance, allowing it to make authentication requests to the auth service.


56-56: LGTM!

Binding the server to the address specified in the configuration allows for flexibility in deploying the application to different environments.

@@ -2,5 +2,5 @@ use uuid::Uuid;

pub fn generate_id(length: usize, prefix: &str) -> String {
let _ = length;
Copy link
Contributor

Choose a reason for hiding this comment

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

Remove the unused parameter.

The length parameter is unused in the function body.

Please remove the unused parameter:

-pub fn generate_id(length: usize, prefix: &str) -> String {
+pub fn generate_id(prefix: &str) -> Uuid {
-    let _ = length;

Committable suggestion was skipped due to low confidence.

Copy link
Contributor

@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: 0

Outside diff range and nitpick comments (1)
websocket/crates/infra/src/lib.rs (1)

5-6: LGTM!

Re-exporting the auth_middleware and JwtValidator from the auth module is a good practice to make them accessible to other parts of the application.

Consider creating a separate middleware module to house all the middleware functions, including auth_middleware. This can help keep the codebase more organized and modular.

Review details

Configuration used: .coderabbit.yaml
Review profile: CHILL

Commits

Files that changed from the base of the PR and between b2484e9 and 72528e4.

Files ignored due to path filters (1)
  • websocket/Cargo.lock is excluded by !**/*.lock, !**/*.lock
Files selected for processing (20)
  • .gitignore (1 hunks)
  • api/internal/app/app.go (1 hunks)
  • api/internal/app/public.go (1 hunks)
  • websocket/Cargo.toml (2 hunks)
  • websocket/crates/common/Cargo.toml (1 hunks)
  • websocket/crates/common/src/config.rs (1 hunks)
  • websocket/crates/common/src/lib.rs (1 hunks)
  • websocket/crates/domain/src/project.rs (2 hunks)
  • websocket/crates/domain/src/utils.rs (1 hunks)
  • websocket/crates/infra/Cargo.toml (2 hunks)
  • websocket/crates/infra/src/auth/error.rs (1 hunks)
  • websocket/crates/infra/src/auth/jwt.rs (1 hunks)
  • websocket/crates/infra/src/auth/middleware.rs (1 hunks)
  • websocket/crates/infra/src/auth/mod.rs (1 hunks)
  • websocket/crates/infra/src/lib.rs (1 hunks)
  • websocket/crates/infra/src/main.rs (3 hunks)
  • websocket/crates/infra/src/socket/handler.rs (3 hunks)
  • websocket/crates/services/Cargo.toml (1 hunks)
  • websocket/crates/services/src/auth.rs (1 hunks)
  • websocket/crates/services/src/lib.rs (1 hunks)
Files skipped from review due to trivial changes (4)
  • .gitignore
  • websocket/crates/common/src/config.rs
  • websocket/crates/services/Cargo.toml
  • websocket/crates/services/src/lib.rs
Files skipped from review as they are similar to previous changes (13)
  • api/internal/app/app.go
  • api/internal/app/public.go
  • websocket/Cargo.toml
  • websocket/crates/common/Cargo.toml
  • websocket/crates/common/src/lib.rs
  • websocket/crates/domain/src/project.rs
  • websocket/crates/domain/src/utils.rs
  • websocket/crates/infra/Cargo.toml
  • websocket/crates/infra/src/auth/error.rs
  • websocket/crates/infra/src/auth/middleware.rs
  • websocket/crates/infra/src/auth/mod.rs
  • websocket/crates/infra/src/socket/handler.rs
  • websocket/crates/services/src/auth.rs
Additional comments not posted (12)
websocket/crates/infra/src/lib.rs (2)

1-1: LGTM!

The addition of the auth module is a good step towards implementing authentication functionality in the application.


7-7: LGTM!

Re-exporting the Config from the common module is a good practice to make it accessible to other parts of the application.

websocket/crates/infra/src/main.rs (5)

3-4: LGTM!

The imports are relevant and necessary for implementing the middleware layer and authentication handling in the Axum router.


10-11: LGTM!

The imports are relevant and necessary for loading configuration from environment variables and instantiating an authentication service client.


30-34: LGTM!

Loading configuration from environment variables is a good practice for managing application settings. Instantiating the AuthServiceClient with the loaded configuration is necessary for implementing authentication functionality.


40-43: LGTM!

Adding a middleware layer using from_fn and integrating auth_middleware into the routing logic is necessary for implementing authentication handling for incoming requests.


58-58: LGTM!

Replacing the hardcoded server address with a dynamic one loaded from the configuration is a good practice for flexibility and maintainability.

websocket/crates/infra/src/auth/jwt.rs (5)

1-8: LGTM!

The import statements are relevant and necessary for the functionality implemented in this file. There are no unused imports.


9-50: LGTM!

The JwtValidator struct and its associated methods are well-designed and implemented:

  • The struct encapsulates the necessary dependencies (AuthServiceClient and cache) for JWT verification.
  • The new method correctly initializes instances of JwtValidator with the required dependencies.
  • The verify method effectively handles the caching and verification logic, checking the cache first and sending a request to the authentication service if the token is not found in the cache.
  • The error handling in the verify method is appropriate, returning a JwtError for verification failures.

The code is clean, readable, and follows best practices.


52-57: LGTM!

The test module is properly defined and annotated with #[cfg(test)] to ensure it is only compiled during testing. The necessary dependencies for testing, such as wiremock, are imported correctly.


58-80: LGTM!

The test function test_jwt_verify_success is well-written and thoroughly tests the successful verification of a valid token:

  • The test setup using wiremock is appropriate for simulating the authentication service and setting up mock responses.
  • The test correctly creates an instance of JwtValidator with the mocked client and cache duration.
  • The test asserts the expected behavior of the verify method for a valid token, ensuring that the method returns the correct result.
  • The test also verifies that the cache is working correctly by calling verify multiple times and ensuring the expected result is returned.

The test covers the important aspects of the verify method and provides confidence in its correctness.


82-103: LGTM!

The test function test_jwt_verify_failure is well-written and effectively tests the handling of an invalid token:

  • The test setup using wiremock is appropriate for simulating the authentication service and setting up a mock response for an invalid token.
  • The test correctly creates an instance of JwtValidator with the mocked client and cache duration.
  • The test asserts the expected error behavior of the verify method for an invalid token, ensuring that the method returns the correct error type.
  • The test uses pattern matching to ensure that the returned error is of the expected type JwtError::VerificationFailed.

The test covers the important error handling aspect of the verify method and provides confidence in its correctness.

Copy link
Contributor

@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: 1

Outside diff range and nitpick comments (1)
websocket/crates/infra/examples/simple_client.rs (1)

4-11: Consider making the WebSocket URL configurable.

The code establishes a WebSocket connection and splits the stream into read and write halves, which is a good approach for separate handling.

However, the WebSocket URL is currently hardcoded. Consider making it configurable, such as reading from a configuration file or environment variable, to improve flexibility and reusability of the client.

Review details

Configuration used: .coderabbit.yaml
Review profile: CHILL

Commits

Files that changed from the base of the PR and between 72528e4 and 6b7afe5.

Files ignored due to path filters (1)
  • websocket/Cargo.lock is excluded by !**/*.lock, !**/*.lock
Files selected for processing (4)
  • websocket/Cargo.toml (2 hunks)
  • websocket/crates/infra/Cargo.toml (2 hunks)
  • websocket/crates/infra/examples/authenticated_client.rs (1 hunks)
  • websocket/crates/infra/examples/simple_client.rs (1 hunks)
Files skipped from review as they are similar to previous changes (2)
  • websocket/Cargo.toml
  • websocket/crates/infra/Cargo.toml
Additional comments not posted (11)
websocket/crates/infra/examples/simple_client.rs (3)

1-3: LGTM!

The imports are relevant and required for the WebSocket client implementation.


13-21: LGTM!

Spawning a separate task for handling incoming messages allows for concurrent processing, which is a good practice.

The task continuously listens for messages and handles them appropriately by printing to the console or logging an error message in case of failure.


23-36: LGTM!

The loop in the main task allows users to continuously send messages until they choose to exit by typing "exit," providing a simple and intuitive way to interact with the WebSocket server.

User input is read from the standard input and sent as a text message to the server, which is appropriate for this example client.

websocket/crates/infra/examples/authenticated_client.rs (8)

1-5: LGTM!

The import statements are necessary for the functionality of the WebSocket client.


13-14: LGTM!

The URL parsing and printing are implemented correctly and provide clarity.


16-28: LGTM!

The request creation with the necessary headers and JWT token is implemented correctly.


31-76: LGTM!

The connection handling, message handling, and main loop implementation are robust and well-structured.


69-70: LGTM!

The proper abortion of the read task before shutting down is a good practice to ensure clean termination.


72-75: LGTM!

The error handling for connection failures is implemented correctly.


78-80: LGTM!

The final println statement and the return of Ok(()) are appropriate for the main function.


82-89: LGTM!

The generate_key function is implemented correctly. It generates a random 16-byte key and encodes it using base64 with the standard encoding, which is suitable for the WebSocket connection.

Comment on lines +10 to +11
let jwt_token = "your_jwt_token_here";
println!("Using JWT token: {}", jwt_token);
Copy link
Contributor

Choose a reason for hiding this comment

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

Consider using an environment variable or configuration file for the JWT token.

Hardcoding the JWT token in the source code is not recommended as it poses a security risk. Consider using an environment variable or a configuration file to store the token securely.

Copy link
Contributor

@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: 2

Review details

Configuration used: .coderabbit.yaml
Review profile: CHILL

Commits

Files that changed from the base of the PR and between 6b7afe5 and bb14515.

Files ignored due to path filters (1)
  • websocket/Cargo.lock is excluded by !**/*.lock, !**/*.lock
Files selected for processing (20)
  • .gitignore (1 hunks)
  • api/internal/app/app.go (1 hunks)
  • api/internal/app/public.go (1 hunks)
  • websocket/Cargo.toml (2 hunks)
  • websocket/crates/common/Cargo.toml (1 hunks)
  • websocket/crates/common/src/config.rs (1 hunks)
  • websocket/crates/common/src/lib.rs (1 hunks)
  • websocket/crates/infra/Cargo.toml (2 hunks)
  • websocket/crates/infra/examples/authenticated_client.rs (1 hunks)
  • websocket/crates/infra/examples/simple_client.rs (1 hunks)
  • websocket/crates/infra/src/auth/error.rs (1 hunks)
  • websocket/crates/infra/src/auth/jwt.rs (1 hunks)
  • websocket/crates/infra/src/auth/middleware.rs (1 hunks)
  • websocket/crates/infra/src/auth/mod.rs (1 hunks)
  • websocket/crates/infra/src/lib.rs (1 hunks)
  • websocket/crates/infra/src/main.rs (3 hunks)
  • websocket/crates/infra/src/socket/handler.rs (3 hunks)
  • websocket/crates/services/Cargo.toml (1 hunks)
  • websocket/crates/services/src/auth.rs (1 hunks)
  • websocket/crates/services/src/lib.rs (1 hunks)
Files skipped from review due to trivial changes (4)
  • .gitignore
  • websocket/crates/common/src/config.rs
  • websocket/crates/services/Cargo.toml
  • websocket/crates/services/src/lib.rs
Files skipped from review as they are similar to previous changes (15)
  • api/internal/app/app.go
  • api/internal/app/public.go
  • websocket/Cargo.toml
  • websocket/crates/common/Cargo.toml
  • websocket/crates/common/src/lib.rs
  • websocket/crates/infra/Cargo.toml
  • websocket/crates/infra/examples/authenticated_client.rs
  • websocket/crates/infra/examples/simple_client.rs
  • websocket/crates/infra/src/auth/error.rs
  • websocket/crates/infra/src/auth/jwt.rs
  • websocket/crates/infra/src/auth/middleware.rs
  • websocket/crates/infra/src/auth/mod.rs
  • websocket/crates/infra/src/lib.rs
  • websocket/crates/infra/src/socket/handler.rs
  • websocket/crates/services/src/auth.rs
Additional comments not posted (1)
websocket/crates/infra/src/main.rs (1)

40-43: Ensure all necessary routes are protected by the authentication middleware

You've integrated the auth_middleware using from_fn, which is great for securing routes. Please verify that all routes requiring authentication are covered by this middleware to prevent unauthorized access.

Run the following script to list all routes and ensure the middleware is applied appropriately:

Verification successful

Authentication middleware is correctly applied to the main application route

The auth_middleware is properly implemented and applied to the "/:room" route in the main application. It's set up using the layer method with from_fn, which ensures that all subsequent routes (in this case, the single "/:room" route) are protected by the authentication middleware.

The other route definitions found in the middleware.rs file appear to be for testing purposes and are not part of the main application flow.

Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Verify that all routes are protected by the authentication middleware.

# List all route definitions
rg --type rust 'route\('

# Check where the middleware is applied
rg --type rust 'layer\(from_fn.*auth_middleware'

Length of output: 360


Script:

#!/bin/bash
# Search for any usage of auth_middleware
rg --type rust 'auth_middleware'

# Look for other potential middleware applications
rg --type rust 'layer\('

# Display the content of the main.rs file
cat websocket/crates/infra/src/main.rs

Length of output: 4686

Comment on lines 58 to 60
let listener = tokio::net::TcpListener::bind(&config.server_addr)
.await
.unwrap();
Copy link
Contributor

Choose a reason for hiding this comment

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

Handle potential errors when binding to the server address

Using .unwrap() on TcpListener::bind may cause the application to panic if binding fails (e.g., the port is already in use). It's better to handle this error gracefully by logging it and exiting the application with a non-zero status code.

Apply this diff to handle the error more gracefully:

-let listener = tokio::net::TcpListener::bind(&config.server_addr)
-    .await
-    .unwrap();
+let listener = match tokio::net::TcpListener::bind(&config.server_addr).await {
+    Ok(listener) => listener,
+    Err(e) => {
+        tracing::error!("Failed to bind to {}: {}", &config.server_addr, e);
+        std::process::exit(1);
+    }
+};
Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
let listener = tokio::net::TcpListener::bind(&config.server_addr)
.await
.unwrap();
let listener = match tokio::net::TcpListener::bind(&config.server_addr).await {
Ok(listener) => listener,
Err(e) => {
tracing::error!("Failed to bind to {}: {}", &config.server_addr, e);
std::process::exit(1);
}
};

@kasugamirai kasugamirai force-pushed the feat/websocket-auth branch 2 times, most recently from e19b317 to 57a9208 Compare September 17, 2024 18:51
Copy link
Contributor

@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: 1

Review details

Configuration used: .coderabbit.yaml
Review profile: CHILL

Commits

Files that changed from the base of the PR and between e19b317 and 57a9208.

Files ignored due to path filters (1)
  • websocket/Cargo.lock is excluded by !**/*.lock, !**/*.lock
Files selected for processing (20)
  • .gitignore (1 hunks)
  • api/internal/app/app.go (1 hunks)
  • api/internal/app/public.go (1 hunks)
  • websocket/Cargo.toml (3 hunks)
  • websocket/crates/common/Cargo.toml (1 hunks)
  • websocket/crates/common/src/config.rs (1 hunks)
  • websocket/crates/common/src/lib.rs (1 hunks)
  • websocket/crates/infra/Cargo.toml (2 hunks)
  • websocket/crates/infra/examples/authenticated_client.rs (1 hunks)
  • websocket/crates/infra/examples/simple_client.rs (1 hunks)
  • websocket/crates/infra/src/auth/error.rs (1 hunks)
  • websocket/crates/infra/src/auth/jwt.rs (1 hunks)
  • websocket/crates/infra/src/auth/middleware.rs (1 hunks)
  • websocket/crates/infra/src/auth/mod.rs (1 hunks)
  • websocket/crates/infra/src/lib.rs (1 hunks)
  • websocket/crates/infra/src/main.rs (3 hunks)
  • websocket/crates/infra/src/socket/handler.rs (3 hunks)
  • websocket/crates/services/Cargo.toml (1 hunks)
  • websocket/crates/services/src/auth.rs (1 hunks)
  • websocket/crates/services/src/lib.rs (1 hunks)
Files skipped from review due to trivial changes (3)
  • .gitignore
  • websocket/crates/services/Cargo.toml
  • websocket/crates/services/src/auth.rs
Files skipped from review as they are similar to previous changes (16)
  • api/internal/app/app.go
  • api/internal/app/public.go
  • websocket/Cargo.toml
  • websocket/crates/common/Cargo.toml
  • websocket/crates/common/src/config.rs
  • websocket/crates/common/src/lib.rs
  • websocket/crates/infra/Cargo.toml
  • websocket/crates/infra/examples/authenticated_client.rs
  • websocket/crates/infra/examples/simple_client.rs
  • websocket/crates/infra/src/auth/error.rs
  • websocket/crates/infra/src/auth/jwt.rs
  • websocket/crates/infra/src/auth/middleware.rs
  • websocket/crates/infra/src/auth/mod.rs
  • websocket/crates/infra/src/lib.rs
  • websocket/crates/infra/src/socket/handler.rs
  • websocket/crates/services/src/lib.rs
Additional comments not posted (3)
websocket/crates/infra/src/main.rs (3)

3-4: Imports are appropriate

The added imports for middleware and JWT validator are correctly included.


10-12: Imports are correctly added

The inclusion of Config and AuthServiceClient is necessary for configuration management and authentication services.


40-43: Middleware integration is correct

The authentication middleware is properly integrated using from_fn and auth_middleware. This setup ensures that every incoming request passes through the JWT validation process.

Comment on lines 30 to 41
let config = Config::from_env().expect("Failed to load configuration");

let auth_client =
AuthServiceClient::new(&config.auth_service_url).expect("Failed to create auth client");
let jwt_validator = JwtValidator::new(auth_client, Duration::from_secs(300));

Copy link
Contributor

@coderabbitai coderabbitai bot Sep 17, 2024

Choose a reason for hiding this comment

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

Handle configuration initialization errors gracefully

Using expect() on Config::from_env() and AuthServiceClient::new() can cause the application to panic if configuration loading or client creation fails. It's better practice to handle these errors gracefully by logging them and exiting the application with a non-zero status code.

Apply this diff to handle the errors more gracefully:

-    let config = Config::from_env().expect("Failed to load configuration");
+    let config = match Config::from_env() {
+        Ok(cfg) => cfg,
+        Err(e) => {
+            tracing::error!("Failed to load configuration: {}", e);
+            std::process::exit(1);
+        }
+    };

-    let auth_client =
-        AuthServiceClient::new(&config.auth_service_url).expect("Failed to create auth client");
+    let auth_client = match AuthServiceClient::new(&config.auth_service_url) {
+        Ok(client) => client,
+        Err(e) => {
+            tracing::error!("Failed to create auth client: {}", e);
+            std::process::exit(1);
+        }
+    };
Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
let config = Config::from_env().expect("Failed to load configuration");
let auth_client =
AuthServiceClient::new(&config.auth_service_url).expect("Failed to create auth client");
let jwt_validator = JwtValidator::new(auth_client, Duration::from_secs(300));
let config = match Config::from_env() {
Ok(cfg) => cfg,
Err(e) => {
tracing::error!("Failed to load configuration: {}", e);
std::process::exit(1);
}
};
let auth_client = match AuthServiceClient::new(&config.auth_service_url) {
Ok(client) => client,
Err(e) => {
tracing::error!("Failed to create auth client: {}", e);
std::process::exit(1);
}
};
let jwt_validator = JwtValidator::new(auth_client, Duration::from_secs(300));

Copy link
Contributor

Choose a reason for hiding this comment

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

@kasugamirai Can you check this?

Copy link
Contributor

Choose a reason for hiding this comment

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

Seems like the humans are having a chat. I'll hop back into my burrow for now. If you need me again, just tag @coderabbitai in a new comment, and I'll come hopping out!

Copy link
Contributor

@pyshx pyshx left a comment

Choose a reason for hiding this comment

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

Please remove unnecessary dependencies.

Comment on lines 30 to 41
let config = Config::from_env().expect("Failed to load configuration");

let auth_client =
AuthServiceClient::new(&config.auth_service_url).expect("Failed to create auth client");
let jwt_validator = JwtValidator::new(auth_client, Duration::from_secs(300));

Copy link
Contributor

Choose a reason for hiding this comment

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

@kasugamirai Can you check this?

websocket/Cargo.toml Outdated Show resolved Hide resolved
Copy link
Contributor

@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: 1

Outside diff range and nitpick comments (1)
websocket/crates/infra/src/main.rs (1)

46-49: Evaluate the necessity of cloning jwt_validator

In the middleware layer, you're cloning jwt_validator inside the closure:

let jwt_validator = jwt_validator.clone();

If jwt_validator is cheap to clone (e.g., if it implements Clone efficiently or is wrapped in an Arc), this is acceptable. Otherwise, consider passing a reference or using an Arc to manage shared ownership without the overhead of cloning large objects.

Review details

Configuration used: .coderabbit.yaml
Review profile: CHILL

Commits

Files that changed from the base of the PR and between 96e30ed and 6ca0767.

Files selected for processing (1)
  • websocket/crates/infra/src/main.rs (2 hunks)
Additional comments not posted (4)
websocket/crates/infra/src/main.rs (4)

24-30: Ensure application exits with a non-zero status code on configuration load failure

In the error handling for Config::from_env(), using return; will cause the application to exit with a status code of zero, which indicates success. To properly signal that an error has occurred, consider exiting with a non-zero status code using std::process::exit(1);.


32-38: Ensure application exits with a non-zero status code on authentication client initialization failure

Similarly, when AuthServiceClient::new() fails, using return; will exit with a zero status code. It's better to use std::process::exit(1); to indicate to the operating system that the application terminated due to an error.


64-70: Ensure application exits with a non-zero status code when binding to the server address fails

If the application fails to bind to the server address and uses return;, it exits with a zero status code, implying a successful termination. To reflect the error state correctly, use std::process::exit(1); after logging the error.


72-78: Ensure application exits with a non-zero status code when retrieving the local address fails

When listener.local_addr() fails, the application currently logs the error and returns. This leads to an exit with a zero status code. Consider using std::process::exit(1); to exit with a non-zero status code, indicating an abnormal termination due to an error.

@kasugamirai kasugamirai changed the title feat(websocket): Add jwt module to ws connection feat(websocket): Add jwt support to ws connection Sep 24, 2024
Copy link
Contributor

@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: 1

Outside diff range and nitpick comments (3)
websocket/Cargo.toml (2)

45-45: Consider updating dotenv to the latest version

The addition of the dotenv crate is good for managing environment variables, which can be useful for JWT configuration. However, the current version (0.15.0) is slightly outdated. Consider updating to the latest version (0.15.1) for potential bug fixes and improvements.

-dotenv = "0.15.0"
+dotenv = "0.15.1"

53-54: LGTM with suggestion: Addition of once_cell and rand dependencies

The addition of once_cell and rand crates is appropriate. once_cell is useful for lazy static initialization, while rand is great for generating random values, potentially for token generation or testing.

However, the once_cell version (1.18.0) is slightly outdated. Consider updating to the latest version (1.19.0) for potential improvements and bug fixes.

-once_cell = "1.18.0"
+once_cell = "1.19.0"
websocket/crates/infra/src/main.rs (1)

40-40: LGTM: JwtValidator initialization

The JwtValidator is correctly initialized with the AuthServiceClient and a timeout, which is essential for the JWT support feature.

Consider making the timeout duration configurable through the Config struct to allow for easier adjustments in different environments.

Review details

Configuration used: .coderabbit.yaml
Review profile: CHILL

Commits

Files that changed from the base of the PR and between 6ca0767 and 126f2a0.

Files ignored due to path filters (1)
  • websocket/Cargo.lock is excluded by !**/*.lock, !**/*.lock
Files selected for processing (20)
  • .gitignore (1 hunks)
  • api/internal/app/app.go (1 hunks)
  • api/internal/app/public.go (1 hunks)
  • websocket/Cargo.toml (1 hunks)
  • websocket/crates/common/Cargo.toml (1 hunks)
  • websocket/crates/common/src/config.rs (1 hunks)
  • websocket/crates/common/src/lib.rs (1 hunks)
  • websocket/crates/infra/Cargo.toml (1 hunks)
  • websocket/crates/infra/examples/authenticated_client.rs (1 hunks)
  • websocket/crates/infra/examples/simple_client.rs (1 hunks)
  • websocket/crates/infra/src/auth/error.rs (1 hunks)
  • websocket/crates/infra/src/auth/jwt.rs (1 hunks)
  • websocket/crates/infra/src/auth/middleware.rs (1 hunks)
  • websocket/crates/infra/src/auth/mod.rs (1 hunks)
  • websocket/crates/infra/src/lib.rs (1 hunks)
  • websocket/crates/infra/src/main.rs (2 hunks)
  • websocket/crates/infra/src/socket/handler.rs (3 hunks)
  • websocket/crates/services/Cargo.toml (1 hunks)
  • websocket/crates/services/src/auth.rs (1 hunks)
  • websocket/crates/services/src/lib.rs (1 hunks)
Files skipped from review as they are similar to previous changes (18)
  • .gitignore
  • api/internal/app/app.go
  • api/internal/app/public.go
  • websocket/crates/common/Cargo.toml
  • websocket/crates/common/src/config.rs
  • websocket/crates/common/src/lib.rs
  • websocket/crates/infra/Cargo.toml
  • websocket/crates/infra/examples/authenticated_client.rs
  • websocket/crates/infra/examples/simple_client.rs
  • websocket/crates/infra/src/auth/error.rs
  • websocket/crates/infra/src/auth/jwt.rs
  • websocket/crates/infra/src/auth/middleware.rs
  • websocket/crates/infra/src/auth/mod.rs
  • websocket/crates/infra/src/lib.rs
  • websocket/crates/infra/src/socket/handler.rs
  • websocket/crates/services/Cargo.toml
  • websocket/crates/services/src/auth.rs
  • websocket/crates/services/src/lib.rs
Additional comments not posted (15)
websocket/Cargo.toml (8)

42-42: LGTM: Addition of base64 dependency

The addition of the base64 crate is appropriate for JWT-related operations. The version 0.22.1 is current and should provide good performance and security.


43-43: LGTM: Addition of cached dependency

The cached crate (version 0.53.1) is a good choice for implementing caching mechanisms. This can be particularly useful for caching validated JWT tokens, potentially improving performance in high-traffic scenarios.


46-46: LGTM: Addition of futures-util dependency

The addition of futures-util = "0.3" is appropriate for working with futures in async Rust programming. The version specification allows for automatic updates to the latest patch version, which is a good practice for minor improvements and bug fixes.


48-50: LGTM: Addition of http, http-body-util, and hyper dependencies

The addition of http, http-body-util, and hyper crates is appropriate for handling HTTP-related functionality, which is essential for WebSocket connections and JWT validation. The versions are up-to-date and should work well together.


51-51: LGTM: Addition of jsonwebtoken dependency

The addition of the jsonwebtoken crate (version 9.3.0) is excellent and directly supports the PR objective of adding JWT support to WebSocket connections. This crate provides robust functionality for working with JWTs.


56-57: LGTM: Addition of reqwest, rsa, and tokio-tungstenite dependencies

The addition of reqwest, rsa, and tokio-tungstenite crates is excellent:

  • reqwest with JSON feature is great for making HTTP requests, possibly for token validation.
  • rsa with PEM feature is essential for JWT signing and verification.
  • tokio-tungstenite is crucial for WebSocket support in an async Rust environment.

All versions are up-to-date, and the selected features are appropriate for the project's needs.

Also applies to: 64-64


63-63: LGTM: Tokio update and addition of url and wiremock dependencies

Excellent updates and additions:

  • Updating tokio to version 1.40.0 keeps the project on the latest version of this crucial async runtime.
  • The url crate (version 2.5.2) is great for parsing and handling URLs in web applications.
  • Adding wiremock (version 0.6.2) is excellent for mocking HTTP APIs in tests, enhancing the project's testability.

All versions are up-to-date, and these changes will contribute to a more robust and testable codebase.

Also applies to: 69-71


42-71: Overall assessment: Well-structured dependency additions for JWT and WebSocket support

The changes to Cargo.toml are well-aligned with the PR objective of adding JWT support to WebSocket connections. The new dependencies cover all necessary aspects:

  • JWT handling (jsonwebtoken, base64)
  • WebSocket support (tokio-tungstenite)
  • HTTP and API interactions (hyper, reqwest)
  • Cryptography (rsa)
  • Testing and mocking (wiremock)

The updates to existing dependencies, particularly tokio, keep the project up-to-date. The addition of utilities like cached and once_cell suggests a focus on performance and clean code structure.

A few minor version updates were suggested for dotenv and once_cell, but these are not critical. Overall, these changes provide a solid foundation for implementing JWT support in WebSocket connections.

websocket/crates/infra/src/main.rs (7)

3-4: LGTM: New imports support JWT and configuration features

The added imports for middleware, authentication, and configuration components align well with the PR objective of adding JWT support to the WebSocket connection.

Also applies to: 9-11


24-30: LGTM: Improved configuration loading with error handling

The configuration loading has been improved by implementing proper error handling and logging. This change addresses the feedback from previous reviews and enhances the robustness of the application.


32-38: LGTM: Robust AuthServiceClient initialization

The AuthServiceClient initialization now includes proper error handling and logging, addressing the feedback from previous reviews. This change improves the reliability of the application's authentication setup.


46-49: LGTM: Authentication middleware successfully integrated

The authentication middleware has been correctly implemented and integrated into the router. This change fulfills the PR objective of adding JWT support to the WebSocket connection.


53-53: LGTM: Enhanced error handling

The error handling has been improved by including the application state in the handle_error function. This change allows for more context-aware error responses.


64-80: LGTM: Robust server binding with improved error handling

The server binding process has been significantly improved:

  1. It now uses the address from the configuration.
  2. Proper error handling and logging have been implemented for both the binding process and local address retrieval.

These changes address the feedback from previous reviews and enhance the reliability of the server startup process.


Line range hint 1-101: Overall assessment: Significant improvements in WebSocket server implementation

This PR has successfully implemented JWT support for the WebSocket connection, addressing the main objective. The changes include:

  1. Proper configuration management and error handling.
  2. Integration of JWT validation through middleware.
  3. Improved error handling throughout the server setup and runtime.

These enhancements significantly improve the robustness and security of the WebSocket server. The code quality has been notably improved, addressing previous review comments and introducing better practices.

A few minor suggestions have been made for further improvements, but overall, this PR represents a substantial step forward in the project's development.

Comment on lines +82 to +89
if let Err(e) = axum::serve(
listener,
app.into_make_service_with_connect_info::<SocketAddr>(),
)
.await
{
tracing::error!("server error: {}", e);
}
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue

Consider improving server error handling

While the addition of error logging for server runtime errors is a good improvement, the current implementation doesn't exit the application on critical errors. This might lead to unexpected behavior if the server encounters a fatal error.

Consider modifying the error handling to exit the application with a non-zero status code on critical errors:

    if let Err(e) = axum::serve(
        listener,
        app.into_make_service_with_connect_info::<SocketAddr>(),
    )
    .await
    {
        tracing::error!("server error: {}", e);
+       std::process::exit(1);
    }

This ensures that the application terminates properly on critical server errors, allowing for easier detection and handling of issues in production environments.

Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
if let Err(e) = axum::serve(
listener,
app.into_make_service_with_connect_info::<SocketAddr>(),
)
.await
{
tracing::error!("server error: {}", e);
}
if let Err(e) = axum::serve(
listener,
app.into_make_service_with_connect_info::<SocketAddr>(),
)
.await
{
tracing::error!("server error: {}", e);
std::process::exit(1);
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants