ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [Spring Security] OAuth2 client의 StackOverflowException
    개발/Spring 2024. 4. 16. 10:47

    대학 축제 공연 티켓팅 서비스 Uket 프로젝트의 로그인 기능을 개발하던 와중 발생한 에러,,,

    에러 전문

    2024-04-16T10:14:19.771+09:00 ERROR 85157 --- [nio-8080-exec-3] o.a.c.c.C.[.[.[/].[dispatcherServlet]    : Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Filter execution threw an exception] with root cause
    
    java.lang.StackOverflowError: null
    	at java.base/java.lang.ref.Reference.refersToImpl(Reference.java:384) ~[na:na]
    	at java.base/java.lang.ref.Reference.refersTo(Reference.java:375) ~[na:na]
    	at java.base/java.lang.reflect.AccessibleObject.isAccessChecked(AccessibleObject.java:704) ~[na:na]
    	at java.base/java.lang.reflect.AccessibleObject.verifyAccess(AccessibleObject.java:735) ~[na:na]
    	at java.base/java.lang.reflect.AccessibleObject.checkAccess(AccessibleObject.java:713) ~[na:na]
    	at java.base/java.lang.reflect.Method.invoke(Method.java:571) ~[na:na]
    	at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:351) ~[spring-aop-6.1.5.jar:6.1.5]
    	at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:213) ~[spring-aop-6.1.5.jar:6.1.5]
    	at jdk.proxy2/jdk.proxy2.$Proxy151.authenticate(Unknown Source) ~[na:na]
    	at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:103) ~[na:na]
    	at java.base/java.lang.reflect.Method.invoke(Method.java:580) ~[na:na]
    	at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:351) ~[spring-aop-6.1.5.jar:6.1.5]
    	at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:213) ~[spring-aop-6.1.5.jar:6.1.5]
    	at jdk.proxy2/jdk.proxy2.$Proxy151.authenticate(Unknown Source) ~[na:na]
    	at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:103) ~[na:na]
    	at java.base/java.lang.reflect.Method.invoke(Method.java:580) ~[na:na]
        ...

    뭐가 문제였지?

    현재 서버에서 OAuth2 로그인처리를 하는 로직을 OAuth2 client를 사용해서 처리하도록 설정했다. 그렇다 보니 디버깅하기가 쉽지 않았고 이 에러는 구글링을 해봐도 쉽사리 답이 나오질 않았었다...


    내 경우에는 2가지 경우에서 해당 에러가 발생했다. 다행히 첫번째 경우에서는 구글링을 통해 해결했다.

    카카오 로그인의 client-authentication-method

    이 에러는 구글링을 통해서 발견했다. 로깅 레벨을 DEBUG로 하고 돌려보면 위 에러 이외에 추가적인 로그를 살펴볼 수 있다.

    2024-04-16T10:17:14.709+09:00 DEBUG 85373 --- [nio-8080-exec-3] o.s.web.client.RestTemplate              : HTTP POST https://kauth.kakao.com/oauth/token
    2024-04-16T10:17:14.713+09:00 DEBUG 85373 --- [nio-8080-exec-3] o.s.web.client.RestTemplate              : Accept=[application/json, application/*+json]
    2024-04-16T10:17:14.713+09:00 DEBUG 85373 --- [nio-8080-exec-3] o.s.web.client.RestTemplate              : Writing [{grant_type=[authorization_code], code=[카카오로부터 받은 인가코드], redirect_uri=[http://localhost:8080/login/oauth2/code/kakao]}] as "application/x-www-form-urlencoded;charset=UTF-8"
    2024-04-16T10:17:14.820+09:00 DEBUG 85373 --- [nio-8080-exec-3] o.s.web.client.RestTemplate              : Response 401 UNAUTHORIZED

     

    보시다시피 401 UNAUTHORIZED문제가 생기기에 잘못된 요청을 보낸다는 것을 알 수 있다.

    그래서 체크해봐야할 것은

     

    1. 카카오 로그인에 추가 보안설정을 해서 client_secret키를 같이 보내야 하는데 이를 빼먹은 경우

    2. client-authentication-method: client_secret_post 설정을 빼먹은 경우

     

    카카오 로그인을 OAuht2 client를 통해 진행하려는 경우 application.yml에 추가 설정이 필요했다.

    spring:
      security:
        oauth2:
          client:
            registration:
              kakao:
                client-name: kakao
                authorization-grant-type: authorization_code
                client-authentication-method: client_secret_post
                scope:
                  - name
                  - account_email

    kakao는 인증 요청 메서드가 다르기에 임의로 설정해줘야한다..!

    registration 설정에 client-authentication-method: client_secret_post를 추가하도록 하자,,,

    만약 설정해뒀더라도 client-authentication-method: POST로 설정되어 있는 분들은 security가 버전업하면서 client_secret_post로 설정해줘야 한다고 하니 참고하시면 좋겠다.

    핫스팟에서의 통신 오류..?

    kakao로그인 문제를 해결하고 룰루랄라 하고 있다가 프론트와 진행사항을 공유하던 와중 로그인을 했더니 갑자기 white label 페이지가 뜨는게 아닌가,,, 코드를 전혀 손댄게 없던 상황이라 너무 어이가 없었다. 로그를 보니 StackOverFlowException이 또 발생하고 있었다. 

     

    이번에도 DEBUG 옵션으로 로그를 살펴보니

    2024-04-16T10:17:14.709+09:00 DEBUG 85373 --- [nio-8080-exec-3] o.s.web.client.RestTemplate              : HTTP POST https://kauth.kakao.com/oauth/token
    2024-04-16T10:17:14.713+09:00 DEBUG 85373 --- [nio-8080-exec-3] o.s.web.client.RestTemplate              : Accept=[application/json, application/*+json]
    2024-04-16T10:17:14.713+09:00 DEBUG 85373 --- [nio-8080-exec-3] o.s.web.client.RestTemplate              : Writing [{grant_type=[authorization_code], code=[카카오로부터 받은 인가코드], redirect_uri=[http://localhost:8080/login/oauth2/code/kakao]}] as "application/x-www-form-urlencoded;charset=UTF-8"

    이번엔 401문제도 아니고 카카오 뿐만 아니라 구글도 동일한 에러가 발생했다.

     

    미치고 팔짝 뛸 노릇이었다... 그래서 일단 oauth2 client가 로그인을 진행하는 로직을 살펴봤다.

    1. "/oauth2/authorization/{provider}" 로 요청을 보내면 OAuth2AuthorizationRequestRedirectFilter 가 이를 처리해서 해당 서비스의 로그인 페이지로 리다이렉트 시켜준다.

    2. "/login/oauth2/code/{provider}" 로 서비스에 redirect-url을 설정해놓으면 로그인 성공 시, OAuth2LoginAuthenticationFilter가 이를 처리하고 OAuth2LoginAuthenticationProvider를 호출해 서비스에 발급받은 인가 코드를 가지고 유저 정보 access 토큰 발급 요청을 하고 발급받은 토큰으로 유저정보를 가져와 처리한다.

     

    로그를 보면 현재 access 토큰 발급 요청을 보내는 부분에서 에러가 발생한다. 다만 어떤 응답코드도 알려주지 않아서 도무지 알 방법이 없었다. 아마 OAuth2LoginAuthenticationFilter 부분에서 오류가 발생하는 것 같은데 디버깅을 해도 찾아내기가 쉽지 않았다.

    결론

    결론은 핫스팟이 문제였다... 밖에서 코딩을 하느랴 핫스팟에 연결해서 하고 있었는데, 지친 상태로 집에 와서 다시 로그인을 해보니 아무 이상없이 동작하는 것이었다... 구글링을 해봤지만 명확한 원인을 알 수 없어 감히 추측을 해보자면

     

    1. 보안 정책 상, 핫스팟으로 연결된 네트워크인 경우 소셜 로그인 서버 측에서 인가를 해주지 않는다.

    2. 핫스팟은 유동 ip이므로 이 곳에서 문제가 발생...

    (참고 사이트 : https://codingmoonkwa.tistory.com/255)

     

    코드를 건든적이 없는데 안된다면 내가 핫스팟에 연결되어 있는 상태로 서버를 띄운건 아닌지 심각하게 고민해보자...

    참고로 GPT-4의 원인에 대한 답변은 다음과 같다.

     

    Q : 내 노트북을 핫스팟에 연결한 상태로 소셜 로그인 서버에 인증 요청을 보내면 인증이 거부되는 경우가 있어?

    A :

    더보기

    노트북을 핫스팟에 연결한 상태에서 소셜 로그인 서버에 인증 요청을 보내면 인증이 거부되는 경우가 발생할 수 있는 몇 가지 이유가 있습니다. 이러한 상황은 네트워크 구성, 보안 정책, 그리고 네트워크의 안정성과 관련이 있을 수 있습니다. 여기 몇 가지 가능한 원인과 해결 방법을 살펴보겠습니다.

    1. IP 주소 변동

    핫스팟을 통한 인터넷 연결은 일반적으로 모바일 네트워크를 사용합니다. 모바일 네트워크의 IP 주소는 동적으로 변경될 수 있으며, 때때로 매우 빠르게 변할 수 있습니다. 소셜 로그인과 같은 일부 서비스는 보안 목적으로 IP 주소의 변화를 감지하고, 이를 잠재적인 보안 위협으로 간주하여 접근을 차단할 수 있습니다.

    해결책: 가능하다면 더 안정적인 Wi-Fi 네트워크에 연결하거나, VPN을 사용하여 IP 주소의 변동성을 관리해 보세요.

    2. 네트워크 지연 및 불안정

    핫스팟 연결은 때때로 네트워크 지연(레이턴시)이 높거나 연결이 불안정할 수 있습니다. 이러한 불안정성은 인증 프로세스 중 중요한 데이터 패킷의 손실로 이어질 수 있으며, 결과적으로 인증 요청이 거부될 수 있습니다.

    해결책: 연결 상태를 확인하고, 네트워크 신호가 강한 위치로 이동해 보세요. 또한, 다른 네트워크(예: 고정된 Wi-Fi)를 사용해 보는 것도 좋습니다.

    3. 보안 정책 및 제한

    일부 소셜 로그인 서비스는 특정 유형의 네트워크(예: 공용 네트워크, 모바일 네트워크)에서 오는 요청을 제한할 수 있습니다. 이는 부정 접근을 방지하기 위한 조치로, 사용자의 보안을 강화하기 위해 설정됩니다.

    해결책: 소셜 로그인 서비스의 보안 설정을 확인하고, 필요한 경우 인증 정책을 조정해야 할 수 있습니다. 또는 서비스 제공업체의 고객 지원팀에 문의하여 조언을 구할 수도 있습니다.

    4. 네트워크 보안 설정

    핫스팟을 통한 연결은 방화벽이나 보안 프로토콜 설정이 적절히 구성되지 않았을 수 있습니다. 이 경우, 소셜 로그인 요청이 차단될 수 있습니다.

    해결책: 핫스팟 장치의 보안 설정을 검토하고, 필요한 포트가 열려 있고, 필요한 통신이 허용되도록 설정하세요.

    5. 쿠키 및 세션 문제

    브라우저 설정이나 네트워크 구성에 따라 쿠키 또는 세션 정보가 제대로 전송되지 않을 수도 있습니다. 이는 로그인 시 필요한 인증 정보가 손실될 수 있음을 의미합니다.

    해결책: 브라우저 쿠키를 확인하고, 필요한 경우 쿠키를 삭제한 후 다시 시도해 보세요. 또는 다른 브라우저나 비밀 모드를 사용해 보는 것도 좋습니다.

    이러한 문제를 해결하려면 여러 접근 방식을 시도해 보고, 네트워크 환경과 설정을 최적화하는 것이 중요합니다. 만약 문제가 지속된다면, 네트워크 전문가에게 도움을 요청하거나, 소셜 로그인 서비스 제공업체의 고객 지원팀과 상의하는 것도 고려해야 합니다.

Designed by Tistory.