Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,13 @@ private Mono<HttpResponse> attemptRedirect(final HttpPipelineCallContext context
if (redirectStrategy.shouldAttemptRedirect(context, httpResponse, redirectAttempt,
attemptedRedirectUrls)) {
HttpRequest redirectRequestCopy = redirectStrategy.createRedirectRequest(httpResponse);
return httpResponse.getBody()

// Clear the authorization header to avoid the client to be redirected to an untrusted third party server
// causing it to leak your authorization token to.
httpResponse.getHeaders().remove("Authorization");
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If we remove the "Authorization" header, how does the redirected request get authorized?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it is expected behavior to remove the authorization header before we redirect for security reasons.
So that we don't forward the authorization token to an untrusted/unwanted site.

It could be the service's responsibility to set the auth tokens accordingly in the redirect request so that it is forwarded correctly I would think.

Ref: Azure/azure-sdk-for-net#22876 (comment)


return httpResponse
.getBody()
.ignoreElements()
.then(attemptRedirect(context, next, redirectRequestCopy, redirectAttempt + 1, attemptedRedirectUrls));
} else {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@
import com.azure.core.http.MockHttpResponse;
import com.azure.core.http.clients.NoOpHttpClient;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.ValueSource;
import reactor.core.publisher.Mono;

import java.net.MalformedURLException;
Expand All @@ -25,6 +27,7 @@
import java.util.function.Function;

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNull;

public class RedirectPolicyTest {

Expand Down Expand Up @@ -53,14 +56,16 @@ public Mono<HttpResponse> send(HttpRequest request) {
assertEquals(308, response.getStatusCode());
}

@Test
public void defaultRedirectWhen308() throws Exception {
@ParameterizedTest
@ValueSource(ints = {308, 307, 301, 302})
public void defaultRedirectExpectedStatusCodes(int statusCode) throws Exception {
RecordingHttpClient httpClient = new RecordingHttpClient(request -> {
if (request.getUrl().toString().equals("http://localhost/")) {
Map<String, String> headers = new HashMap<>();
headers.put("Location", "http://redirecthost/");
headers.put("Authorization", "12345");
HttpHeaders httpHeader = new HttpHeaders(headers);
return Mono.just(new MockHttpResponse(request, 308, httpHeader));
return Mono.just(new MockHttpResponse(request, statusCode, httpHeader));
} else {
return Mono.just(new MockHttpResponse(request, 200));
}
Expand All @@ -74,8 +79,8 @@ public void defaultRedirectWhen308() throws Exception {
HttpResponse response = pipeline.send(new HttpRequest(HttpMethod.GET,
new URL("http://localhost/"))).block();

// assertEquals(2, httpClient.getCount());
assertEquals(200, response.getStatusCode());
assertNull(response.getHeaders().getValue("Authorization"));
}

@Test
Expand Down Expand Up @@ -326,6 +331,32 @@ public Mono<HttpResponse> send(HttpRequest request) {
assertEquals(401, response.getStatusCode());
}

@Test
public void defaultRedirectAuthorizationHeaderCleared() throws Exception {
RecordingHttpClient httpClient = new RecordingHttpClient(request -> {
if (request.getUrl().toString().equals("http://localhost/")) {
Map<String, String> headers = new HashMap<>();
headers.put("Location", "http://redirecthost/");
headers.put("Authorization", "12345");
HttpHeaders httpHeader = new HttpHeaders(headers);
return Mono.just(new MockHttpResponse(request, 308, httpHeader));
} else {
return Mono.just(new MockHttpResponse(request, 200));
}
});

HttpPipeline pipeline = new HttpPipelineBuilder()
.httpClient(httpClient)
.policies(new RedirectPolicy())
.build();

HttpResponse response = pipeline.send(new HttpRequest(HttpMethod.GET,
new URL("http://localhost/"))).block();

assertEquals(200, response.getStatusCode());
assertNull(response.getHeaders().getValue("Authorization"));
}

static class RecordingHttpClient implements HttpClient {

private final AtomicInteger count = new AtomicInteger();
Expand Down