Skip to content

Commit e6cc86e

Browse files
committed
fixup! SCANJLIB-306 Restore authentication support for proxy + SSL
1 parent 65e5af8 commit e6cc86e

File tree

3 files changed

+18
-10
lines changed

3 files changed

+18
-10
lines changed

lib/pom.xml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -141,6 +141,7 @@
141141
<systemPropertyVariables>
142142
<user.language>en</user.language>
143143
<user.country>US</user.country>
144+
<jdk.http.auth.tunneling.disabledSchemes>foo</jdk.http.auth.tunneling.disabledSchemes>
144145
</systemPropertyVariables>
145146
<environmentVariables>
146147
<LANGUAGE>en_US</LANGUAGE>

lib/src/main/java/org/sonarsource/scanner/lib/internal/http/ScannerHttpClient.java

Lines changed: 5 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -142,28 +142,23 @@ private <G> G callUrl(String url, boolean authentication, @Nullable String accep
142142
}
143143

144144
private <G> G callUrlWithRedirects(String url, boolean authentication, @Nullable String acceptHeader, ResponseHandler<G> responseHandler) {
145-
return callUrlWithRedirectsAndProxyAuth(url, authentication, acceptHeader, responseHandler, 0, false);
145+
return callUrlWithRedirectsAndProxyAuth(url, authentication, acceptHeader, responseHandler, 0);
146146
}
147147

148148
private <G> G callUrlWithRedirectsAndProxyAuth(String url, boolean authentication, @Nullable String acceptHeader, ResponseHandler<G> responseHandler,
149-
int redirectCount, boolean proxyAuthRetry) {
149+
int redirectCount) {
150150
if (redirectCount > 10) {
151151
throw new IllegalStateException("Too many redirects (>10) for URL: " + url);
152152
}
153153

154-
var request = prepareRequest(url, acceptHeader, authentication, proxyAuthRetry);
154+
var request = prepareRequest(url, acceptHeader, authentication);
155155

156156
HttpResponse<InputStream> response = null;
157157
Instant start = Instant.now();
158158
try {
159159
LOG.debug("--> {} {}", request.method(), request.uri());
160160
response = httpClient.send(request, HttpResponse.BodyHandlers.ofInputStream());
161161

162-
if (response.statusCode() == 407 && !proxyAuthRetry && httpConfig.getProxyUser() != null) {
163-
LOG.debug("Received 407 Proxy Authentication Required, retrying request");
164-
return callUrlWithRedirectsAndProxyAuth(url, authentication, acceptHeader, responseHandler, redirectCount, true);
165-
}
166-
167162
if (isRedirect(response.statusCode())) {
168163
var locationHeader = response.headers().firstValue("Location");
169164
if (locationHeader.isPresent()) {
@@ -172,7 +167,7 @@ private <G> G callUrlWithRedirectsAndProxyAuth(String url, boolean authenticatio
172167
URI originalUri = URI.create(url);
173168
redirectUrl = originalUri.getScheme() + "://" + originalUri.getAuthority() + redirectUrl;
174169
}
175-
return callUrlWithRedirectsAndProxyAuth(redirectUrl, authentication, acceptHeader, responseHandler, redirectCount + 1, proxyAuthRetry);
170+
return callUrlWithRedirectsAndProxyAuth(redirectUrl, authentication, acceptHeader, responseHandler, redirectCount + 1);
176171
}
177172
}
178173

@@ -218,7 +213,7 @@ private interface ResponseHandler<G> {
218213
G apply(HttpResponse<InputStream> response) throws IOException;
219214
}
220215

221-
private HttpRequest prepareRequest(String url, @Nullable String acceptHeader, boolean authentication, boolean proxyAuthRetry) {
216+
private HttpRequest prepareRequest(String url, @Nullable String acceptHeader, boolean authentication) {
222217
var timeout = httpConfig.getResponseTimeout().isZero() ? httpConfig.getSocketTimeout() : httpConfig.getResponseTimeout();
223218

224219
var requestBuilder = HttpRequest.newBuilder()

lib/src/test/java/org/sonarsource/scanner/lib/internal/http/ScannerHttpClientTest.java

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@
4646
import org.sonarsource.scanner.lib.internal.util.System2;
4747
import testutils.LogTester;
4848

49+
import static com.github.tomakehurst.wiremock.client.WireMock.absent;
4950
import static org.mockito.ArgumentMatchers.any;
5051
import static org.mockito.Mockito.mock;
5152
import static org.mockito.Mockito.when;
@@ -264,9 +265,14 @@ class WithProxy {
264265
@BeforeEach
265266
void configureMocks(TestInfo info) {
266267
if (info.getTags().contains(PROXY_AUTH_ENABLED)) {
268+
// This scenario simulates a proxy that requires authentication and does not accept preemptive auth:
269+
// the first request without Proxy-Authorization header gets a 407 with the Proxy-Authenticate challenge, then the client retries with the Proxy-Authorization header.
270+
// This is not used because the Scanner HttpClient sends Proxy-Authorization preemptively by default,
271+
// but keep it just in case we want to support it once we upgrade to JDK 24+ (because of https://bugs.openjdk.org/browse/JDK-8326949)
267272
proxyMock.stubFor(get(urlMatching("/batch/.*"))
268273
.inScenario("Proxy Auth")
269274
.whenScenarioStateIs(STARTED)
275+
.withHeader("Proxy-Authorization", absent())
270276
.willReturn(aResponse()
271277
.withStatus(407)
272278
.withHeader("Proxy-Authenticate", "Basic realm=\"Access to the proxy\""))
@@ -275,6 +281,12 @@ void configureMocks(TestInfo info) {
275281
.inScenario("Proxy Auth")
276282
.whenScenarioStateIs("Challenge returned")
277283
.willReturn(aResponse().proxiedFrom(sonarqube.baseUrl())));
284+
// Preemptive authentication (if client sends Proxy-Authorization on the first try) should also be accepted by the proxy
285+
proxyMock.stubFor(get(urlMatching("/batch/.*"))
286+
.inScenario("Proxy Auth")
287+
.whenScenarioStateIs(STARTED)
288+
.withHeader("Proxy-Authorization", equalTo("Basic " + Base64.getEncoder().encodeToString("proxyUser:proxyPassword".getBytes(StandardCharsets.UTF_8))))
289+
.willReturn(aResponse().proxiedFrom(sonarqube.baseUrl())));
278290
} else {
279291
proxyMock.stubFor(get(urlMatching("/batch/.*")).willReturn(aResponse().proxiedFrom(sonarqube.baseUrl())));
280292
}

0 commit comments

Comments
 (0)