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