Skip to content

Conversation

@Gyuhyeok99
Copy link
Contributor

@Gyuhyeok99 Gyuhyeok99 commented Mar 7, 2025

User description

관련 이슈

작업 내용

지원서 전체 현황 조회 API에 관리자(ADMIN) 전용 접근 제한 기능을 구현했습니다.

  1. @RequireAdminAccess 어노테이션 생성
  • 관리자 전용 API에 적용할 수 있는 커스텀 어노테이션
  1. AOP를 활용한 권한 검사 로직 구현
  • 메소드 파라미터에서 SiteUser 객체를 자동으로 찾아 권한 검사
  • ADMIN 역할이 아닌 경우 예외 발생

특이 사항

현재는 관리자(ADMIN) 전용 API만 구분하도록 간단하게 구현하였는데 추후에 멘토 등의 복잡한 구분이 생기게 될 때 좀 더 범용적인 역할 기반 접근 제어로 확장해야할 거 같습니다.

리뷰 요구사항 (선택)

  • 제가 AOP를 실제 적용해보는 건 사실 처음이라 부족한 부분 말씀해주시면 좀 더 공부해서 반영해보겠습니다
  • 어노테이션 이름을 RequireAdminAccess로 지었는데 괜찮나요?

PR Type

Enhancement, Tests


Description

  • Added @RequireAdminAccess annotation for admin-only API access.

  • Implemented AOP-based admin authorization logic.

  • Restricted access to application overview API to admins.

  • Added unit tests for admin authorization aspect.


Changes walkthrough 📝

Relevant files
Enhancement
ApplicationController.java
Restrict application overview API to admins                           

src/main/java/com/example/solidconnection/application/controller/ApplicationController.java

  • Added @RequireAdminAccess annotation to restrict access.
  • Applied annotation to the getApplicants method.
  • +2/-0     
    RequireAdminAccess.java
    Add custom annotation for admin access                                     

    src/main/java/com/example/solidconnection/custom/security/annotation/RequireAdminAccess.java

  • Created custom annotation @RequireAdminAccess.
  • Defined it for method-level access control.
  • +11/-0   
    AdminAuthorizationAspect.java
    Implement AOP-based admin authorization logic                       

    src/main/java/com/example/solidconnection/custom/security/aspect/AdminAuthorizationAspect.java

  • Implemented AOP aspect for admin access control.
  • Validates SiteUser role as ADMIN.
  • Throws exception for unauthorized access.
  • +35/-0   
    Tests
    AdminAuthorizationAspectTest.java
    Add tests for admin authorization aspect                                 

    src/test/java/com/example/solidconnection/custom/security/aspect/AdminAuthorizationAspectTest.java

  • Added unit tests for admin access control aspect.
  • Verified behavior for admin and non-admin users.
  • Tested unrestricted access for non-annotated methods.
  • +99/-0   

    Need help?
  • Type /help how to ... in the comments thread for any questions about Qodo Merge usage.
  • Check out the documentation for more information.
  • Summary by CodeRabbit

    • New Features
      • Enhanced security measures now require administrative privileges to access certain sensitive features, ensuring that only authorized admin users can perform these operations.

    @Gyuhyeok99 Gyuhyeok99 requested review from nayonsoso and wibaek March 7, 2025 03:37
    @Gyuhyeok99 Gyuhyeok99 self-assigned this Mar 7, 2025
    @coderabbitai
    Copy link

    coderabbitai bot commented Mar 7, 2025

    Walkthrough

    The changes implement an admin access control mechanism within the application. A new annotation @RequireAdminAccess is introduced to mark methods as restricted to admin users. An aspect, AdminAuthorizationAspect, intercepts calls to annotated methods and validates the user's role, throwing an exception if the user lacks admin privileges. Additionally, tests have been added to verify that admin users have access while non-admin users are denied access. These updates ensure that methods requiring administrative permission enforce proper security checks at runtime.

    Changes

    File(s) Change Summary
    src/.../ApplicationController.java Added @RequireAdminAccess annotation to getApplicants method to restrict access to admin users.
    src/.../RequireAdminAccess.java
    src/.../AdminAuthorizationAspect.java
    Introduced a new annotation @RequireAdminAccess and a corresponding Spring Aspect AdminAuthorizationAspect that intercepts annotated methods, checks for a SiteUser with the ADMIN role, and enforces access control.
    src/test/.../AdminAuthorizationAspectTest.java Added tests to validate that admin-restricted methods are accessible to users with ADMIN roles and inaccessible to non-admins, including verifying expected exception responses for unauthorized access.

    Sequence Diagram(s)

    sequenceDiagram
        participant Client
        participant Controller as ApplicationController
        participant Aspect as AdminAuthorizationAspect
        participant User as SiteUser
    
        Client->>Controller: Call getApplicants()
        Controller->>Aspect: Intercept method (@RequireAdminAccess)
        Aspect->>User: Retrieve and check user role
        alt User role is ADMIN
            Aspect->>Controller: Proceed with method execution
            Controller->>Client: Return ApplicationsResponse
        else User role is NOT ADMIN
            Aspect->>Controller: Throw CustomException (ACCESS_DENIED)
            Controller->>Client: Return error response
        end
    
    Loading

    Poem

    I hopped through code with agile grace,
    Adding checks to secure our place.
    With annotations and aspects weaving the flow,
    Admin rights ensure the system's glow.
    In every line, a hop of cheer,
    CodeRabbit leads—our path is clear!

    ✨ Finishing Touches
    • 📝 Generate Docstrings

    Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

    ❤️ 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 generate docstrings to generate docstrings for this 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.

    @qodo-code-review
    Copy link

    Qodo Merge was enabled for this repository. To continue using it, please link your Git account with your Qodo account here.

    PR Reviewer Guide 🔍

    Here are some key observations to aid the review process:

    🎫 Ticket compliance analysis ✅

    253 - PR Code Verified

    Compliant requirements:

    • 지원서 전체 현황은 관리자(어드민)만 볼 수 있도록 변경

    Requires further human verification:

    • 일반 사용자는 본인이 지원한 학교만 확인 가능하도록 함 (PR에서는 관리자 접근 제한만 구현되었고, 일반 사용자의 본인 지원 학교만 확인하는 기능은 확인할 수 없음)

    ⏱️ Estimated effort to review: 2 🔵🔵⚪⚪⚪
    🧪 PR contains tests
    🔒 No security concerns identified
    ⚡ Recommended focus areas for review

    Null User Handling

    The aspect checks if siteUser is null but doesn't verify if this is expected. Consider if a more specific error message would be appropriate when no user is found versus when a non-admin user attempts access.

    if (siteUser == null || !ADMIN.equals(siteUser.getRole())) {
        throw new CustomException(ACCESS_DENIED);
    Type Safety

    The aspect searches for SiteUser by type without considering parameter names. This could lead to unexpected behavior if multiple SiteUser parameters exist in a method signature.

    for (Object arg : joinPoint.getArgs()) {
        if (arg instanceof SiteUser) {
            siteUser = (SiteUser) arg;
            break;
        }

    @qodo-code-review
    Copy link

    Qodo Merge was enabled for this repository. To continue using it, please link your Git account with your Qodo account here.

    PR Code Suggestions ✨

    Explore these optional code suggestions:

    CategorySuggestion                                                                                                                                    Impact
    Security
    Fix multiple user handling

    The aspect doesn't handle the case where multiple SiteUser arguments might be
    present in the method. It will only check the first one it finds, which could
    lead to incorrect authorization decisions.

    src/main/java/com/example/solidconnection/custom/security/aspect/AdminAuthorizationAspect.java [20-34]

     @Around("@annotation(requireAdminAccess)")
     public Object checkAdminAccess(ProceedingJoinPoint joinPoint,
                                    RequireAdminAccess requireAdminAccess) throws Throwable {
         SiteUser siteUser = null;
         for (Object arg : joinPoint.getArgs()) {
             if (arg instanceof SiteUser) {
                 siteUser = (SiteUser) arg;
    -            break;
    +            if (ADMIN.equals(siteUser.getRole())) {
    +                return joinPoint.proceed();
    +            }
             }
         }
    -    if (siteUser == null || !ADMIN.equals(siteUser.getRole())) {
    -        throw new CustomException(ACCESS_DENIED);
    -    }
    -    return joinPoint.proceed();
    +    throw new CustomException(ACCESS_DENIED);
     }
    • Apply this suggestion
    Suggestion importance[1-10]: 3

    __

    Why: The suggestion addresses a potential security issue where the aspect might not properly handle methods with multiple SiteUser arguments. However, this is a low-probability edge case as most methods would typically have only one authenticated user parameter, as shown in the controller examples.

    Low
    • More

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

    🧹 Nitpick comments (5)
    src/main/java/com/example/solidconnection/custom/security/annotation/RequireAdminAccess.java (1)

    8-11: Consider making the annotation future-proof by supporting multiple roles.
    Although this annotation name is descriptive for the current use case (ADMIN access), you may want to add optional metadata or rename it in the future if you introduce more roles (e.g., MENTOR). This ensures extensibility without introducing additional annotations or rewriting existing logic.

    src/main/java/com/example/solidconnection/application/controller/ApplicationController.java (1)

    42-42: Evaluate redundancy between AOP-based access check and validateSiteUserCanViewApplicants.
    You are already restricting this endpoint to admin users via the @RequireAdminAccess aspect. Calling applicationQueryService.validateSiteUserCanViewApplicants may be redundant unless it includes extra logic beyond pure admin role validation. Consider consolidating or removing duplicate checks to avoid confusion.

    src/main/java/com/example/solidconnection/custom/security/aspect/AdminAuthorizationAspect.java (2)

    15-19: Good use of Spring AOP and dependency injection.
    Annotating this class with @Aspect, @Component, and @RequiredArgsConstructor cleanly ties it into the Spring ecosystem. If your role-based needs grow, consider exploring advanced Spring Security features to keep your authorization logic centralized and maintainable.


    20-34: Consider expanding role checks and adding logging.
    The loop neatly retrieves the first SiteUser argument, but if multiple user objects exist, only the first is checked. You might also add a log entry when access is granted or denied, to aid in troubleshooting. Future expansions might account for multiple roles or a more granular permission system if needed.

    src/test/java/com/example/solidconnection/custom/security/aspect/AdminAuthorizationAspectTest.java (1)

    28-64: Consider adding a test for null user scenario.

    The current tests cover admin and non-admin user scenarios, but there's no test for how the aspect handles a null SiteUser parameter. Consider adding a test case to verify the behavior when a null user is passed to an admin-only method.

    @Test
    void 사용자가_null인_경우_어드민_전용_메소드에_접근하면_예외_응답을_반환한다() {
        // given
        SiteUser nullUser = null;
    
        // when & then
        assertThatCode(() -> testService.adminOnlyMethod(nullUser))
                .isInstanceOf(CustomException.class)
                .hasMessage(ACCESS_DENIED.getMessage());
    }
    📜 Review details

    Configuration used: CodeRabbit UI
    Review profile: CHILL
    Plan: Pro

    📥 Commits

    Reviewing files that changed from the base of the PR and between 90cee69 and 1f9546f.

    📒 Files selected for processing (4)
    • src/main/java/com/example/solidconnection/application/controller/ApplicationController.java (2 hunks)
    • src/main/java/com/example/solidconnection/custom/security/annotation/RequireAdminAccess.java (1 hunks)
    • src/main/java/com/example/solidconnection/custom/security/aspect/AdminAuthorizationAspect.java (1 hunks)
    • src/test/java/com/example/solidconnection/custom/security/aspect/AdminAuthorizationAspectTest.java (1 hunks)
    🔇 Additional comments (4)
    src/main/java/com/example/solidconnection/application/controller/ApplicationController.java (1)

    9-9: No concerns with this import.
    This is a standard import statement, so there’s nothing special to address.

    src/test/java/com/example/solidconnection/custom/security/aspect/AdminAuthorizationAspectTest.java (3)

    21-64: Well-structured test cases with good coverage of authorization scenarios.

    The test class effectively verifies the admin authorization aspect with three key test cases:

    1. Admin users can access admin-only methods
    2. Non-admin users receive an access denied exception when attempting to access admin-only methods
    3. Methods without the RequireAdminAccess annotation are accessible to all users

    The Given-When-Then structure makes the tests clear and readable.


    66-76: Good utility method for test user creation.

    This helper method cleanly encapsulates the creation of different user types with various roles, making the test cases more concise and maintainable.


    79-98: Effective test configuration with sample service implementation.

    The test configuration and TestService implementation provide a clean way to test the aspect functionality in isolation. The contrast between annotated and non-annotated methods allows for thorough verification of the aspect's behavior.

    Copy link
    Member

    @wibaek wibaek left a comment

    Choose a reason for hiding this comment

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

    Spring AOP를 활용하여 권한 체크를 구현하셨군요! 쉽게 사용하기 좋은 접근 방식인 것 같습니다.

    기존에는 /admin 경로에 대해 Spring Security의 필터 체인을 사용하여 관리자 페이지 접근을 제한했던 것으로 알고 있습니다. 그런데 이번 방식이 도입되면서 관리자 권한 체크 방식이 두 가지로 나뉘게 되는데, 이에 대한 의견이 궁금합니다.

    저는 /admin 경로 기반 화이트리스트 방식을 유지하면서 AOP 기반의 권한 체크를 병행하는 것도 좋은 방법이라고 생각합니다. 이렇게 하면, 관리자 API들이 /admin 경로 아래에 있을 때 어노테이션을 실수로 누락하여 발생할 수 있는 문제를 사전에 방지할 수도 있고 말이죠.

    @Gyuhyeok99
    Copy link
    Contributor Author

    맞습니다! 영서님과 논의했을 때, 모든 권한을 Spring Security의 필터 체인에서만 관리하면 신규 개발자가 이에 대해 실수할 가능성이 높다고 판단했습니다. 그래서 컨트롤러 단에서 권한 체크를 할 수 있도록 AOP를 활용하여 구현하게 되었습니다.

    말씀하신 것처럼, admin 관련 api는 SecurityFilterChain에서 한 번에 관리하는 것이 적절하다고 생각했습니다. 이를 통해 어드민 API가 /admin 경로 아래에 있을 때, 어노테이션 누락 등의 실수를 방지할 수 있다는 점에서 동의합니다!

    Copy link
    Collaborator

    @nayonsoso nayonsoso left a comment

    Choose a reason for hiding this comment

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

    저는 /admin 경로 기반 화이트리스트 방식을 유지하면서 AOP 기반의 권한 체크를 병행하는 것도 좋은 방법이라고 생각합니다.

    동의합니다😊

    • AOP 기반의 권한 체크 → uri 는 유지하면서 권한만 변경
    • /admin 경로 기반 화이트리스트 방식 → uri 패턴으로도 방어해서 실수도 방지

    할 수 있으니 좋다 생각합니다.


    제가 AOP를 실제 적용해보는 건 사실 처음이라 부족한 부분 말씀해주시면 좀 더 공부해서 반영해보겠습니다

    코드도 적절히 구현하시고 테스트도 잘 작성하셨습니다!


    어노테이션 이름을 RequireAdminAccess로 지었는데 괜찮나요?

    적절하다 생각합니다👍

    @Gyuhyeok99 Gyuhyeok99 merged commit 2117baa into solid-connection:develop Mar 8, 2025
    1 check passed
    @Gyuhyeok99 Gyuhyeok99 deleted the feat/253-admin-only-application-view branch May 11, 2025 15:51
    Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

    Labels

    Projects

    None yet

    Development

    Successfully merging this pull request may close these issues.

    feat: 지원서 전체 현황 관리자만 볼 수 있게 변경

    3 participants