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

Development: Enable bearer authentication #9403

Open
wants to merge 15 commits into
base: develop
Choose a base branch
from

Conversation

janthoXO
Copy link
Contributor

@janthoXO janthoXO commented Oct 1, 2024

Checklist

General

Server

  • Important: I implemented the changes with a very good performance and prevented too many (unnecessary) and too complex database calls.
  • I strictly followed the principle of data economy for all database calls.
  • I strictly followed the server coding and design guidelines.
  • I added multiple integration tests (Spring) related to the features (with a high test coverage).
  • I added pre-authorization annotations according to the guidelines and checked the course groups for all new REST Calls (security).
  • I documented the Java code using JavaDoc style.

Motivation and Context

For some clients it is best practise or they are only able to use authentication with a Authorization Header, so called bearer. One client which is not able to use cookies is the VSCode Plugin. Therefore Artemis should be adjusted to use Bearer Tokens as well

Description

The Authentication now also accepts JWT in the Authentication Header. It checks first for a valid JWT in the cookie and afterwards in the Authentication Header.
The authenticate endpoint is adjusted accordingly to also return the token in the body

Steps for Testing

Postman testing or code review:
Postman Testing:
ArtemisTokens.postman_collection.json

  1. Send a request to POST {{base_url}}/api/public/authenticate

  2. Verify that you get a token in the body response

  3. Send a request to GET {{base_url}}/api/courses/for-dashboard

  4. Verify that you get a 200 response

  5. Send a request to GET {{base_url}}/api/courses/for-dashboard with the header Authorization: Bearer {{access_token}} from the body of the authenticate request

  6. verify that you get a 400 because you used both Authorization Header and Cookie

  7. Delete the cookie in Postman

  8. Send a request to GET {{base_url}}/api/courses/for-dashboard with the header Authorization: Bearer {{access_token}} from the body of the authenticate request

  9. verify you now get a 200 because only the Authorization Header is used

Testserver States

Note

These badges show the state of the test servers.
Green = Currently available, Red = Currently locked
Click on the badges to get to the test servers.







Review Progress

Test Coverage

Class/File Line Coverage Confirmation (assert/expect)
JWTFilter 97%
TokenProvider 95%
PublicUserJwtResource 87%

Screenshots

Summary by CodeRabbit

Release Notes

  • New Features

    • Enhanced JWT validation process during WebSocket handshake, removing cookie dependency.
    • Updated authentication response to return JWT token in a structured format.
    • Added a method for retrieving specific claims from a JWT token.
  • Bug Fixes

    • Improved error handling for invalid JWTs during WebSocket handshake.
  • Tests

    • Added assertions to verify Bearer token in authentication tests.
    • New test method for JWT filter behavior with Bearer tokens.
    • Renamed existing test method for clarity.
  • Chores

    • Minor formatting adjustments and removal of unused imports in test files.

@coderabbitai pause

@janthoXO janthoXO self-assigned this Oct 1, 2024
@janthoXO janthoXO requested a review from a team as a code owner October 1, 2024 19:18
Copy link

coderabbitai bot commented Oct 1, 2024

Walkthrough

The pull request introduces significant changes to the JWT validation process across multiple classes. The WebsocketConfiguration class now validates JWTs directly through a new method, eliminating cookie dependency. The JWTFilter class has been refactored to streamline token extraction from both cookies and Authorization headers. The PublicUserJwtResource class's authorize method now returns a map containing the JWT upon successful authentication. Additionally, test classes have been updated to enhance coverage for JWT validation scenarios. A new method for retrieving claims from JWTs has also been added to the TokenProvider class.

Changes

File Change Summary
src/main/java/de/tum/cit/aet/artemis/core/config/websocket/WebsocketConfiguration.java Updated JWT validation process during WebSocket handshake; removed cookie dependency; added error handling for invalid JWTs in beforeHandshake method.
src/main/java/de/tum/cit/aet/artemis/core/security/jwt/JWTFilter.java Refactored JWT extraction and validation; introduced extractValidJwt, getJwtFromCookie, and getJwtFromBearer methods; removed isJwtCookieValid.
src/main/java/de/tum/cit/aet/artemis/core/web/open/PublicUserJwtResource.java Changed return type of authorize method to ResponseEntity<Map<String, String>> to return JWT access token upon successful authentication.
src/test/java/de/tum/cit/aet/artemis/core/authentication/InternalAuthenticationIntegrationTest.java Added assertion for Bearer token in testJWTAuthentication; minor formatting adjustments and removed unused import.
src/test/java/de/tum/cit/aet/artemis/core/security/jwt/JWTFilterTest.java Renamed testJWTFilter to testJWTFilterCookie; added testJWTFilterBearer to verify JWT filter behavior with Bearer token.
src/main/java/de/tum/cit/aet/artemis/core/security/jwt/TokenProvider.java Added getClaim method for retrieving claims from JWT tokens; no changes to existing methods.

Possibly related PRs

Suggested labels

bugfix, ready for review, programming

Suggested reviewers

  • SimonEntholzer
  • dfuchss
  • HawKhiem
  • eceeeren
  • magaupp

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 or @coderabbitai title 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.

@github-actions github-actions bot added server Pull requests that update Java code. (Added Automatically!) core Pull requests that affect the corresponding module labels Oct 1, 2024
@janthoXO janthoXO added the security Pull requests that address a security vulnerability label Oct 1, 2024
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 6

🧹 Outside diff range comments (3)
src/main/java/de/tum/cit/aet/artemis/core/web/open/PublicUserJwtResource.java (3)

Line range hint 72-89: LGTM! Consider standardizing error responses.

The changes to the authorize method align well with the PR objectives. Returning the JWT token in the response body enables clients that can't use cookies to authenticate successfully. This change maintains RESTful principles and doesn't introduce apparent security risks.

A minor suggestion for improvement:

Consider standardizing the error response for consistency with the authorizeSAML2 method. You could include an error message in the response body or a custom header for unauthorized requests:

- return ResponseEntity.status(HttpStatus.UNAUTHORIZED).build();
+ return ResponseEntity.status(HttpStatus.UNAUTHORIZED)
+     .header("X-artemisApp-error", "Invalid credentials")
+     .build();

This change would provide more informative error responses across different authentication methods.


Line range hint 1-156: Consider updating documentation and client-side code.

The changes to the authorize method successfully enable bearer authentication without affecting the overall structure or responsibility of the PublicUserJwtResource class. This modification aligns well with the PR objectives and maintains backwards compatibility.

To ensure a smooth transition and maintain system coherence:

  1. Update any relevant API documentation to reflect the new response format of the authorize endpoint.
  2. Review and update client-side code that interacts with this endpoint to handle the new response format correctly.
  3. Consider adding a note in the PR description about potential client-side changes required.

These steps will help maintain consistency across the system and prevent potential integration issues.


Line range hint 1-156: Refactor suggestion: Improve code reuse for error handling.

The code generally adheres well to the provided coding guidelines. To further improve code quality and maintainability:

Consider extracting the error handling logic into a separate method to promote code reuse. This change would align with the principles of avoiding duplication and improving maintainability. Here's a suggested refactor:

private ResponseEntity<String> handleAuthenticationError(String errorMessage) {
    log.warn(errorMessage);
    return ResponseEntity.status(HttpStatus.UNAUTHORIZED)
        .header("X-artemisApp-error", errorMessage)
        .build();
}

Then, in the authorize method:

catch (BadCredentialsException ex) {
    return handleAuthenticationError("Wrong credentials during login for user " + loginVM.getUsername());
}

This refactoring would make it easier to maintain consistent error handling across different authentication methods in the future.

📜 Review details

Configuration used: .coderabbit.yaml
Review profile: ASSERTIVE

📥 Commits

Files that changed from the base of the PR and between b7a816e and 5dec295.

📒 Files selected for processing (3)
  • src/main/java/de/tum/cit/aet/artemis/core/config/websocket/WebsocketConfiguration.java (2 hunks)
  • src/main/java/de/tum/cit/aet/artemis/core/security/jwt/JWTFilter.java (2 hunks)
  • src/main/java/de/tum/cit/aet/artemis/core/web/open/PublicUserJwtResource.java (2 hunks)
🧰 Additional context used
📓 Path-based instructions (3)
src/main/java/de/tum/cit/aet/artemis/core/config/websocket/WebsocketConfiguration.java (1)

Pattern src/main/java/**/*.java: naming:CamelCase; principles:{single_responsibility,small_methods,no_duplication}; db:{perf_queries,datetime_not_timestamp}; rest:{stateless,singleton,delegate_logic,http_only,minimal_dtos}; dtos:{java_records,no_entities,min_data,single_resp}; di:constructor_injection; kiss:simple_code; file_handling:os_indep_paths; practices:{least_access,avoid_transactions,code_reuse,static_member_ref,prefer_primitives}; sql:{param_annotation,uppercase,avoid_subqueries};java:avoid_star_imports

src/main/java/de/tum/cit/aet/artemis/core/security/jwt/JWTFilter.java (1)

Pattern src/main/java/**/*.java: naming:CamelCase; principles:{single_responsibility,small_methods,no_duplication}; db:{perf_queries,datetime_not_timestamp}; rest:{stateless,singleton,delegate_logic,http_only,minimal_dtos}; dtos:{java_records,no_entities,min_data,single_resp}; di:constructor_injection; kiss:simple_code; file_handling:os_indep_paths; practices:{least_access,avoid_transactions,code_reuse,static_member_ref,prefer_primitives}; sql:{param_annotation,uppercase,avoid_subqueries};java:avoid_star_imports

src/main/java/de/tum/cit/aet/artemis/core/web/open/PublicUserJwtResource.java (1)

Pattern src/main/java/**/*.java: naming:CamelCase; principles:{single_responsibility,small_methods,no_duplication}; db:{perf_queries,datetime_not_timestamp}; rest:{stateless,singleton,delegate_logic,http_only,minimal_dtos}; dtos:{java_records,no_entities,min_data,single_resp}; di:constructor_injection; kiss:simple_code; file_handling:os_indep_paths; practices:{least_access,avoid_transactions,code_reuse,static_member_ref,prefer_primitives}; sql:{param_annotation,uppercase,avoid_subqueries};java:avoid_star_imports

🔇 Additional comments (4)
src/main/java/de/tum/cit/aet/artemis/core/web/open/PublicUserJwtResource.java (1)

Line range hint 1-156: Overall assessment: Changes are well-implemented and align with project goals.

The modifications to the PublicUserJwtResource class successfully implement bearer authentication as intended. The changes are focused, maintain backwards compatibility, and adhere to the project's coding guidelines.

Key points:

  1. The authorize method now returns the JWT token in the response body, enabling clients that can't use cookies.
  2. The changes don't introduce apparent security vulnerabilities.
  3. The code maintains good quality and follows most coding guidelines.

Suggestions for improvement:

  1. Standardize error responses across authentication methods.
  2. Extract error handling logic to a separate method for better code reuse.
  3. Update relevant documentation and client-side code to reflect the changes.

These improvements will enhance code maintainability, consistency, and overall system integration. Once these minor adjustments are addressed, the changes appear ready for merging.

src/main/java/de/tum/cit/aet/artemis/core/config/websocket/WebsocketConfiguration.java (2)

22-22: LGTM: Import changes align with the new JWT extraction method.

The removal of the Cookie import and addition of HttpServletRequest import are consistent with the changes in the beforeHandshake method, supporting the new JWT extraction approach.


Line range hint 1-389: Overall changes enhance WebSocket authentication while maintaining existing functionality.

The modifications to this file successfully implement bearer token authentication for WebSocket connections, as outlined in the PR objectives. The changes are minimal and focused, affecting only the necessary parts of the code:

  1. Updated imports to support the new JWT extraction method.
  2. Modified the beforeHandshake method to use JWTFilter.extractValidJwt, enabling both cookie-based and bearer token authentication.

These changes improve the flexibility of the authentication mechanism, particularly benefiting clients that cannot use cookies, such as the mentioned VSCode Plugin. The implementation adheres to the coding guidelines, especially the "stateless" principle for REST APIs.

The rest of the file remains unchanged, preserving the existing WebSocket configuration and functionality. This targeted approach minimizes the risk of unintended side effects while achieving the desired enhancement.

src/main/java/de/tum/cit/aet/artemis/core/security/jwt/JWTFilter.java (1)

55-65: Ensure consistent token validation order

Currently, the method first checks the cookie for a valid JWT and then the Authorization header. Ensure that this order aligns with the intended authentication precedence. If the Authorization header should take precedence, consider checking it first.

To confirm the desired precedence, please verify if clients are expected to prioritize the Authorization header over cookies.

@janthoXO janthoXO added ready for review and removed security Pull requests that address a security vulnerability labels Oct 1, 2024
Copy link
Contributor

@iyannsch iyannsch left a comment

Choose a reason for hiding this comment

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

Nice changes! I really like the way you adapt to existing code and implement such an important feature in such a lightweight way 🔥
I left a couple of aspects, please answer in the thread. You also have some server-tests failing which might need your attention..

@janthoXO janthoXO requested a review from iyannsch October 2, 2024 11:46
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

📜 Review details

Configuration used: .coderabbit.yaml
Review profile: ASSERTIVE

📥 Commits

Files that changed from the base of the PR and between 5dec295 and a3d0fbb.

📒 Files selected for processing (1)
  • src/main/java/de/tum/cit/aet/artemis/core/security/jwt/JWTFilter.java (2 hunks)
🧰 Additional context used
📓 Path-based instructions (1)
src/main/java/de/tum/cit/aet/artemis/core/security/jwt/JWTFilter.java (1)

Pattern src/main/java/**/*.java: naming:CamelCase; principles:{single_responsibility,small_methods,no_duplication}; db:{perf_queries,datetime_not_timestamp}; rest:{stateless,singleton,delegate_logic,http_only,minimal_dtos}; dtos:{java_records,no_entities,min_data,single_resp}; di:constructor_injection; kiss:simple_code; file_handling:os_indep_paths; practices:{least_access,avoid_transactions,code_reuse,static_member_ref,prefer_primitives}; sql:{param_annotation,uppercase,avoid_subqueries};java:avoid_star_imports

🔇 Additional comments (5)
src/main/java/de/tum/cit/aet/artemis/core/security/jwt/JWTFilter.java (5)

12-12: Correct Use of @Nullable Annotation

The @Nullable annotation is now correctly imported from org.springframework.lang.Nullable, enhancing compatibility within the Spring Framework and avoiding potential conflicts with javax.annotation.Nullable.


35-43: Proper Extraction and Authentication of JWT Tokens

The doFilter method has been appropriately updated to extract the JWT token using extractValidJwt. The authentication is effectively set in the SecurityContextHolder when a valid token is found, ensuring that both cookie-based and header-based tokens are supported.


54-64: Efficient Consolidation of Token Extraction Logic

The extractValidJwt method efficiently consolidates the logic for retrieving a valid JWT token from both the cookie and the Authorization header. This improves code readability and adheres to the DRY (Don't Repeat Yourself) principle.


72-77: Robust Handling in getJwtFromCookie Method

The getJwtFromCookie method correctly checks for a null cookie and returns the JWT value when available. This ensures robustness in scenarios where the cookie might not be present.


85-91: Accurate Extraction and Trimming in getJwtFromBearer Method

The getJwtFromBearer method accurately extracts the JWT token from the Authorization header and trims any leading or trailing whitespace. This prevents token validation issues due to formatting inconsistencies.

@janthoXO janthoXO changed the title Enable bearer authentication General Enable bearer authentication Oct 2, 2024
@janthoXO janthoXO changed the title General Enable bearer authentication General: Enable bearer authentication Oct 2, 2024
iyannsch
iyannsch previously approved these changes Oct 3, 2024
Copy link
Contributor

@iyannsch iyannsch left a comment

Choose a reason for hiding this comment

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

Code LGTM

coderabbitai[bot]
coderabbitai bot previously approved these changes Oct 4, 2024
Copy link
Contributor

@pzdr7 pzdr7 left a comment

Choose a reason for hiding this comment

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

If possible, could you also add a test that checks if it successfully extracts the Bearer token?

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

📜 Review details

Configuration used: .coderabbit.yaml
Review profile: ASSERTIVE

📥 Commits

Files that changed from the base of the PR and between a3d0fbb and b59f8ad.

📒 Files selected for processing (2)
  • src/main/java/de/tum/cit/aet/artemis/core/config/websocket/WebsocketConfiguration.java (1 hunks)
  • src/main/java/de/tum/cit/aet/artemis/core/security/jwt/JWTFilter.java (2 hunks)
🧰 Additional context used
📓 Path-based instructions (2)
src/main/java/de/tum/cit/aet/artemis/core/config/websocket/WebsocketConfiguration.java (1)

Pattern src/main/java/**/*.java: naming:CamelCase; principles:{single_responsibility,small_methods,no_duplication}; db:{perf_queries,datetime_not_timestamp}; rest:{stateless,singleton,delegate_logic,http_only,minimal_dtos}; dtos:{java_records,no_entities,min_data,single_resp}; di:constructor_injection; kiss:simple_code; file_handling:os_indep_paths; practices:{least_access,avoid_transactions,code_reuse,static_member_ref,prefer_primitives}; sql:{param_annotation,uppercase,avoid_subqueries};java:avoid_star_imports

src/main/java/de/tum/cit/aet/artemis/core/security/jwt/JWTFilter.java (1)

Pattern src/main/java/**/*.java: naming:CamelCase; principles:{single_responsibility,small_methods,no_duplication}; db:{perf_queries,datetime_not_timestamp}; rest:{stateless,singleton,delegate_logic,http_only,minimal_dtos}; dtos:{java_records,no_entities,min_data,single_resp}; di:constructor_injection; kiss:simple_code; file_handling:os_indep_paths; practices:{least_access,avoid_transactions,code_reuse,static_member_ref,prefer_primitives}; sql:{param_annotation,uppercase,avoid_subqueries};java:avoid_star_imports

coderabbitai[bot]
coderabbitai bot previously approved these changes Oct 5, 2024
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Outside diff range and nitpick comments (2)
src/main/java/de/tum/cit/aet/artemis/core/security/jwt/JWTFilter.java (2)

65-69: Consider logging authentication method conflicts

When both authentication methods are present, it would be helpful to log this security-relevant event for monitoring and debugging purposes.

Apply this diff:

         if (cookie != null && authHeader != null) {
             // Single Method Enforcement: Only one method of authentication is allowed
+            logger.warn("Request contains both JWT cookie and Authorization header - rejecting request");
             httpServletResponse.setStatus(HttpServletResponse.SC_BAD_REQUEST);
             return null;
         }

99-105: Consider additional validation for bearer token format

While the current implementation checks for "Bearer " prefix, consider adding length validation to prevent potential security issues with malformed tokens.

Apply this diff:

     private static @Nullable String getJwtFromBearer(@Nullable String jwtBearer) {
-        if (!StringUtils.hasText(jwtBearer) || !jwtBearer.startsWith("Bearer ")) {
+        if (!StringUtils.hasText(jwtBearer) || !jwtBearer.startsWith("Bearer ") || jwtBearer.length() < 8) {
             return null;
         }
 
         return jwtBearer.substring(7).trim();
     }
📜 Review details

Configuration used: .coderabbit.yaml
Review profile: CHILL

📥 Commits

Reviewing files that changed from the base of the PR and between e8bde67 and 8df1a6b.

📒 Files selected for processing (2)
  • src/main/java/de/tum/cit/aet/artemis/core/config/websocket/WebsocketConfiguration.java (2 hunks)
  • src/main/java/de/tum/cit/aet/artemis/core/security/jwt/JWTFilter.java (2 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • src/main/java/de/tum/cit/aet/artemis/core/config/websocket/WebsocketConfiguration.java
🧰 Additional context used
📓 Path-based instructions (1)
src/main/java/de/tum/cit/aet/artemis/core/security/jwt/JWTFilter.java (1)

Pattern src/main/java/**/*.java: naming:CamelCase; principles:{single_responsibility,small_methods,no_duplication}; db:{perf_queries,datetime_not_timestamp}; rest:{stateless,singleton,delegate_logic,http_only,minimal_dtos}; dtos:{java_records,no_entities,min_data,single_resp}; di:constructor_injection; kiss:simple_code; file_handling:os_indep_paths; practices:{least_access,avoid_transactions,code_reuse,static_member_ref,prefer_primitives}; sql:{param_annotation,uppercase,avoid_subqueries};java:avoid_star_imports

🔇 Additional comments (2)
src/main/java/de/tum/cit/aet/artemis/core/security/jwt/JWTFilter.java (2)

35-46: LGTM! Clean implementation of dual authentication handling

The changes properly integrate both cookie and bearer token authentication while maintaining thread safety with SecurityContextHolder. The early return on bad request status is a good practice for request validation.


57-78: Verify consistent JWT extraction across the codebase

Let's ensure that JWT extraction is consistently handled across the codebase to prevent security bypasses.

✅ Verification successful

Let me gather more specific information about JWT token handling to ensure there are no inconsistencies.


Based on the comprehensive analysis of the codebase, I can now provide the final response:

JWT extraction implementation is consistent and secure

The JWT extraction logic in JWTFilter is the primary and consistent implementation across the codebase. The only other JWT-related authentication occurs in PyrisJobService which uses a different context (internal service communication) and maintains proper token validation.

  • The JWTFilter properly handles both cookie and header-based tokens with mutual exclusivity
  • Token validation is consistently performed through TokenProvider.validateTokenForAuthority()
  • No security bypasses or inconsistent JWT extraction implementations were found
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Check for other JWT extraction implementations that might bypass security checks

# Search for JWT-related token extractions
echo "Searching for JWT token extractions..."
rg -l "getHeader.*Authorization|getCookie.*jwt" --type java

# Search for SecurityContextHolder usage
echo "Searching for SecurityContextHolder usage..."
rg -l "SecurityContextHolder" --type java

# Search for TokenProvider usage
echo "Searching for TokenProvider usage..."
ast-grep --pattern 'class $_ {
  $$$
  $x: TokenProvider
  $$$
}'

Length of output: 3337


Script:

#!/bin/bash
# Check for actual JWT token extraction implementations
echo "Checking JWT extraction implementations..."
rg -A 5 "getHeader\(\"Authorization\"\)|getCookie.*jwt" --type java

# Check for other security filter implementations
echo "Checking security filter implementations..."
rg -l "extends.*Filter|implements.*Filter" --type java

# Check for TokenProvider usage in authentication context
echo "Checking TokenProvider authentication usage..."
rg -B 2 -A 5 "TokenProvider.*authenticate|validateToken" --type java

Length of output: 18577

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 5

🧹 Outside diff range and nitpick comments (1)
src/main/java/de/tum/cit/aet/artemis/core/security/jwt/JWTFilter.java (1)

38-44: Add logging for authentication failures

When authentication fails due to multiple authentication methods being used, the error is silently handled. Consider adding logging to track security-related issues.

 try {
     jwtToken = extractValidJwt(httpServletRequest, this.tokenProvider);
 }
 catch (IllegalArgumentException e) {
+    log.warn("Authentication failed: {}", e.getMessage());
     httpServletResponse.sendError(HttpServletResponse.SC_BAD_REQUEST);
     return;
 }
📜 Review details

Configuration used: .coderabbit.yaml
Review profile: CHILL

📥 Commits

Reviewing files that changed from the base of the PR and between 8df1a6b and 9ca745b.

📒 Files selected for processing (3)
  • src/main/java/de/tum/cit/aet/artemis/core/config/websocket/WebsocketConfiguration.java (2 hunks)
  • src/main/java/de/tum/cit/aet/artemis/core/security/jwt/JWTFilter.java (2 hunks)
  • src/main/java/de/tum/cit/aet/artemis/core/security/jwt/TokenProvider.java (1 hunks)
🧰 Additional context used
📓 Path-based instructions (3)
src/main/java/de/tum/cit/aet/artemis/core/config/websocket/WebsocketConfiguration.java (1)

Pattern src/main/java/**/*.java: naming:CamelCase; principles:{single_responsibility,small_methods,no_duplication}; db:{perf_queries,datetime_not_timestamp}; rest:{stateless,singleton,delegate_logic,http_only,minimal_dtos}; dtos:{java_records,no_entities,min_data,single_resp}; di:constructor_injection; kiss:simple_code; file_handling:os_indep_paths; practices:{least_access,avoid_transactions,code_reuse,static_member_ref,prefer_primitives}; sql:{param_annotation,uppercase,avoid_subqueries};java:avoid_star_imports

src/main/java/de/tum/cit/aet/artemis/core/security/jwt/JWTFilter.java (1)

Pattern src/main/java/**/*.java: naming:CamelCase; principles:{single_responsibility,small_methods,no_duplication}; db:{perf_queries,datetime_not_timestamp}; rest:{stateless,singleton,delegate_logic,http_only,minimal_dtos}; dtos:{java_records,no_entities,min_data,single_resp}; di:constructor_injection; kiss:simple_code; file_handling:os_indep_paths; practices:{least_access,avoid_transactions,code_reuse,static_member_ref,prefer_primitives}; sql:{param_annotation,uppercase,avoid_subqueries};java:avoid_star_imports

src/main/java/de/tum/cit/aet/artemis/core/security/jwt/TokenProvider.java (1)

Pattern src/main/java/**/*.java: naming:CamelCase; principles:{single_responsibility,small_methods,no_duplication}; db:{perf_queries,datetime_not_timestamp}; rest:{stateless,singleton,delegate_logic,http_only,minimal_dtos}; dtos:{java_records,no_entities,min_data,single_resp}; di:constructor_injection; kiss:simple_code; file_handling:os_indep_paths; practices:{least_access,avoid_transactions,code_reuse,static_member_ref,prefer_primitives}; sql:{param_annotation,uppercase,avoid_subqueries};java:avoid_star_imports

🔇 Additional comments (5)
src/main/java/de/tum/cit/aet/artemis/core/security/jwt/JWTFilter.java (1)

117-119: Verify consistent token validation across the codebase

Let's ensure that the token validation logic is consistently applied across all authentication points.

✅ Verification successful

Let me gather more specific information about the token validation implementation to ensure consistency.


Based on the verification results, I can now provide a final response:

Token validation implementation is consistent and well-tested

The token validation is properly implemented through a single, centralized method validateTokenForAuthority in the TokenProvider class, which is consistently used across the codebase. The implementation:

  • Handles all validation cases (malformed, expired, unsupported tokens)
  • Is thoroughly tested with comprehensive test coverage
  • Includes security metrics for monitoring invalid tokens
  • Is properly integrated with both cookie and bearer token authentication in JWTFilter
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Check for consistent token validation across the codebase

# Find all files that might handle JWT validation
echo "Searching for JWT validation patterns..."
rg -l "validateToken|getAuthentication|SecurityContextHolder" --type java

# Check for potential JWT handling without proper validation
echo "Checking for potential JWT handling without validation..."
ast-grep --pattern 'getHeader("Authorization")' --lang java

# Look for other JWT cookie handling
echo "Checking for other JWT cookie handling..."
rg -A 3 "getCookie.*jwt" --type java

Length of output: 6961


Script:

#!/bin/bash
# Check token validation implementation details

# Look for validateTokenForAuthority implementation
echo "Checking TokenProvider validation implementation..."
rg -A 10 "validateTokenForAuthority" --type java

# Check for other token validation methods
echo "Checking other validation methods..."
rg -A 5 "validateToken" --type java

# Look for JWT filter usage
echo "Checking JWT filter configuration..."
ast-grep --pattern 'extends SecurityConfigurerAdapter<DefaultSecurityFilterChain, HttpSecurity>' --lang java

Length of output: 25403

src/main/java/de/tum/cit/aet/artemis/core/security/jwt/TokenProvider.java (2)

173-176: Security review: Implementation maintains security standards.

The new getClaim method:

  • Correctly reuses the secure parseClaims method which validates the token signature
  • Maintains existing security measures and error tracking
  • Doesn't introduce new security vulnerabilities

173-176: Verify integration with bearer token handling.

Let's verify how this new method integrates with the bearer token authentication flow.

✅ Verification successful

Let me gather more information about the JWT validation flow and the actual usage of the new method.


Let me check one more aspect to understand the JWT authentication flow and the usage of claims.


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

The new getClaim method is properly integrated with the bearer token authentication flow

The implementation is correctly positioned within the JWT authentication flow:

  • The JWTFilter properly extracts bearer tokens from the Authorization header
  • Token validation is handled through validateTokenForAuthority method
  • The new getClaim method complements the existing claims extraction functionality, where claims.get() is already used for authority claims

The changes align well with the PR's objective to support bearer authentication for the VSCode plugin, as evidenced by:

  • Presence of VSCode-related configurations in the codebase
  • Proper bearer token extraction in JWTFilter
  • Flexible claim extraction capability through the new method
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Check usage of getClaim method in JWT validation flow
# and integration with bearer token handling

# Check for JWT extraction from Authorization header
rg -l "Authorization.*Bearer" src/

# Check for usage of getClaim method
ast-grep --pattern 'getClaim($_, $_, $_)'

# Check for WebSocket security configuration
fd -e java -e kt --full-path "websocket.*config"

Length of output: 989


Script:

#!/bin/bash
# Check JWT filter implementation and token validation
rg -A 5 "class JWTFilter" src/
rg -A 10 "resolveToken" src/

# Check WebSocket security configuration for JWT usage
cat src/main/java/de/tum/cit/aet/artemis/core/config/websocket/WebsocketSecurityConfiguration.java

# Look for other potential JWT claim extractions
rg "claims\.get\(" src/

Length of output: 3255


Script:

#!/bin/bash
# Check the TokenProvider implementation for authentication flow
rg -A 10 "validateToken|authenticate" src/main/java/de/tum/cit/aet/artemis/core/security/jwt/

# Look for bearer token extraction
rg -A 5 "Bearer" src/main/java/de/tum/cit/aet/artemis/core/security/jwt/

# Check for any VSCode plugin related configurations or endpoints
fd vscode src/
rg -l "vscode|VSCode" src/

Length of output: 4458

src/main/java/de/tum/cit/aet/artemis/core/config/websocket/WebsocketConfiguration.java (2)

30-30: LGTM: Import added for HTTP status codes.

The addition of HttpStatusCode import is appropriate for the new error handling.


205-205: Verify JWT validation implementation across the codebase.

The JWT validation has been moved to JWTFilter.extractValidJwt, which is a good centralization of authentication logic. Let's verify the implementation and test coverage.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Outside diff range and nitpick comments (2)
src/main/java/de/tum/cit/aet/artemis/core/security/jwt/JWTFilter.java (2)

65-85: Add security audit logging

For security-critical operations, it's important to log authentication attempts and failures. This helps with security auditing and troubleshooting.

Apply this diff to add logging:

+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;

 public class JWTFilter extends GenericFilterBean {
+    private static final Logger logger = LoggerFactory.getLogger(JWTFilter.class);

     public static @Nullable String extractValidJwt(HttpServletRequest httpServletRequest, TokenProvider tokenProvider) {
         var cookie = WebUtils.getCookie(httpServletRequest, JWT_COOKIE_NAME);
         var authHeader = httpServletRequest.getHeader(AUTHORIZATION_HEADER);
 
         if (cookie == null && authHeader == null) {
+            logger.debug("No authentication token found in request");
             return null;
         }
 
         if (cookie != null && authHeader != null) {
+            logger.warn("Multiple authentication methods detected in request from IP: {}", httpServletRequest.getRemoteAddr());
             throw new IllegalArgumentException("Multiple authentication methods detected: Both JWT cookie and Bearer token are present");
         }
 
         String jwtToken = cookie != null ? getJwtFromCookie(cookie) : getJwtFromBearer(authHeader);
 
         if (!isJwtValid(tokenProvider, jwtToken)) {
+            logger.warn("Invalid authentication token detected from IP: {}", httpServletRequest.getRemoteAddr());
             return null;
         }
 
+        logger.debug("Valid authentication token processed");
         return jwtToken;
     }

Security concern: JWT tokens are being logged

There are two instances where JWT tokens are being logged, which could potentially expose sensitive authentication information:

  1. In TokenProvider.java:
log.info("Invalid JWT token: {}", authToken);
  1. In PublicLtiResource.java:
log.info("LTI request: JWT token is invalid: {}", token, e);

These logging statements should be modified to:

  • Remove the actual token value from the log message
  • Use appropriate log levels (e.g., debug for invalid tokens)
  • Only log non-sensitive metadata if needed for debugging
🔗 Analysis chain

Line range hint 1-124: Verify token logging practices

Let's ensure that JWT tokens are not being logged anywhere in the codebase to prevent security risks.


Let me analyze the search results carefully. I notice two instances of token logging in the codebase:

  1. In TokenProvider.java:
log.info("Invalid JWT token: {}", authToken);
  1. In PublicLtiResource.java:
log.info("LTI request: JWT token is invalid: {}", token, e);

Let me verify if these are the only instances and check their context.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Check for potential JWT token logging
# Expected results: No instances of logging JWT tokens should be found

echo "Checking for potential JWT token logging..."

# Search for logging statements that might contain JWT tokens
rg -i "log\.(debug|info|warn|error).*jwt.*token|bearer" --type java

# Search for debug print statements that might expose tokens
rg -i "system\.out\.print.*jwt.*token|bearer" --type java

echo "Note: Review any matches carefully to ensure tokens are not being logged"

Length of output: 10227


Script:

#!/bin/bash
# Get more context around the logging statements
echo "Context for TokenProvider.java logging:"
rg -B 5 -A 5 'log\.info.*Invalid JWT token' --type java

echo -e "\nContext for PublicLtiResource.java logging:"
rg -B 5 -A 5 'LTI request: JWT token is invalid' --type java

Length of output: 2808

📜 Review details

Configuration used: .coderabbit.yaml
Review profile: CHILL

📥 Commits

Reviewing files that changed from the base of the PR and between 9ca745b and 3e93d8c.

📒 Files selected for processing (1)
  • src/main/java/de/tum/cit/aet/artemis/core/security/jwt/JWTFilter.java (3 hunks)
🧰 Additional context used
📓 Path-based instructions (1)
src/main/java/de/tum/cit/aet/artemis/core/security/jwt/JWTFilter.java (1)

Pattern src/main/java/**/*.java: naming:CamelCase; principles:{single_responsibility,small_methods,no_duplication}; db:{perf_queries,datetime_not_timestamp}; rest:{stateless,singleton,delegate_logic,http_only,minimal_dtos}; dtos:{java_records,no_entities,min_data,single_resp}; di:constructor_injection; kiss:simple_code; file_handling:os_indep_paths; practices:{least_access,avoid_transactions,code_reuse,static_member_ref,prefer_primitives}; sql:{param_annotation,uppercase,avoid_subqueries};java:avoid_star_imports

🔇 Additional comments (1)
src/main/java/de/tum/cit/aet/artemis/core/security/jwt/JWTFilter.java (1)

50-53: ⚠️ Potential issue

Clear SecurityContext when JWT is invalid

When no valid JWT is found, the SecurityContext should be explicitly cleared to prevent any potential security issues from previous authentications.

Apply this diff to improve security:

 if (jwtToken != null) {
     Authentication authentication = this.tokenProvider.getAuthentication(jwtToken);
     SecurityContextHolder.getContext().setAuthentication(authentication);
+} else {
+    SecurityContextHolder.clearContext();
 }

Likely invalid or redundant comment.

Copy link
Contributor

@muradium muradium left a comment

Choose a reason for hiding this comment

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

Tested on TS9 by sending requests using Postman. Token is received correctly, and you can't use token and authentication header together as expected.

Copy link
Contributor

@SimonEntholzer SimonEntholzer left a comment

Choose a reason for hiding this comment

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

Tested with postman on Ts9. Works as described. Code lgtm to me too

Copy link
Contributor

@iyannsch iyannsch left a comment

Choose a reason for hiding this comment

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

Reapprove after merge

Copy link
Contributor

@az108 az108 left a comment

Choose a reason for hiding this comment

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

Code reapprove

Copy link
Contributor

@kaancayli kaancayli left a comment

Choose a reason for hiding this comment

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

reapprove

@iyannsch iyannsch requested a review from Mtze November 29, 2024 09:16
@Mtze Mtze added the maintainer-approved The feature maintainer has approved the PR label Nov 29, 2024
Copy link

@magkue magkue left a comment

Choose a reason for hiding this comment

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

Code approve

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
core Pull requests that affect the corresponding module maintainer-approved The feature maintainer has approved the PR ready to merge server Pull requests that update Java code. (Added Automatically!) tests
Projects
Status: Maintainer Approved
Development

Successfully merging this pull request may close these issues.