mirror of
https://github.com/square/okhttp.git
synced 2026-01-27 04:22:07 +03:00
Fail gracefully on a 401 response code with no WWW-Authenticate header.
This is more lenient than necessary; the HTTP spec says this:
10.4.2 401 Unauthorized
The request requires user authentication. The response MUST include a
WWW-Authenticate header field (section 14.47) containing a challenge
applicable to the requested resource.
Not throwing will still cause the request to fail, since the 401
response code triggers an IOException. But this type of failure is
more recoverable and allows the caller to inspect the headers and
response body.
This commit is contained in:
@@ -423,13 +423,15 @@ public class HttpURLConnectionImpl extends OkHttpConnection {
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the authorization credentials on the base of provided challenge.
|
||||
* Returns the authorization credentials that may satisfy the challenge.
|
||||
* Returns null if a challenge header was not provided or if credentials
|
||||
* were not available.
|
||||
*/
|
||||
private String getAuthorizationCredentials(RawHeaders responseHeaders, String challengeHeader)
|
||||
throws IOException {
|
||||
List<Challenge> challenges = HeaderParser.parseChallenges(responseHeaders, challengeHeader);
|
||||
if (challenges.isEmpty()) {
|
||||
throw new IOException("No authentication challenges found");
|
||||
return null;
|
||||
}
|
||||
|
||||
for (Challenge challenge : challenges) {
|
||||
|
||||
@@ -981,6 +981,39 @@ public final class URLConnectionTest extends TestCase {
|
||||
assertEquals(Arrays.toString(requestBody), Arrays.toString(request.getBody()));
|
||||
}
|
||||
|
||||
public void testNonStandardAuthenticationScheme() throws Exception {
|
||||
RecordingAuthenticator authenticator = new RecordingAuthenticator();
|
||||
Authenticator.setDefault(authenticator);
|
||||
MockResponse pleaseAuthenticate = new MockResponse()
|
||||
.setResponseCode(401)
|
||||
.addHeader("WWW-Authenticate: Foo")
|
||||
.setBody("Please authenticate.");
|
||||
server.enqueue(pleaseAuthenticate);
|
||||
server.play();
|
||||
|
||||
OkHttpConnection connection = openConnection(server.getUrl("/"));
|
||||
assertEquals(401, connection.getResponseCode());
|
||||
assertEquals(Collections.<String>emptyList(), authenticator.calls);
|
||||
}
|
||||
|
||||
public void testNonStandardAuthenticationSchemeWithRealm() throws Exception {
|
||||
RecordingAuthenticator authenticator = new RecordingAuthenticator();
|
||||
Authenticator.setDefault(authenticator);
|
||||
MockResponse pleaseAuthenticate = new MockResponse()
|
||||
.setResponseCode(401)
|
||||
.addHeader("WWW-Authenticate: Foo realm=\"Bar\"")
|
||||
.setBody("Please authenticate.");
|
||||
server.enqueue(pleaseAuthenticate);
|
||||
server.play();
|
||||
|
||||
OkHttpConnection connection = openConnection(server.getUrl("/"));
|
||||
assertEquals(401, connection.getResponseCode());
|
||||
assertEquals(1, authenticator.calls.size());
|
||||
String call = authenticator.calls.get(0);
|
||||
assertTrue(call, call.contains("scheme=Foo"));
|
||||
assertTrue(call, call.contains("prompt=Bar"));
|
||||
}
|
||||
|
||||
public void testSetValidRequestMethod() throws Exception {
|
||||
server.play();
|
||||
assertValidRequestMethod("GET");
|
||||
@@ -2078,4 +2111,20 @@ public final class URLConnectionTest extends TestCase {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
private static class RecordingAuthenticator extends Authenticator {
|
||||
private final List<String> calls = new ArrayList<String>();
|
||||
|
||||
@Override protected PasswordAuthentication getPasswordAuthentication() {
|
||||
this.calls.add("host=" + getRequestingHost()
|
||||
+ " port=" + getRequestingPort()
|
||||
+ " site=" + getRequestingSite()
|
||||
+ " url=" + getRequestingURL()
|
||||
+ " type=" + getRequestorType()
|
||||
+ " prompt=" + getRequestingPrompt()
|
||||
+ " protocol=" + getRequestingProtocol()
|
||||
+ " scheme=" + getRequestingScheme());
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user