1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30 package org.apache.commons.httpclient.auth;
31
32 import java.io.IOException;
33 import java.util.Map;
34
35 import org.apache.commons.httpclient.FakeHttpMethod;
36 import org.apache.commons.httpclient.Header;
37 import org.apache.commons.httpclient.HttpClient;
38 import org.apache.commons.httpclient.HttpStatus;
39 import org.apache.commons.httpclient.HttpVersion;
40 import org.apache.commons.httpclient.UsernamePasswordCredentials;
41 import org.apache.commons.httpclient.protocol.Protocol;
42 import org.apache.commons.httpclient.server.HttpService;
43 import org.apache.commons.httpclient.server.RequestLine;
44 import org.apache.commons.httpclient.server.SimpleHttpServer;
45 import org.apache.commons.httpclient.server.SimpleRequest;
46 import org.apache.commons.httpclient.server.SimpleResponse;
47
48 import junit.framework.Test;
49 import junit.framework.TestCase;
50 import junit.framework.TestSuite;
51
52 /***
53 * Test Methods for DigestScheme Authentication.
54 *
55 * @author Rodney Waldhoff
56 * @author <a href="mailto:jsdever@apache.org">Jeff Dever</a>
57 * @author <a href="mailto:oleg@ural.ru">Oleg Kalnichevski</a>
58 */
59 public class TestDigestAuth extends TestCase {
60
61
62 public TestDigestAuth(String testName) {
63 super(testName);
64 }
65
66
67 public static void main(String args[]) {
68 String[] testCaseName = { TestDigestAuth.class.getName() };
69 junit.textui.TestRunner.main(testCaseName);
70 }
71
72
73
74 public static Test suite() {
75 return new TestSuite(TestDigestAuth.class);
76 }
77
78 public void testDigestAuthenticationWithNoRealm() throws Exception {
79 String challenge = "Digest";
80 try {
81 AuthScheme authscheme = new DigestScheme();
82 authscheme.processChallenge(challenge);
83 fail("Should have thrown MalformedChallengeException");
84 } catch(MalformedChallengeException e) {
85
86 }
87 }
88
89 public void testDigestAuthenticationWithNoRealm2() throws Exception {
90 String challenge = "Digest ";
91 try {
92 AuthScheme authscheme = new DigestScheme();
93 authscheme.processChallenge(challenge);
94 fail("Should have thrown MalformedChallengeException");
95 } catch(MalformedChallengeException e) {
96
97 }
98 }
99
100 public void testDigestAuthenticationWithDefaultCreds() throws Exception {
101 String challenge = "Digest realm=\"realm1\", nonce=\"f2a3f18799759d4f1a1c068b92b573cb\"";
102 FakeHttpMethod method = new FakeHttpMethod("/");
103 UsernamePasswordCredentials cred = new UsernamePasswordCredentials("username","password");
104 AuthScheme authscheme = new DigestScheme();
105 authscheme.processChallenge(challenge);
106 String response = authscheme.authenticate(cred, method);
107 Map table = AuthChallengeParser.extractParams(response);
108 assertEquals("username", table.get("username"));
109 assertEquals("realm1", table.get("realm"));
110 assertEquals("/", table.get("uri"));
111 assertEquals("f2a3f18799759d4f1a1c068b92b573cb", table.get("nonce"));
112 assertEquals("e95a7ddf37c2eab009568b1ed134f89a", table.get("response"));
113 }
114
115 public void testDigestAuthentication() throws Exception {
116 String challenge = "Digest realm=\"realm1\", nonce=\"f2a3f18799759d4f1a1c068b92b573cb\"";
117 UsernamePasswordCredentials cred = new UsernamePasswordCredentials("username","password");
118 FakeHttpMethod method = new FakeHttpMethod("/");
119 AuthScheme authscheme = new DigestScheme();
120 authscheme.processChallenge(challenge);
121 String response = authscheme.authenticate(cred, method);
122 Map table = AuthChallengeParser.extractParams(response);
123 assertEquals("username", table.get("username"));
124 assertEquals("realm1", table.get("realm"));
125 assertEquals("/", table.get("uri"));
126 assertEquals("f2a3f18799759d4f1a1c068b92b573cb", table.get("nonce"));
127 assertEquals("e95a7ddf37c2eab009568b1ed134f89a", table.get("response"));
128 }
129
130 public void testDigestAuthenticationWithQueryStringInDigestURI() throws Exception {
131 String challenge = "Digest realm=\"realm1\", nonce=\"f2a3f18799759d4f1a1c068b92b573cb\"";
132 UsernamePasswordCredentials cred = new UsernamePasswordCredentials("username","password");
133 FakeHttpMethod method = new FakeHttpMethod("/");
134 method.setQueryString("param=value");
135 AuthScheme authscheme = new DigestScheme();
136 authscheme.processChallenge(challenge);
137 String response = authscheme.authenticate(cred, method);
138 Map table = AuthChallengeParser.extractParams(response);
139 assertEquals("username", table.get("username"));
140 assertEquals("realm1", table.get("realm"));
141 assertEquals("/?param=value", table.get("uri"));
142 assertEquals("f2a3f18799759d4f1a1c068b92b573cb", table.get("nonce"));
143 assertEquals("a847f58f5fef0bc087bcb9c3eb30e042", table.get("response"));
144 }
145
146 public void testDigestAuthenticationWithMultipleRealms() throws Exception {
147 String challenge1 = "Digest realm=\"realm1\", nonce=\"abcde\"";
148 String challenge2 = "Digest realm=\"realm2\", nonce=\"123546\"";
149 UsernamePasswordCredentials cred = new UsernamePasswordCredentials("username","password");
150 UsernamePasswordCredentials cred2 = new UsernamePasswordCredentials("uname2","password2");
151
152 FakeHttpMethod method = new FakeHttpMethod("/");
153 AuthScheme authscheme1 = new DigestScheme();
154 authscheme1.processChallenge(challenge1);
155 String response1 = authscheme1.authenticate(cred, method);
156 Map table = AuthChallengeParser.extractParams(response1);
157 assertEquals("username", table.get("username"));
158 assertEquals("realm1", table.get("realm"));
159 assertEquals("/", table.get("uri"));
160 assertEquals("abcde", table.get("nonce"));
161 assertEquals("786f500303eac1478f3c2865e676ed68", table.get("response"));
162
163 AuthScheme authscheme2 = new DigestScheme();
164 authscheme2.processChallenge(challenge2);
165 String response2 = authscheme2.authenticate(cred2, method);
166 table = AuthChallengeParser.extractParams(response2);
167 assertEquals("uname2", table.get("username"));
168 assertEquals("realm2", table.get("realm"));
169 assertEquals("/", table.get("uri"));
170 assertEquals("123546", table.get("nonce"));
171 assertEquals("0283edd9ef06a38b378b3b74661391e9", table.get("response"));
172 }
173
174 /***
175 * Test digest authentication using the MD5-sess algorithm.
176 */
177 public void testDigestAuthenticationMD5Sess() throws Exception {
178
179
180 String realm="realm";
181 String username="username";
182 String password="password";
183 String nonce="e273f1776275974f1a120d8b92c5b3cb";
184
185 String challenge="Digest realm=\"" + realm + "\", "
186 + "nonce=\"" + nonce + "\", "
187 + "opaque=\"SomeString\", "
188 + "stale=false, "
189 + "algorithm=MD5-sess, "
190 + "qop=\"auth,auth-int\"";
191
192 UsernamePasswordCredentials cred =
193 new UsernamePasswordCredentials(username, password);
194 FakeHttpMethod method = new FakeHttpMethod("/");
195
196 AuthScheme authscheme = new DigestScheme();
197 authscheme.processChallenge(challenge);
198 String response = authscheme.authenticate(cred, method);
199 assertTrue(response.indexOf("nc=00000001") > 0);
200 assertTrue(response.indexOf("qop=auth") > 0);
201 Map table = AuthChallengeParser.extractParams(response);
202 assertEquals(username, table.get("username"));
203 assertEquals(realm, table.get("realm"));
204 assertEquals("MD5-sess", table.get("algorithm"));
205 assertEquals("/", table.get("uri"));
206 assertEquals(nonce, table.get("nonce"));
207 assertEquals(1, Integer.parseInt((String) table.get("nc"),16));
208 assertTrue(null != table.get("cnonce"));
209 assertEquals("SomeString", table.get("opaque"));
210 assertEquals("auth", table.get("qop"));
211
212 assertTrue(null != table.get("response"));
213 }
214
215 /***
216 * Test digest authentication using the MD5-sess algorithm.
217 */
218 public void testDigestAuthenticationMD5SessNoQop() throws Exception {
219
220
221 String realm="realm";
222 String username="username";
223 String password="password";
224 String nonce="e273f1776275974f1a120d8b92c5b3cb";
225
226 String challenge="Digest realm=\"" + realm + "\", "
227 + "nonce=\"" + nonce + "\", "
228 + "opaque=\"SomeString\", "
229 + "stale=false, "
230 + "algorithm=MD5-sess";
231
232 UsernamePasswordCredentials cred =
233 new UsernamePasswordCredentials(username, password);
234 FakeHttpMethod method = new FakeHttpMethod("/");
235
236 AuthScheme authscheme = new DigestScheme();
237 authscheme.processChallenge(challenge);
238 String response = authscheme.authenticate(cred, method);
239
240 Map table = AuthChallengeParser.extractParams(response);
241 assertEquals(username, table.get("username"));
242 assertEquals(realm, table.get("realm"));
243 assertEquals("MD5-sess", table.get("algorithm"));
244 assertEquals("/", table.get("uri"));
245 assertEquals(nonce, table.get("nonce"));
246 assertTrue(null == table.get("nc"));
247 assertEquals("SomeString", table.get("opaque"));
248 assertTrue(null == table.get("qop"));
249
250 assertTrue(null != table.get("response"));
251 }
252
253 /***
254 * Test digest authentication with invalud qop value
255 */
256 public void testDigestAuthenticationMD5SessInvalidQop() throws Exception {
257
258
259 String realm="realm";
260 String username="username";
261 String password="password";
262 String nonce="e273f1776275974f1a120d8b92c5b3cb";
263
264 String challenge="Digest realm=\"" + realm + "\", "
265 + "nonce=\"" + nonce + "\", "
266 + "opaque=\"SomeString\", "
267 + "stale=false, "
268 + "algorithm=MD5-sess, "
269 + "qop=\"jakarta\"";
270
271 UsernamePasswordCredentials cred =
272 new UsernamePasswordCredentials(username, password);
273 try {
274 AuthScheme authscheme = new DigestScheme();
275 authscheme.processChallenge(challenge);
276 fail("MalformedChallengeException exception expected due to invalid qop value");
277 } catch(MalformedChallengeException e) {
278 }
279 }
280
281 private class StaleNonceService implements HttpService {
282
283 public StaleNonceService() {
284 super();
285 }
286
287 public boolean process(final SimpleRequest request, final SimpleResponse response)
288 throws IOException
289 {
290 RequestLine requestLine = request.getRequestLine();
291 HttpVersion ver = requestLine.getHttpVersion();
292 Header auth = request.getFirstHeader("Authorization");
293 if (auth == null) {
294 response.setStatusLine(ver, HttpStatus.SC_UNAUTHORIZED);
295 response.addHeader(new Header("WWW-Authenticate",
296 "Digest realm=\"realm1\", nonce=\"ABC123\""));
297 response.setBodyString("Authorization required");
298 return true;
299 } else {
300 Map table = AuthChallengeParser.extractParams(auth.getValue());
301 String nonce = (String)table.get("nonce");
302 if (nonce.equals("ABC123")) {
303 response.setStatusLine(ver, HttpStatus.SC_UNAUTHORIZED);
304 response.addHeader(new Header("WWW-Authenticate",
305 "Digest realm=\"realm1\", nonce=\"321CBA\", stale=\"true\""));
306 response.setBodyString("Authorization required");
307 return true;
308 } else {
309 response.setStatusLine(ver, HttpStatus.SC_OK);
310 response.setBodyString("Authorization successful");
311 return true;
312 }
313 }
314 }
315 }
316
317
318 public void testDigestAuthenticationWithStaleNonce() throws Exception {
319
320 SimpleHttpServer server = new SimpleHttpServer();
321 server.setTestname(getName());
322 server.setHttpService(new StaleNonceService());
323
324
325 HttpClient client = new HttpClient();
326 client.getHostConfiguration().setHost(
327 server.getLocalAddress(), server.getLocalPort(),
328 Protocol.getProtocol("http"));
329
330 client.getState().setCredentials(AuthScope.ANY,
331 new UsernamePasswordCredentials("username","password"));
332
333 FakeHttpMethod httpget = new FakeHttpMethod("/");
334 try {
335 client.executeMethod(httpget);
336 } finally {
337 httpget.releaseConnection();
338 }
339 assertNotNull(httpget.getStatusLine());
340 assertEquals(HttpStatus.SC_OK, httpget.getStatusLine().getStatusCode());
341 Map table = AuthChallengeParser.extractParams(
342 httpget.getRequestHeader("Authorization").getValue());
343 assertEquals("username", table.get("username"));
344 assertEquals("realm1", table.get("realm"));
345 assertEquals("/", table.get("uri"));
346 assertEquals("321CBA", table.get("nonce"));
347 assertEquals("7f5948eefa115296e9279225041527b3", table.get("response"));
348 server.destroy();
349 }
350
351 }