spring-cloud-gateway icon indicating copy to clipboard operation
spring-cloud-gateway copied to clipboard

TokenRelayGatewayFilter always fetches access token via refresh token

Open viZu opened this issue 4 years ago • 2 comments

Describe the bug Note: this is a bug report which originates from https://github.com/spring-projects/spring-security/issues/10082. The original Bug in that issue was already fixed.

When using TokenRelayGatewayFilterFactory for passing access tokens to downstream services, that filter always fetches the access token via the the refresh token which is stored within the current users session. This is unnecessary since a session still might have a valid access token stored, which is not yet expired. This can be easily reproduced by creating a sample application and set the breakpoint in WebClientReactiveRefreshTokenTokenResponseClient#populateTokenRequestBody which is always called.

I implemented a Workaround which first checks the access token before fetching a new access token via the refresh token:

import org.springframework.beans.factory.annotation.Autowired
import org.springframework.security.oauth2.client.OAuth2AuthorizeRequest
import org.springframework.security.oauth2.client.OAuth2AuthorizedClient
import org.springframework.security.oauth2.client.ReactiveOAuth2AuthorizedClientManager
import org.springframework.security.oauth2.client.authentication.OAuth2AuthenticationToken
import org.springframework.security.oauth2.client.web.server.ServerOAuth2AuthorizedClientRepository
import org.springframework.security.oauth2.core.OAuth2AccessToken
import org.springframework.stereotype.Service
import org.springframework.web.server.ServerWebExchange
import reactor.core.publisher.Mono
import java.security.Principal
import java.time.Instant

@Service
class Oauth2AccessTokenProvider(
    @Autowired private val serverOAuth2AuthorizedClientRepository: ServerOAuth2AuthorizedClientRepository,
    @Autowired private val clientManager: ReactiveOAuth2AuthorizedClientManager
) {
    fun provideAccessToken(exchange: ServerWebExchange): Mono<OAuth2AccessToken> {
        return exchange.getPrincipal<Principal>()
            .filter { it is OAuth2AuthenticationToken }
            .cast(OAuth2AuthenticationToken::class.java)
            .flatMap { token ->
                serverOAuth2AuthorizedClientRepository.loadAuthorizedClient<OAuth2AuthorizedClient>(
                    token.authorizedClientRegistrationId,
                    token,
                    exchange
                )
                    .map { client -> client.accessToken }
                    .filter { accessToken -> accessToken.expiresAt?.isAfter(Instant.now()) ?: false }
                    .switchIfEmpty(fallbackFetchToken(exchange, token))
            }
    }

    private fun fallbackFetchToken(
        exchange: ServerWebExchange,
        oauth2Authentication: OAuth2AuthenticationToken
    ): Mono<OAuth2AccessToken> {
        val clientRegistrationId = oauth2Authentication.authorizedClientRegistrationId
        val request = OAuth2AuthorizeRequest.withClientRegistrationId(clientRegistrationId)
            .attribute(ServerWebExchange::class.java.name, exchange)
            .principal(oauth2Authentication).build()
        return clientManager.authorize(request)
            .map { it.accessToken }
    }

}

Sample If possible, please provide a test case or sample application that reproduces the problem. This makes it much easier for us to diagnose the problem and to verify that we have fixed it.

viZu avatar Jul 28 '21 16:07 viZu

Are you willing to submit a PR?

spencergibb avatar Oct 07 '21 00:10 spencergibb

Hi @spencergibb , I create fix PR https://github.com/spring-cloud/spring-cloud-gateway/pull/3202! Can you simply check my PR? thanks! 🙇

injae-kim avatar Dec 31 '23 13:12 injae-kim

Hi @injae-kim. Thanks for the PR and taking a deep look at the token relay filter!

Before proceeding, can we review your configuration and discuss why the issue you're facing may be happening? Spring Security's ReactiveOAuth2AuthorizedClientManager will automatically handle re-using access tokens if they are still active. It seems possible you have an incorrect configuration. Can you share a minimal reproducible sample that demonstrates the behavior you're seeing?

sjohnr avatar Mar 08 '24 20:03 sjohnr

Spring Security's ReactiveOAuth2AuthorizedClientManager will automatically handle re-using access tokens if they are still active.

oh I just think that this issue is still valid and need to fix. 😅

sorry for bothering you, I'll close my PR~ then we can close this issue too?

injae-kim avatar Mar 11 '24 14:03 injae-kim

oh I just think that this issue is still valid and need to fix. 😅

@injae-kim, thanks for clarifying. I'm not convinced this is a valid issue, but I'd like to understand it more. Are you saying you did not encounter this issue yourself?

sorry for bothering you, I'll close my PR~ then we can close this issue too?

No problem @injae-kim. I think we need to check with the reporter to see if we can get more information. @viZu, perhaps you can provide some more information? See above comment.

sjohnr avatar Mar 11 '24 14:03 sjohnr

Are you saying you did not encounter this issue yourself?

yep! by https://github.com/spring-cloud/spring-cloud-gateway/issues/2316#issuecomment-937343720, I think this issue is verified as bug so I can create PR :)

Let's wait more information~!

injae-kim avatar Mar 11 '24 14:03 injae-kim

If you would like us to look at this issue, please provide the requested information. If the information is not provided within the next 7 days this issue will be closed.

spring-cloud-issues avatar Mar 20 '24 22:03 spring-cloud-issues

Closing due to lack of requested feedback. If you would like us to look at this issue, please provide the requested information and we will re-open the issue.

spring-cloud-issues avatar Mar 27 '24 22:03 spring-cloud-issues