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 testDigestAuthenticationWithMultipleRealms() throws Exception {
130 String challenge1 = "Digest realm=\"realm1\", nonce=\"abcde\"";
131 String challenge2 = "Digest realm=\"realm2\", nonce=\"123546\"";
132 UsernamePasswordCredentials cred = new UsernamePasswordCredentials("username","password");
133 UsernamePasswordCredentials cred2 = new UsernamePasswordCredentials("uname2","password2");
134
135 FakeHttpMethod method = new FakeHttpMethod("/");
136 AuthScheme authscheme1 = new DigestScheme();
137 authscheme1.processChallenge(challenge1);
138 String response1 = authscheme1.authenticate(cred, method);
139 Map table = AuthChallengeParser.extractParams(response1);
140 assertEquals("username", table.get("username"));
141 assertEquals("realm1", table.get("realm"));
142 assertEquals("/", table.get("uri"));
143 assertEquals("abcde", table.get("nonce"));
144 assertEquals("786f500303eac1478f3c2865e676ed68", table.get("response"));
145
146 AuthScheme authscheme2 = new DigestScheme();
147 authscheme2.processChallenge(challenge2);
148 String response2 = authscheme2.authenticate(cred2, method);
149 table = AuthChallengeParser.extractParams(response2);
150 assertEquals("uname2", table.get("username"));
151 assertEquals("realm2", table.get("realm"));
152 assertEquals("/", table.get("uri"));
153 assertEquals("123546", table.get("nonce"));
154 assertEquals("0283edd9ef06a38b378b3b74661391e9", table.get("response"));
155 }
156
157 /***
158 * Test digest authentication using the MD5-sess algorithm.
159 */
160 public void testDigestAuthenticationMD5Sess() throws Exception {
161
162
163 String realm="realm";
164 String username="username";
165 String password="password";
166 String nonce="e273f1776275974f1a120d8b92c5b3cb";
167
168 String challenge="Digest realm=\"" + realm + "\", "
169 + "nonce=\"" + nonce + "\", "
170 + "opaque=\"SomeString\", "
171 + "stale=false, "
172 + "algorithm=MD5-sess, "
173 + "qop=\"auth,auth-int\"";
174
175 UsernamePasswordCredentials cred =
176 new UsernamePasswordCredentials(username, password);
177 FakeHttpMethod method = new FakeHttpMethod("/");
178
179 AuthScheme authscheme = new DigestScheme();
180 authscheme.processChallenge(challenge);
181 String response = authscheme.authenticate(cred, method);
182 assertTrue(response.indexOf("nc=00000001") > 0);
183 assertTrue(response.indexOf("qop=auth") > 0);
184 Map table = AuthChallengeParser.extractParams(response);
185 assertEquals(username, table.get("username"));
186 assertEquals(realm, table.get("realm"));
187 assertEquals("MD5-sess", table.get("algorithm"));
188 assertEquals("/", table.get("uri"));
189 assertEquals(nonce, table.get("nonce"));
190 assertEquals(1, Integer.parseInt((String) table.get("nc"),16));
191 assertTrue(null != table.get("cnonce"));
192 assertEquals("SomeString", table.get("opaque"));
193 assertEquals("auth", table.get("qop"));
194
195 assertTrue(null != table.get("response"));
196 }
197
198 /***
199 * Test digest authentication using the MD5-sess algorithm.
200 */
201 public void testDigestAuthenticationMD5SessNoQop() throws Exception {
202
203
204 String realm="realm";
205 String username="username";
206 String password="password";
207 String nonce="e273f1776275974f1a120d8b92c5b3cb";
208
209 String challenge="Digest realm=\"" + realm + "\", "
210 + "nonce=\"" + nonce + "\", "
211 + "opaque=\"SomeString\", "
212 + "stale=false, "
213 + "algorithm=MD5-sess";
214
215 UsernamePasswordCredentials cred =
216 new UsernamePasswordCredentials(username, password);
217 FakeHttpMethod method = new FakeHttpMethod("/");
218
219 AuthScheme authscheme = new DigestScheme();
220 authscheme.processChallenge(challenge);
221 String response = authscheme.authenticate(cred, method);
222
223 Map table = AuthChallengeParser.extractParams(response);
224 assertEquals(username, table.get("username"));
225 assertEquals(realm, table.get("realm"));
226 assertEquals("MD5-sess", table.get("algorithm"));
227 assertEquals("/", table.get("uri"));
228 assertEquals(nonce, table.get("nonce"));
229 assertTrue(null == table.get("nc"));
230 assertEquals("SomeString", table.get("opaque"));
231 assertTrue(null == table.get("qop"));
232
233 assertTrue(null != table.get("response"));
234 }
235
236 /***
237 * Test digest authentication with invalud qop value
238 */
239 public void testDigestAuthenticationMD5SessInvalidQop() throws Exception {
240
241
242 String realm="realm";
243 String username="username";
244 String password="password";
245 String nonce="e273f1776275974f1a120d8b92c5b3cb";
246
247 String challenge="Digest realm=\"" + realm + "\", "
248 + "nonce=\"" + nonce + "\", "
249 + "opaque=\"SomeString\", "
250 + "stale=false, "
251 + "algorithm=MD5-sess, "
252 + "qop=\"jakarta\"";
253
254 UsernamePasswordCredentials cred =
255 new UsernamePasswordCredentials(username, password);
256 try {
257 AuthScheme authscheme = new DigestScheme();
258 authscheme.processChallenge(challenge);
259 fail("MalformedChallengeException exception expected due to invalid qop value");
260 } catch(MalformedChallengeException e) {
261 }
262 }
263
264 private class StaleNonceService implements HttpService {
265
266 public StaleNonceService() {
267 super();
268 }
269
270 public boolean process(final SimpleRequest request, final SimpleResponse response)
271 throws IOException
272 {
273 RequestLine requestLine = request.getRequestLine();
274 HttpVersion ver = requestLine.getHttpVersion();
275 Header auth = request.getFirstHeader("Authorization");
276 if (auth == null) {
277 response.setStatusLine(ver, HttpStatus.SC_UNAUTHORIZED);
278 response.addHeader(new Header("WWW-Authenticate",
279 "Digest realm=\"realm1\", nonce=\"ABC123\""));
280 response.setBodyString("Authorization required");
281 return true;
282 } else {
283 Map table = AuthChallengeParser.extractParams(auth.getValue());
284 String nonce = (String)table.get("nonce");
285 if (nonce.equals("ABC123")) {
286 response.setStatusLine(ver, HttpStatus.SC_UNAUTHORIZED);
287 response.addHeader(new Header("WWW-Authenticate",
288 "Digest realm=\"realm1\", nonce=\"321CBA\", stale=\"true\""));
289 response.setBodyString("Authorization required");
290 return true;
291 } else {
292 response.setStatusLine(ver, HttpStatus.SC_OK);
293 response.setBodyString("Authorization successful");
294 return true;
295 }
296 }
297 }
298 }
299
300
301 public void testDigestAuthenticationWithStaleNonce() throws Exception {
302
303 SimpleHttpServer server = new SimpleHttpServer();
304 server.setTestname(getName());
305 server.setHttpService(new StaleNonceService());
306
307
308 HttpClient client = new HttpClient();
309 client.getHostConfiguration().setHost(
310 server.getLocalAddress(), server.getLocalPort(),
311 Protocol.getProtocol("http"));
312
313 client.getState().setCredentials(AuthScope.ANY,
314 new UsernamePasswordCredentials("username","password"));
315
316 FakeHttpMethod httpget = new FakeHttpMethod("/");
317 try {
318 client.executeMethod(httpget);
319 } finally {
320 httpget.releaseConnection();
321 }
322 assertNotNull(httpget.getStatusLine());
323 assertEquals(HttpStatus.SC_OK, httpget.getStatusLine().getStatusCode());
324 Map table = AuthChallengeParser.extractParams(
325 httpget.getRequestHeader("Authorization").getValue());
326 assertEquals("username", table.get("username"));
327 assertEquals("realm1", table.get("realm"));
328 assertEquals("/", table.get("uri"));
329 assertEquals("321CBA", table.get("nonce"));
330 assertEquals("7f5948eefa115296e9279225041527b3", table.get("response"));
331 server.destroy();
332 }
333
334 }