Expected Behavior

When using Spring Security OAuth2 Client, even if we misconfigured the user info endpoint which result in an OAuth2AuthenticationException, the exception should be processed instead of an internal error which result in HTTP status 500.

Current Behavior

When using Spring Security OAuth2 Client, if a wrong user info endpoint which response contains invalid content type 'text/html' is configured, an OAuth2AuthenticationException will be thrown in the process of oauth callback request, if we use Spring Data session redis at the same time, an SerializationException will be thrown:

2023-09-06 15:20:07,322 [http-nio-8081-exec-4] WARN  [org.springframework.web.servlet.mvc.method.annotation.ExceptionHandlerExceptionResolver] [ExceptionHandlerExceptionResolver.java:434] [trace=9ac654b769f4296f,span=9ac654b769f4296f][tenant=javaapptest,region=] [TID: N/A] - Failure in @ExceptionHandler com.zatech.octopus.component.exception.resolver.MessageSourceExceptionHandler#handler(Throwable, HttpServletRequest, HttpServletResponse)
org.springframework.data.redis.serializer.SerializationException: Cannot serialize; nested exception is org.springframework.core.serializer.support.SerializationFailedException: Failed to serialize object using DefaultSerializer; nested exception is java.io.NotSerializableException: sun.reflect.generics.reflectiveObjects.ParameterizedTypeImpl
    at org.springframework.data.redis.serializer.JdkSerializationRedisSerializer.serialize(JdkSerializationRedisSerializer.java:96)
    at org.springframework.data.redis.core.AbstractOperations.rawHashValue(AbstractOperations.java:186)
    at org.springframework.data.redis.core.DefaultHashOperations.putAll(DefaultHashOperations.java:209)
    at org.springframework.data.redis.core.DefaultBoundHashOperations.putAll(DefaultBoundHashOperations.java:187)
    at org.springframework.session.data.redis.RedisIndexedSessionRepository$RedisSession.saveDelta(RedisIndexedSessionRepository.java:811)
    at org.springframework.session.data.redis.RedisIndexedSessionRepository$RedisSession.save(RedisIndexedSessionRepository.java:799)
    at org.springframework.session.data.redis.RedisIndexedSessionRepository$RedisSession.access$000(RedisIndexedSessionRepository.java:686)
    at org.springframework.session.data.redis.RedisIndexedSessionRepository.save(RedisIndexedSessionRepository.java:415)
    at org.springframework.session.data.redis.RedisIndexedSessionRepository.save(RedisIndexedSessionRepository.java:251)
    at org.springframework.cloud.sleuth.instrument.session.TraceSessionRepository.lambda$save$1(TraceSessionRepository.java:74)
    at org.springframework.cloud.sleuth.instrument.session.TraceSessionRepository.lambda$wrap$0(TraceSessionRepository.java:63)

I'm not sure what cause the OAuth2AuthenticationException cannot be serialized, the OAuth2AuthenticationException looks like this:

Spring Security Exceptions should be handled correctly even if user info endpoint is misconfigured

Context

A sample to reproduce the issue can be found here: https://github.com/wapkch/spring-security-oauth2-client-demo


spring:
  security:
    oauth2:
      client:
        registration:
          azure:
            client-id:
            client-secret:
            authorization-grant-type: authorization_code
            scope: openid,profile
            redirect-uri: http://localhost:8080/login/oauth2/code/callback
        provider:
          azure:
            authorization-uri:
            token-uri:
            user-info-uri: https://www.google.com # Intentionally configured incorrectly 
            user-name-attribute: preferred_username
            jwk-set-uri:
  1. Fill in the blank configs,
  2. Start the application
  3. Access http://localhost:8081/

Then we can reproduce: Spring Security Exceptions should be handled correctly even if user info endpoint is misconfigured

And the log:

2023-09-06 15:20:07,322 [http-nio-8081-exec-4] WARN  [org.springframework.web.servlet.mvc.method.annotation.ExceptionHandlerExceptionResolver] [ExceptionHandlerExceptionResolver.java:434] [trace=9ac654b769f4296f,span=9ac654b769f4296f][tenant=javaapptest,region=] [TID: N/A] - Failure in @ExceptionHandler com.zatech.octopus.component.exception.resolver.MessageSourceExceptionHandler#handler(Throwable, HttpServletRequest, HttpServletResponse)
org.springframework.data.redis.serializer.SerializationException: Cannot serialize; nested exception is org.springframework.core.serializer.support.SerializationFailedException: Failed to serialize object using DefaultSerializer; nested exception is java.io.NotSerializableException: sun.reflect.generics.reflectiveObjects.ParameterizedTypeImpl
    at org.springframework.data.redis.serializer.JdkSerializationRedisSerializer.serialize(JdkSerializationRedisSerializer.java:96)
    at org.springframework.data.redis.core.AbstractOperations.rawHashValue(AbstractOperations.java:186)
    at org.springframework.data.redis.core.DefaultHashOperations.putAll(DefaultHashOperations.java:209)
    at org.springframework.data.redis.core.DefaultBoundHashOperations.putAll(DefaultBoundHashOperations.java:187)
    at org.springframework.session.data.redis.RedisIndexedSessionRepository$RedisSession.saveDelta(RedisIndexedSessionRepository.java:811)
    at org.springframework.session.data.redis.RedisIndexedSessionRepository$RedisSession.save(RedisIndexedSessionRepository.java:799)
    at org.springframework.session.data.redis.RedisIndexedSessionRepository$RedisSession.access$000(RedisIndexedSessionRepository.java:686)
    at org.springframework.session.data.redis.RedisIndexedSessionRepository.save(RedisIndexedSessionRepository.java:415)

Comment From: marcusdacoregio

Hi, @wapkch. Unfortunately, I have not been able to reproduce the error. Can you provide a minimal, reproducible sample that has everything that we need to reproduce it? You can use the Spring Authorization Server and the Testcontainers support in Spring Boot to make it easier to run.

Comment From: wapkch

Hi, @marcusdacoregio Thanks for reply. I have updated the demo. The issue can be reproduced by the following steps: 1. Start the application using com.example.springsecurityoauth2clientdemo.SpringSecurityOauth2ClientDemoApplicationTests#main 2. Access http://127.0.0.1:8080/sso using a web browser 3. login with username/password (user1/password) 4. The issues can be produced.

Comment From: marcusdacoregio

Related https://github.com/spring-projects/spring-framework/issues/31283

Comment From: marcusdacoregio

Hi, @wapkch. This has been resolved as part of https://github.com/spring-projects/spring-framework/issues/31283, available in Spring Framework 6.0.13. Thank you.