From 5114190cb6e2c59fa451be1f5f7ecc179387a2bf Mon Sep 17 00:00:00 2001 From: Rob Winch Date: Wed, 21 Aug 2019 08:31:30 -0500 Subject: [PATCH] Fix WebClient Memory Leaks WebClient exchange requires that the body is consumed. Before this commit there were places where an Exception was thrown without consuming the body if the status was not successful. There was also the potential for the statusCode invocation to throw an Exception of the status code was not defined which would cause a leak. This commit ensures that before the Exception is thrown the body is consumed. It also uses the http status in a way that will ensure an Exception is not thrown. Fixes gh-7293 --- ...activeClientCredentialsTokenResponseClient.java | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/endpoint/WebClientReactiveClientCredentialsTokenResponseClient.java b/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/endpoint/WebClientReactiveClientCredentialsTokenResponseClient.java index e081d8248a..14c87ae0cf 100644 --- a/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/endpoint/WebClientReactiveClientCredentialsTokenResponseClient.java +++ b/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/endpoint/WebClientReactiveClientCredentialsTokenResponseClient.java @@ -15,7 +15,10 @@ */ package org.springframework.security.oauth2.client.endpoint; +import org.springframework.core.io.buffer.DataBuffer; +import org.springframework.core.io.buffer.DataBufferUtils; import org.springframework.http.HttpHeaders; +import org.springframework.http.HttpStatus; import org.springframework.http.MediaType; import org.springframework.security.oauth2.client.registration.ClientRegistration; import org.springframework.security.oauth2.core.ClientAuthenticationMethod; @@ -65,15 +68,18 @@ public class WebClientReactiveClientCredentialsTokenResponseClient implements Re .headers(headers(clientRegistration)) .body(body) .exchange() - .flatMap(response ->{ - if (!response.statusCode().is2xxSuccessful()){ + .flatMap(response -> { + HttpStatus status = HttpStatus.resolve(response.rawStatusCode()); + if (status == null || !status.is2xxSuccessful()) { // extract the contents of this into a method named oauth2AccessTokenResponse but has an argument for the response - throw WebClientResponseException.create(response.rawStatusCode(), + return response.bodyToFlux(DataBuffer.class) + .map(DataBufferUtils::release) + .then(Mono.error(WebClientResponseException.create(response.rawStatusCode(), "Cannot get token, expected 2xx HTTP Status code", null, null, null - ); + ))); } return response.body(oauth2AccessTokenResponse()); }) .map(response -> {