Skip to content

MOSU-kmc feat: 본인인증 연동 구현(이쿠죠잇!)#131

Merged
wlgns12370 merged 12 commits intodevelopfrom
feature/kmc
Jul 24, 2025
Merged

MOSU-kmc feat: 본인인증 연동 구현(이쿠죠잇!)#131
wlgns12370 merged 12 commits intodevelopfrom
feature/kmc

Conversation

@wlgns12370
Copy link
Contributor

@wlgns12370 wlgns12370 commented Jul 24, 2025

✨ 구현한 기능

  • 본인인증 연동 구현

📢 논의하고 싶은 내용

  • x

🎸 기타

  • x

Summary by CodeRabbit

  • New Features

    • Added KMC (Korea Mobile Certification) identity verification integration with new REST and MVC endpoints, services, and JSP views.
    • Introduced one-time sign-up tokens with dedicated providers and repositories for enhanced signup verification.
    • Added user ID retrieval and improved password management endpoints.
    • Implemented custom annotations and argument resolvers for refresh token handling in API requests.
  • Improvements

    • Separated account and profile registration steps in sign-up flow.
    • Enabled CORS with default settings and updated JWT token handling.
    • Refined user profile endpoints to use authenticated user details instead of explicit user IDs.
    • Updated default user roles and added new authentication-related error codes.
    • Enhanced token management by replacing legacy token services with provider-based implementations.
  • Bug Fixes

    • Fixed cookie naming inconsistencies for access and refresh tokens.
  • Documentation

    • Added detailed Swagger annotations for sign-up request fields.
  • Chores

    • Updated build configuration with new plugins and dependencies.
    • Expanded .gitignore to exclude additional directories.
    • Added Spring MVC view resolver configuration.
    • Added GitHub Actions step to clone external jar dependencies.
  • Tests

    • Added placeholder test classes for KMC service and user encoder service.

@coderabbitai
Copy link

coderabbitai bot commented Jul 24, 2025

Warning

Rate limit exceeded

@wlgns12370 has exceeded the limit for the number of commits or files that can be reviewed per hour. Please wait 7 minutes and 1 seconds before requesting another review.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

📥 Commits

Reviewing files that changed from the base of the PR and between 4953906 and bfe8dd9.

📒 Files selected for processing (2)
  • .github/workflows/docker-ci.yaml (3 hunks)
  • Dockerfile (1 hunks)

Walkthrough

This update introduces a comprehensive refactor and feature addition centered on authentication, token management, and KMC (Korea Mobile Certification) integration. It removes legacy token services, introduces provider-based token management, adds KMC verification flows with supporting controllers, services, and DTOs, and updates user role handling and profile endpoints. Several new configuration files and JSP views are added to support KMC workflows.

Changes

File(s) / Group Change Summary
.gitignore, build.gradle, application.yml, security-config.yml, src/test/resources/security-config.yml, .github/workflows/docker-ci.yaml Updated ignore patterns, build plugins/dependencies, JPA and view resolver config, security and KMC config, and added CI step to clone libs.
src/main/java/life/mosu/mosuserver/application/auth/AccessTokenService.java, DanalVerificationService.java, VerificationService.java, AuthTokenManager.java Removed legacy authentication and verification services and interfaces.
src/main/java/life/mosu/mosuserver/application/auth/AuthService.java, presentation/auth/AuthController.java, presentation/auth/AuthControllerDocs.java Refactored token reissue flow to accept refresh token as a header string, updated method signatures and imports.
src/main/java/life/mosu/mosuserver/application/auth/SignUpService.java, presentation/auth/SignUpController.java, presentation/auth/SignUpControllerDocs.java, presentation/auth/dto/SignUpAccountRequest.java, presentation/auth/dto/SignUpRequest.java Split sign-up into account and profile steps, updated DTOs and controller signatures, added Swagger annotations.
src/main/java/life/mosu/mosuserver/application/auth/PrincipalDetails.java, PrincipalDetailsService.java Minor refactors: removed Lombok getter, reformatted code.
src/main/java/life/mosu/mosuserver/application/auth/provider/AccessTokenProvider.java, AuthTokenManager.java, JwtTokenProvider.java, OneTimeTokenProvider.java, RefreshTokenProvider.java Introduced provider-based token management classes, refactored and renamed from legacy services, updated token lifecycle logic.
src/main/java/life/mosu/mosuserver/application/oauth/OAuthUserService.java, domain/user/UserRole.java Changed default OAuth user role from ROLE_PENDING to ROLE_USER, renamed enum constant for pending role.
src/main/java/life/mosu/mosuserver/domain/auth/refresh/... Moved refresh token domain classes to a new package, minor code style changes.
src/main/java/life/mosu/mosuserver/domain/auth/signup/... Introduced sign-up token domain model, repository, Redis entity, and key-value repository for one-time tokens.
src/main/java/life/mosu/mosuserver/domain/user/service/UserEncoderService.java, UserEncoderServiceTest.java Added a new domain service and a (commented-out) test for user encoding logic.
src/main/java/life/mosu/mosuserver/global/annotation/DomainService.java Added a new custom annotation for domain services.
src/main/java/life/mosu/mosuserver/global/config/KmcConfig.java, SecurityConfig.java Added KMC bean config, enabled CORS in security config.
src/main/java/life/mosu/mosuserver/global/exception/AuthenticationException.java, ErrorCode.java Added authentication exception class and new error codes for verification failures.
src/main/java/life/mosu/mosuserver/global/handler/OAuth2LoginSuccessHandler.java Updated import for new token manager location.
src/main/java/life/mosu/mosuserver/global/resolver/UserIdArgumentResolver.java Removed dependency on legacy token service, added logging.
src/main/java/life/mosu/mosuserver/infra/kmc/... Added KMC integration: REST and MVC controllers, service, cryptography manager, data mapper, DTOs, properties, event handling, and legacy support.
src/main/java/life/mosu/mosuserver/presentation/admin/annotation/RefreshTokenHeader.java, presentation/auth/resolver/RefreshTokenHeaderArgumentResolver.java Added custom annotation and argument resolver for extracting refresh token headers.
src/main/java/life/mosu/mosuserver/presentation/oauth/AccessTokenFilter.java, SignUpTokenService.java Refactored access token filter to use providers, added sign-up token validation service.
src/main/java/life/mosu/mosuserver/presentation/profile/ProfileController.java, ProfileControllerDocs.java Changed profile create/update endpoints to use authenticated principal instead of explicit user ID.
src/main/java/life/mosu/mosuserver/presentation/user/MyUserController.java, presentation/user/dto/FindIdRequest.java, FindIdResponse.java Added find-id endpoint and DTOs, reorganized user endpoints under /user/me.
src/main/webapp/WEB-INF/views/request.jsp, result.jsp, start.jsp, step1.jsp, step2.jsp Added JSP views for KMC identity verification flows.
src/test/java/life/mosu/mosuserver/infra/kmc/KmcServiceTest.java Added placeholder test for KMC service.

Sequence Diagram(s)

sequenceDiagram
    participant Client
    participant AuthController
    participant AuthService
    participant AuthTokenManager
    participant AccessTokenProvider
    participant RefreshTokenProvider

    Client->>AuthController: POST /auth/reissue (Refresh-Token header)
    AuthController->>AuthService: reissueAccessToken(refreshToken)
    AuthService->>AuthTokenManager: reissueAccessToken(refreshToken)
    AuthTokenManager->>RefreshTokenProvider: getAuthentication(refreshToken)
    RefreshTokenProvider-->>AuthTokenManager: Authentication (User)
    AuthTokenManager->>RefreshTokenProvider: invalidateToken(userId)
    AuthTokenManager->>AccessTokenProvider: generateJwtToken(user)
    AuthTokenManager->>RefreshTokenProvider: generateJwtToken(user)
    AuthTokenManager-->>AuthService: Token DTO
    AuthService-->>AuthController: Token DTO
    AuthController-->>Client: Response with new token
Loading
sequenceDiagram
    participant Client
    participant KmcAuthController
    participant KmcService
    participant KmcCryptoManager
    participant KmcEventTxService

    Client->>KmcAuthController: POST /kmc/confirm (KmcCertRequest)
    KmcAuthController->>KmcService: createCertRequest(request)
    KmcService->>KmcCryptoManager: encryptRequestData(request, certNum)
    KmcCryptoManager-->>KmcService: encryptedData
    KmcService->>KmcEventTxService: publishIssueEvent(certNum, expiration)
    KmcEventTxService-->>KmcService: (void)
    KmcService-->>KmcAuthController: KmcCertResponse
    KmcAuthController-->>Client: KmcCertResponse
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

  • mosu-dev/mosu-server#85: Both PRs modify the OAuthUserService class's user role assignment logic, indicating a direct connection in user role handling.
  • mosu-dev/mosu-server#50: Both PRs refactor token management and the AuthService/AuthTokenManager classes, directly relating to changes in authentication flows.
  • mosu-dev/mosu-server#127: Both PRs refactor the sign-up process and SignUpService class, indicating related changes in user registration flow.

Suggested labels

우선순위 중

Suggested reviewers

  • jbh010204

Poem

In the garden where code and carrots grow,
A rabbit hops where new features flow.
Tokens are minted, KMC now in play,
Providers and beans keep bugs at bay.
With JSPs and configs, the garden's in bloom—
Hop, hop, hooray! For review time looms.
🥕✨

✨ Finishing Touches
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch feature/kmc

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.
    • Explain this complex logic.
    • 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 explain this code block.
    • @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 explain its main purpose.
    • @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.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

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 generate sequence diagram to generate a sequence diagram of the changes in this PR.
  • @coderabbitai generate unit tests to generate unit tests 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.

Copy link

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

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

Summary of Changes

Hello @wlgns12370, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request primarily focuses on integrating KMC (Korea Mobile Certification) for identity verification, which is a significant new feature. This integration involves substantial changes across the application, including refactoring of existing authentication and token management services, introducing new domain and infrastructure components for KMC, and updating the user signup flow to incorporate this verification step. Additionally, there are general infrastructure updates and minor refactorings to improve code organization and maintainability.

Highlights

  • KMC Identity Verification Integration: Implemented a comprehensive system for KMC (Korea Mobile Certification) identity verification, including new controllers, services, DTOs, and a crypto manager to handle the entire verification flow.
  • Authentication and Token Management Refactoring: Revamped the JWT token management by introducing new Provider classes (e.g., AccessTokenProvider, RefreshTokenProvider, JwtTokenProvider) and a centralized AuthTokenManager, replacing older Service classes for better modularity and clarity.
  • Multi-step Signup Flow Enhancement: Modified the user signup process to support a multi-step approach, separating account creation from profile registration, and integrated a new OneTimeTokenProvider and SignUpTokenService for managing one-time verification tokens.
  • Infrastructure and Dependency Updates: Updated build.gradle to include WAR deployment, KMC SDK dependencies, JSP/Servlet support, and Testcontainers for improved testing. Also, application.yml was updated for JSP view resolution and ddl-auto setting.
  • Security Configuration Adjustments: Updated the Spring Security configuration to enable proper CORS handling and introduced a custom RefreshTokenHeader argument resolver for cleaner API design.
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point in your pull request via creating an issue comment (i.e. comment on the pull request page) using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in issue comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments or fill out our survey to provide feedback.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

Copy link

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

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

Code Review

This pull request introduces a significant new feature for identity verification with KMC. The refactoring of authentication components into providers is a great step towards a cleaner architecture. I've reviewed the changes and found several areas that need attention before this can be merged. My main concerns are around production safety, such as the use of ddl-auto: update, hardcoded URLs, and logging of sensitive data. I've also identified a couple of critical logic errors and several areas for improvement in terms of code quality and maintainability.

Comment on lines +64 to +91
private void logDecryptedData(String[] tokens) {
if (!log.isInfoEnabled()) return;

String ci = decryptCiDiValue(tokens[CI_INDEX]);
String di = decryptCiDiValue(tokens[DI_INDEX]);

log.info("[KMCIS] Parsed User Information:");
log.info(" - CertNum: {}", tokens[CERT_NUM_INDEX]);
log.info(" - Name: {}", tokens[NAME_INDEX]);
log.info(" - PhoneNo: {}", tokens[PHONE_NO_INDEX]);
log.info(" - Decrypted CI: {}", ci);
log.info(" - Decrypted DI: {}", di);
log.info(" - PlusInfo: {}", tokens[PLUS_INFO_INDEX]);

logPlusInfoDetail(tokens[PLUS_INFO_INDEX]);
}

// production 시 삭제
private void logPlusInfoDetail(String plusInfo) {
if (!StringUtils.hasText(plusInfo) || !plusInfo.contains("@")) return;

String[] parts = plusInfo.split("@", -1);
if (parts.length == 3) {
byte[] decodedBytes = new Base32().decode(parts[1]);
String decodedPassword = new String(decodedBytes);
log.info(" - Parsed PlusInfo -> loginId: {}, password(decoded): {}, term: {}", parts[0], decodedPassword, parts[2]);
}
}

Choose a reason for hiding this comment

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

critical

The methods logDecryptedData and logPlusInfoDetail are marked with comments // production 시 삭제 (delete in production). This is a very risky practice, as this code could easily be deployed to production by mistake, leading to sensitive user information (like decoded passwords) being logged. This kind of debug logging should be handled through proper mechanisms, such as using a DEBUG log level and configuring log levels per environment, or using Spring profiles to conditionally enable/disable certain beans or logic. Please remove this code before merging.

Comment on lines +25 to +27
// Redis에 토큰 정보가 없으면 유효하지 않은 것으로 간주
if (signUpToken == null) {
throw new AuthenticationException("유효하지 않은 회원가입 토큰입니다.");

Choose a reason for hiding this comment

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

critical

The if (signUpToken == null) check is unreachable code. The oneTimeTokenProvider.getSignUpToken() method calls signUpTokenRepository.findByCertNum(), which in turn throws a CustomRuntimeException if the token is not found, so it will never return null. This null check should be removed as it's dead code and can be misleading.

Comment on lines +11 to +13
public void e(String a) {
System.out.println("Encoding: " + a);
}

Choose a reason for hiding this comment

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

high

The UserEncoderService class appears to be experimental or placeholder code. The method e has a non-descriptive name and uses System.out.println, which should be avoided in favor of a proper logger. This class should be either completed with proper implementation or removed from the codebase to avoid confusion and dead code.

String cert = kmcService.createCertRequest(request).tr_cert();

model.addAttribute("tr_cert", cert);
model.addAttribute("tr_url", "http://localhost:8080/api/v1/kmc/tr-url");

Choose a reason for hiding this comment

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

high

The callback URL for KMC is hardcoded. This makes the application difficult to configure for different environments (development, staging, production). This URL should be externalized into a configuration file (e.g., application.yml) and injected via @Value or a configuration properties class.

Suggested change
model.addAttribute("tr_url", "http://localhost:8080/api/v1/kmc/tr-url");
model.addAttribute("tr_url", kmcProperties.getTrUrl()); // Assuming you add trUrl to KmcProperties

Comment on lines +23 to +25
private final WebClient webClient = WebClient.builder()
.baseUrl("https://www.kmcert.com/kmcis/api")
.build();

Choose a reason for hiding this comment

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

high

The base URL for the KMC API is hardcoded. This will cause issues when deploying to different environments or if the API endpoint changes. This URL should be moved to a configuration file (like application.yml) and injected as a property.

    private final WebClient webClient;

    public LegacyService(IcertSecuManager seed, KmcService kmcService, @Value("${kmc.api.base-url}") String kmcApiBaseUrl) {
        this.seed = seed;
        this.kmcService = kmcService;
        this.webClient = WebClient.builder()
            .baseUrl(kmcApiBaseUrl)
            .build();
    }

show-sql: true
hibernate:
ddl-auto: create-drop
ddl-auto: update

Choose a reason for hiding this comment

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

high

Using spring.jpa.hibernate.ddl-auto: update is not recommended for production environments. It can lead to an inconsistent database schema and potential data loss. The official Spring documentation warns against its use in production. Since you are using Flyway for database migrations, you should rely on it to manage the schema. I recommend changing this property to validate to ensure the Hibernate entity model is in sync with the database schema managed by Flyway, or none to let Flyway handle everything.

      ddl-auto: validate

Comment on lines +54 to +65
private Claims parseClaims(String token) {
try {
return Jwts.parserBuilder()
.setSigningKey(key)
.build()
.parseClaimsJws(token)
.getBody();
} catch (ExpiredJwtException exception) {
return exception.getClaims();
}

}

Choose a reason for hiding this comment

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

medium

The parseClaims method catches ExpiredJwtException and returns the claims, effectively hiding that the token has expired. This can lead to unexpected behavior in calling methods, as they might operate on data from an expired token. It's generally better to either let the exception propagate to be handled by the caller or to wrap it in a custom application exception. This makes the token validation logic more explicit and robust.

    private Claims parseClaims(String token) {
        return Jwts.parserBuilder()
                .setSigningKey(key)
                .build()
                .parseClaimsJws(token)
                .getBody();
    }


public enum UserRole {
ROLE_USER, ROLE_ADMIN, ROLE_PENDING;
ROLE_USER, ROLE_ADMIN, PENDING

Choose a reason for hiding this comment

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

medium

The enum constants for UserRole are named inconsistently. ROLE_USER and ROLE_ADMIN have the ROLE_ prefix, while PENDING does not. For consistency and to align with Spring Security's convention (where the ROLE_ prefix is often added automatically), it's better to apply the same naming convention to all enum constants.

Suggested change
ROLE_USER, ROLE_ADMIN, PENDING
ROLE_USER, ROLE_ADMIN, ROLE_PENDING


PrincipalDetails principal = (PrincipalDetails) authentication.getPrincipal();

log.info("principalID: {}", principal.getId());

Choose a reason for hiding this comment

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

medium

Logging a user's principal ID at the INFO level can lead to excessive and potentially sensitive data in production logs. It's better to use the DEBUG level for this kind of detailed diagnostic information.

Suggested change
log.info("principalID: {}", principal.getId());
log.debug("principalID: {}", principal.getId());

* KMC 본인인증 요청 데이터(tr_cert)를 암호화
*/
public String encryptRequestData(KmcCertRequest request, String certNum) {
String currentDate = new SimpleDateFormat("yyyyMMddHHmmss").format(new Date());

Choose a reason for hiding this comment

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

medium

SimpleDateFormat is a legacy, mutable, and not thread-safe class. It's recommended to use the modern java.time.format.DateTimeFormatter from Java 8 onwards, which is immutable and thread-safe.

Suggested change
String currentDate = new SimpleDateFormat("yyyyMMddHHmmss").format(new Date());
String currentDate = java.time.format.DateTimeFormatter.ofPattern("yyyyMMddHHmmss").format(java.time.LocalDateTime.now());

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

🔭 Outside diff range comments (1)
build.gradle (1)

105-109: Remove duplicate Testcontainers dependencies.

The Testcontainers dependencies are duplicated at the end of the file, which could lead to confusion and potential version conflicts.

- testImplementation 'org.springframework.boot:spring-boot-testcontainers:3.3.5'
- testImplementation 'org.testcontainers:testcontainers:1.19.3'
- testImplementation 'org.testcontainers:junit-jupiter:1.19.3'
- testImplementation 'org.testcontainers:mysql:1.20.0'
🧹 Nitpick comments (34)
src/main/java/life/mosu/mosuserver/domain/auth/refresh/RefreshTokenRedisEntity.java (1)

1-1: Package relocation is sensible; double-check bean scanning & Redis key naming

Moving refresh-token artifacts into auth.refresh clarifies the bounded context.
Two quick follow-ups:

  1. Ensure Spring’s component scan (if restricted with @ComponentScan(basePackages = …)) includes the new package.
  2. @RedisHash(value = "token_verification") is now slightly misleading for a refresh-token entity; consider renaming to something like "refresh_token" for clarity.
src/main/java/life/mosu/mosuserver/presentation/admin/annotation/RefreshTokenHeader.java (1)

1-13: Consider relocating to a more appropriate package.

The annotation implementation is correct, but the package location presentation.admin.annotation seems inappropriate since this annotation is used for general authentication token handling, not admin-specific functionality. Consider moving it to presentation.auth.annotation or similar.

src/main/java/life/mosu/mosuserver/domain/auth/signup/SignUpTokenRedisEntity.java (1)

18-20: Remove redundant @indexed annotation on @id field.

The certNum field is annotated with both @Id and @Indexed. The @Id annotation already makes the field unique and searchable in Redis, making the @Indexed annotation redundant and potentially confusing.

 @Id
-@Indexed
 private String certNum;
src/main/resources/security-config.yml (1)

43-45: Fix formatting issue: add newline at end of file.

The KMC configuration addition looks good and follows the established pattern of using environment variables. However, the static analysis tool correctly identified a missing newline at the end of the file.

Apply this diff to fix the formatting:

 kmc:
   cpid: ${KMC_CPID}
-  url-code: ${KMC_URLCODE}
+  url-code: ${KMC_URLCODE}
+
src/main/java/life/mosu/mosuserver/infra/kmc/dto/KmcApiRequest.java (1)

1-6: Consider adding validation and documentation for this DTO.

The record implementation is clean and follows good practices. Consider these optional enhancements:

+import jakarta.validation.constraints.NotBlank;
+
+/**
+ * DTO for KMC API request containing authentication token and date.
+ *
+ * @param apiToken the API authentication token
+ * @param apiDate the API request date
+ */
 public record KmcApiRequest(
+        @NotBlank
         String apiToken,
+        @NotBlank
         String apiDate
 ) {}
src/main/java/life/mosu/mosuserver/infra/kmc/dto/KmcCertResponse.java (1)

3-10: Consider field naming convention consistency.

The field name tr_cert uses snake_case while the factory method parameter trCert uses camelCase. If the snake_case name isn't required by an external API specification, consider using consistent camelCase naming (trCert) for better Java convention alignment.

If the snake_case is required by external API contracts, consider adding a comment explaining this requirement:

public record KmcCertResponse(
+       // Field name matches external KMC API specification
        String tr_cert
) {
src/main/java/life/mosu/mosuserver/infra/kmc/KmcProperties.java (1)

7-14: Consider validation & richer typing for properties

  1. expireTime is stored as Long, which loses time-unit semantics. Spring Boot supports java.time.Duration, making configuration like 5m, 30s, etc., self-documenting.
  2. Adding Bean Validation (@Validated, @NotBlank, @Positive) guards against misconfiguration at startup.
-import lombok.Data;
+import lombok.Data;
+import jakarta.validation.constraints.NotBlank;
+import jakarta.validation.constraints.Positive;
+import org.springframework.validation.annotation.Validated;
@@
-@Data
-@Component
-@ConfigurationProperties(prefix = "kmc")
+@Data
+@Validated
+@Component
+@ConfigurationProperties(prefix = "kmc")
 public class KmcProperties {
-    private String cpId;
-    private String urlCode;
-    private Long expireTime;
+    @NotBlank
+    private String cpId;
+
+    @NotBlank
+    private String urlCode;
+
+    @Positive
+    private Duration expireTime;
 }
src/main/java/life/mosu/mosuserver/domain/auth/signup/SignUpTokenRepository.java (1)

3-8: Return Optional to avoid nulls

Repository callers currently have to handle potential null returns. Returning Optional<SignUpToken> makes the contract explicit and eliminates ambiguity.

-    SignUpToken findByCertNum(String certNum);
+    Optional<SignUpToken> findByCertNum(String certNum);

Corresponding implementation adjustments will be trivial.

src/main/webapp/WEB-INF/views/request.jsp (1)

7-7: Consider security implications of auto-form submission.

Auto-submitting forms on page load can be problematic from both UX and security perspectives. Consider adding user confirmation or a brief delay before submission.

-<body onload="javascript:document.reqKMCISForm.submit();">
+<body onload="setTimeout(function(){ document.reqKMCISForm.submit(); }, 2000);">
src/main/java/life/mosu/mosuserver/presentation/oauth/SignUpTokenService.java (1)

25-32: Consider transaction safety for token deletion.

The token is deleted immediately after validation, which could lead to issues if the downstream processing fails. Consider whether the deletion should happen within a transaction or after successful completion of the signup process.

This depends on your business requirements - if you want strict one-time use regardless of downstream success, the current approach is fine. If you want to allow retry on processing failures, consider delaying the deletion.

src/main/java/life/mosu/mosuserver/application/auth/kmc/tx/KmcTxEventFactory.java (1)

8-14: Consider improving type safety with a more specific return type.

The implementation is correct but the return type TxEvent<?> could be more specific for better type safety.

Consider updating the return type to be more specific:

 @Override
-public TxEvent<?> create(KmcContext context) {
+public TxEvent<KmcContext> create(KmcContext context) {
     return new KmcIssueTxEvent(context.isSuccess(), context);
 }

This would provide better compile-time type checking and make the intent clearer.

src/main/java/life/mosu/mosuserver/presentation/auth/AuthController.java (1)

6-6: Consider relocating the RefreshTokenHeader annotation.

The @RefreshTokenHeader annotation is imported from the admin package but used for general authentication purposes. This seems architecturally inconsistent.

Consider moving the annotation to a more appropriate package like:

  • life.mosu.mosuserver.presentation.auth.annotation
  • life.mosu.mosuserver.global.annotation

This would better reflect its general-purpose nature rather than admin-specific usage.

src/main/java/life/mosu/mosuserver/application/auth/provider/OneTimeTokenProvider.java (1)

19-20: Consider making constants more maintainable

The token type and key are defined as static final fields, but they could be externalized to configuration for better maintainability.

Consider moving these to application properties:

-private static final String tokenType = "ONE_TIME";
-private static final String TOKEN_TYPE_KEY = "type";
+private final String tokenType;
+private final String tokenTypeKey;

public OneTimeTokenProvider(
        @Value("${jwt.access-token.expire-time}") final Long expireTime,
        @Value("${jwt.secret}") final String secretKey,
+       @Value("${jwt.one-time-token.type:ONE_TIME}") final String tokenType,
+       @Value("${jwt.one-time-token.type-key:type}") final String tokenTypeKey,
        SignUpTokenRepository signUpTokenRepository
) {
    this.expireTime = expireTime;
    this.key = Keys.hmacShaKeyFor(Decoders.BASE64.decode(secretKey));
+   this.tokenType = tokenType;
+   this.tokenTypeKey = tokenTypeKey;
    this.signUpTokenRepository = signUpTokenRepository;
}
src/test/resources/security-config.yml (3)

43-46: KMC configuration looks good, but fix the file formatting.

The KMC configuration properly uses environment variables. However, please add a newline at the end of the file as indicated by the static analysis tool.

 kmc:
   cpid: ${KMC_CPID}
   url-code: ${KMC_URLCODE}
-  expire-time: ${KMC_EXPIRE_TIME}
+  expire-time: ${KMC_EXPIRE_TIME}
+

43-46: KMC configuration looks good, but fix the formatting issue.

The KMC configuration properly uses environment variables for sensitive data. However, please add a newline character at the end of the file as indicated by the static analysis tool.

 kmc:
   cpid: ${KMC_CPID}
   url-code: ${KMC_URLCODE}
-  expire-time: ${KMC_EXPIRE_TIME}
+  expire-time: ${KMC_EXPIRE_TIME}
+

25-28: Consider local development implications of secure cookie settings.

The secure: true setting requires HTTPS, which might cause issues in local development environments. Consider using profiles or environment-specific configurations.

 server:
   servlet:
     session:
       cookie:
         http-only: true
-        secure: true
+        secure: ${COOKIE_SECURE:false}
         same-site: None
src/main/webapp/WEB-INF/views/step1.jsp (4)

1-17: Good cache control implementation, but improve code comments.

The cache control headers properly prevent caching of this sensitive form. However, consider using English comments in source code to improve accessibility and prevent potential encoding issues.


18-34: Secure random number generation, but update character encoding.

The SecureRandom implementation is correct and properly seeded. However, consider updating from EUC-KR to UTF-8 encoding for better international compatibility.

-<%@ page contentType="text/html;charset=ksc5601" %>
+<%@ page contentType="text/html;charset=UTF-8" %>

And update the meta tag:

-<meta http-equiv="Content-Type" content="text/html; charset=euc-kr">
+<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">

20-34: Secure random number generation with minor optimization opportunity.

The use of SecureRandom is appropriate for generating certification request numbers. However, explicitly setting the seed with System.currentTimeMillis() is unnecessary as SecureRandom self-seeds securely.

     java.security.SecureRandom ran = new java.security.SecureRandom();
-    ran.setSeed(System.currentTimeMillis());

130-140: Consider modernizing the form layout.

The table-based layout is functional but outdated. Consider using CSS Grid or Flexbox for better responsive design and accessibility.

src/main/webapp/WEB-INF/views/start.jsp (1)

45-51: Consider using a more robust mobile detection approach

User agent string parsing can be unreliable and requires maintenance as new devices are released. Consider using feature detection or CSS media queries instead.

-        var UserAgent = navigator.userAgent;
-        var isMobile = false;
-        if (UserAgent.match(
-                /iPhone|iPad|Android|Windows CE|BlackBerry|Symbian|Windows Phone|webOS|Opera Mini|Opera Mobi|POLARIS|IEMobile|lgtelecom|nokia|SonyEricsson/i)
-            != null || UserAgent.match(/LG|SAMSUNG|Samsung/) != null) {
-          isMobile = true;
-        }
+        // Use modern approach for mobile detection
+        var isMobile = /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent) 
+                       || window.matchMedia("(max-width: 768px)").matches;
src/main/java/life/mosu/mosuserver/infra/kmc/legacy/LegacyService.java (1)

66-66: Avoid blocking operations in reactive code

Using .block() on a reactive stream defeats the purpose of using WebClient. Consider making this method return a reactive type or use RestTemplate if synchronous behavior is required.

-                    .bodyToMono(KmcVerificationRequest.class)
-                    .block();
+                    .bodyToMono(KmcVerificationRequest.class)
+                    .block(Duration.ofSeconds(30)); // Add timeout at minimum
src/main/java/life/mosu/mosuserver/presentation/oauth/AccessTokenFilter.java (2)

61-61: Fix typo in log message

There's a typo in the log message: "oath2" should be "oauth2".

-            log.info("oath2 관련 요청: {}", request.getRequestURI());
+            log.info("oauth2 관련 요청: {}", request.getRequestURI());

51-56: Inconsistent token extraction methods

The filter uses different token extraction methods for different endpoints: bearer tokens from headers for signup endpoints and cookies for other API endpoints. This inconsistency might cause confusion. Consider documenting this behavior or standardizing the approach.

Consider implementing a unified token resolution strategy that checks both sources (header and cookie) with a clear precedence order, or clearly document why different endpoints require different token sources.

Also applies to: 66-72

src/main/java/life/mosu/mosuserver/infra/kmc/legacy/KmcMvcController.java (1)

55-63: Improve error handling with specific exceptions

The generic exception handling makes it difficult to diagnose issues. Consider catching specific exceptions and providing more detailed error information.

         try {
             // 토큰 검증 및 사용자 정보 조회 로직
             KmcUserInfo userInfo = legacyService.validateTokenAndGetResult(apiToken, apiCertNum);
             model.addAttribute("userInfo", userInfo);
             return "success"; // 성공 시 보여줄 JSP 페이지
+        } catch (CustomRuntimeException e) {
+            log.error("KMC verification failed: {}", e.getMessage());
+            model.addAttribute("errorCode", e.getErrorCode());
+            model.addAttribute("errorMessage", e.getMessage());
+            return "error";
         } catch (Exception e) {
+            log.error("Unexpected error during KMC verification", e);
             model.addAttribute("errorMessage", e.getMessage());
             return "error"; // 실패 시 보여줄 JSP 페이지
         }
src/main/java/life/mosu/mosuserver/application/auth/kmc/tx/KmcTxEventListener.java (1)

17-17: Consider removing class-level @transactional annotation.

The class-level @Transactional(propagation = Propagation.NOT_SUPPORTED) annotation may be unnecessary since transactional event listeners already execute outside the original transaction context by design.

-@Transactional(propagation = Propagation.NOT_SUPPORTED)
 public class KmcTxEventListener {
src/main/java/life/mosu/mosuserver/application/auth/provider/RefreshTokenProvider.java (2)

37-42: Consider adding input validation for user ID.

The invalidateToken method doesn't validate the input parameter, which could lead to issues with null or invalid user IDs.

 public void invalidateToken(final Long id) {
+    if (id == null || id <= 0) {
+        throw new CustomRuntimeException(ErrorCode.INVALID_USER_ID);
+    }
     if (!refreshTokenRepository.existsByUserId(id)) {
         throw new CustomRuntimeException(ErrorCode.NOT_EXIST_REFRESH_TOKEN);
     }
     refreshTokenRepository.deleteByUserId(id);
 }

44-52: Add validation for token caching parameters.

The cacheToken method should validate its parameters to prevent invalid data from being stored.

 public void cacheToken(final Long userId, final String refreshToken) {
+    if (userId == null || userId <= 0) {
+        throw new CustomRuntimeException(ErrorCode.INVALID_USER_ID);
+    }
+    if (refreshToken == null || refreshToken.trim().isEmpty()) {
+        throw new CustomRuntimeException(ErrorCode.INVALID_REFRESH_TOKEN);
+    }
     refreshTokenRepository.save(
         RefreshToken.of(
             userId,
             refreshToken,
             expireTime
         )
     );
 }
src/main/java/life/mosu/mosuserver/infra/kmc/KmcService.java (1)

28-28: Consider using a more robust certification number generation strategy.

Using UUID for certification numbers is generally good, but consider implementing collision detection or using a more deterministic approach if uniqueness is critical for your use case.

You might want to consider:

  1. Adding a retry mechanism for UUID collision (though rare)
  2. Using a cryptographically secure random generator
  3. Including timestamp-based components for better traceability
build.gradle (1)

111-115: Document the reason for forcing Apache Commons Lang version.

The resolution strategy forcing Apache Commons Lang to version 3.18.0 suggests there might be dependency conflicts. This should be documented to help future maintainers understand the reasoning.

 configurations.configureEach {
     resolutionStrategy {
+        // Force Apache Commons Lang version to resolve conflicts with [specific dependency]
         force 'org.apache.commons:commons-lang3:3.18.0'
     }
 }
src/main/java/life/mosu/mosuserver/infra/kmc/KmcAuthController.java (1)

19-26: Consider adding rate limiting for authentication endpoints.

KMC authentication endpoints should have rate limiting to prevent abuse and potential security attacks.

Consider implementing:

  1. Rate limiting annotations (e.g., @RateLimiter)
  2. Request throttling based on IP address
  3. Additional security headers for authentication endpoints
  4. CORS configuration if needed for cross-origin requests
src/main/java/life/mosu/mosuserver/presentation/profile/ProfileController.java (1)

6-6: Remove unused import for @UserId annotation

The @UserId annotation import is no longer used in this controller after refactoring to use @AuthenticationPrincipal. Consider removing this unused import.

src/main/java/life/mosu/mosuserver/infra/kmc/KmcCryptoManager.java (1)

63-65: Improve exception handling specificity

Consider creating a custom exception type for KMC-related errors instead of using generic RuntimeException. This would help with error handling at higher levels.

-        } catch (Exception e) {
-            throw new RuntimeException("KMC 인증 결과를 처리하는 중 오류가 발생했습니다.", e);
+        } catch (SecurityException e) {
+            throw e; // Re-throw security exceptions as-is
+        } catch (Exception e) {
+            throw new KmcProcessingException("KMC 인증 결과를 처리하는 중 오류가 발생했습니다.", e);
         }

You'll need to create a KmcProcessingException class extending RuntimeException.

src/main/java/life/mosu/mosuserver/domain/auth/signup/SignUpTokenRedisRepository.java (1)

15-18: Consider adding logging for better observability.

Adding debug/trace logging for save operations would help with debugging and monitoring token lifecycle in production environments.

 @Override
 public void save(SignUpToken signUpToken) {
+    log.debug("Saving sign-up token with certNum: {}", signUpToken.getCertNum());
     SignUpTokenRedisEntity entity = SignUpTokenRedisEntity.from(signUpToken);
     repository.save(entity);
 }
📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between 3b5f8d1 and d73cc38.

⛔ Files ignored due to path filters (8)
  • .DS_Store is excluded by !**/.DS_Store
  • gradle/.DS_Store is excluded by !**/.DS_Store
  • src/.DS_Store is excluded by !**/.DS_Store
  • src/main/.DS_Store is excluded by !**/.DS_Store
  • src/main/resources/.DS_Store is excluded by !**/.DS_Store
  • src/main/resources/db/.DS_Store is excluded by !**/.DS_Store
  • src/main/webapp/.DS_Store is excluded by !**/.DS_Store
  • src/main/webapp/WEB-INF/.DS_Store is excluded by !**/.DS_Store
📒 Files selected for processing (82)
  • .gitignore (1 hunks)
  • build.gradle (4 hunks)
  • src/main/java/life/mosu/mosuserver/application/auth/AccessTokenService.java (0 hunks)
  • src/main/java/life/mosu/mosuserver/application/auth/AuthService.java (2 hunks)
  • src/main/java/life/mosu/mosuserver/application/auth/AuthTokenManager.java (0 hunks)
  • src/main/java/life/mosu/mosuserver/application/auth/DanalVerificationService.java (0 hunks)
  • src/main/java/life/mosu/mosuserver/application/auth/PrincipalDetails.java (1 hunks)
  • src/main/java/life/mosu/mosuserver/application/auth/PrincipalDetailsService.java (1 hunks)
  • src/main/java/life/mosu/mosuserver/application/auth/SignUpService.java (2 hunks)
  • src/main/java/life/mosu/mosuserver/application/auth/VerificationService.java (0 hunks)
  • src/main/java/life/mosu/mosuserver/application/auth/kmc/KmcEventTxService.java (1 hunks)
  • src/main/java/life/mosu/mosuserver/application/auth/kmc/tx/KmcContext.java (1 hunks)
  • src/main/java/life/mosu/mosuserver/application/auth/kmc/tx/KmcIssueTxEvent.java (1 hunks)
  • src/main/java/life/mosu/mosuserver/application/auth/kmc/tx/KmcTxEventFactory.java (1 hunks)
  • src/main/java/life/mosu/mosuserver/application/auth/kmc/tx/KmcTxEventListener.java (1 hunks)
  • src/main/java/life/mosu/mosuserver/application/auth/kmc/tx/KmcTxFailureHandler.java (1 hunks)
  • src/main/java/life/mosu/mosuserver/application/auth/provider/AccessTokenProvider.java (1 hunks)
  • src/main/java/life/mosu/mosuserver/application/auth/provider/AuthTokenManager.java (1 hunks)
  • src/main/java/life/mosu/mosuserver/application/auth/provider/JwtTokenProvider.java (4 hunks)
  • src/main/java/life/mosu/mosuserver/application/auth/provider/OneTimeTokenProvider.java (1 hunks)
  • src/main/java/life/mosu/mosuserver/application/auth/provider/RefreshTokenProvider.java (2 hunks)
  • src/main/java/life/mosu/mosuserver/application/oauth/OAuthUserService.java (1 hunks)
  • src/main/java/life/mosu/mosuserver/application/payment/tx/PaymentTxEventListener.java (1 hunks)
  • src/main/java/life/mosu/mosuserver/application/payment/tx/PaymentTxFailureHandler.java (1 hunks)
  • src/main/java/life/mosu/mosuserver/domain/auth/refresh/RefreshToken.java (1 hunks)
  • src/main/java/life/mosu/mosuserver/domain/auth/refresh/RefreshTokenKeyValueRepository.java (1 hunks)
  • src/main/java/life/mosu/mosuserver/domain/auth/refresh/RefreshTokenRedisEntity.java (1 hunks)
  • src/main/java/life/mosu/mosuserver/domain/auth/refresh/RefreshTokenRedisRepository.java (2 hunks)
  • src/main/java/life/mosu/mosuserver/domain/auth/refresh/RefreshTokenRepository.java (1 hunks)
  • src/main/java/life/mosu/mosuserver/domain/auth/signup/SignUpToken.java (1 hunks)
  • src/main/java/life/mosu/mosuserver/domain/auth/signup/SignUpTokenKeyValueRepository.java (1 hunks)
  • src/main/java/life/mosu/mosuserver/domain/auth/signup/SignUpTokenRedisEntity.java (1 hunks)
  • src/main/java/life/mosu/mosuserver/domain/auth/signup/SignUpTokenRedisRepository.java (1 hunks)
  • src/main/java/life/mosu/mosuserver/domain/auth/signup/SignUpTokenRepository.java (1 hunks)
  • src/main/java/life/mosu/mosuserver/domain/user/UserRole.java (1 hunks)
  • src/main/java/life/mosu/mosuserver/domain/user/service/UserEncoderService.java (1 hunks)
  • src/main/java/life/mosu/mosuserver/global/annotation/DomainService.java (1 hunks)
  • src/main/java/life/mosu/mosuserver/global/config/KmcConfig.java (1 hunks)
  • src/main/java/life/mosu/mosuserver/global/config/SecurityConfig.java (2 hunks)
  • src/main/java/life/mosu/mosuserver/global/exception/AuthenticationException.java (1 hunks)
  • src/main/java/life/mosu/mosuserver/global/exception/ErrorCode.java (1 hunks)
  • src/main/java/life/mosu/mosuserver/global/handler/OAuth2LoginSuccessHandler.java (1 hunks)
  • src/main/java/life/mosu/mosuserver/global/resolver/UserIdArgumentResolver.java (3 hunks)
  • src/main/java/life/mosu/mosuserver/infra/kmc/KmcAuthController.java (1 hunks)
  • src/main/java/life/mosu/mosuserver/infra/kmc/KmcCryptoManager.java (1 hunks)
  • src/main/java/life/mosu/mosuserver/infra/kmc/KmcDataMapper.java (1 hunks)
  • src/main/java/life/mosu/mosuserver/infra/kmc/KmcProperties.java (1 hunks)
  • src/main/java/life/mosu/mosuserver/infra/kmc/KmcService.java (1 hunks)
  • src/main/java/life/mosu/mosuserver/infra/kmc/dto/KmcApiRequest.java (1 hunks)
  • src/main/java/life/mosu/mosuserver/infra/kmc/dto/KmcCertRequest.java (1 hunks)
  • src/main/java/life/mosu/mosuserver/infra/kmc/dto/KmcCertResponse.java (1 hunks)
  • src/main/java/life/mosu/mosuserver/infra/kmc/dto/KmcResultCallbackRequest.java (1 hunks)
  • src/main/java/life/mosu/mosuserver/infra/kmc/dto/KmcResultCallbackResponse.java (1 hunks)
  • src/main/java/life/mosu/mosuserver/infra/kmc/dto/KmcUserInfo.java (1 hunks)
  • src/main/java/life/mosu/mosuserver/infra/kmc/dto/KmcVerificationRequest.java (1 hunks)
  • src/main/java/life/mosu/mosuserver/infra/kmc/legacy/KmcMvcController.java (1 hunks)
  • src/main/java/life/mosu/mosuserver/infra/kmc/legacy/LegacyService.java (1 hunks)
  • src/main/java/life/mosu/mosuserver/presentation/admin/annotation/RefreshTokenHeader.java (1 hunks)
  • src/main/java/life/mosu/mosuserver/presentation/auth/AuthController.java (2 hunks)
  • src/main/java/life/mosu/mosuserver/presentation/auth/AuthControllerDocs.java (2 hunks)
  • src/main/java/life/mosu/mosuserver/presentation/auth/SignUpController.java (3 hunks)
  • src/main/java/life/mosu/mosuserver/presentation/auth/SignUpControllerDocs.java (1 hunks)
  • src/main/java/life/mosu/mosuserver/presentation/auth/dto/SignUpAccountRequest.java (2 hunks)
  • src/main/java/life/mosu/mosuserver/presentation/auth/dto/SignUpRequest.java (1 hunks)
  • src/main/java/life/mosu/mosuserver/presentation/auth/resolver/RefreshTokenHeaderArgumentResolver.java (1 hunks)
  • src/main/java/life/mosu/mosuserver/presentation/oauth/AccessTokenFilter.java (4 hunks)
  • src/main/java/life/mosu/mosuserver/presentation/oauth/SignUpTokenService.java (1 hunks)
  • src/main/java/life/mosu/mosuserver/presentation/profile/ProfileController.java (3 hunks)
  • src/main/java/life/mosu/mosuserver/presentation/profile/ProfileControllerDocs.java (3 hunks)
  • src/main/java/life/mosu/mosuserver/presentation/user/MyUserController.java (3 hunks)
  • src/main/java/life/mosu/mosuserver/presentation/user/dto/FindIdRequest.java (1 hunks)
  • src/main/java/life/mosu/mosuserver/presentation/user/dto/FindIdResponse.java (1 hunks)
  • src/main/resources/application.yml (2 hunks)
  • src/main/resources/security-config.yml (1 hunks)
  • src/main/webapp/WEB-INF/views/request.jsp (1 hunks)
  • src/main/webapp/WEB-INF/views/result.jsp (1 hunks)
  • src/main/webapp/WEB-INF/views/start.jsp (1 hunks)
  • src/main/webapp/WEB-INF/views/step1.jsp (1 hunks)
  • src/main/webapp/WEB-INF/views/step2.jsp (1 hunks)
  • src/test/java/life/mosu/mosuserver/domain/user/service/UserEncoderServiceTest.java (1 hunks)
  • src/test/java/life/mosu/mosuserver/infra/kmc/KmcServiceTest.java (1 hunks)
  • src/test/resources/security-config.yml (1 hunks)
💤 Files with no reviewable changes (4)
  • src/main/java/life/mosu/mosuserver/application/auth/AccessTokenService.java
  • src/main/java/life/mosu/mosuserver/application/auth/DanalVerificationService.java
  • src/main/java/life/mosu/mosuserver/application/auth/VerificationService.java
  • src/main/java/life/mosu/mosuserver/application/auth/AuthTokenManager.java
🧰 Additional context used
🧬 Code Graph Analysis (6)
src/main/java/life/mosu/mosuserver/application/payment/tx/PaymentTxFailureHandler.java (1)
src/main/java/life/mosu/mosuserver/global/runner/ApplicationSchoolPreWarmRunner.java (1)
  • RequiredArgsConstructor (9-19)
src/main/java/life/mosu/mosuserver/global/config/KmcConfig.java (1)
src/main/java/life/mosu/mosuserver/global/config/SecurityConfig.java (1)
  • Configuration (32-129)
src/main/java/life/mosu/mosuserver/application/auth/provider/AuthTokenManager.java (2)
src/main/java/life/mosu/mosuserver/presentation/auth/resolver/RefreshTokenHeaderArgumentResolver.java (1)
  • Component (12-32)
src/main/java/life/mosu/mosuserver/application/auth/AuthTokenManager.java (1)
  • AuthTokenManager (12-44)
src/main/java/life/mosu/mosuserver/domain/auth/signup/SignUpTokenRedisEntity.java (1)
src/main/java/life/mosu/mosuserver/domain/auth/refresh/RefreshTokenRedisEntity.java (1)
  • Getter (13-31)
src/main/java/life/mosu/mosuserver/application/auth/kmc/tx/KmcTxFailureHandler.java (1)
src/main/java/life/mosu/mosuserver/application/auth/kmc/tx/KmcTxEventListener.java (1)
  • Slf4j (14-39)
src/main/java/life/mosu/mosuserver/application/auth/kmc/tx/KmcTxEventListener.java (2)
src/main/java/life/mosu/mosuserver/application/auth/kmc/tx/KmcTxFailureHandler.java (1)
  • Slf4j (9-21)
src/main/java/life/mosu/mosuserver/application/auth/kmc/tx/KmcTxEventFactory.java (1)
  • Component (7-14)
🪛 YAMLlint (1.37.1)
src/main/resources/security-config.yml

[error] 45-45: no new line character at the end of file

(new-line-at-end-of-file)

src/test/resources/security-config.yml

[error] 46-46: no new line character at the end of file

(new-line-at-end-of-file)

🪛 GitHub Actions: Docker CI/CD
src/main/java/life/mosu/mosuserver/global/config/KmcConfig.java

[error] 2-10: Package 'com.icert.comm.secu' does not exist. Import and method return type 'IcertSecuManager' cannot be resolved.

src/main/java/life/mosu/mosuserver/infra/kmc/KmcCryptoManager.java

[error] 3-3: Package 'com.icert.comm.secu' does not exist. Import of 'IcertSecuManager' failed.


[error] 13-17: Cannot find symbol 'IcertSecuManager'. Class reference and @requiredargsconstructor annotation usage failed.

src/main/java/life/mosu/mosuserver/infra/kmc/legacy/LegacyService.java

[error] 3-3: Package 'com.icert.comm.secu' does not exist. Import of 'IcertSecuManager' failed.


[error] 18-21: Cannot find symbol 'IcertSecuManager'. Class reference and @requiredargsconstructor annotation usage failed.

🔇 Additional comments (93)
src/main/java/life/mosu/mosuserver/global/annotation/DomainService.java (1)

11-22: Well-designed custom annotation following Spring conventions.

The @DomainService annotation is properly implemented with appropriate meta-annotations and correctly delegates the value attribute to Spring's @Component using @AliasFor. This provides a semantic marker for domain services while maintaining Spring's component scanning functionality.

src/main/java/life/mosu/mosuserver/presentation/user/MyUserController.java (2)

21-21: Request mapping change looks good.

The change from /user to /user/me better reflects the user-centric nature of these endpoints and follows RESTful conventions.


45-53: Good restoration of password change functionality.

The password change method now properly returns the service response data instead of just a success message, which improves the API's usefulness.

src/main/java/life/mosu/mosuserver/application/payment/tx/PaymentTxFailureHandler.java (1)

13-16: Annotation order change looks good and keeps it consistent with other components

@Component first and Lombok second is commonly adopted in the codebase, and there are no functional side-effects.
No further action required.

src/main/java/life/mosu/mosuserver/domain/auth/refresh/RefreshTokenKeyValueRepository.java (1)

1-1: Package update acknowledged

Interface signature unchanged; only namespace adjusted. Confirm that any @EnableRedisRepositories / @EnableKeyValueRepositories annotations reference the new base package.

src/main/java/life/mosu/mosuserver/domain/auth/refresh/RefreshToken.java (1)

1-1: Domain segregation approved

The record now lives in a dedicated refresh package, improving cohesion. No code issues spotted.

src/main/java/life/mosu/mosuserver/domain/auth/refresh/RefreshTokenRepository.java (1)

1-1: Namespace shift acknowledged

Only location changed. Make sure any explicit component-scanning config or constructor injection reflects the updated package path.

.gitignore (1)

42-44: LGTM! Standard .gitignore improvements.

The changes broaden the logs ignore pattern from a specific file to the entire directory and add exclusion for the libs directory, which aligns well with the build configuration updates mentioned in the summary.

src/main/java/life/mosu/mosuserver/domain/auth/signup/SignUpToken.java (1)

3-17: Well-designed domain record.

The record implementation follows best practices with immutable data fields, clear factory methods, and appropriate conversion from the Redis entity. The design is clean and serves its purpose well as a domain model for signup tokens.

src/main/java/life/mosu/mosuserver/domain/auth/signup/SignUpTokenRedisEntity.java (1)

12-28: Well-structured Redis entity following established patterns.

The entity follows the same design pattern as RefreshTokenRedisEntity with appropriate annotations, constructor access levels, and factory method. The implementation correctly uses @TimeToLive for automatic expiration.

src/main/java/life/mosu/mosuserver/application/auth/provider/JwtTokenProvider.java (3)

1-1: Excellent refactoring to provider pattern.

The move to the provider package and making the class abstract demonstrates good separation of concerns, positioning this as a base class for specific token providers.


33-45: Improved constructor consistency.

The parameter rename from userJpaRepository to userRepository improves naming consistency and makes the constructor more readable.


53-116: Solid JWT implementation with proper security practices.

The core JWT functionality correctly implements:

  • HMAC SHA-256 signing algorithm
  • Token type validation to prevent token confusion attacks
  • Proper expiration checking
  • Appropriate exception handling for various JWT parsing scenarios

The removal of HTTP request handling methods properly separates token operations from request processing concerns.

src/main/java/life/mosu/mosuserver/global/handler/OAuth2LoginSuccessHandler.java (1)

7-7: LGTM: Import update follows package restructuring.

The import change correctly reflects the relocation of AuthTokenManager to the provider package as part of the authentication refactoring.

src/main/java/life/mosu/mosuserver/application/oauth/OAuthUserService.java (1)

63-63: No active role enforcement—default ROLE_USER change has no current impact

The codebase isn’t enforcing any role checks at the moment:

  • SecurityConfig.authorizeHttpRequests().anyRequest().permitAll()
  • All @PreAuthorize("…hasRole('…')") and .hasRole() calls are commented out
  • No controllers or service methods actively restrict access by role

As a result, switching the OAuth default from PENDING to ROLE_USER does not alter access control today. If you plan to enforce role-based access in the future, be sure to:

  • Un-comment or add requestMatchers(...).hasRole(...) rules in SecurityConfig.java
  • Re-enable @PreAuthorize (or @Secured) on protected endpoints
  • Review default assignments for all user-creation flows (e.g., OAuth vs. standard signup)
src/main/java/life/mosu/mosuserver/application/auth/PrincipalDetailsService.java (1)

21-22: LGTM: Formatting improvement.

The multi-line formatting improves readability without changing the logic.

src/main/resources/application.yml (1)

52-55: LGTM: JSP view resolver configuration is correct.

The MVC view configuration properly enables JSP rendering with the standard /WEB-INF/views/ prefix and .jsp suffix, supporting the KMC identity verification UI implementation.

src/main/java/life/mosu/mosuserver/global/config/SecurityConfig.java (1)

76-76: Verify CORS configuration for KMC integration

I couldn’t locate any KMC-related endpoints or header requirements in the codebase, so please manually confirm that:

  • The corsConfigurationSource() bean’s allowedOrigins list includes every KMC callback/origin URL.
  • allowedHeaders is restricted to only the headers KMC actually sends (e.g., Authorization, Content-Type) rather than *.
  • allowCredentials(true) is acceptable for your security posture when paired with those specific origins and headers.
src/main/java/life/mosu/mosuserver/application/auth/PrincipalDetails.java (1)

12-14: LGTM: Clean up redundant annotation and improve formatting.

The removal of the @Getter annotation is correct since record fields automatically generate getter methods, making the annotation redundant. The multi-line formatting also improves readability.

src/main/java/life/mosu/mosuserver/domain/auth/refresh/RefreshTokenRedisRepository.java (2)

1-1: LGTM: Package relocation improves domain organization.

Moving refresh token classes to a dedicated refresh package consolidates related functionality and improves code organization.


19-19: LGTM: Minor style improvement.

Removing the final modifier from the local variable improves code consistency, as final is not necessary for local variables that are only assigned once.

src/main/java/life/mosu/mosuserver/global/resolver/UserIdArgumentResolver.java (1)

8-8: LGTM: Logging capability added.

Adding the @Slf4j annotation enables logging functionality for the resolver.

src/main/java/life/mosu/mosuserver/presentation/auth/dto/SignUpAccountRequest.java (1)

23-23: LGTM: Password example update aligns with branding.

The updated password example maintains complexity requirements while using domain-specific branding.

src/main/java/life/mosu/mosuserver/application/payment/tx/PaymentTxEventListener.java (1)

13-15: LGTM: Annotation ordering improvement.

The repositioning of annotations improves consistency with other transactional event handling classes without affecting functionality.

src/main/java/life/mosu/mosuserver/domain/auth/signup/SignUpTokenKeyValueRepository.java (1)

5-7: Repository definition looks good

The interface correctly extends KeyValueRepository and will be detected automatically by Spring Data. No further action required.

src/main/java/life/mosu/mosuserver/global/exception/ErrorCode.java (1)

27-28: Error-code additions are consistent

The newly added VERIFICATION_FAILED (401) and NOT_FOUND_SIGN_UP_TOKEN (404) codes follow the existing naming and status conventions. 👍

src/main/java/life/mosu/mosuserver/application/auth/kmc/tx/KmcIssueTxEvent.java (1)

5-9: Event wrapper is minimal and correct

Extending TxEvent<KmcContext> with a passthrough constructor suffices for the current use-case; no issues spotted.

src/main/java/life/mosu/mosuserver/global/exception/AuthenticationException.java (1)

1-19: LGTM! Well-designed authentication exception class.

The implementation follows Java exception best practices with appropriate constructors and a useful loginId field for debugging authentication failures. The design is clean and focused.

src/main/webapp/WEB-INF/views/request.jsp (1)

11-15: tr_cert and tr_url are internal values – no XSS risk
Both ${tr_cert} and ${tr_url} in request.jsp are populated by your controller (see KmcMvcController.java:model.addAttribute(...)) and by the KMC crypto service (encrypted, Base64‐safe output), not from user input. They cannot be manipulated by an attacker and therefore do not introduce an XSS vector.

• tr_cert is generated and encrypted in KmcCryptoManager
• tr_url is hard-coded in KmcMvcController

If you’d like defense-in-depth, you can render them with JSTL’s <c:out escapeXml="true">, but no further validation is required here.

src/main/java/life/mosu/mosuserver/presentation/auth/SignUpControllerDocs.java (2)

14-14: Clarify the operation description.

The description mentions "step 1, step 2를 모두 받는" (receives both step 1 and step 2) but the method now uses SignUpAccountRequest, which suggests it might only handle the account creation step. Please verify this description accurately reflects the API's functionality.


7-16: LGTM! Consistent refactoring of signup flow.

The changes appropriately reflect the refactoring from SignUpRequest to SignUpAccountRequest, maintaining consistency with the broader signup flow restructuring.

src/main/java/life/mosu/mosuserver/presentation/auth/SignUpController.java (2)

23-23: LGTM! Fixed the incorrect constant name.

Good catch fixing the ACCESS_TOKEN_COOKIE_NAME from "refreshToken" to "accessToken". This constant name now correctly reflects the token type it represents.


7-34: LGTM! Consistent refactoring with signup flow changes.

The change from SignUpRequest to SignUpAccountRequest is consistent with the broader signup flow refactoring and maintains the same functionality.

src/main/java/life/mosu/mosuserver/presentation/auth/AuthControllerDocs.java (1)

22-23: LGTM: Cleaner interface design with custom annotation.

The change from HttpServletRequest to @RefreshTokenHeader String refreshToken simplifies the interface and removes unnecessary coupling to servlet API. This aligns well with the new token provider architecture.

src/main/java/life/mosu/mosuserver/presentation/auth/resolver/RefreshTokenHeaderArgumentResolver.java (1)

18-21: LGTM: Proper parameter validation.

The supportsParameter method correctly validates both the annotation presence and parameter type. This ensures the resolver only handles appropriate parameters.

src/main/java/life/mosu/mosuserver/application/auth/provider/AccessTokenProvider.java (2)

8-18: LGTM: Well-structured token provider implementation.

The class follows good design principles:

  • Clean inheritance from JwtTokenProvider
  • Proper use of constants for token type and header
  • Constructor injection with appropriate @Value annotations
  • Clear separation of concerns

13-14: Verify JWT configuration properties in your application configs

Please confirm that the following properties are declared in your configuration (e.g. src/main/resources/application.yml or application.properties) and use exactly the same names across all token providers:

  • jwt.access-token.expire-time (used by AccessTokenProvider & OneTimeTokenProvider)
  • jwt.refresh-token.expire-time (used by RefreshTokenProvider)
  • jwt.secret (used by all providers)

Ensure there are no typos or mismatches in your config files so that each @Value("${…}") reference resolves correctly at runtime.

src/main/java/life/mosu/mosuserver/presentation/auth/dto/SignUpRequest.java (1)

3-13: LGTM: Good API documentation with Swagger annotations.

The addition of @Schema annotations improves API documentation clarity. The Korean descriptions properly describe the two-step signup process:

  • Step 1: Account information (계정 정보)
  • Step 2: Profile information (프로필 정보)
src/main/webapp/WEB-INF/views/result.jsp (1)

56-56: LGTM: Functional test link for development.

The link to restart the KMC verification process is useful for testing and development purposes.

src/main/java/life/mosu/mosuserver/application/auth/AuthService.java (1)

3-3: LGTM! Import updated to use provider-based token management.

The import change aligns with the architectural refactoring from legacy token services to the new provider-based approach.

src/main/java/life/mosu/mosuserver/application/auth/SignUpService.java (3)

26-30: LGTM! Clean separation of account creation step

The refactored signUp method properly focuses on account creation and token generation, with clear transaction boundaries.


32-37: LGTM! Well-structured profile registration step

The new registerProfile method provides a clean separation of the profile creation step, with appropriate transaction management and clear delegation to the processor.


5-5: Verify new AuthTokenManager integration across services

Please confirm that all usages of the provider-based AuthTokenManager match its new API. Currently, references exist in:

  • SignUpService
    src/main/java/life/mosu/mosuserver/application/auth/SignUpService.java
    • import at line 5
    • field injection at line 22

  • AuthService
    src/main/java/life/mosu/mosuserver/application/auth/AuthService.java
    • import at line 3
    • field injection at line 23

  • OAuth2LoginSuccessHandler
    src/main/java/life/mosu/mosuserver/global/handler/OAuth2LoginSuccessHandler.java
    • import at line 7
    • field injection at line 24

Ensure each call site aligns with the methods and constructor signature defined in application/auth/provider/AuthTokenManager.java. If the interface changed (method names, parameters, return types), update these classes accordingly.

src/main/java/life/mosu/mosuserver/domain/auth/signup/SignUpTokenRedisRepository.java (8)

14-18: LGTM! Clean repository implementation.

The save method correctly converts the domain object to the Redis entity and delegates to the underlying repository.


20-26: Excellent error handling with domain-specific exception.

The method properly handles the not-found case by throwing a custom exception with a specific error code, which provides better error context than a generic exception.


28-31: Simple and appropriate delete implementation.

The delete operation correctly delegates to the underlying repository. No error handling needed as Redis delete operations are idempotent.


8-12: Clean repository implementation setup.

The class structure follows Spring Data repository patterns correctly with proper annotations and dependency injection.


14-18: Proper domain-to-entity conversion in save method.

The save method correctly converts the domain model to Redis entity before persistence, following clean architecture principles.


20-26: Appropriate exception handling and entity-to-domain conversion.

The method properly handles the case when token is not found with a descriptive custom exception and correctly converts the Redis entity back to domain model.


28-31: Straightforward delete operation.

The delete method implementation is clean and follows the expected pattern for repository delete operations.


8-32: LGTM! Clean repository implementation with proper error handling.

The implementation follows repository pattern best practices with appropriate exception handling for missing tokens. The conversion between domain objects and Redis entities is properly handled.

src/test/resources/security-config.yml (10)

1-21: Well-structured OAuth2 configuration with proper security practices.

The Kakao OAuth2 configuration correctly uses environment variables for sensitive data and follows standard OAuth2 patterns.


22-29: Good security configuration for session cookies.

The cookie settings include appropriate security flags: http-only prevents XSS attacks, secure ensures HTTPS transmission, and same-site: None allows cross-origin requests as needed.


30-36: Proper JWT configuration with environment variable usage.

JWT secrets and expiration times are correctly configured via environment variables, maintaining security best practices.


37-38: Clear endpoint configuration.

The reissue endpoint is clearly defined for token management.


40-42: Appropriate use of environment variable for target URL.

The target URL configuration follows the pattern of using environment variables for deployment-specific values.


1-20: Well-configured OAuth2 setup with proper security practices.

The Kakao OAuth2 configuration correctly uses environment variables for sensitive data and follows standard OAuth2 patterns with appropriate scopes and endpoints.


22-28: Secure session cookie configuration.

The session cookie settings follow security best practices with http-only, secure, and appropriate same-site settings for cross-origin OAuth flows.


30-35: Proper JWT configuration with environment variable usage.

The JWT configuration correctly uses environment variables for the secret and allows separate expiration times for access and refresh tokens, following JWT best practices.


37-41: Clean endpoint and target URL configuration.

The endpoint configuration is straightforward and properly uses environment variables for the target URL.


1-46: LGTM! Well-structured security configuration with proper environment variable usage.

The configuration properly externalizes sensitive values and follows security best practices for session management and OAuth2 setup.

src/main/java/life/mosu/mosuserver/presentation/profile/ProfileControllerDocs.java (8)

12-12: Appropriate imports for authentication principal injection.

The new imports support the cleaner authentication approach using Spring Security's principal injection.

Also applies to: 18-18


29-31: Excellent security improvement with authentication principal injection.

Replacing explicit userId parameters with @AuthenticationPrincipal PrincipalDetails is a significant security improvement. This ensures the user ID is derived from the authenticated session rather than potentially manipulated request parameters, and provides a cleaner API design.

Also applies to: 38-40


12-18: Improved security with authentication principal injection.

The addition of imports for PrincipalDetails and @AuthenticationPrincipal supports the security improvement of using injected authenticated user context instead of explicit user ID parameters.


29-32: Excellent security improvement in create method.

Replacing the explicit userId parameter with @AuthenticationPrincipal PrincipalDetails prevents potential parameter tampering and ensures users can only create profiles for their authenticated identity.


38-43: No action needed: getProfile is intentionally parameterized for public access

The getProfile(@RequestParam Long userId) endpoint in ProfileController.java is designed to retrieve any user’s profile by ID, whereas the create and update operations rightly restrict access to the authenticated user via @AuthenticationPrincipal. This distinction is intentional and aligns with the API’s requirements for public profile viewing versus secured profile modification.


29-32: LGTM! Improved security by using authenticated principal.

Changing from explicit userId parameter to @AuthenticationPrincipal prevents potential authorization bypasses and follows Spring Security best practices.


38-43: LGTM! Consistent with create method security improvements.

The update method correctly uses authenticated principal instead of explicit user ID parameter.


50-53: Dismiss suggestion: getProfile intentionally uses a userId query for public profile retrieval

The getProfile endpoint and its service layer both take an explicit userId and don’t reference the authenticated principal, indicating it’s designed to fetch any user’s profile by ID (not just the caller’s). No change needed.

• Controller signature (src/main/java/life/mosu/mosuserver/presentation/profile/ProfileController.java:56)
• Service implementation (src/main/java/life/mosu/mosuserver/application/profile/ProfileService.java:49)

Likely an incorrect or invalid review comment.

src/main/java/life/mosu/mosuserver/application/auth/provider/AuthTokenManager.java (9)

12-17: Excellent architectural improvement with provider pattern.

The new provider-based approach provides better separation of concerns compared to the previous service-based implementation. Clean dependency injection follows Spring best practices.


19-27: Well-structured token generation with proper caching.

The method correctly generates both tokens, caches the refresh token for later validation, and constructs the response with appropriate expiration times. The provider-based token generation is clean and maintainable.


29-42: Significant improvement in API design and testability.

The new implementation accepting a String parameter instead of HttpServletRequest is much cleaner and more testable. The token reissuance flow is correct: validates input, extracts user context, invalidates old token, and generates new token pair. The invalidateToken method name is more descriptive than the previous deleteRefreshToken.


12-17: Clean provider pattern implementation.

The refactoring to use AccessTokenProvider and RefreshTokenProvider improves separation of concerns and code organization. The move to the provider package is also architecturally sound.


19-27: Token generation logic correctly updated for provider pattern.

The method properly uses the new providers and maintains the same token generation workflow. The reference to JwtTokenProvider.BEARER_TYPE and the cacheToken method align with the provider pattern refactoring.


29-42: Excellent API improvement with cleaner method signature.

The change from HttpServletRequest to String refreshTokenString parameter is a significant improvement:

  1. Better separation of concerns - HTTP request handling is moved to the argument resolver layer
  2. More testable - No need to mock HttpServletRequest in unit tests
  3. Cleaner API - Method focus is purely on token logic

The updated method names (invalidateToken vs deleteRefreshToken) and the upfront null check also improve code clarity.


12-27: LGTM! Excellent refactoring with improved separation of concerns.

The new provider-based approach is much cleaner than the previous service-based implementation. Moving from HttpServletRequest parameter to direct token string improves testability and follows single responsibility principle.


29-42: LGTM! Improved API design with cleaner token reissuance.

The method signature change from HttpServletRequest to String refreshTokenString is a significant improvement - it separates HTTP concerns from business logic and makes the method more testable and reusable.


25-26: Verified BEARER_TYPE in JwtTokenProvider
Confirmed that JwtTokenProvider defines

protected static final String BEARER_TYPE = "Bearer";

at line 25 in
src/main/java/life/mosu/mosuserver/application/auth/provider/JwtTokenProvider.java. No further action required.

src/main/webapp/WEB-INF/views/start.jsp (1)

79-81: Incorrect review context—no XSS risk here
The controller’s GET handler for /req returns step2.jsp, not start.jsp, so the original file reference is invalid. Moreover, tr_url and tr_ver are hard-coded, and tr_cert is generated by a trusted service (not user input), so there’s no untrusted data being rendered. You can ignore the XSS sanitization warning in this case.

Likely an incorrect or invalid review comment.

src/main/java/life/mosu/mosuserver/application/auth/kmc/tx/KmcTxEventListener.java (1)

26-29: Consider security implications of logging certification numbers.

The certification number (certNum) appears to be sensitive data that is being logged at DEBUG level. Evaluate whether this could pose a security risk in production environments.

Please review your logging policy and security requirements to determine if certification numbers should be logged, masked, or excluded from logs entirely.

src/main/java/life/mosu/mosuserver/application/auth/provider/RefreshTokenProvider.java (1)

1-27: Excellent refactoring of token provider architecture.

The refactoring from service-based to provider-based architecture with clear separation of concerns is well-implemented. The use of static final constants and improved method naming (invalidateToken vs deleteRefreshToken) enhances readability and maintainability.

build.gradle (2)

5-5: Good addition of WAR plugin for JSP support.

The addition of the war plugin properly supports the new JSP views for KMC authentication flows.


28-28: No local JARs detected in libs/ – build reproducibility unaffected

I ran fd -e jar libs/ and found no JARs in the libs directory, so the fileTree inclusion has no effect today. There’s nothing to document or version. Feel free to leave this configuration as-is.

src/main/java/life/mosu/mosuserver/infra/kmc/KmcAuthController.java (1)

21-22: Good use of consistent REST mapping and component structure.

The controller follows good REST conventions with clear endpoint mapping and proper dependency injection.

src/main/java/life/mosu/mosuserver/presentation/profile/ProfileController.java (3)

34-42: Good security improvement using authenticated principal

The change from explicit user ID parameter to authenticated principal is a security improvement, ensuring users can only create profiles for themselves. The logging addition is helpful for debugging.


44-53: Consistent security improvement for profile updates

The implementation is consistent with the create method, ensuring users can only update their own profiles through authenticated principal.


55-61: Verify the intended access pattern for profile viewing

Unlike create and update methods that use authenticated principal, getProfile still accepts any user ID as a parameter. This allows viewing any user's profile. Please verify if this is the intended behavior - should profile viewing be public or restricted?

Consider adding @PreAuthorize annotation if access control is needed.

src/main/java/life/mosu/mosuserver/infra/kmc/KmcCryptoManager.java (1)

74-74: Verify the empty string parameter in decryption

The getDec method is called with an empty string as the second parameter. Please verify if this is correct according to the KMC SDK documentation. If this parameter represents an encryption key or IV, it should not be empty.

src/main/java/life/mosu/mosuserver/infra/kmc/KmcDataMapper.java (3)

13-19: LGTM! Clean dependency injection setup.

The class structure follows Spring conventions with proper dependency injection. The dependencies on KmcCryptoManager and OneTimeTokenProvider are appropriate for the KMC data mapping functionality.


21-35: Good use of constants to eliminate magic numbers.

The field index constants improve code readability and maintainability. However, I notice there's no constant defined for index 7 (jumps from GENDER_INDEX = 6 to NAME_INDEX = 8).

Could you verify if index 7 is intentionally skipped in the KMC response format? If it contains data that should be processed, consider adding a constant for it.


93-104: Well-implemented utility method with proper error handling.

This decryption utility method follows good practices:

  • Proper exception handling with fallback values
  • Appropriate logging level for failures
  • Null/empty string validation

Currently only used by the logging methods that should be removed. Consider if CI/DI values are needed for the actual business logic (user identification, deduplication, etc.) - if so, this method should remain and be integrated into the main mapping flow.

Are the decrypted CI/DI values needed for business logic like user deduplication or identification? If so, they should be included in the KmcUserInfo DTO.

src/main/webapp/WEB-INF/views/step1.jsp (2)

11-16: LGTM! Proper cache control headers for security.

The cache control headers properly prevent caching of sensitive authentication pages, which is important for security.


26-33: LGTM! Secure random number generation implementation.

Using SecureRandom with proper seeding is the correct approach for generating cryptographically secure random numbers for authentication purposes.

Comment on lines +47 to +48
public Token reissueAccessToken(final String refreshTokenHeader) {
return authTokenManager.reissueAccessToken(refreshTokenHeader);
Copy link

Choose a reason for hiding this comment

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

💡 Verification agent

🧩 Analysis chain

LGTM! Method signature improvement enhances testability and separation of concerns.

The change from HttpServletRequest to String refreshTokenHeader decouples the service layer from HTTP servlet dependencies, making the code more testable and following better architectural principles.

Verify that proper validation is implemented in the controller layer or argument resolver to ensure the refresh token string is valid before reaching this service method:


🏁 Script executed:

#!/bin/bash
# Description: Verify that RefreshTokenHeaderArgumentResolver properly validates the refresh token
# Expected: Find validation logic in the argument resolver or controller

# Search for the RefreshTokenHeaderArgumentResolver implementation
ast-grep --pattern 'class RefreshTokenHeaderArgumentResolver {
  $$$
}'

# Search for RefreshTokenHeader annotation usage and validation
rg -A 10 "@RefreshTokenHeader"

Length of output: 1347


Missing RefreshTokenHeaderArgumentResolver & validation for refreshTokenHeader

I couldn’t find any implementation of RefreshTokenHeaderArgumentResolver or validation logic for the @RefreshTokenHeader parameter. Without it, malformed or missing refresh-token values will reach the service layer unchecked.

Please add and wire up a HandlerMethodArgumentResolver (e.g. RefreshTokenHeaderArgumentResolver) that:

  • Extracts the header value
  • Verifies it’s non-null/non-blank
  • Validates its format (e.g. proper JWT structure)
  • Fails fast with a clear 4xx response on invalid input

Likely locations to update:

  • Create src/main/java/life/mosu/mosuserver/presentation/auth/RefreshTokenHeaderArgumentResolver.java implementing HandlerMethodArgumentResolver
  • Register it in your MVC configuration
  • Ensure controller method in AuthController.java relies on this resolver
🤖 Prompt for AI Agents
In src/main/java/life/mosu/mosuserver/application/auth/AuthService.java around
lines 47-48, the refreshTokenHeader parameter lacks validation and a custom
argument resolver. Create a new class RefreshTokenHeaderArgumentResolver in
src/main/java/life/mosu/mosuserver/presentation/auth/ that implements
HandlerMethodArgumentResolver to extract the refresh token header, check it is
non-null and non-blank, validate its JWT format, and throw a 4xx error on
invalid input. Register this resolver in the MVC configuration so it is used
automatically in controller methods, and update AuthController.java to use the
@RefreshTokenHeader annotation on the parameter to leverage this validation
before reaching the service layer.

Comment on lines +17 to +23
@Transactional
public void publishIssueEvent(String certNum, Long expiration) {
TxEvent<?> event = eventFactory.create(
KmcContext.ofSuccess(certNum, expiration)
);
txEventPublisher.publish(event);
}
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Add parameter validation for certification number

The method doesn't validate input parameters, which could lead to runtime issues if null or empty values are passed.

Add parameter validation:

@Transactional
public void publishIssueEvent(String certNum, Long expiration) {
+   if (certNum == null || certNum.trim().isEmpty()) {
+       throw new IllegalArgumentException("Certificate number cannot be null or empty");
+   }
+   if (expiration == null || expiration <= 0) {
+       throw new IllegalArgumentException("Expiration must be positive");
+   }
+   
    TxEvent<?> event = eventFactory.create(
            KmcContext.ofSuccess(certNum, expiration)
    );
    txEventPublisher.publish(event);
}
📝 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
@Transactional
public void publishIssueEvent(String certNum, Long expiration) {
TxEvent<?> event = eventFactory.create(
KmcContext.ofSuccess(certNum, expiration)
);
txEventPublisher.publish(event);
}
@Transactional
public void publishIssueEvent(String certNum, Long expiration) {
if (certNum == null || certNum.trim().isEmpty()) {
throw new IllegalArgumentException("Certificate number cannot be null or empty");
}
if (expiration == null || expiration <= 0) {
throw new IllegalArgumentException("Expiration must be positive");
}
TxEvent<?> event = eventFactory.create(
KmcContext.ofSuccess(certNum, expiration)
);
txEventPublisher.publish(event);
}
🤖 Prompt for AI Agents
In
src/main/java/life/mosu/mosuserver/application/auth/kmc/KmcEventTxService.java
around lines 17 to 23, the publishIssueEvent method lacks validation for the
certNum parameter. Add checks to ensure certNum is neither null nor empty before
proceeding. If validation fails, throw an appropriate exception such as
IllegalArgumentException with a clear message. This prevents runtime errors
caused by invalid input.

Comment on lines +25 to +32
@Transactional
public void publishFailureEvent(String certNum) {
TxEvent<?> event = eventFactory.create(
KmcContext.ofFailure(certNum)
);
txEventPublisher.publish(event);
}
}
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Add parameter validation for failure events

Similar to the success case, the failure event method should validate the certification number parameter.

@Transactional
public void publishFailureEvent(String certNum) {
+   if (certNum == null || certNum.trim().isEmpty()) {
+       throw new IllegalArgumentException("Certificate number cannot be null or empty");
+   }
+   
    TxEvent<?> event = eventFactory.create(
            KmcContext.ofFailure(certNum)
    );
    txEventPublisher.publish(event);
}
📝 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
@Transactional
public void publishFailureEvent(String certNum) {
TxEvent<?> event = eventFactory.create(
KmcContext.ofFailure(certNum)
);
txEventPublisher.publish(event);
}
}
@Transactional
public void publishFailureEvent(String certNum) {
if (certNum == null || certNum.trim().isEmpty()) {
throw new IllegalArgumentException("Certificate number cannot be null or empty");
}
TxEvent<?> event = eventFactory.create(
KmcContext.ofFailure(certNum)
);
txEventPublisher.publish(event);
}
}
🤖 Prompt for AI Agents
In
src/main/java/life/mosu/mosuserver/application/auth/kmc/KmcEventTxService.java
around lines 25 to 32, the publishFailureEvent method lacks validation for the
certNum parameter. Add a check at the start of the method to validate certNum
(e.g., ensure it is not null or empty) and handle invalid input appropriately,
such as throwing an IllegalArgumentException, to match the validation approach
used in the success event method.

Comment on lines +10 to +16
public static KmcContext ofSuccess(String certNum, Long expiration) {
return new KmcContext(certNum, expiration, true);
}

public static KmcContext ofFailure(String certNum) {
return new KmcContext(certNum, 0L, false);
}
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Add parameter validation to factory methods

The factory methods don't validate input parameters, which could lead to invalid contexts being created.

Add validation to factory methods:

public static KmcContext ofSuccess(String certNum, Long expiration) {
+   if (certNum == null || certNum.trim().isEmpty()) {
+       throw new IllegalArgumentException("Certificate number cannot be null or empty");
+   }
+   if (expiration == null || expiration <= 0) {
+       throw new IllegalArgumentException("Expiration must be positive");
+   }
    return new KmcContext(certNum, expiration, true);
}

public static KmcContext ofFailure(String certNum) {
+   if (certNum == null || certNum.trim().isEmpty()) {
+       throw new IllegalArgumentException("Certificate number cannot be null or empty");
+   }
    return new KmcContext(certNum, 0L, false);
}
📝 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
public static KmcContext ofSuccess(String certNum, Long expiration) {
return new KmcContext(certNum, expiration, true);
}
public static KmcContext ofFailure(String certNum) {
return new KmcContext(certNum, 0L, false);
}
public static KmcContext ofSuccess(String certNum, Long expiration) {
if (certNum == null || certNum.trim().isEmpty()) {
throw new IllegalArgumentException("Certificate number cannot be null or empty");
}
if (expiration == null || expiration <= 0) {
throw new IllegalArgumentException("Expiration must be positive");
}
return new KmcContext(certNum, expiration, true);
}
public static KmcContext ofFailure(String certNum) {
if (certNum == null || certNum.trim().isEmpty()) {
throw new IllegalArgumentException("Certificate number cannot be null or empty");
}
return new KmcContext(certNum, 0L, false);
}
🤖 Prompt for AI Agents
In src/main/java/life/mosu/mosuserver/application/auth/kmc/tx/KmcContext.java
around lines 10 to 16, the factory methods ofSuccess and ofFailure lack input
parameter validation. Add checks to ensure certNum is not null or empty, and for
ofSuccess, verify expiration is a positive value. Throw appropriate exceptions
if validations fail to prevent creation of invalid KmcContext instances.

Comment on lines +18 to +24
public SignUpToken toSignUpToken() {
return SignUpToken.of(
this.certNum,
this.expiration
);
}
}
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Consider validating success state before token conversion

The toSignUpToken method converts the context to a SignUpToken without checking if the context represents a successful operation. This could create tokens for failed KMC attempts.

Add success state validation:

public SignUpToken toSignUpToken() {
+   if (!isSuccess) {
+       throw new IllegalStateException("Cannot create SignUpToken from failed KMC context");
+   }
    return SignUpToken.of(
        this.certNum,
        this.expiration
    );
}

Committable suggestion skipped: line range outside the PR's diff.

🤖 Prompt for AI Agents
In src/main/java/life/mosu/mosuserver/application/auth/kmc/tx/KmcContext.java
around lines 18 to 24, the toSignUpToken method converts the context to a
SignUpToken without verifying if the context indicates a successful operation.
To fix this, add a check for the success state before creating the SignUpToken,
and only proceed with token creation if the context represents success;
otherwise, handle the failure case appropriately, such as throwing an exception
or returning null.

Comment on lines 126 to 129
<td align=center>�������URL</td>
<td align=left><input type="text" name="tr_url" size="41"
value="http://�����纰 ���/kmcis_web_sample_step03.jsp"></td>
</tr>
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Update hardcoded return URL placeholder.

The return URL field contains a hardcoded placeholder that should be updated to reflect the actual deployment environment.

-value="http://서비스별 도메인/kmcis_web_sample_step03.jsp"
+value="${pageContext.request.scheme}://${pageContext.request.serverName}${pageContext.request.contextPath}/api/v1/step3"

Committable suggestion skipped: line range outside the PR's diff.

🤖 Prompt for AI Agents
In src/main/webapp/WEB-INF/views/step1.jsp around lines 126 to 129, the input
field for the return URL currently has a hardcoded placeholder URL. Replace this
hardcoded URL with a dynamic value or a configuration-based URL that reflects
the actual deployment environment to ensure it works correctly across different
setups.

Comment on lines +8 to +31
function submitKmcForm() {
var KMCIS_window;
var UserAgent = navigator.userAgent;

// 모바일 기기인지 확인합니다.
if (UserAgent.match(
/iPhone|iPad|Android|Windows CE|BlackBerry|Symbian|Windows Phone|webOS|Opera Mini|Opera Mobi|POLARIS|IEMobile|lgtelecom|nokia|SonyEricsson/i)
!= null || UserAgent.match(/LG|SAMSUNG|Samsung/) != null) {
document.reqKMCISForm.target = ''; // 모바일은 현재 창에서 진행합니다.
} else {
// PC 환경에서는 팝업 창을 엽니다.
KMCIS_window = window.open('', 'KMCISWindow',
'width=425, height=550, resizable=0, scrollbars=no, status=0, titlebar=0, left=435, top=250');

if (KMCIS_window == null) {
alert("팝업이 차단되었습니다. 팝업 차단을 해제하고 다시 시도해주세요.");
return; // 팝업이 차단되면 더 이상 진행하지 않습니다.
}
document.reqKMCISForm.target = 'KMCISWindow'; // form의 타겟을 팝업창으로 설정합니다.
}

// form을 전송합니다.
document.reqKMCISForm.submit();
}
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Improve mobile detection and popup handling for better maintainability.

The current implementation has several areas for improvement:

  1. Simplify mobile detection: The current regex is overly complex and brittle:
-        if (UserAgent.match(
-                /iPhone|iPad|Android|Windows CE|BlackBerry|Symbian|Windows Phone|webOS|Opera Mini|Opera Mobi|POLARIS|IEMobile|lgtelecom|nokia|SonyEricsson/i)
-            != null || UserAgent.match(/LG|SAMSUNG|Samsung/) != null) {
+        var isMobile = /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(UserAgent);
+        if (isMobile) {
  1. Make popup dimensions responsive:
-          KMCIS_window = window.open('', 'KMCISWindow',
-              'width=425, height=550, resizable=0, scrollbars=no, status=0, titlebar=0, left=435, top=250');
+          var width = 425;
+          var height = 550;
+          var left = (screen.width - width) / 2;
+          var top = (screen.height - height) / 2;
+          KMCIS_window = window.open('', 'KMCISWindow',
+              `width=${width}, height=${height}, resizable=0, scrollbars=no, status=0, titlebar=0, left=${left}, top=${top}`);
📝 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
function submitKmcForm() {
var KMCIS_window;
var UserAgent = navigator.userAgent;
// 모바일 기기인지 확인합니다.
if (UserAgent.match(
/iPhone|iPad|Android|Windows CE|BlackBerry|Symbian|Windows Phone|webOS|Opera Mini|Opera Mobi|POLARIS|IEMobile|lgtelecom|nokia|SonyEricsson/i)
!= null || UserAgent.match(/LG|SAMSUNG|Samsung/) != null) {
document.reqKMCISForm.target = ''; // 모바일은 현재 창에서 진행합니다.
} else {
// PC 환경에서는 팝업 창을 엽니다.
KMCIS_window = window.open('', 'KMCISWindow',
'width=425, height=550, resizable=0, scrollbars=no, status=0, titlebar=0, left=435, top=250');
if (KMCIS_window == null) {
alert("팝업이 차단되었습니다. 팝업 차단을 해제하고 다시 시도해주세요.");
return; // 팝업이 차단되면 더 이상 진행하지 않습니다.
}
document.reqKMCISForm.target = 'KMCISWindow'; // form의 타겟을 팝업창으로 설정합니다.
}
// form을 전송합니다.
document.reqKMCISForm.submit();
}
function submitKmcForm() {
var KMCIS_window;
var UserAgent = navigator.userAgent;
// 모바일 기기인지 확인합니다.
var isMobile = /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(UserAgent);
if (isMobile) {
document.reqKMCISForm.target = ''; // 모바일은 현재 창에서 진행합니다.
} else {
// PC 환경에서는 팝업 창을 엽니다.
var width = 425;
var height = 550;
var left = (screen.width - width) / 2;
var top = (screen.height - height) / 2;
KMCIS_window = window.open('', 'KMCISWindow',
`width=${width}, height=${height}, resizable=0, scrollbars=no, status=0, titlebar=0, left=${left}, top=${top}`);
if (KMCIS_window == null) {
alert("팝업이 차단되었습니다. 팝업 차단을 해제하고 다시 시도해주세요.");
return; // 팝업이 차단되면 더 이상 진행하지 않습니다.
}
document.reqKMCISForm.target = 'KMCISWindow'; // form의 타겟을 팝업창으로 설정합니다.
}
// form을 전송합니다.
document.reqKMCISForm.submit();
}
🤖 Prompt for AI Agents
In src/main/webapp/WEB-INF/views/step2.jsp around lines 8 to 31, the mobile
device detection uses a complex and brittle regex, and the popup window
dimensions are fixed. Simplify mobile detection by using a more maintainable and
widely accepted method, such as checking for 'Mobi' in the user agent string.
Adjust the popup window dimensions to be responsive based on the user's screen
size instead of fixed values, calculating width, height, and position
dynamically to improve usability across different screen resolutions.

Comment on lines +37 to +42
<form name="reqKMCISForm" method="post"
action="https://www.kmcert.com/kmcis/web/kmcisReq.jsp">
<input type="hidden" name="tr_cert" value="${tr_cert}">
<input type="hidden" name="tr_url" value="${tr_url}">
<input type="hidden" name="tr_ver" value="V2">

Copy link

Choose a reason for hiding this comment

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

💡 Verification agent

❓ Verification inconclusive

Externalize the KMC URL and add security considerations.

The hardcoded external URL poses maintenance and security concerns.

  1. Externalize the KMC URL:
 <form name="reqKMCISForm" method="post"
-      action="https://www.kmcert.com/kmcis/web/kmcisReq.jsp">
+      action="${kmcCertificationUrl}">
  1. Add CSRF protection if not already handled at the framework level.

  2. Validate server-side: Ensure all hidden input values are validated on the backend before being rendered to prevent injection attacks.

Verify that proper security measures are in place:


🏁 Script executed:

#!/bin/bash
# Description: Check for KMC URL configuration and CSRF protection
# Expected: Find externalized configuration and security measures

# Search for KMC URL configuration
rg -r "kmcCertificationUrl|kmc.*url" --type java

# Check for CSRF protection configuration
rg -r "csrf|CSRF" --type java -A 5

Length of output: 881


🏁 Script executed:

#!/bin/bash
set -e

# Search for an externalized KMC URL in properties, YAML, or Java configuration
rg -n -e "kmcCertificationUrl" -t properties -t yml -t java

# Search for CSRF protection setup in Java or XML (e.g., Spring Security)
rg -n -e "csrf" -t java -t xml

Length of output: 103


Externalize the KMC URL & Add CSRF Protection

The JSP still contains a hard-coded external endpoint and no visible CSRF token. Please:

  • Move the KMC endpoint into a config (e.g. application.properties or web.xml), and reference it in the JSP:
     <form name="reqKMCISForm" method="post"
    -      action="https://www.kmcert.com/kmcis/web/kmcisReq.jsp">
    +      action="${kmcCertificationUrl}">
  • Inject a CSRF token into every form (assuming Spring Security, for example):
     <input type="hidden" name="tr_ver" value="V2">
    +<input type="hidden" name="${_csrf.parameterName}" value="${_csrf.token}">
  • On the backend, validate all incoming parameters (tr_cert, tr_url, tr_ver) to guard against tampering.
📝 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
<form name="reqKMCISForm" method="post"
action="https://www.kmcert.com/kmcis/web/kmcisReq.jsp">
<input type="hidden" name="tr_cert" value="${tr_cert}">
<input type="hidden" name="tr_url" value="${tr_url}">
<input type="hidden" name="tr_ver" value="V2">
<form name="reqKMCISForm" method="post"
action="${kmcCertificationUrl}">
<input type="hidden" name="tr_cert" value="${tr_cert}">
<input type="hidden" name="tr_url" value="${tr_url}">
<input type="hidden" name="tr_ver" value="V2">
<input type="hidden" name="${_csrf.parameterName}" value="${_csrf.token}">
🤖 Prompt for AI Agents
In src/main/webapp/WEB-INF/views/step2.jsp around lines 37 to 42, the form
action URL is hard-coded and lacks CSRF protection. Move the KMC endpoint URL
into a configuration file like application.properties or web.xml, then reference
this config property in the JSP to avoid hardcoding. Add a CSRF token input
field to the form, using the framework's standard method (e.g., Spring
Security's CSRF token tag or expression). Additionally, ensure the backend
controller validates all incoming parameters (tr_cert, tr_url, tr_ver) to
prevent tampering.

Comment on lines +1 to +19
//package life.mosu.mosuserver.domain.user.service;
//
//import static org.junit.jupiter.api.Assertions.*;
//
//import lombok.RequiredArgsConstructor;
//import org.junit.jupiter.api.Test;
//import org.springframework.beans.factory.annotation.Autowired;
//
//@RequiredArgsConstructor(onConstructor_ = @Autowired)
//class UserEncoderServiceTest {
//
//
// private UserEncoderService userEncoderService;
//
// @Test
// void e() {
// userEncoderService.e("awef");
// }
//} No newline at end of file
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

Remove commented-out placeholder test code.

This entire test class is commented out and contains no meaningful test logic. Commented-out code should not be committed to the repository as it adds noise and maintenance overhead.

Consider either:

  1. Remove this file entirely if the service doesn't need testing yet
  2. Implement a proper test with assertions and Spring Boot test annotations

If you choose to implement the test, use this structure:

-//package life.mosu.mosuserver.domain.user.service;
-//
-//import static org.junit.jupiter.api.Assertions.*;
-//
-//import lombok.RequiredArgsConstructor;
-//import org.junit.jupiter.api.Test;
-//import org.springframework.beans.factory.annotation.Autowired;
-//
-//@RequiredArgsConstructor(onConstructor_ = @Autowired)
-//class UserEncoderServiceTest {
-//
-//
-//    private UserEncoderService userEncoderService;
-//
-//    @Test
-//    void e() {
-//        userEncoderService.e("awef");
-//    }
-//}
+package life.mosu.mosuserver.domain.user.service;
+
+import org.junit.jupiter.api.Test;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.context.SpringBootTest;
+
+@SpringBootTest
+class UserEncoderServiceTest {
+
+    @Autowired
+    private UserEncoderService userEncoderService;
+
+    @Test
+    void shouldEncodeString() {
+        // Add meaningful test assertions here
+        userEncoderService.e("test");
+        // Assert expected behavior
+    }
+}
📝 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
//package life.mosu.mosuserver.domain.user.service;
//
//import static org.junit.jupiter.api.Assertions.*;
//
//import lombok.RequiredArgsConstructor;
//import org.junit.jupiter.api.Test;
//import org.springframework.beans.factory.annotation.Autowired;
//
//@RequiredArgsConstructor(onConstructor_ = @Autowired)
//class UserEncoderServiceTest {
//
//
// private UserEncoderService userEncoderService;
//
// @Test
// void e() {
// userEncoderService.e("awef");
// }
//}
package life.mosu.mosuserver.domain.user.service;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
@SpringBootTest
class UserEncoderServiceTest {
@Autowired
private UserEncoderService userEncoderService;
@Test
void shouldEncodeString() {
// Add meaningful test assertions here
userEncoderService.e("test");
// e.g. assertThat(...).isEqualTo(...)
}
}
🤖 Prompt for AI Agents
In
src/test/java/life/mosu/mosuserver/domain/user/service/UserEncoderServiceTest.java
lines 1 to 19, the entire test class is commented out and contains no meaningful
test logic. Remove this commented-out placeholder test code entirely to avoid
clutter in the repository. If testing is needed, either delete this file or
create a proper test class with valid test methods, assertions, and necessary
Spring Boot test annotations.

Comment on lines +7 to +14
class KmcServiceTest {

@Test
@DisplayName("KMC 본인인증 요청 데이터 생성 테스트")
void encryptTrCert() {
Assertions.assertEquals(1, 1);
}
} No newline at end of file
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Implement meaningful test logic for KMC identity verification.

This placeholder test with a trivial assertion (Assertions.assertEquals(1, 1)) needs proper implementation to test KMC identity verification request data generation as indicated by the method name and display name.

Would you like me to help generate proper test implementation based on the KMC service functionality, or should this be tracked as a separate task?

🤖 Prompt for AI Agents
In src/test/java/life/mosu/mosuserver/infra/kmc/KmcServiceTest.java around lines
7 to 14, the test method encryptTrCert currently contains only a trivial
assertion and lacks meaningful test logic. Replace the placeholder assertion
with actual test code that verifies the correct generation of KMC identity
verification request data, using relevant inputs and asserting expected outputs
based on the KMC service's functionality.

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.

Review continued from previous batch...

Comment on lines +43 to +47
implementation 'javax.servlet:jstl:1.2'
implementation "org.apache.tomcat.embed:tomcat-embed-jasper"

// swagger
implementation "org.springdoc:springdoc-openapi-starter-webmvc-ui:2.7.0"
implementation "org.springdoc:springdoc-openapi-starter-webmvc-ui:2.8.9"
Copy link

Choose a reason for hiding this comment

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

💡 Verification agent

🧩 Analysis chain

Verify JSP dependency versions for security.

The JSP and servlet dependencies should be checked for known security vulnerabilities, especially since they're handling user authentication flows.


🌐 Web query:

Are there any known security vulnerabilities in javax.servlet:jstl:1.2 and org.apache.tomcat.embed:tomcat-embed-jasper for Spring Boot 3.4.5?

💡 Result:

There are known security vulnerabilities affecting both javax.servlet:jstl:1.2 and, indirectly, some versions of org.apache.tomcat.embed:tomcat-embed-jasper, which you should consider when using them with Spring Boot 3.4.5.

javax.servlet:jstl:1.2

  • This version is affected by a security vulnerability (notably, XXE and Remote Code Execution via XSLT extension) that allows processing of external entities in untrusted XML documents, posing a risk of information disclosure or arbitrary code execution[4][1][7].
  • The vulnerability applies to Standard Taglib up to version 1.2.1 (javax.servlet:jstl:1.2 is affected)[4].
  • Remediation: Use a newer, compatible taglib implementation, such as org.apache.taglibs:taglibs-standard-impl:1.2.5, or jakarta equivalents, as suggested in multiple security advisories[4]. JSTL 1.2 is outdated and not considered secure for modern deployments.

org.apache.tomcat.embed:tomcat-embed-jasper

  • This artifact is a part of the embedded Tomcat used in Spring Boot for JSP/Servlet processing.
  • Recent security disclosures, such as CVE-2025-24813, affect Apache Tomcat itself, specifically in handling HTTP PUT requests, which could allow unauthenticated remote code execution under non-default, uncommon configurations[2]. The vulnerability can affect applications using embedded Tomcat if exploitable configurations are present.
  • Remediation: Use a version of Tomcat (and thus tomcat-embed-jasper) that includes patches for all relevant CVEs (especially CVE-2025-24813). Monitor the official Tomcat security pages for the exact fixed versions[9][6]. Spring Boot does not always include the latest Tomcat by default, so explicit version management may be needed.
  • No direct vulnerabilities in tomcat-embed-jasper itself were listed in Snyk, but the underlying Tomcat engine must be kept up to date[5].

Key Recommendations

  • Avoid javax.servlet:jstl:1.2. If you require JSTL, use a maintained implementation (such as org.apache.taglibs:taglibs-standard-impl:1.2.5) to address known vulnerabilities[4].
  • Ensure Tomcat (embedded via tomcat-embed-jasper) is up to date and at a version patched for known CVEs, especially CVE-2025-24813[2].
  • Regularly review your dependency versions for security advisories.

Caveats & Limitations

  • The identified vulnerabilities depend on application use and configuration. Not all environments may be directly exploitable, but risk remains significant if defaults are used or if untrusted XML/XSLT inputs are processed.
  • No comprehensive vulnerability list for org.apache.tomcat.embed:tomcat-embed-jasper as a standalone artifact was provided[5]; always refer to Tomcat’s official security notifications[9].

In summary: javax.servlet:jstl:1.2 is insecure and should be replaced; keep Tomcat and related embed packages updated to a patched version matching Spring Boot 3.4.5, watching for any new disclosures.

Citations:


Update JSP/Servlet dependencies to secure versions

Please replace the outdated JSTL artifact and pin your embedded Tomcat to a patched release:

• File: build.gradle (lines 43–47)
• Replace javax.servlet:jstl:1.2 (XXE/RCE risk) with a maintained implementation
• Pin tomcat-embed-jasper to a Tomcat version patched for CVE-2025-24813 (and other recent CVEs)

Suggested diff:

-    implementation 'javax.servlet:jstl:1.2'
-    implementation "org.apache.tomcat.embed:tomcat-embed-jasper"
+    implementation 'org.apache.taglibs:taglibs-standard-impl:1.2.5'
+    implementation "org.apache.tomcat.embed:tomcat-embed-jasper:10.1.17"

(Optional) If you’re migrating fully to Jakarta EE 9+, consider:

implementation 'jakarta.servlet.jsp.jstl-api:3.0.0'
implementation 'org.apache.taglibs:taglibs-standard-impl:3.0.0'
🤖 Prompt for AI Agents
In build.gradle around lines 43 to 47, update the JSP/Servlet dependencies to
secure versions by replacing 'javax.servlet:jstl:1.2' with a maintained JSTL
implementation such as 'jakarta.servlet.jsp.jstl-api:3.0.0' and
'org.apache.taglibs:taglibs-standard-impl:3.0.0'. Also, pin
'org.apache.tomcat.embed:tomcat-embed-jasper' to a specific Tomcat version that
includes patches for CVE-2025-24813 and other recent vulnerabilities to ensure
security.

Comment on lines +24 to +30
public void afterCommitHandler(KmcIssueTxEvent event) {
KmcContext ctx = event.getContext();
log.debug("[AFTER_COMMIT] 커밋 후 처리 시작: certNum={}", ctx.certNum());
SignUpToken token = ctx.toSignUpToken();
repository.save(token);
log.debug("[AFTER_COMMIT] 커밋 후 처리 완료: certNum={}", ctx.certNum());
}
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Add exception handling to prevent event processing failures.

The afterCommitHandler method lacks exception handling, which could cause the event processing to fail silently or propagate exceptions that might affect other parts of the system.

 @TransactionalEventListener(phase = TransactionPhase.AFTER_COMMIT)
 public void afterCommitHandler(KmcIssueTxEvent event) {
-    KmcContext ctx = event.getContext();
-    log.debug("[AFTER_COMMIT] 커밋 후 처리 시작: certNum={}", ctx.certNum());
-    SignUpToken token = ctx.toSignUpToken();
-    repository.save(token);
-    log.debug("[AFTER_COMMIT] 커밋 후 처리 완료: certNum={}", ctx.certNum());
+    try {
+        KmcContext ctx = event.getContext();
+        log.debug("[AFTER_COMMIT] 커밋 후 처리 시작: certNum={}", ctx.certNum());
+        SignUpToken token = ctx.toSignUpToken();
+        repository.save(token);
+        log.debug("[AFTER_COMMIT] 커밋 후 처리 완료: certNum={}", ctx.certNum());
+    } catch (Exception ex) {
+        log.error("[AFTER_COMMIT] 토큰 저장 실패: certNum={}", event.getContext().certNum(), ex);
+        // Consider whether to rethrow or handle gracefully based on business requirements
+    }
📝 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
public void afterCommitHandler(KmcIssueTxEvent event) {
KmcContext ctx = event.getContext();
log.debug("[AFTER_COMMIT] 커밋 후 처리 시작: certNum={}", ctx.certNum());
SignUpToken token = ctx.toSignUpToken();
repository.save(token);
log.debug("[AFTER_COMMIT] 커밋 후 처리 완료: certNum={}", ctx.certNum());
}
@TransactionalEventListener(phase = TransactionPhase.AFTER_COMMIT)
public void afterCommitHandler(KmcIssueTxEvent event) {
try {
KmcContext ctx = event.getContext();
log.debug("[AFTER_COMMIT] 커밋 후 처리 시작: certNum={}", ctx.certNum());
SignUpToken token = ctx.toSignUpToken();
repository.save(token);
log.debug("[AFTER_COMMIT] 커밋 후 처리 완료: certNum={}", ctx.certNum());
} catch (Exception ex) {
log.error("[AFTER_COMMIT] 토큰 저장 실패: certNum={}", event.getContext().certNum(), ex);
// Consider whether to rethrow or handle gracefully based on business requirements
}
}
🤖 Prompt for AI Agents
In
src/main/java/life/mosu/mosuserver/application/auth/kmc/tx/KmcTxEventListener.java
around lines 24 to 30, the afterCommitHandler method does not have exception
handling, risking silent failures or unhandled exceptions during event
processing. Add a try-catch block around the method's logic to catch any
exceptions, log the error details for troubleshooting, and prevent exceptions
from propagating and affecting other system components.

Comment on lines +32 to +38
@TransactionalEventListener(phase = TransactionPhase.AFTER_ROLLBACK)
public void afterRollbackHandler(KmcIssueTxEvent event) {
KmcContext ctx = event.getContext();
log.debug("[AFTER_ROLLBACK] 롤백 후 처리 시작: certNum={}", ctx.certNum());
kmcFailureHandler.handle(event);
log.debug("[AFTER_ROLLBACK] 롤백 후 처리 완료: certNum={}", ctx.certNum());
}
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Add exception handling for rollback event processing.

Similar to the commit handler, the rollback handler should have proper exception handling to prevent cascading failures.

 @TransactionalEventListener(phase = TransactionPhase.AFTER_ROLLBACK)
 public void afterRollbackHandler(KmcIssueTxEvent event) {
-    KmcContext ctx = event.getContext();
-    log.debug("[AFTER_ROLLBACK] 롤백 후 처리 시작: certNum={}", ctx.certNum());
-    kmcFailureHandler.handle(event);
-    log.debug("[AFTER_ROLLBACK] 롤백 후 처리 완료: certNum={}", ctx.certNum());
+    try {
+        KmcContext ctx = event.getContext();
+        log.debug("[AFTER_ROLLBACK] 롤백 후 처리 시작: certNum={}", ctx.certNum());
+        kmcFailureHandler.handle(event);
+        log.debug("[AFTER_ROLLBACK] 롤백 후 처리 완료: certNum={}", ctx.certNum());
+    } catch (Exception ex) {
+        log.error("[AFTER_ROLLBACK] 롤백 처리 실패: certNum={}", event.getContext().certNum(), ex);
+    }
📝 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
@TransactionalEventListener(phase = TransactionPhase.AFTER_ROLLBACK)
public void afterRollbackHandler(KmcIssueTxEvent event) {
KmcContext ctx = event.getContext();
log.debug("[AFTER_ROLLBACK] 롤백 후 처리 시작: certNum={}", ctx.certNum());
kmcFailureHandler.handle(event);
log.debug("[AFTER_ROLLBACK] 롤백 후 처리 완료: certNum={}", ctx.certNum());
}
@TransactionalEventListener(phase = TransactionPhase.AFTER_ROLLBACK)
public void afterRollbackHandler(KmcIssueTxEvent event) {
try {
KmcContext ctx = event.getContext();
log.debug("[AFTER_ROLLBACK] 롤백 후 처리 시작: certNum={}", ctx.certNum());
kmcFailureHandler.handle(event);
log.debug("[AFTER_ROLLBACK] 롤백 후 처리 완료: certNum={}", ctx.certNum());
} catch (Exception ex) {
log.error("[AFTER_ROLLBACK] 롤백 처리 실패: certNum={}", event.getContext().certNum(), ex);
}
}
🤖 Prompt for AI Agents
In
src/main/java/life/mosu/mosuserver/application/auth/kmc/tx/KmcTxEventListener.java
around lines 32 to 38, the afterRollbackHandler method lacks exception handling,
which may cause cascading failures during rollback event processing. Wrap the
method body in a try-catch block to catch any exceptions thrown by
kmcFailureHandler.handle(event) or other code, and log the exception details
appropriately to prevent the exception from propagating further.

Comment on lines +27 to +34
@PostMapping("/confirm")
public ResponseEntity<ApiResponseWrapper<KmcCertResponse>> handleKmcResult(
@RequestBody KmcCertRequest request
) {
log.info("STEP1 - KMC 본인인증 요청: {}", request.serviceTerm());
KmcCertResponse response = kmcService.createCertRequest(request);
return ResponseEntity.ok(ApiResponseWrapper.success(HttpStatus.OK, "성공", response));
}
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Add request validation and consider security implications.

The endpoint lacks input validation and handles sensitive authentication data. Consider adding validation annotations and security measures.

 @PostMapping("/confirm")
 public ResponseEntity<ApiResponseWrapper<KmcCertResponse>> handleKmcResult(
-        @RequestBody KmcCertRequest request
+        @Valid @RequestBody KmcCertRequest request
 ) {
     log.info("STEP1 - KMC 본인인증 요청: {}", request.serviceTerm());
     KmcCertResponse response = kmcService.createCertRequest(request);
     return ResponseEntity.ok(ApiResponseWrapper.success(HttpStatus.OK, "성공", response));
 }
🤖 Prompt for AI Agents
In src/main/java/life/mosu/mosuserver/infra/kmc/KmcAuthController.java around
lines 27 to 34, the handleKmcResult method lacks input validation and security
considerations for sensitive authentication data. Add validation annotations
such as @Valid to the KmcCertRequest parameter and ensure the KmcCertRequest
class has appropriate validation constraints on its fields. Additionally,
consider implementing security measures like authentication, authorization
checks, and input sanitization to protect the endpoint from unauthorized access
and malicious input.

Comment on lines +36 to +43
@PostMapping("/decrypt")
public ResponseEntity<ApiResponseWrapper<KmcResultCallbackResponse>> tokenDecrypt(
@RequestBody KmcResultCallbackRequest request
) {
log.info("STEP2 - KMC 본인인증 요청: {}", request.apiToken());
KmcResultCallbackResponse response = kmcService.tokenDecrypt(request.apiToken());
return ResponseEntity.ok(ApiResponseWrapper.success(HttpStatus.OK, "성공", response));
}
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Consider security implications of token logging.

Logging the API token in step 2 could be a security risk as tokens are sensitive authentication data.

 @PostMapping("/decrypt")
 public ResponseEntity<ApiResponseWrapper<KmcResultCallbackResponse>> tokenDecrypt(
-        @RequestBody KmcResultCallbackRequest request
+        @Valid @RequestBody KmcResultCallbackRequest request
 ) {
-    log.info("STEP2 - KMC 본인인증 요청: {}", request.apiToken());
+    log.info("STEP2 - KMC 본인인증 요청 수신 (토큰 길이: {})", 
+             request.apiToken() != null ? request.apiToken().length() : 0);
     KmcResultCallbackResponse response = kmcService.tokenDecrypt(request.apiToken());
     return ResponseEntity.ok(ApiResponseWrapper.success(HttpStatus.OK, "성공", response));
 }
📝 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
@PostMapping("/decrypt")
public ResponseEntity<ApiResponseWrapper<KmcResultCallbackResponse>> tokenDecrypt(
@RequestBody KmcResultCallbackRequest request
) {
log.info("STEP2 - KMC 본인인증 요청: {}", request.apiToken());
KmcResultCallbackResponse response = kmcService.tokenDecrypt(request.apiToken());
return ResponseEntity.ok(ApiResponseWrapper.success(HttpStatus.OK, "성공", response));
}
@PostMapping("/decrypt")
public ResponseEntity<ApiResponseWrapper<KmcResultCallbackResponse>> tokenDecrypt(
@Valid @RequestBody KmcResultCallbackRequest request
) {
log.info("STEP2 - KMC 본인인증 요청 수신 (토큰 길이: {})",
request.apiToken() != null ? request.apiToken().length() : 0);
KmcResultCallbackResponse response = kmcService.tokenDecrypt(request.apiToken());
return ResponseEntity.ok(ApiResponseWrapper.success(HttpStatus.OK, "성공", response));
}
🤖 Prompt for AI Agents
In src/main/java/life/mosu/mosuserver/infra/kmc/KmcAuthController.java around
lines 36 to 43, the API token is logged directly which poses a security risk.
Remove or mask the token value in the log statement to avoid exposing sensitive
authentication data. Instead of logging the full token, log a non-sensitive
identifier or a masked version to maintain traceability without compromising
security.

response.setHeader("Cache-Control", "no-cache"); // HTTP1.1 ij�� ����
}
%>
<%@ page contentType="text/html;charset=ksc5601" %>
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

Fix encoding inconsistency to prevent character corruption.

The page declares charset=ksc5601 but should use UTF-8 for consistency with modern applications and to properly handle Korean characters.

-<%@ page contentType="text/html;charset=ksc5601" %>
+<%@ page contentType="text/html;charset=UTF-8" %>

Also update the meta tag:

-<meta http-equiv="Content-Type" content="text/html; charset=euc-kr">
+<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
📝 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
<%@ page contentType="text/html;charset=ksc5601" %>
<%@ page contentType="text/html;charset=UTF-8" %>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
🤖 Prompt for AI Agents
In src/main/webapp/WEB-INF/views/step1.jsp at line 18, the page directive sets
the contentType charset to ksc5601, which can cause character encoding issues.
Change the charset to UTF-8 in the page directive to ensure consistent encoding
and proper handling of Korean characters. Also update the HTML meta tag to
specify UTF-8 as the charset to match the page directive.

Comment on lines 35 to 83
<html>
<head>
<title>������������ �׽�Ʈ</title>
<meta http-equiv="Content-Type" content="text/html; charset=euc-kr">
<meta name="robots" content="noindex">
<style>
<!--
body, p, ol, ul, td {
font-family: ����;
font-size: 12px;
}

a:link {
size: 9px;
color: #000000;
text-decoration: none;
line-height: 12px
}

a:visited {
size: 9px;
color: #555555;
text-decoration: none;
line-height: 12px
}

a:hover {
color: #ff9900;
text-decoration: none;
line-height: 12px
}

.style1 {
color: #6b902a;
font-weight: bold;
}

.style2 {
color: #666666
}

.style3 {
color: #3b5d00;
font-weight: bold;
}

-->
</style>
</head>
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Modernize HTML structure and fix encoding inconsistencies.

The HTML structure uses legacy attributes and has encoding conflicts between the JSP page directive (ksc5601) and the meta tag (euc-kr). Consider modernizing the HTML and using web-safe fonts.

 <head>
     <title>본인인증서비스 테스트</title>
-    <meta http-equiv="Content-Type" content="text/html; charset=euc-kr">
+    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
     <meta name="robots" content="noindex">

Consider replacing Korean font names with web-safe alternatives:

-        font-family: 굴림;
+        font-family: "Malgun Gothic", "Apple Gothic", sans-serif;
📝 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
<html>
<head>
<title>본인인증서비스 테스트</title>
<meta http-equiv="Content-Type" content="text/html; charset=euc-kr">
<meta name="robots" content="noindex">
<style>
<!--
body, p, ol, ul, td {
font-family: 굴림;
font-size: 12px;
}
a:link {
size: 9px;
color: #000000;
text-decoration: none;
line-height: 12px
}
a:visited {
size: 9px;
color: #555555;
text-decoration: none;
line-height: 12px
}
a:hover {
color: #ff9900;
text-decoration: none;
line-height: 12px
}
.style1 {
color: #6b902a;
font-weight: bold;
}
.style2 {
color: #666666
}
.style3 {
color: #3b5d00;
font-weight: bold;
}
-->
</style>
</head>
<html>
<head>
<title>본인인증서비스 테스트</title>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<meta name="robots" content="noindex">
<style>
<!--
body, p, ol, ul, td {
font-family: "Malgun Gothic", "Apple Gothic", sans-serif;
font-size: 12px;
}
a:link {
size: 9px;
color: #000000;
text-decoration: none;
line-height: 12px
}
a:visited {
size: 9px;
color: #555555;
text-decoration: none;
line-height: 12px
}
a:hover {
color: #ff9900;
text-decoration: none;
line-height: 12px
}
.style1 {
color: #6b902a;
font-weight: bold;
}
.style2 {
color: #666666
}
.style3 {
color: #3b5d00;
font-weight: bold;
}
-->
</style>
</head>
🤖 Prompt for AI Agents
In src/main/webapp/WEB-INF/views/step1.jsp between lines 35 and 83, the HTML
uses outdated attributes and has conflicting character encodings between the JSP
directive (ksc5601) and the meta tag (euc-kr). Update the meta charset tag to
use UTF-8 for consistency and modern standards. Replace the Korean font '굴림'
with web-safe font families like 'Arial, sans-serif' or 'Malgun Gothic, Arial,
sans-serif' to ensure better cross-platform compatibility. Also, remove legacy
HTML comments inside the style tag and clean up CSS properties like 'size' which
are invalid for links.

Comment on lines 127 to 128
<td align=left><input type="text" name="tr_url" size="41"
value="http://�����纰 ���/kmcis_web_sample_step03.jsp"></td>
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Address additional hardcoded URL in return URL field.

The return URL field contains a hardcoded placeholder URL that needs to be properly configured.

-                                      value="http://도메인명 입력/kmcis_web_sample_step03.jsp">
+                                      value="${pageContext.request.contextPath}/api/v1/kmc/result">

Committable suggestion skipped: line range outside the PR's diff.

🤖 Prompt for AI Agents
In src/main/webapp/WEB-INF/views/step1.jsp around lines 127 to 128, the input
field for the return URL contains a hardcoded placeholder URL. Replace this
hardcoded URL with a dynamic value or configuration reference that correctly
sets the return URL based on the application's routing or environment settings
to avoid using fixed, static URLs.

<tr>
<td align=center>�������URL</td>
<td align=left><input type="text" name="tr_url" size="41"
value="http://�����纰 ���/kmcis_web_sample_step03.jsp"></td>
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Replace placeholder URL with actual configuration.

The placeholder URL should be replaced with actual configuration or removed if not needed.

-value="http://사용자서버 주소/kmcis_web_sample_step03.jsp">
+value="${returnUrl}">

Committable suggestion skipped: line range outside the PR's diff.

🤖 Prompt for AI Agents
In src/main/webapp/WEB-INF/views/step1.jsp at line 128, the value attribute
contains a placeholder URL "http://고객사별 경로/kmcis_web_sample_step03.jsp". Replace
this placeholder with the actual configured URL needed for the application or
remove the attribute entirely if it is not required.

kmc:
cpid: ${KMC_CPID}
url-code: ${KMC_URLCODE}
expire-time: ${KMC_EXPIRE_TIME} No newline at end of file
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

Fix missing newline at end of file.

Static analysis correctly identified a missing newline character at the end of the file, which should be added for POSIX compliance.

 kmc:
   cpid: ${KMC_CPID}
   url-code: ${KMC_URLCODE}
-  expire-time: ${KMC_EXPIRE_TIME}
+  expire-time: ${KMC_EXPIRE_TIME}
+
📝 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
expire-time: ${KMC_EXPIRE_TIME}
kmc:
cpid: ${KMC_CPID}
url-code: ${KMC_URLCODE}
expire-time: ${KMC_EXPIRE_TIME}
🧰 Tools
🪛 YAMLlint (1.37.1)

[error] 46-46: no new line character at the end of file

(new-line-at-end-of-file)

🤖 Prompt for AI Agents
In src/test/resources/security-config.yml at line 46, the file is missing a
newline character at the end. Add a newline character after the last line to
ensure POSIX compliance and satisfy static analysis requirements.

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

🧹 Nitpick comments (1)
.github/workflows/docker-ci.yaml (1)

26-30: Minor optimisation: clone only the required artefact

If the jar is the only asset you need, consider enabling sparse-checkout (supported by actions/checkout) or, better yet, publish the jar to a package registry (GitHub Packages / Maven) and declare it as a Gradle dependency. This keeps the CI pipeline stateless, reproducible, and avoids bloating the Docker image with an embedded VCS directory.

📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between d73cc38 and 4953906.

📒 Files selected for processing (1)
  • .github/workflows/docker-ci.yaml (1 hunks)

Comment on lines 26 to 30
- name: Clone external repo with jar
run: |
mkdir -p ./libs
cd ./libs
git clone https://x-access-token:${{ secrets.GH_PAT }}@github.com/mosu-dev/mosu-kmc-jar.git .
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

⚠️ Potential issue

Replace custom PAT with the built-in GITHUB_TOKEN and use actions/checkout for safer, cleaner access

Passing a personal access token on the CLI exposes it to accidental logging and requires manual rotation.
GitHub Actions already provides a short-lived, least-privilege token (GITHUB_TOKEN) that is masked in logs and automatically scoped to the current repository.
actions/checkout supports checking out another private repo with that token, avoiding the need for git clone scripting entirely.

-      - name: Clone external repo with jar
-        run: |
-          mkdir -p ./libs
-          cd ./libs
-          git clone https://x-access-token:${{ secrets.GH_PAT }}@github.com/mosu-dev/mosu-kmc-jar.git .
+      - name: Checkout KMC jar repo
+        uses: actions/checkout@v3
+        with:
+          repository: mosu-dev/mosu-kmc-jar
+          token: ${{ secrets.GITHUB_TOKEN }}
+          path: libs          # checks out directly into ./libs
+          fetch-depth: 1      # shallow clone for speed

Benefits
• No long-lived PAT in secrets
• Token automatically rotated by GitHub
• Simpler, more declarative workflow step
• Shallow clone cuts runner time/bandwidth

🤖 Prompt for AI Agents
In .github/workflows/docker-ci.yaml around lines 26 to 30, replace the manual
git clone command using a personal access token with the built-in GITHUB_TOKEN
and the actions/checkout action. Remove the mkdir, cd, and git clone steps, and
instead add a step using actions/checkout configured to checkout the external
private repository with the GITHUB_TOKEN for authentication. This will improve
security by avoiding exposing a long-lived PAT, simplify the workflow, and
enable a shallow clone.

@wlgns12370 wlgns12370 changed the title MOSU-kmc feat: 본인인증 연동 구현 MOSU-kmc feat: 본인인증 연동 구현(이쿠죠잇!) Jul 24, 2025
@wlgns12370 wlgns12370 merged commit 4c7bddd into develop Jul 24, 2025
2 checks passed
@wlgns12370 wlgns12370 deleted the feature/kmc branch August 7, 2025 01:41
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant