Index: net/http/http_network_transaction_unittest.cc |
=================================================================== |
--- net/http/http_network_transaction_unittest.cc (revision 10666) |
+++ net/http/http_network_transaction_unittest.cc (working copy) |
@@ -1412,6 +1412,131 @@ |
EXPECT_EQ(100, response->headers->GetContentLength()); |
} |
+// Test NTLM authentication. |
+// TODO(wtc): This test doesn't work because we need to control the 8 random |
+// bytes and the "workstation name" for a deterministic expected result. |
+TEST_F(HttpNetworkTransactionTest, DISABLED_NTLMAuth) { |
+ scoped_ptr<net::ProxyService> proxy_service(CreateNullProxyService()); |
+ scoped_ptr<net::HttpTransaction> trans(new net::HttpNetworkTransaction( |
+ CreateSession(proxy_service.get()), &mock_socket_factory)); |
+ |
+ net::HttpRequestInfo request; |
+ request.method = "GET"; |
+ request.url = GURL("http://172.22.68.17/kids/login.aspx"); |
+ request.load_flags = 0; |
+ |
+ MockWrite data_writes1[] = { |
+ MockWrite("GET /kids/login.aspx HTTP/1.1\r\n" |
+ "Host: 172.22.68.17\r\n" |
+ "Connection: keep-alive\r\n\r\n"), |
+ }; |
+ |
+ MockRead data_reads1[] = { |
+ MockRead("HTTP/1.1 401 Access Denied\r\n"), |
+ // Negotiate and NTLM are often requested together. We only support NTLM. |
+ MockRead("WWW-Authenticate: Negotiate\r\n"), |
+ MockRead("WWW-Authenticate: NTLM\r\n"), |
+ MockRead("Connection: close\r\n"), |
+ MockRead("Content-Length: 42\r\n"), |
+ MockRead("Content-Type: text/html\r\n"), |
+ MockRead("Proxy-Support: Session-Based-Authentication\r\n\r\n"), |
+ // Missing content -- won't matter, as connection will be reset. |
+ MockRead(false, net::ERR_UNEXPECTED), |
+ }; |
+ |
+ MockWrite data_writes2[] = { |
+ // After automatically restarting with a null identity, this is the |
+ // request we should be issuing -- the final header line contains a Type |
+ // 1 message. |
+ MockWrite("GET /kids/login.aspx HTTP/1.1\r\n" |
+ "Host: 172.22.68.17\r\n" |
+ "Connection: keep-alive\r\n" |
+ "Authorization: NTLM " |
+ "TlRMTVNTUAABAAAAB4IIAAAAAAAAAAAAAAAAAAAAAAA=\r\n\r\n"), |
+ |
+ // After calling trans->RestartWithAuth(), we should send a Type 3 message |
+ // (the credentials for the origin server). The second request continues |
+ // on the same connection. |
+ MockWrite("GET /kids/login.aspx HTTP/1.1\r\n" |
+ "Host: 172.22.68.17\r\n" |
+ "Connection: keep-alive\r\n" |
+ "Authorization: NTLM TlRMTVNTUAADAAAAGAAYAHAAAAAYABgAiA" |
+ "AAAAAAAABAAAAAGAAYAEAAAAAYABgAWAAAAAAAAAAAAAAABYIIAHQA" |
+ "ZQBzAHQAaQBuAGcALQBuAHQAbABtAHcAdABjAGgAYQBuAGcALQBjAG" |
+ "8AcgBwAMertjYHfqUhAAAAAAAAAAAAAAAAAAAAAEP3kddZKtMDMssm" |
+ "KYA6SCllVGUeyoQppQ==\r\n\r\n"), |
+ }; |
+ |
+ MockRead data_reads2[] = { |
+ // The origin server responds with a Type 2 message. |
+ MockRead("HTTP/1.1 401 Access Denied\r\n"), |
+ MockRead("WWW-Authenticate: NTLM " |
+ "TlRMTVNTUAACAAAADAAMADgAAAAFgokCTroKF1e/DRcAAAAAAAAAALo" |
+ "AugBEAAAABQEoCgAAAA9HAE8ATwBHAEwARQACAAwARwBPAE8ARwBMAE" |
+ "UAAQAaAEEASwBFAEUAUwBBAFIAQQAtAEMATwBSAFAABAAeAGMAbwByA" |
+ "HAALgBnAG8AbwBnAGwAZQAuAGMAbwBtAAMAQABhAGsAZQBlAHMAYQBy" |
+ "AGEALQBjAG8AcgBwAC4AYQBkAC4AYwBvAHIAcAAuAGcAbwBvAGcAbAB" |
+ "lAC4AYwBvAG0ABQAeAGMAbwByAHAALgBnAG8AbwBnAGwAZQAuAGMAbw" |
+ "BtAAAAAAA=\r\n"), |
+ MockRead("Content-Length: 42\r\n"), |
+ MockRead("Content-Type: text/html\r\n"), |
+ MockRead("Proxy-Support: Session-Based-Authentication\r\n\r\n"), |
+ MockRead("You are not authorized to view this page\r\n"), |
+ |
+ // Lastly we get the desired content. |
+ MockRead("HTTP/1.1 200 OK\r\n"), |
+ MockRead("Content-Type: text/html; charset=utf-8\r\n"), |
+ MockRead("Content-Length: 13\r\n\r\n"), |
+ MockRead("Please Login\r\n"), |
+ MockRead(false, net::OK), |
+ }; |
+ |
+ MockSocket data1; |
+ data1.reads = data_reads1; |
+ data1.writes = data_writes1; |
+ MockSocket data2; |
+ data2.reads = data_reads2; |
+ data2.writes = data_writes2; |
+ mock_sockets[0] = &data1; |
+ mock_sockets[1] = &data2; |
+ mock_sockets[2] = NULL; |
+ |
+ TestCompletionCallback callback1; |
+ |
+ int rv = trans->Start(&request, &callback1); |
+ EXPECT_EQ(net::ERR_IO_PENDING, rv); |
+ |
+ rv = callback1.WaitForResult(); |
+ EXPECT_EQ(net::OK, rv); |
+ |
+ const net::HttpResponseInfo* response = trans->GetResponseInfo(); |
+ EXPECT_FALSE(response == NULL); |
+ |
+ // The password prompt info should have been set in response->auth_challenge. |
+ EXPECT_FALSE(response->auth_challenge.get() == NULL); |
+ |
+ // TODO(eroman): this should really include the effective port (80) |
+ EXPECT_EQ(L"172.22.68.17", response->auth_challenge->host); |
+ EXPECT_EQ(L"", response->auth_challenge->realm); |
+ EXPECT_EQ(L"ntlm", response->auth_challenge->scheme); |
+ |
+ // Pass a null identity to the first RestartWithAuth. |
+ // TODO(wtc): In the future we may pass the actual identity to the first |
+ // RestartWithAuth. |
+ |
+ TestCompletionCallback callback2; |
+ |
+ rv = trans->RestartWithAuth(L"testing-ntlm", L"testing-ntlm", &callback2); |
+ EXPECT_EQ(net::ERR_IO_PENDING, rv); |
+ |
+ rv = callback2.WaitForResult(); |
+ EXPECT_EQ(net::OK, rv); |
+ |
+ response = trans->GetResponseInfo(); |
+ EXPECT_TRUE(response->auth_challenge.get() == NULL); |
+ EXPECT_EQ(13, response->headers->GetContentLength()); |
+} |
+ |
// Test reading a server response which has only headers, and no body. |
// After some maximum number of bytes is consumed, the transaction should |
// fail with ERR_RESPONSE_HEADERS_TOO_BIG. |