Skip to content

Commit

Permalink
Merge pull request #31 from square/jwilson/auth
Browse files Browse the repository at this point in the history
Fix Authenticator callbacks to include full information.
  • Loading branch information
JakeWharton committed Sep 25, 2012
2 parents c37f520 + 5d4e9ac commit 9ecb2a8
Show file tree
Hide file tree
Showing 2 changed files with 89 additions and 36 deletions.
15 changes: 12 additions & 3 deletions src/main/java/libcore/net/http/HttpURLConnectionImpl.java
Original file line number Diff line number Diff line change
Expand Up @@ -445,9 +445,18 @@ private String getAuthorizationCredentials(RawHeaders responseHeaders, String ch

for (Challenge challenge : challenges) {
// use the global authenticator to get the password
PasswordAuthentication auth = Authenticator.requestPasswordAuthentication(
getConnectToInetAddress(), getConnectToPort(), url.getProtocol(),
challenge.realm, challenge.scheme);
PasswordAuthentication auth;
if (responseHeaders.getResponseCode() == HTTP_PROXY_AUTH) {
InetSocketAddress proxyAddress = (InetSocketAddress) proxy.address();
auth = Authenticator.requestPasswordAuthentication(
proxyAddress.getHostName(), getConnectToInetAddress(),
proxyAddress.getPort(), url.getProtocol(), challenge.realm,
challenge.scheme, url, Authenticator.RequestorType.PROXY);
} else {
auth = Authenticator.requestPasswordAuthentication(
url.getHost(), getConnectToInetAddress(), url.getPort(), url.getProtocol(),
challenge.realm, challenge.scheme, url, Authenticator.RequestorType.SERVER);
}
if (auth == null) {
continue;
}
Expand Down
110 changes: 77 additions & 33 deletions src/test/java/libcore/net/http/URLConnectionTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -78,13 +78,6 @@
* Android's URLConnectionTest.
*/
public final class URLConnectionTest extends TestCase {

private static final Authenticator SIMPLE_AUTHENTICATOR = new Authenticator() {
protected PasswordAuthentication getPasswordAuthentication() {
return new PasswordAuthentication("username", "password".toCharArray());
}
};

/** base64("username:password") */
private static final String BASE_64_CREDENTIALS = "dXNlcm5hbWU6cGFzc3dvcmQ=";

Expand Down Expand Up @@ -717,7 +710,7 @@ public void testProxyConnectIncludesProxyHeadersOnly()
}

public void testProxyAuthenticateOnConnect() throws Exception {
Authenticator.setDefault(SIMPLE_AUTHENTICATOR);
Authenticator.setDefault(new RecordingAuthenticator());
server.useHttps(sslContext.getSocketFactory(), true);
server.enqueue(new MockResponse()
.setResponseCode(407)
Expand Down Expand Up @@ -1069,7 +1062,7 @@ private void testAuthenticateWithStreamingPost(StreamingMode streamingMode) thro
server.enqueue(pleaseAuthenticate);
server.play();

Authenticator.setDefault(SIMPLE_AUTHENTICATOR);
Authenticator.setDefault(new RecordingAuthenticator());
OkHttpConnection connection = openConnection(server.getUrl("/"));
connection.setDoOutput(true);
byte[] requestBody = { 'A', 'B', 'C', 'D' };
Expand All @@ -1094,36 +1087,78 @@ private void testAuthenticateWithStreamingPost(StreamingMode streamingMode) thro
}

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);
List<String> calls = authCallsForHeader("WWW-Authenticate: Foo");
assertEquals(Collections.<String>emptyList(), calls);
}

public void testNonStandardAuthenticationSchemeWithRealm() throws Exception {
RecordingAuthenticator authenticator = new RecordingAuthenticator();
List<String> calls = authCallsForHeader("WWW-Authenticate: Foo realm=\"Bar\"");
assertEquals(1, calls.size());
String call = calls.get(0);
assertTrue(call, call.contains("scheme=Foo"));
assertTrue(call, call.contains("prompt=Bar"));
}

// Digest auth is currently unsupported. Test that digest requests should fail reasonably.
// http://code.google.com/p/android/issues/detail?id=11140
public void testDigestAuthentication() throws Exception {
List<String> calls = authCallsForHeader("WWW-Authenticate: Digest "
+ "realm=\"testrealm@host.com\", qop=\"auth,auth-int\", "
+ "nonce=\"dcd98b7102dd2f0e8b11d0f600bfb0c093\", "
+ "opaque=\"5ccc069c403ebaf9f0171e9517f40e41\"");
assertEquals(1, calls.size());
String call = calls.get(0);
assertTrue(call, call.contains("scheme=Digest"));
assertTrue(call, call.contains("prompt=testrealm@host.com"));
}

public void testAllAttributesSetInServerAuthenticationCallbacks() throws Exception {
List<String> calls = authCallsForHeader("WWW-Authenticate: Basic realm=\"Bar\"");
assertEquals(1, calls.size());
URL url = server.getUrl("/");
String call = calls.get(0);
assertTrue(call, call.contains("host=" + url.getHost()));
assertTrue(call, call.contains("port=" + url.getPort()));
assertTrue(call, call.contains("site=" + InetAddress.getAllByName(url.getHost())[0]));
assertTrue(call, call.contains("url=" + url));
assertTrue(call, call.contains("type=" + Authenticator.RequestorType.SERVER));
assertTrue(call, call.contains("prompt=Bar"));
assertTrue(call, call.contains("protocol=http"));
assertTrue(call, call.toLowerCase().contains("scheme=basic")); // lowercase for the RI.
}

public void testAllAttributesSetInProxyAuthenticationCallbacks() throws Exception {
List<String> calls = authCallsForHeader("Proxy-Authenticate: Basic realm=\"Bar\"");
assertEquals(1, calls.size());
URL url = server.getUrl("/");
String call = calls.get(0);
assertTrue(call, call.contains("host=" + url.getHost()));
assertTrue(call, call.contains("port=" + url.getPort()));
assertTrue(call, call.contains("site=" + InetAddress.getAllByName(url.getHost())[0]));
assertTrue(call, call.contains("url=http://android.com"));
assertTrue(call, call.contains("type=" + Authenticator.RequestorType.PROXY));
assertTrue(call, call.contains("prompt=Bar"));
assertTrue(call, call.contains("protocol=http"));
assertTrue(call, call.toLowerCase().contains("scheme=basic")); // lowercase for the RI.
}

private List<String> authCallsForHeader(String authHeader) throws IOException {
boolean proxy = authHeader.startsWith("Proxy-");
int responseCode = proxy ? 407 : 401;
RecordingAuthenticator authenticator = new RecordingAuthenticator(null);
Authenticator.setDefault(authenticator);
MockResponse pleaseAuthenticate = new MockResponse()
.setResponseCode(401)
.addHeader("WWW-Authenticate: Foo realm=\"Bar\"")
.setResponseCode(responseCode)
.addHeader(authHeader)
.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"));
OkHttpConnection connection = proxy
? openConnection(new URL("http://android.com"), server.toProxyAddress())
: openConnection(server.getUrl("/"));
assertEquals(responseCode, connection.getResponseCode());
return authenticator.calls;
}

public void testSetValidRequestMethod() throws Exception {
Expand Down Expand Up @@ -1283,7 +1318,7 @@ public void testAuthenticateWithPost() throws Exception {
server.enqueue(new MockResponse().setBody("Successful auth!"));
server.play();

Authenticator.setDefault(SIMPLE_AUTHENTICATOR);
Authenticator.setDefault(new RecordingAuthenticator());
OkHttpConnection connection = openConnection(server.getUrl("/"));
connection.setDoOutput(true);
byte[] requestBody = { 'A', 'B', 'C', 'D' };
Expand Down Expand Up @@ -1318,7 +1353,7 @@ public void testAuthenticateWithGet() throws Exception {
server.enqueue(new MockResponse().setBody("Successful auth!"));
server.play();

Authenticator.setDefault(SIMPLE_AUTHENTICATOR);
Authenticator.setDefault(new RecordingAuthenticator());
OkHttpConnection connection = openConnection(server.getUrl("/"));
assertEquals("Successful auth!", readAscii(connection.getInputStream(), Integer.MAX_VALUE));

Expand Down Expand Up @@ -2226,6 +2261,15 @@ public boolean verify(String hostname, SSLSession session) {

private static class RecordingAuthenticator extends Authenticator {
private final List<String> calls = new ArrayList<String>();
private final PasswordAuthentication authentication;

public RecordingAuthenticator(PasswordAuthentication authentication) {
this.authentication = authentication;
}

public RecordingAuthenticator() {
this(new PasswordAuthentication("username", "password".toCharArray()));
}

@Override protected PasswordAuthentication getPasswordAuthentication() {
this.calls.add("host=" + getRequestingHost()
Expand All @@ -2236,7 +2280,7 @@ private static class RecordingAuthenticator extends Authenticator {
+ " prompt=" + getRequestingPrompt()
+ " protocol=" + getRequestingProtocol()
+ " scheme=" + getRequestingScheme());
return null;
return authentication;
}
}
}

0 comments on commit 9ecb2a8

Please sign in to comment.