-
Notifications
You must be signed in to change notification settings - Fork 4
feat: apple login #503
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat: apple login #503
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,23 @@ | ||
| package upbrella.be.config | ||
|
|
||
| import org.springframework.boot.web.servlet.ServletContextInitializer | ||
| import org.springframework.context.annotation.Bean | ||
| import org.springframework.context.annotation.Configuration | ||
| import org.springframework.context.annotation.Profile | ||
| import javax.servlet.SessionCookieConfig | ||
|
|
||
| @Configuration | ||
| @Profile("prod") | ||
| class SessionCookieConfig { | ||
|
|
||
| @Bean | ||
| fun servletContextInitializer(): ServletContextInitializer { | ||
| return ServletContextInitializer { servletContext -> | ||
| val sessionCookieConfig: SessionCookieConfig = servletContext.sessionCookieConfig | ||
| sessionCookieConfig.setSecure(true) | ||
| sessionCookieConfig.setHttpOnly(true) | ||
| sessionCookieConfig.setDomain("upbrella.co.kr") | ||
| sessionCookieConfig.setPath("/") | ||
| } | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -4,11 +4,13 @@ import org.slf4j.LoggerFactory | |
| import org.springframework.http.ResponseEntity | ||
| import org.springframework.web.bind.annotation.* | ||
| import org.springframework.web.client.HttpClientErrorException | ||
| import org.springframework.web.servlet.view.RedirectView | ||
| import upbrella.be.rent.service.RentService | ||
| import upbrella.be.user.dto.request.JoinRequest | ||
| import upbrella.be.user.dto.request.LoginCodeRequest | ||
| import upbrella.be.user.dto.request.UpdateBankAccountRequest | ||
| import upbrella.be.user.dto.response.* | ||
| import upbrella.be.user.dto.token.AppleOauthInfo | ||
| import upbrella.be.user.dto.token.KakaoOauthInfo | ||
| import upbrella.be.user.dto.token.OauthToken | ||
| import upbrella.be.user.exception.InvalidLoginCodeException | ||
|
|
@@ -26,6 +28,7 @@ class UserController( | |
| private val oauthLoginService: OauthLoginService, | ||
| private val userService: UserService, | ||
| private val kakaoOauthInfo: KakaoOauthInfo, | ||
| private val appleOauthInfo: AppleOauthInfo, | ||
| private val rentService: RentService, | ||
| private val blackListService: BlackListService, | ||
| ) { | ||
|
|
@@ -86,16 +89,69 @@ class UserController( | |
| )) | ||
| } | ||
|
|
||
| @PostMapping("/auth/apple") | ||
| fun appleLoginCallback( | ||
| session: HttpSession, | ||
| @RequestParam code: String, | ||
| @RequestParam(required = false) state: String?, | ||
| @RequestParam(required = false) id_token: String?, | ||
| @RequestParam(required = false) user: String? | ||
| ): RedirectView { | ||
| log.info("Apple login callback received - code: ${code.take(10)}...") | ||
|
|
||
| val appleOauthToken: OauthToken | ||
|
|
||
| try { | ||
| appleOauthToken = oauthLoginService.getOauthToken(code, appleOauthInfo)!! | ||
| } catch (e: HttpClientErrorException) { | ||
| log.error("Apple login failed", e) | ||
| return RedirectView("https://upbrella.co.kr/login?error=apple_login_failed") | ||
| } catch (e: Exception) { | ||
| log.error("Unexpected error during Apple login", e) | ||
| return RedirectView("https://upbrella.co.kr/login?error=server_error") | ||
| } | ||
|
|
||
| // id_token이 없으면 에러 | ||
| if (appleOauthToken.idToken.isNullOrEmpty()) { | ||
| log.error("Apple ID token is null or empty") | ||
| return RedirectView("https://upbrella.co.kr/login?error=no_id_token") | ||
| } | ||
|
|
||
| try { | ||
| val appleLoggedInUser = oauthLoginService.processAppleLogin(appleOauthToken.idToken!!) | ||
| session.setAttribute("appleUser", appleLoggedInUser) | ||
|
|
||
| log.info("Apple social login success - redirecting to frontend") | ||
| return RedirectView("https://upbrella.co.kr/login?apple=success") | ||
| } catch (e: Exception) { | ||
| log.error("Apple ID token validation failed", e) | ||
| return RedirectView("https://upbrella.co.kr/login?error=token_validation_failed") | ||
| } | ||
| } | ||
|
Comment on lines
+92
to
+130
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'll verify the three main concerns in this Apple OAuth callback review. Let me start by exploring the codebase to understand the full OAuth flow and check the specific issues raised. Let me search more broadly and also check the structure: I need to run shell scripts to examine the codebase. Let me start the investigation: Find UserController and related filesecho "=== Finding UserController ===" echo "" echo "" Let me use a more targeted approach: Search for the UserController filerg -l "appleLoginCallback" --type kt 2>/dev/null | head -5 Let me try a broader search: List directory structurefind . -type d -name "user" | head -10 Let me search for files containing the code snippet: Let me try a different approach and look at git repository structure: Now let me search for Apple login related code: Let me search for state parameter handling: Let me search for configuration of redirect URLs: Let me check for application properties or configuration files: Let me search for other OAuth providers to see the pattern: Let me check for OauthLoginService implementation: Let me try to get all Kotlin files and examine the structure: Get all Kotlin filesfind . -type f -name "*.kt" 2>/dev/null | wc -l Look for controller filesfind . -type f -name "*.kt" 2>/dev/null | grep -i controller Let me search for the specific error messages from the code: Let me try searching with the GitHub endpoint: Let me search broadly for all file extensions to understand the project better: Let me try listing repository files more directly: Now let me examine those files for Apple login logic: Search for Apple in all Kotlin filesgit ls-files --full-name | grep ".kt$" | xargs rg "apple|Apple" -i -l | head -10 Let me get the full file content of UserController if it exists: Let me try a different pattern search: Now let me examine the authentication/OAuth flow more carefully: Search for all POST mapping with authgit ls-files --full-name | grep ".kt$" | xargs grep -n "@PostMapping" 2>/dev/null | grep -i "auth" | head -20 Let me search for session attribute handling: Search for session state or state validationgit ls-files --full-name | grep ".kt$" | xargs grep -n "session.*state|setAttribute.*state|getAttribute.*state" 2>/dev/null | head -20 Let me look for the Apple OAuth configuration: Search for Apple OAuth configurationgit ls-files --full-name | xargs grep -n "apple.*oauth|AppleOauth" 2>/dev/null -i | head -20 Let me search for where the Apple login is initiated: Search for Apple login start or initiategit ls-files --full-name | grep ".kt$" | xargs grep -n "appleLogin|apple.*login" 2>/dev/null -i | head -30 Let me try searching for the URL that's hard-coded: Let me check if there's configuration for base URL: Look for property filesgit ls-files --full-name | grep -E ".(yml|yaml|properties)$" Let me check the content of those config files: Read application config files if they existgit ls-files --full-name | grep -E "application.*.(yml|yaml|properties)$" | xargs cat 2>/dev/null | head -100 Let me search for all OAuth-related endpoints: Let me get a comprehensive list of all controller methods: Let me try to find the file using a broader search: Search all files containing both "PostMapping" and "/auth/apple"git ls-files --full-name | xargs grep -l "PostMapping.*apple|apple.*PostMapping" 2>/dev/null Let me search more broadly: Find all files mentioning "auth/apple"git ls-files --full-name | xargs grep -l "/auth/apple" 2>/dev/null Let me examine the git history or search the PR: Check the git diff to see what files changedgit diff --name-only main...HEAD 2>/dev/null | head -20 Let me try to get the current branch and see what files are in the PR: Let me check the git status and recent changes: Let me try to find files containing the exact method signature: Search for the method signaturerg "fun appleLoginCallback" -t kt -B 5 -A 30 2>/dev/null Let me try using ast-grep to find this function: Try to find the function with ast-grepast-grep --pattern 'fun appleLoginCallback($$$) { $$$ }' 2>/dev/null | head -50 Let me search for all files in the repository: List all kotlin filesfind . -name "*.kt" -type f 2>/dev/null | head -50 Great! Now let me examine the UserController file: Read the UserController filecat -n ./src/main/kotlin/upbrella/be/user/controller/UserController.kt | sed -n '1,150p' Perfect! Now let me check the OauthLoginService to understand how state is handled: Find and examine OauthLoginServicefind . -name "OauthLoginService" -o -name "oauthService*" | grep -v ".class" <function_calls> Find oauth service filesfind . -type f -name "ervice.kt" | grep -i oauth | head -10 Let me search for the service classes: <function_calls> List service directoryls -la ./src/main/kotlin/upbrella/be/*/service/ 2>/dev/null | head -100 <function_calls> Find all Kotlin files in service directoriesfind ./src/main/kotlin -type f -name "*Service.kt" 2>/dev/null | head -20 <function_calls> Search for OauthLoginServicerg "class OauthLoginService" -t kt -B 2 -A 20 2>/dev/null Let me search more broadly for oauth: Let me check the entire service directory structure: Let me look for the oauth package: Let me examine the UserController imports to understand where oauthLoginService comes from: Check the beginning of UserController to see importscat ./src/main/kotlin/upbrella/be/user/controller/UserController.kt | head -50 <function_calls> Search for OauthLoginService anywhere in the codebaserg "OauthLoginService" -t kt 2>/dev/null | head -20 Let me check what's imported: Get imports from UserControllergrep -n "^import" ./src/main/kotlin/upbrella/be/user/controller/UserController.kt | grep -i oauth <function_calls> Get all importsgrep -n "^import" ./src/main/kotlin/upbrella/be/user/controller/UserController.kt <function_calls> Search for files containing OauthLoginService class definitionrg "class.*OauthLoginService" -t kt 2>/dev/null Let me search with a wildcard: Search for interface or class definitionsrg "^class|^interface|^object" -t kt | grep -i oauth Let me look for service definitions: Find all service classesfind ./src/main/kotlin -name "*Service.kt" -type f Let me check each service file: Get file listfind ./src/main/kotlin -name "*Service.kt" -type f | xargs -I {} sh -c 'echo "=== {} ===" && head -20 "{}"' Let me look at all Kotlin files in the oauth package (if it exists): List all directoriesfind ./src/main/kotlin/upbrella/be -type d 2>/dev/null <function_calls> Search in lent/login/oauth directoriesls -la ./src/main/kotlin/upbrella/be/lent/ 2>/dev/null || echo "lent dir not found" Let me search all Kotlin files: Find all Kotlin files and search for the service classfind ./src/main/kotlin -name "*.kt" -type f -exec grep -l "OauthLoginService" {} ; Let me now check for other OAuth callbacks to understand the pattern: Search for other login callbacks (google, kakao)grep -n "LoginCallback|login.*callback" ./src/main/kotlin/upbrella/be/user/controller/UserController.kt -i Let me view more of the UserController file: Get line count and view more sectionswc -l ./src/main/kotlin/upbrella/be/user/controller/UserController.kt <function_calls> View the full file to understand contextcat ./src/main/kotlin/upbrella/be/user/controller/UserController.kt Now let me search for the OauthLoginService: Search all Kotlin files for OauthLoginService class or interfacerg "class|interface|object" -t kt -A 2 | grep -B 2 "OauthLoginService" Let me search differently: Look for all files with OAuth in namefind . -name "oauth" -o -name "OAuth" 2>/dev/null | grep -v ".git" | head -20 <function_calls> Search for login packagefind ./src/main/kotlin -type d | grep -i login <function_calls> Check what's in the lent directoryls -la ./src/main/kotlin/upbrella/be/lent/ 2>/dev/null <function_calls> Find all directories under befind ./src/main/kotlin/upbrella/be -maxdepth 1 -type d <function_calls> List all subdirectories with service subdirfind ./src/main/kotlin/upbrella/be -name "service" -type d -exec ls {} ; <function_calls> Get lent/service directory contentsls -la ./src/main/kotlin/upbrella/be/lent/service/ <function_calls> List all files in that service directoryfind ./src/main/kotlin/upbrella/be/lent/service -name "*.kt" -type f Great! Let me examine the OauthLoginService: Read OauthLoginServicecat -n ./src/main/kotlin/upbrella/be/lent/service/OauthLoginService.kt Perfect! Now let me search for where the Apple login is initiated to understand state handling: Search for Apple login initiation endpointsgrep -rn "@.*Mapping.*apple|/auth/apple" ./src/main/kotlin -i | head -20 <function_calls> Search for any state-related session handlinggrep -rn "state|State" ./src/main/kotlin/upbrella/be/user -i | head -30 Let me search for state in the entire codebase: Search for session state validationgrep -rn "session.*state|state.*session|getAttribute.*state|setAttribute.*state" ./src/main/kotlin -i | head -20 <function_calls> Search for CSRF protection or state validationgrep -rn "csrf|CSRF|state.*validation|validate.*state" ./src/main/kotlin -i | head -20 Now let me check if there's a login initiation endpoint: Search for any mapping that initiates Apple logingrep -rn "GetMapping|PostMapping|@.*Mapping" ./src/main/kotlin/upbrella/be/user -B 2 -A 2 | grep -E "apple|Apple|login|Login" -i Let me check the configuration files: Find and check configuration filesfind . -name "application*.yml" -o -name "application*.yaml" -o -name "application*.properties" | head -10 <function_calls> Check if properties file exists and examine itcat ./src/main/resources/application.yml 2>/dev/null || cat ./src/main/resources/application.properties 2>/dev/null || cat ./src/main/resources/application.yaml 2>/dev/null Let me check the resources directory: List resources directoryls -la ./src/main/resources/ 2>/dev/null | head -20 <function_calls> Find all config filesfind ./src -name ".yml" -o -name ".yaml" -o -name "*.properties" 2>/dev/null Let me check what controllers exist and look for others: Find all controller filesfind ./src -name "*Controller.kt" 2>/dev/null Let me examine the google login callback to see if it has the same pattern: View lines around googleLoginCallbacksed -n '130,180p' ./src/main/kotlin/upbrella/be/user/controller/UserController.kt <function_calls> View the rest of the filesed -n '180,210p' ./src/main/kotlin/upbrella/be/user/controller/UserController.kt Let me check the OauthInfo classes: Search for OauthInfo classfind ./src -name "OauthInfo" -o -name "oauthinfo*" -i <function_calls> Search for AppleOauthInfogrep -rn "AppleOauthInfo|class.*OauthInfo" ./src/main/kotlin -i | head -20 Let me search for configuration classes: Find config or entity filesfind ./src/main/kotlin -name "*Config.kt" -o -name "*Property.kt" -o -name "*Entity.kt" | head -20 <function_calls> List all files in lent directoryfind ./src/main/kotlin/upbrella/be/lent -name "*.kt" -type f <function_calls> Check config packagels -la ./src/main/kotlin/upbrella/be/lent/config/ 2>/dev/null || echo "No config dir found" <function_calls> Find all files in lentfind ./src/main/kotlin/upbrella/be/lent -type f -name "*.kt" | xargs ls -la <function_calls> Show directory structurefind ./src/main/kotlin/upbrella/be/lent -type d <function_calls> View the OauthProperty filecat ./src/main/kotlin/upbrella/be/lent/config/property/OauthProperty.kt Perfect! Now let me check if there's state validation: Search for CSRF token, state generation, or validationgrep -rn "UUID|random|state|csrf" ./src/main/kotlin/upbrella/be/lent -i | head -30 Let me check for @value or @ConfigurationProperties usage: Check how OauthProperty is usedgrep -rn "OauthProperty|@value" ./src/main/kotlin/upbrella/be -i | head -20 Let me check the entire lent package structure: List all Kotlin files in lent packagefind ./src/main/kotlin/upbrella/be/lent -name "*.kt" -type f -exec echo "=== {} ===" ; -exec head -20 {} ; <function_calls> Get list of filesfind ./src/main/kotlin/upbrella/be/lent -name "*.kt" -type f Let me examine each file: OauthProperty (already showed)Check OauthTokenecho "=== OauthToken ===" echo "" <function_calls> Check remaining filesecho "=== AppleOauthInfo ===" echo "" <function_calls> Check for any other oauth info classesfind ./src/main/kotlin -name "OauthInfo" -o -name "oauthInfo*" -i <function_calls> Check OauthProperty constructor detailscat ./src/main/kotlin/upbrella/be/lent/config/property/OauthProperty.kt Let me check if there's frontend URL configuration: Search for frontend URL or redirect URL configurationgrep -rn "frontend|redirectUri|redirect.url|frontendUrl" ./src/main/kotlin -i | head -20 <function_calls> Search in the entire codebase for the hardcoded URLgrep -rn "upbrella.co.kr" ./src --include=".kt" --include=".yml" --include=".yaml" --include=".properties" <function_calls> Search in test files as well to understand the patternsfind ./src -name "*.kt" -type f | xargs grep -l "upbrella.co.kr" | head -10 Let me search for any other OAuth implementation in the repo for comparison: Search for Google OAuth or Kakao OAuthgrep -rn "google.*callback|kakao.*callback|google.*login|kakao.*login" ./src/main/kotlin -i Let me check the full UserController again for Google callback: Show lines around googleLoginCallbacksed -n '130,160p' ./src/main/kotlin/upbrella/be/user/controller/UserController.kt | cat -n Now let me search for any CSRF or state validation mechanism in the entire codebase: Search for any CSRF or state-related codegrep -rn "state" ./src/main/kotlin/upbrella/be -i -A 2 -B 2 | head -100 <function_calls> Check if there's any validation of the state parameter anywhererg "state.*validate|validate.*state|state.*check|check.*state" -i -t kt Let me check the README or documentation: Check README or other documentationfind . -name "README*" -o -name "*.md" | head -10 Let me look for any environment-specific configuration: Find all yaml/properties filesfind . -name ".yml" -o -name ".yaml" -o -name "*.properties" | head -20 <function_calls> Try to find any application configurationfind ./src/main/resources -type f | head -20 Let me check if there's a pom.xml or build.gradle: Check for build filesls -la | grep -E "pom.xml|build.gradle|settings.gradle" Let me check the OauthLoginService more carefully to see if it validates state: Get the full OauthLoginService file with wc firstwc -l ./src/main/kotlin/upbrella/be/lent/service/OauthLoginService.kt <function_calls> View the full service filecat -n ./src/main/kotlin/upbrella/be/lent/service/OauthLoginService.kt Perfect! Now let me verify the specific issues and create a summary. Let me also check if there are any tests that show how state should be handled: Find test files related to OAuthfind ./src/test -name "OAuth" -o -name "oauth" -o -name "Apple" | head -10 <function_calls> Find test files for UserControllerfind ./src/test -name "UserController" <function_calls> Find all test filesfind ./src/test -name "*.kt" -type f | head -10 Let me now verify the exact line numbers in the code to ensure accuracy: Get the exact appleLoginCallback method with line numberssed -n '92,130p' ./src/main/kotlin/upbrella/be/user/controller/UserController.kt | cat -n Ensure CSRF state parameter validation is implemented, remove unused request parameters, and externalize hard-coded redirect URLs in OAuth callbacks The review identifies legitimate issues that I've confirmed throughout the codebase:
🤖 Prompt for AI Agents |
||
|
|
||
| @PostMapping("/users/login") | ||
| fun upbrellaLogin(session: HttpSession): ResponseEntity<CustomResponse<Unit>> { | ||
| if (session.getAttribute("kakaoUser") == null) { | ||
| throw NotSocialLoginedException("[ERROR] 카카오 로그인을 먼저 해주세요.") | ||
| val kakaoUser = session.getAttribute("kakaoUser") as? KakaoLoginResponse | ||
| val appleUser = session.getAttribute("appleUser") as? AppleLoginResponse | ||
|
|
||
| if (kakaoUser == null && appleUser == null) { | ||
| throw NotSocialLoginedException("[ERROR] 소셜 로그인을 먼저 해주세요.") | ||
| } | ||
|
|
||
| val kakaoUser = session.getAttribute("kakaoUser") as KakaoLoginResponse | ||
| val loggedInUser = userService.login(kakaoUser.id!!) | ||
| val loggedInUser = when { | ||
| kakaoUser != null -> { | ||
| val user = userService.login(kakaoUser.id!!) | ||
| session.removeAttribute("kakaoUser") | ||
| user | ||
| } | ||
| appleUser != null -> { | ||
| val user = userService.loginApple(appleUser.sub!!) | ||
| session.removeAttribute("appleUser") | ||
| user | ||
| } | ||
| else -> throw NotSocialLoginedException("[ERROR] 소셜 로그인을 먼저 해주세요.") | ||
| } | ||
|
|
||
| session.removeAttribute("kakaoUser") | ||
| session.setAttribute("user", loggedInUser) | ||
|
|
||
| log.info("UUL 로그인 성공") | ||
|
|
@@ -125,17 +181,30 @@ class UserController( | |
|
|
||
| @PostMapping("/users/join") | ||
| fun kakaoJoin(session: HttpSession, @RequestBody @Valid joinRequest: JoinRequest): ResponseEntity<CustomResponse<Unit>> { | ||
| val kakaoUser = session.getAttribute("kakaoUser") as KakaoLoginResponse? | ||
| val kakaoUser = session.getAttribute("kakaoUser") as? KakaoLoginResponse | ||
| val appleUser = session.getAttribute("appleUser") as? AppleLoginResponse | ||
|
|
||
| if (session.getAttribute("user") != null) { | ||
| throw LoginedMemberException("[ERROR] 이미 로그인된 상태입니다.") | ||
| } | ||
| if (kakaoUser == null) { | ||
| throw NotSocialLoginedException("[ERROR] 카카오 로그인을 먼저 해주세요.") | ||
| if (kakaoUser == null && appleUser == null) { | ||
| throw NotSocialLoginedException("[ERROR] 소셜 로그인을 먼저 해주세요.") | ||
| } | ||
|
|
||
| val loggedInUser = when { | ||
| kakaoUser != null -> { | ||
| val user = userService.join(kakaoUser, joinRequest) | ||
| session.removeAttribute("kakaoUser") | ||
| user | ||
| } | ||
| appleUser != null -> { | ||
| val user = userService.joinApple(appleUser, joinRequest) | ||
| session.removeAttribute("appleUser") | ||
| user | ||
| } | ||
| else -> throw NotSocialLoginedException("[ERROR] 소셜 로그인을 먼저 해주세요.") | ||
| } | ||
|
|
||
| val loggedInUser = userService.join(kakaoUser, joinRequest) | ||
| session.removeAttribute("kakaoId") | ||
| session.setAttribute("user", loggedInUser) | ||
|
|
||
| log.info("UNU 회원가입 성공") | ||
|
|
@@ -144,7 +213,7 @@ class UserController( | |
| .body(CustomResponse( | ||
| "success", | ||
| 200, | ||
| "카카오 회원가입 성공", | ||
| "소셜 회원가입 성공", | ||
| null | ||
| )) | ||
| } | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,14 @@ | ||
| package upbrella.be.user.dto.response | ||
|
|
||
| import com.fasterxml.jackson.annotation.JsonProperty | ||
|
|
||
| data class AppleLoginResponse( | ||
| @JsonProperty("sub") | ||
| val sub: String?, // Apple user identifier | ||
|
|
||
| @JsonProperty("email") | ||
| val email: String?, | ||
|
|
||
| @JsonProperty("email_verified") | ||
| val emailVerified: Boolean? | ||
| ) | ||
|
Comment on lines
+5
to
+14
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Consider making Apple's Either make data class AppleLoginResponse(
@JsonProperty("sub")
- val sub: String?, // Apple user identifier
+ val sub: String, // Apple user identifier (always present)Or ensure callers validate before use: val socialIdHash = appleUser.sub?.hashCode()?.toLong()
?: throw IllegalArgumentException("Apple sub is required")🤖 Prompt for AI Agents |
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,92 @@ | ||
| package upbrella.be.user.dto.token | ||
|
|
||
| import org.springframework.beans.factory.annotation.Value | ||
| import org.springframework.context.annotation.Profile | ||
| import org.springframework.stereotype.Component | ||
| import upbrella.be.util.AppleJwtGenerator | ||
| import javax.annotation.PostConstruct | ||
|
|
||
| interface AppleOauthInfo { | ||
| val clientId: String | ||
| val redirectUri: String | ||
| val loginUri: String | ||
| val clientSecret: String | ||
| } | ||
|
|
||
| @Component | ||
| @Profile("dev", "test") | ||
| class DevAppleOauthInfo( | ||
| @Value("\${APPLE_CLIENT_ID_DEV}") | ||
| override val clientId: String, | ||
|
|
||
| @Value("\${APPLE_TEAM_ID_DEV}") | ||
| private val teamId: String, | ||
|
|
||
| @Value("\${APPLE_KEY_ID_DEV}") | ||
| private val keyId: String, | ||
|
|
||
| @Value("\${APPLE_P8_KEY_PATH_DEV}") | ||
| private val p8KeyPath: String, | ||
|
|
||
| @Value("\${APPLE_REDIRECT_URI_DEV}") | ||
| override val redirectUri: String, | ||
|
|
||
| @Value("\${APPLE_LOGIN_URI_DEV}") | ||
| override val loginUri: String, | ||
|
|
||
| private val appleJwtGenerator: AppleJwtGenerator | ||
| ) : AppleOauthInfo { | ||
| private var _clientSecret: String = "" | ||
|
|
||
| override val clientSecret: String | ||
| get() = _clientSecret | ||
|
|
||
| @PostConstruct | ||
| fun init() { | ||
| _clientSecret = appleJwtGenerator.generateClientSecret( | ||
| teamId = teamId, | ||
| keyId = keyId, | ||
| clientId = clientId, | ||
| p8KeyPath = p8KeyPath | ||
| ) | ||
| } | ||
| } | ||
|
|
||
| @Component | ||
| @Profile("prod") | ||
| class ProdAppleOauthInfo( | ||
| @Value("\${APPLE_CLIENT_ID_PROD}") | ||
| override val clientId: String, | ||
|
|
||
| @Value("\${APPLE_TEAM_ID_PROD}") | ||
| private val teamId: String, | ||
|
|
||
| @Value("\${APPLE_KEY_ID_PROD}") | ||
| private val keyId: String, | ||
|
|
||
| @Value("\${APPLE_P8_KEY_PATH_PROD}") | ||
| private val p8KeyPath: String, | ||
|
|
||
| @Value("\${APPLE_REDIRECT_URI_PROD}") | ||
| override val redirectUri: String, | ||
|
|
||
| @Value("\${APPLE_LOGIN_URI_PROD}") | ||
| override val loginUri: String, | ||
|
|
||
| private val appleJwtGenerator: AppleJwtGenerator | ||
| ) : AppleOauthInfo { | ||
| private var _clientSecret: String = "" | ||
|
|
||
| override val clientSecret: String | ||
| get() = _clientSecret | ||
|
|
||
| @PostConstruct | ||
| fun init() { | ||
| _clientSecret = appleJwtGenerator.generateClientSecret( | ||
| teamId = teamId, | ||
| keyId = keyId, | ||
| clientId = clientId, | ||
| p8KeyPath = p8KeyPath | ||
| ) | ||
| } | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🧩 Analysis chain
🏁 Script executed:
Repository: UPbrella/UPbrella_back
Length of output: 296
🌐 Web query:
JJWT library io.jsonwebtoken jjwt-api version 0.11.5 security vulnerabilities CVE💡 Result:
Short answer — yes, there are public security advisories affecting JJWT variants around version 0.11.5:
CVE-2024-31033 (Weak/incorrect key handling in JJWT’s setSigningKey()/signWith()). This CVE/GHSA describes JJWT ignoring certain characters which can make keys appear stronger than they are; it is reported against jjwt-impl up through 0.12.5 (vendor disputes/notes). See NVD/Snyk/other advisories. [1][2][3]
Additional CVEs shown on package pages for jjwt artifacts (0.11.5) are usually from transitive dependencies (notably Jackson-related deserialization and other library CVEs). Maven/MvnRepository listings for jjwt 0.11.5 show dependency CVEs (examples vary by artifact: jjwt-jackson, jjwt-orgjson, jjwt-root). Check the specific artifact(s) you use to see which dependency CVEs apply. [4][5]
What to do
References
If you want, I can (a) run a dependency-tree scan of your build file (pom/gradle) to list which jjwt artifact(s) and transitive CVEs affect you, or (b) recommend exact upgrade versions and mitigation steps for your setup.
🌐 Web query:
BouncyCastle bcpkix-jdk15on version 1.70 security vulnerabilities CVE 2021 2022 2023 2024💡 Result:
Short answer — yes: bcpkix-jdk15on 1.70 is affected by multiple publicly disclosed Bouncy Castle CVEs from 2023–2024. Key items:
Notes:
References
If you want, I can: (a) produce a one-line remediation plan (recommended upgrade versions), or (b) fetch the exact vendor advisory pages/patch commits and provide direct links. Which would you prefer?
🌐 Web query:
latest stable versions io.jsonwebtoken jjwt and org.bouncycastle bcpkix 2025💡 Result:
io.jsonwebtoken (JJWT): latest stable release 0.13.0 — released Aug 20, 2025. [1]
org.bouncycastle (BCP KIX): latest stable bcpkix (bc-java) release 1.82 — released Sep 17, 2025. (There is a 1.83-SNAPSHOT beta available.) [2][3]
Sources:
[1] Maven / JJWT 0.13.0 release details.
[2] Bouncy Castle Java releases — 1.82 release notes (Sep 17, 2025).
[3] Bouncy Castle betas / 1.83-SNAPSHOT listing.
Update dependency versions to address multiple confirmed security vulnerabilities.
Both libraries in lines 91-95 contain publicly disclosed CVEs that require immediate attention:
JJWT 0.11.5:
BouncyCastle 1.70:
Update the snippet to:
🤖 Prompt for AI Agents