Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(52)

Side by Side Diff: tests/standalone/io/http_auth_digest_test.dart

Issue 14740015: Implementation of HTTP digest authentication (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Fix analyzer staticerrors Created 7 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « sdk/lib/io/http_impl.dart ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
2 // for details. All rights reserved. Use of this source code is governed by a
3 // BSD-style license that can be found in the LICENSE file.
4
5 import "package:expect/expect.dart";
6 import 'dart:async';
7 import 'dart:crypto';
8 import 'dart:io';
9 import 'dart:isolate';
10 import 'dart:uri';
11 import 'dart:utf';
12
13 class Server {
14 HttpServer server;
15 bool passwordChanged = false;
16 var ha1;
17
18 static Future<Server> start(String algorithm, String qop) {
19 return new Server()._start(algorithm, qop);
20 }
21
22 Future<Server> _start(String serverAlgorithm, String serverQop) {
23 // Calculate ha1.
24 String realm = "test";
25 String username = "dart";
26 String password = "password";
27 var hasher = new MD5();
28 hasher.add("${username}:${realm}:${password}".codeUnits);
29 ha1 = CryptoUtils.bytesToHex(hasher.close());
30
31 var completer = new Completer();
32 HttpServer.bind("127.0.0.1", 0).then((s) {
33 server = s;
34 server.listen((HttpRequest request) {
35 // Just use a fixed nonce.
36 var nonce = "12345678";
37
38 sendUnauthorizedResponse(HttpResponse response) {
39 response.statusCode = HttpStatus.UNAUTHORIZED;
40 StringBuffer authHeader = new StringBuffer();
41 authHeader.write('Digest');
42 authHeader.write(', realm="$realm"');
43 authHeader.write(', nonce="$nonce"');
44 if (serverAlgorithm != null) {
45 authHeader.write(', algorithm=$serverAlgorithm');
46 }
47 authHeader.write(', domain="/digest/"');
48 if (serverQop != null) authHeader.write(', qop="$serverQop"');
49 response.headers.set(HttpHeaders.WWW_AUTHENTICATE, authHeader);
50 }
51
52 var response = request.response;
53 if (request.headers[HttpHeaders.AUTHORIZATION] != null) {
54 Expect.equals(1, request.headers[HttpHeaders.AUTHORIZATION].length);
55 String authorization =
56 request.headers[HttpHeaders.AUTHORIZATION][0];
57 HeaderValue header =
58 new HeaderValue.fromString(
59 authorization, parameterSeparator: ",");
60 if (header.value == "basic") {
61 sendUnauthorizedResponse(response);
62 } else {
63 var uri = header.parameters["uri"];
64 var qop = header.parameters["qop"];
65 var cnonce = header.parameters["cnonce"];
66 var nc = header.parameters["nc"];
67 Expect.equals("digest", header.value);
68 Expect.equals("dart", header.parameters["username"]);
69 Expect.equals(realm, header.parameters["realm"]);
70 Expect.equals("MD5", header.parameters["algorithm"]);
71 Expect.equals(nonce, header.parameters["nonce"]);
72 Expect.equals(request.uri.path, uri);
73 if (qop != null) {
74 // A server qop of auth-int is downgraded to none by the client.
75 Expect.equals("auth", serverQop);
76 Expect.equals("auth", header.parameters["qop"]);
77 Expect.isNotNull(cnonce);
78 Expect.isNotNull(nc);
79 } else {
80 Expect.isNull(cnonce);
81 Expect.isNull(nc);
82 }
83 Expect.isNotNull(header.parameters["response"]);
84
85 var hasher = new MD5();
86 hasher.add("${request.method}:${uri}".codeUnits);
87 var ha2 = CryptoUtils.bytesToHex(hasher.close());
88
89 var x;
90 hasher = new MD5();
91 if (qop == null || qop == "" || qop == "none") {
92 hasher.add("$ha1:${nonce}:$ha2".codeUnits);
93 } else {
94 hasher.add("$ha1:${nonce}:${nc}:${cnonce}:${qop}:$ha2".codeUnits);
95 }
96 Expect.equals(CryptoUtils.bytesToHex(hasher.close()),
97 header.parameters["response"]);
98
99 // Add a bogus Authentication-Info for testing.
100 var info = 'rspauth="77180d1ab3d6c9de084766977790f482", '
101 'cnonce="8f971178", '
102 'nc=000002c74, '
103 'qop=auth';
104 response.headers.set("Authentication-Info", info);
105 }
106 } else {
107 sendUnauthorizedResponse(response);
108 }
109 response.close();
110 });
111 completer.complete(this);
112 });
113 return completer.future;
114 }
115
116 void shutdown() {
117 server.close();
118 }
119
120 int get port => server.port;
121 }
122
123 void testNoCredentials(String algorithm, String qop) {
124 Server.start(algorithm, qop).then((server) {
125 HttpClient client = new HttpClient();
126
127 // Add digest credentials which does not match the path requested.
128 client.addCredentials(
129 Uri.parse("http://127.0.0.1:${server.port}/xxx"),
130 "test",
131 new HttpClientDigestCredentials("dart", "password"));
132
133 // Add basic credentials for the path requested.
134 client.addCredentials(
135 Uri.parse("http://127.0.0.1:${server.port}/digest"),
136 "test",
137 new HttpClientBasicCredentials("dart", "password"));
138
139 Future makeRequest(Uri url) {
140 return client.getUrl(url)
141 .then((HttpClientRequest request) => request.close())
142 .then((HttpClientResponse response) {
143 Expect.equals(HttpStatus.UNAUTHORIZED, response.statusCode);
144 return response.fold(null, (x, y) {});
145 });
146 }
147
148 var futures = [];
149 for (int i = 0; i < 5; i++) {
150 futures.add(
151 makeRequest(
152 Uri.parse("http://127.0.0.1:${server.port}/digest")));
153 }
154 Future.wait(futures).then((_) {
155 server.shutdown();
156 client.close();
157 });
158 });
159 }
160
161 void testCredentials(String algorithm, String qop) {
162 Server.start(algorithm, qop).then((server) {
163 HttpClient client = new HttpClient();
164
165 Future makeRequest(Uri url) {
166 return client.getUrl(url)
167 .then((HttpClientRequest request) => request.close())
168 .then((HttpClientResponse response) {
169 Expect.equals(HttpStatus.OK, response.statusCode);
170 Expect.equals(1, response.headers["Authentication-Info"].length);
171 return response.fold(null, (x, y) {});
172 });
173 }
174
175 client.addCredentials(
176 Uri.parse("http://127.0.0.1:${server.port}/digest"),
177 "test",
178 new HttpClientDigestCredentials("dart", "password"));
179
180 var futures = [];
181 for (int i = 0; i < 5; i++) {
182 futures.add(
183 makeRequest(
184 Uri.parse("http://127.0.0.1:${server.port}/digest")));
185 }
186 Future.wait(futures).then((_) {
187 server.shutdown();
188 client.close();
189 });
190 });
191 }
192
193 void testBasicAuthenticateCallback(String algorithm, String qop) {
194 Server.start(algorithm, qop).then((server) {
195 HttpClient client = new HttpClient();
196
197 client.authenticate = (Uri url, String scheme, String realm) {
198 Expect.equals("Digest", scheme);
199 Expect.equals("test", realm);
200 Completer completer = new Completer();
201 new Timer(const Duration(milliseconds: 10), () {
202 client.addCredentials(
203 Uri.parse("http://127.0.0.1:${server.port}/digest"),
204 "test",
205 new HttpClientDigestCredentials("dart", "password"));
206 completer.complete(true);
207 });
208 return completer.future;
209 };
210
211 Future makeRequest(Uri url) {
212 return client.getUrl(url)
213 .then((HttpClientRequest request) => request.close())
214 .then((HttpClientResponse response) {
215 Expect.equals(HttpStatus.OK, response.statusCode);
216 Expect.equals(1, response.headers["Authentication-Info"].length);
217 return response.fold(null, (x, y) {});
218 });
219 }
220
221 var futures = [];
222 for (int i = 0; i < 5; i++) {
223 futures.add(
224 makeRequest(
225 Uri.parse("http://127.0.0.1:${server.port}/digest")));
226 }
227 Future.wait(futures).then((_) {
228 server.shutdown();
229 client.close();
230 });
231 });
232 }
233
234 // An Apache virtual directory configuration like this can be used for
235 // running the local server tests.
236 //
237 // <Directory "/usr/local/prj/website/digest/">
238 // AllowOverride None
239 // Order deny,allow
240 // Deny from all
241 // Allow from 127.0.0.0/255.0.0.0 ::1/128
242 // AuthType Digest
243 // AuthName "test"
244 // AuthDigestDomain /digest/
245 // AuthDigestProvider file
246 // AuthUserFile /usr/local/prj/apache/passwd/digest-passwd
247 // Require valid-user
248 // </Directory>
249 //
250
251 void testLocalServerDigest() {
252 HttpClient client = new HttpClient();
253
254 Future makeRequest() {
255 return client.getUrl(Uri.parse("http://127.0.0.1/digest/test"))
256 .then((HttpClientRequest request) => request.close())
257 .then((HttpClientResponse response) {
258 Expect.equals(HttpStatus.OK, response.statusCode);
259 return response.fold(null, (x, y) {});
260 });
261 }
262
263 client.addCredentials(
264 Uri.parse("http://127.0.0.1/digest"),
265 "test",
266 new HttpClientDigestCredentials("dart", "password"));
267
268 client.authenticate = (Uri url, String scheme, String realm) {
269 client.addCredentials(
270 Uri.parse("http://127.0.0.1/digest"),
271 "test",
272 new HttpClientDigestCredentials("dart", "password"));
273 return new Future.value(true);
274 };
275
276 next() {
277 makeRequest().then((_) => next());
278 }
279 next();
280 }
281
282 main() {
283 testNoCredentials(null, null);
284 testNoCredentials("MD5", null);
285 testNoCredentials("MD5", "auth");
286 testCredentials(null, null);
287 testCredentials("MD5", null);
288 testCredentials("MD5", "auth");
289 testCredentials("MD5", "auth-int");
290 testBasicAuthenticateCallback(null, null);
291 testBasicAuthenticateCallback("MD5", null);
292 testBasicAuthenticateCallback("MD5", "auth");
293 testBasicAuthenticateCallback("MD5", "auth-int");
294 // These teste are not normally run. They can be used for locally
295 // testing with another web server (e.g. Apache).
296 //testLocalServerDigest();
297 }
OLDNEW
« no previous file with comments | « sdk/lib/io/http_impl.dart ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698