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(KL-183): logout #69

Merged
merged 4 commits into from
Oct 4, 2024

Conversation

ohhamma
Copy link
Contributor

@ohhamma ohhamma commented Oct 4, 2024

πŸ“Œ μ—°κ΄€λœ 이슈

πŸ“ μž‘μ—… λ‚΄μš©

  • λ‘œκ·Έμ•„μ›ƒ μ„€μ • (토큰 인증 κ³Όμ • ν•„μš”)
  • λ‘œκ·Έμ•„μ›ƒ μ‹œ 토큰 μ‚­μ œ 및 κ΄€λ ¨ μΏ ν‚€ μ‚­μ œ

🌳 μž‘μ—… 브랜치λͺ…

  • KL-183/λ‘œκ·Έμ•„μ›ƒ-κ΅¬ν˜„

πŸ“Έ μŠ€ν¬λ¦°μƒ· (선택)

πŸ’¬ 리뷰 μš”κ΅¬μ‚¬ν•­ (선택)

Summary by CodeRabbit

  • New Features

    • Introduced methods to delete tokens by name and update token details.
    • Added custom logout functionality, enhancing user session management.
    • Implemented access token handling via cookies for improved security.
  • Bug Fixes

    • Streamlined token resolution process, enhancing authentication reliability.
  • Documentation

    • Updated security configurations for logout operations, improving clarity and organization.

@ohhamma ohhamma added the ✨ Feature μƒˆλ‘œμš΄ κΈ°λŠ₯ 개발 및 μš”μ²­ label Oct 4, 2024
@ohhamma ohhamma requested review from idealflower-k and min3m October 4, 2024 10:03
@ohhamma ohhamma self-assigned this Oct 4, 2024
Copy link

coderabbitai bot commented Oct 4, 2024

Important

Review skipped

Auto reviews are disabled on base/target branches other than the default branch.

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

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

Walkthrough

The changes involve enhancements to the token management functionality within the application. A new method for deleting tokens by name has been added to both the TokenRepository and TokenService interfaces. The TokenServiceImpl class introduces methods for updating and deleting tokens, with transactional behavior applied. Two new classes, CustomLogoutHandler and CustomLogoutSuccessHandler, are introduced to manage logout processes. The SecurityConfig class is updated to configure custom logout handling, and the TokenUtil class adds methods for handling access tokens via cookies.

Changes

File Path Change Summary
src/main/java/taco/klkl/domain/token/dao/TokenRepository.java - Added method: void deleteByName(final String name)
src/main/java/taco/klkl/domain/token/service/TokenService.java - Added method: void deleteToken(final String name)
src/main/java/taco/klkl/domain/token/service/TokenServiceImpl.java - Added methods: public void updateToken(final String accessToken, final Token token), public void deleteToken(final String name)
- Added @Transactional annotation to updateToken and deleteToken methods
src/main/java/taco/klkl/global/config/security/CustomLogoutHandler.java - Added class: CustomLogoutHandler
- Added method: void logout(HttpServletRequest request, HttpServletResponse response, Authentication authentication)
src/main/java/taco/klkl/global/config/security/CustomLogoutSuccessHandler.java - Added class: CustomLogoutSuccessHandler
- Added method: void onLogoutSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication)
src/main/java/taco/klkl/global/config/security/SecurityConfig.java - Added fields: private final CustomLogoutHandler customLogoutHandler, private final CustomLogoutSuccessHandler customLogoutSuccessHandler
- Updated logout configuration and filter chain method
src/main/java/taco/klkl/global/config/security/SecurityEndpoint.java - Updated USER_ROLE to include new matcher: new AntPathRequestMatcher("/v1/logout/**")
src/main/java/taco/klkl/global/config/security/TokenAuthenticationFilter.java - Updated method signature: private void setAuthentication(final String accessToken)
- Removed method: private String resolveToken(HttpServletRequest request)
src/main/java/taco/klkl/global/util/TokenUtil.java - Added methods: public String resolveToken(HttpServletRequest request), public void clearAccessTokenCookie(HttpServletResponse response)

Poem

In the garden of code, where tokens play,
New methods sprout, brightening the day.
With a hop and a skip, we clear and we save,
Custom logouts now dance, oh how they behave!
In the realm of security, we twirl and we spin,
Deleting old tokens, let the freshness begin! πŸ‡βœ¨


Thank you for using CodeRabbit. We offer it for free to the OSS community and would appreciate your support in helping us grow. If you find it useful, would you consider giving us a shout-out on your favorite social media?

❀️ Share
πŸͺ§ Tips

Chat

There are 3 ways to chat with CodeRabbit:

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

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

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

Other keywords and placeholders

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

CodeRabbit Configuration File (.coderabbit.yaml)

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

Documentation and Community

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

@ohhamma
Copy link
Contributor Author

ohhamma commented Oct 4, 2024

@coderabbitai review

Copy link

coderabbitai bot commented Oct 4, 2024

βœ… Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

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

🧹 Outside diff range and nitpick comments (11)
src/main/java/taco/klkl/domain/token/service/TokenService.java (2)

13-13: LGTM! Consider adding a Javadoc comment.

The new deleteToken method is well-aligned with the PR objectives for implementing the logout feature. The method signature is consistent with Java conventions and other methods in the interface.

To improve documentation, consider adding a Javadoc comment for the new method. Here's a suggested implementation:

/**
 * Deletes the token associated with the given name.
 *
 * @param name the name of the token to be deleted
 */
void deleteToken(final String name);

Line range hint 1-13: Consider adding a token refresh method and clarify cookie management responsibility.

The TokenService interface provides a good set of basic operations for token management. However, there are two points to consider:

  1. Token Refresh: Given that both refresh and access tokens are handled in the saveOrUpdate method, it might be beneficial to add a dedicated method for refreshing tokens. This is a common operation in token-based authentication systems.

  2. Cookie Management: The PR objectives mention deleting tokens and related cookies upon logout. However, there's no explicit mention of cookie management in this interface. It would be helpful to clarify whether cookie management is the responsibility of this service or if it's handled elsewhere.

Here's a suggestion for adding a refresh method:

/**
 * Refreshes the access token using the provided refresh token.
 *
 * @param refreshToken the refresh token
 * @return the new access token
 */
String refreshToken(final String refreshToken);

Regarding cookie management, if it's meant to be handled by this service, consider adding methods for it. If not, it might be worth documenting where that responsibility lies.

src/main/java/taco/klkl/domain/token/dao/TokenRepository.java (1)

16-17: LGTM! Consider adding documentation and additional methods.

The deleteByName method is a good addition that aligns well with the PR objective of implementing logout functionality. It follows Spring Data JPA naming conventions and is consistent with the existing findByName method.

To further improve the interface, consider the following suggestions:

  1. Add Javadoc to document the method's purpose and parameters.
  2. For consistency, you might want to add a deleteByAccessToken method as well.
  3. If useful for your use case, consider adding a method that returns a boolean indicating whether a deletion occurred (e.g., boolean deleteByName(final String name)).
src/main/java/taco/klkl/global/config/security/CustomLogoutHandler.java (1)

18-27: LGTM with suggestions: Logout method implementation is correct but could be enhanced.

The logout method correctly overrides the LogoutHandler interface and implements the token deletion logic. Good use of null checking and pattern matching for instanceof.

Suggestions for improvement:

  1. Consider logging when the authentication is null or not an instance of UserDetails.
  2. You might want to use the request or response objects, e.g., for clearing cookies or adding headers.

Here's a potential enhancement:

 @Override
 public void logout(
   HttpServletRequest request,
   HttpServletResponse response,
   Authentication authentication
 ) {
   if (authentication != null && authentication.getPrincipal() instanceof UserDetails userDetails) {
     tokenService.deleteToken(userDetails.getUsername());
+    // Clear any relevant cookies
+    // For example: response.addCookie(new Cookie("auth_cookie", null));
+  } else {
+    // Log the unexpected scenario
+    // logger.warn("Logout attempted with invalid authentication");
   }
 }
src/main/java/taco/klkl/global/config/security/CustomLogoutSuccessHandler.java (2)

14-16: LGTM: Class declaration and annotations are appropriate.

The class name and annotations are well-chosen. Implementing LogoutSuccessHandler is correct for customizing logout behavior.

Consider adding a brief Javadoc comment to describe the purpose of this class, which can be helpful for future maintainers. For example:

/**
 * Custom implementation of LogoutSuccessHandler to manage the logout process.
 * This handler clears the access token cookie and sets the appropriate response status.
 */
@Component
@RequiredArgsConstructor
public class CustomLogoutSuccessHandler implements LogoutSuccessHandler {
    // ... rest of the class
}

1-30: Summary: Implementation successfully addresses the logout feature (KL-183).

The CustomLogoutSuccessHandler class effectively implements the logout functionality as described in the PR objectives. It handles token authentication by clearing the access token cookie upon logout, which aligns with the requirement to delete tokens and related cookies.

Key points:

  1. The class is well-structured and follows Spring best practices.
  2. The logout process is correctly implemented, clearing the access token and setting the appropriate response status.
  3. The implementation is concise and focused on the core logout functionality.

While the implementation is solid, consider the suggestions in the previous comments for minor improvements in documentation and error handling.

To further enhance the logout process, consider implementing these additional security measures:

  1. Invalidate the user's session on the server-side if you're using server-side sessions.
  2. If you're using refresh tokens, ensure they are also invalidated during the logout process.
  3. Consider implementing CSRF protection for the logout endpoint if not already in place.

These measures will provide a more robust and secure logout mechanism.

src/main/java/taco/klkl/global/util/TokenUtil.java (3)

17-24: LGTM: Well-implemented token resolution method.

The resolveToken method is efficiently implemented using Java 8+ features. It safely handles null cookies and correctly retrieves the access token.

Suggestions for minor improvements:

  1. Consider adding a comment explaining the significance of a null return value.
  2. Adding debug logging could be beneficial for troubleshooting.

Example:

public String resolveToken(HttpServletRequest request) {
    String token = Optional.ofNullable(request.getCookies())
        .flatMap(cookies -> Arrays.stream(cookies)
            .filter(cookie -> ACCESS_TOKEN.equals(cookie.getName()))
            .findFirst()
            .map(Cookie::getValue))
        .orElse(null);
    
    // Log for debugging (consider using a logging framework)
    System.out.println("Resolved token: " + (token != null ? "found" : "not found"));
    
    return token; // Returns null if the access token cookie is not present
}

36-42: LGTM with suggestions: Access token cookie clearing method.

The clearAccessTokenCookie method effectively clears the access token cookie. However, there are a few security enhancements that could be made:

  1. Set the Secure flag to true to ensure the cookie is only transmitted over HTTPS.
  2. Add the SameSite attribute, as it's present in the addAccessTokenCookie method.
  3. Consider adding debug logging for troubleshooting.

Here's an improved version:

public void clearAccessTokenCookie(HttpServletResponse response) {
    Cookie cookie = new Cookie(ACCESS_TOKEN, null);
    cookie.setPath("/");
    cookie.setHttpOnly(true);
    cookie.setSecure(true); // Ensure cookie is only sent over HTTPS
    cookie.setMaxAge(0);
    cookie.setAttribute("SameSite", "Strict"); // Add SameSite attribute
    response.addCookie(cookie);
    
    // Log for debugging (consider using a logging framework)
    System.out.println("Access token cookie cleared");
}

These changes will enhance the security of the cookie clearing process and maintain consistency with the addAccessTokenCookie method.


Line range hint 1-43: Good overall structure with room for documentation improvement.

The TokenUtil class is well-structured and follows the Single Responsibility Principle by focusing on token-related operations. The new methods complement the existing addAccessTokenCookie method, providing a comprehensive set of token utilities.

Suggestions for improvement:

  1. Add class-level JavaDoc to explain the purpose and usage of the TokenUtil class.
  2. Ensure consistent error handling across all methods (e.g., logging or throwing exceptions).

Example of class-level JavaDoc:

/**
 * Utility class for handling access token operations via cookies.
 * This class provides methods to add, resolve, and clear access token cookies.
 * It is designed to work with HTTP requests and responses in a web application context.
 */
@Component
public class TokenUtil {
    // ... existing methods ...
}

Consider implementing consistent error handling and logging across all methods to improve maintainability and debugging capabilities.

src/main/java/taco/klkl/domain/token/service/TokenServiceImpl.java (1)

Line range hint 1-50: Consider adding logging statements for critical operations.

The overall structure of the class is well-organized and follows Spring best practices. However, to improve observability and debugging, consider adding logging statements for critical operations such as token updates and deletions.

Here's an example of how you might add logging:

 @Override
 @Transactional
 public Token updateToken(final String accessToken, final Token token) {
     if (token == null) {
         throw new IllegalArgumentException("Token cannot be null");
     }
     token.update(token.getRefreshToken(), accessToken);
+    log.info("Token updated for name: {}", token.getName());
     return token;
 }

 @Override
 @Transactional
 public boolean deleteToken(final String name) {
     if (tokenRepository.existsByName(name)) {
         tokenRepository.deleteByName(name);
+        log.info("Token deleted for name: {}", name);
         return true;
     }
+    log.warn("Attempt to delete non-existent token with name: {}", name);
     return false;
 }

These logging statements will provide valuable information for monitoring and troubleshooting the application.

src/main/java/taco/klkl/global/config/security/TokenAuthenticationFilter.java (1)

ResolveToken Method Removal is Incomplete

The resolveToken method is still being used in TokenAuthenticationFilter.java, indicating that it has not been fully removed. Please review and ensure that all usages are addressed before proceeding with its removal.

πŸ”— Analysis chain

Line range hint 1-74: Verify the impact of changes on the codebase

The changes made to this class, including the removal of the resolveToken method and the adjustment of import statements, contribute to a more streamlined and better-organized TokenAuthenticationFilter. To ensure these changes don't have unintended consequences, it would be beneficial to verify their impact on the rest of the codebase.

Run the following script to check for any remaining references to the removed resolveToken method and to verify the usage of TokenUtil:

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Check for references to the removed resolveToken method and verify TokenUtil usage

# Test 1: Search for any remaining references to resolveToken method
echo "Checking for references to resolveToken method:"
rg --type java "resolveToken\(" --glob "!src/main/java/taco/klkl/global/config/security/TokenAuthenticationFilter.java"

# Test 2: Verify the usage of TokenUtil in other files
echo "Verifying TokenUtil usage:"
rg --type java "tokenUtil\.resolveToken\("

# Test 3: Check for any unused imports related to the changes
echo "Checking for potentially unused imports:"
rg --type java "^import.*\.(Optional|ACCESS_TOKEN);"

Length of output: 2157

πŸ“œ Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

πŸ“₯ Commits

Files that changed from the base of the PR and between 6c8946a and b5ca77e.

πŸ“’ Files selected for processing (9)
  • src/main/java/taco/klkl/domain/token/dao/TokenRepository.java (1 hunks)
  • src/main/java/taco/klkl/domain/token/service/TokenService.java (1 hunks)
  • src/main/java/taco/klkl/domain/token/service/TokenServiceImpl.java (1 hunks)
  • src/main/java/taco/klkl/global/config/security/CustomLogoutHandler.java (1 hunks)
  • src/main/java/taco/klkl/global/config/security/CustomLogoutSuccessHandler.java (1 hunks)
  • src/main/java/taco/klkl/global/config/security/SecurityConfig.java (3 hunks)
  • src/main/java/taco/klkl/global/config/security/SecurityEndpoint.java (1 hunks)
  • src/main/java/taco/klkl/global/config/security/TokenAuthenticationFilter.java (2 hunks)
  • src/main/java/taco/klkl/global/util/TokenUtil.java (2 hunks)
πŸ”‡ Additional comments (15)
src/main/java/taco/klkl/global/config/security/CustomLogoutHandler.java (4)

3-10: LGTM: Imports are appropriate and concise.

The imports cover all necessary classes for implementing a custom logout handler, including Jakarta Servlet, Spring Security, Lombok, and the custom TokenService. No unused imports are present.


12-14: LGTM: Class declaration and annotations are well-structured.

The CustomLogoutHandler class is properly annotated with @Component for Spring bean management and @RequiredArgsConstructor for dependency injection. Implementing the LogoutHandler interface is correct for providing custom logout functionality.


16-16: LGTM: Dependency declaration is correct.

The TokenService dependency is properly declared as private final, which, combined with @RequiredArgsConstructor, ensures proper dependency injection and immutability.


1-28: Overall, the CustomLogoutHandler implementation is well-designed and aligns with the PR objectives.

The class correctly implements the LogoutHandler interface, providing a custom logout functionality that deletes the user's token upon logout. The code is well-structured, follows Spring best practices, and uses modern Java features.

A few minor enhancements could be considered:

  1. Adding logging for edge cases.
  2. Utilizing the request and response objects for additional logout-related actions if needed.

These suggestions are optional and don't impact the core functionality of the logout process.

src/main/java/taco/klkl/global/config/security/CustomLogoutSuccessHandler.java (3)

1-13: LGTM: Package declaration and imports are appropriate.

The package structure and imports are well-organized and relevant to the class's purpose. The use of Jakarta EE (Jakarta Servlet) indicates this is a modern Java EE application.


18-18: LGTM: Field declaration looks good.

The use of a final field with constructor injection (via @RequiredArgsConstructor) is a good practice for dependency management.

Let's verify the TokenUtil class to ensure it has the necessary methods:


20-29: LGTM: Method implementation looks good, with some suggestions.

The onLogoutSuccess method correctly implements the logout process by clearing the access token and setting the appropriate response status.

Consider the following suggestions:

  1. Add a log statement to record successful logouts, which can be useful for auditing and debugging.
  2. Consider wrapping the response.getWriter().flush() in a try-catch block to handle potential IOException.

The request and authentication parameters are unused. Let's verify if this is intentional or if there are any security implications:

If no results are found, it's likely that not using these parameters is standard in your application's security setup. However, if other implementations are found that use these parameters, consider whether similar logic should be applied here.

src/main/java/taco/klkl/global/util/TokenUtil.java (1)

5-13: LGTM: Import statements are correctly updated.

The new import statements for HttpServletRequest, Arrays, and Optional are appropriately added to support the new methods in the class.

src/main/java/taco/klkl/global/config/security/SecurityEndpoint.java (1)

44-44: LGTM! Verify logout flow for edge cases.

The addition of the "/v1/logout/**" matcher to the USER_ROLE is consistent with the existing security configuration and ensures that only authenticated users can access the logout endpoint. This is a good security practice.

To ensure the logout functionality works as expected, please verify the following:

  1. An authenticated user can successfully log out.
  2. A logged-out user cannot access the logout endpoint again.
  3. The behavior is consistent across different browsers and devices.

Consider adding appropriate error handling for cases where an unauthenticated user attempts to access the logout endpoint.

src/main/java/taco/klkl/global/config/security/TokenAuthenticationFilter.java (2)

Line range hint 48-58: Improved token resolution process

The replacement of the resolveToken method with tokenUtil.resolveToken(request) is a positive change. It simplifies the code and improves separation of concerns by delegating token resolution to a dedicated utility class. This modification enhances code organization without altering the overall behavior of the method.


71-74: Improved method signature with final modifier

The addition of the final modifier to the accessToken parameter in the setAuthentication method is a good practice. It clearly indicates that the accessToken should not be modified within the method, improving code readability and helping to prevent accidental modifications. This change enhances code quality without affecting the method's functionality.

src/main/java/taco/klkl/global/config/security/SecurityConfig.java (4)

41-42: Fields added for custom logout handlers are correctly declared

The customLogoutHandler and customLogoutSuccessHandler fields are properly added as final and will be injected via constructor injection thanks to the @RequiredArgsConstructor annotation.


76-77: Session management is correctly configured as stateless

Setting the session management policy to SessionCreationPolicy.STATELESS is appropriate for applications that use token-based authentication like JWT, ensuring that the server does not maintain session state.


101-107: Logout configuration is properly implemented

The logout functionality is correctly configured with the custom logout handler and success handler. Setting the logoutUrl to /v1/logout and permitting all users to access it is standard practice to allow users to log out without additional authentication.


101-107: Verify that the custom handlers are properly defined and registered

Ensure that CustomLogoutHandler and CustomLogoutSuccessHandler are properly implemented as beans and manage the necessary logout logic, such as invalidating tokens and clearing cookies.

Run the following script to confirm that the custom handlers are defined in the codebase:

@ohhamma ohhamma merged commit 65d3381 into develop Oct 4, 2024
2 checks passed
@ohhamma ohhamma deleted the KL-183/λ‘œκ·Έμ•„μ›ƒ-κ΅¬ν˜„ branch October 4, 2024 10:21
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
✨ Feature μƒˆλ‘œμš΄ κΈ°λŠ₯ 개발 및 μš”μ²­
Projects
None yet
Development

Successfully merging this pull request may close these issues.

1 participant