001: /*
002: * $Header: /home/jerenkrantz/tmp/commons/commons-convert/cvs/home/cvs/jakarta-commons//httpclient/src/test/org/apache/commons/httpclient/auth/TestDigestAuth.java,v 1.2 2004/11/07 12:31:42 olegk Exp $
003: * $Revision: 480424 $
004: * $Date: 2006-11-29 06:56:49 +0100 (Wed, 29 Nov 2006) $
005: * ====================================================================
006: *
007: * Licensed to the Apache Software Foundation (ASF) under one or more
008: * contributor license agreements. See the NOTICE file distributed with
009: * this work for additional information regarding copyright ownership.
010: * The ASF licenses this file to You under the Apache License, Version 2.0
011: * (the "License"); you may not use this file except in compliance with
012: * the License. You may obtain a copy of the License at
013: *
014: * http://www.apache.org/licenses/LICENSE-2.0
015: *
016: * Unless required by applicable law or agreed to in writing, software
017: * distributed under the License is distributed on an "AS IS" BASIS,
018: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
019: * See the License for the specific language governing permissions and
020: * limitations under the License.
021: * ====================================================================
022: *
023: * This software consists of voluntary contributions made by many
024: * individuals on behalf of the Apache Software Foundation. For more
025: * information on the Apache Software Foundation, please see
026: * <http://www.apache.org/>.
027: *
028: */
029:
030: package org.apache.commons.httpclient.auth;
031:
032: import java.io.IOException;
033: import java.util.Map;
034:
035: import org.apache.commons.httpclient.FakeHttpMethod;
036: import org.apache.commons.httpclient.Header;
037: import org.apache.commons.httpclient.HttpClient;
038: import org.apache.commons.httpclient.HttpStatus;
039: import org.apache.commons.httpclient.HttpVersion;
040: import org.apache.commons.httpclient.UsernamePasswordCredentials;
041: import org.apache.commons.httpclient.protocol.Protocol;
042: import org.apache.commons.httpclient.server.HttpService;
043: import org.apache.commons.httpclient.server.RequestLine;
044: import org.apache.commons.httpclient.server.SimpleHttpServer;
045: import org.apache.commons.httpclient.server.SimpleRequest;
046: import org.apache.commons.httpclient.server.SimpleResponse;
047:
048: import junit.framework.Test;
049: import junit.framework.TestCase;
050: import junit.framework.TestSuite;
051:
052: /**
053: * Test Methods for DigestScheme Authentication.
054: *
055: * @author Rodney Waldhoff
056: * @author <a href="mailto:jsdever@apache.org">Jeff Dever</a>
057: * @author <a href="mailto:oleg@ural.ru">Oleg Kalnichevski</a>
058: */
059: public class TestDigestAuth extends TestCase {
060:
061: // ------------------------------------------------------------ Constructor
062: public TestDigestAuth(String testName) {
063: super (testName);
064: }
065:
066: // ------------------------------------------------------------------- Main
067: public static void main(String args[]) {
068: String[] testCaseName = { TestDigestAuth.class.getName() };
069: junit.textui.TestRunner.main(testCaseName);
070: }
071:
072: // ------------------------------------------------------- TestCase Methods
073:
074: public static Test suite() {
075: return new TestSuite(TestDigestAuth.class);
076: }
077:
078: public void testDigestAuthenticationWithNoRealm() throws Exception {
079: String challenge = "Digest";
080: try {
081: AuthScheme authscheme = new DigestScheme();
082: authscheme.processChallenge(challenge);
083: fail("Should have thrown MalformedChallengeException");
084: } catch (MalformedChallengeException e) {
085: // expected
086: }
087: }
088:
089: public void testDigestAuthenticationWithNoRealm2() throws Exception {
090: String challenge = "Digest ";
091: try {
092: AuthScheme authscheme = new DigestScheme();
093: authscheme.processChallenge(challenge);
094: fail("Should have thrown MalformedChallengeException");
095: } catch (MalformedChallengeException e) {
096: // expected
097: }
098: }
099:
100: public void testDigestAuthenticationWithDefaultCreds()
101: throws Exception {
102: String challenge = "Digest realm=\"realm1\", nonce=\"f2a3f18799759d4f1a1c068b92b573cb\"";
103: FakeHttpMethod method = new FakeHttpMethod("/");
104: UsernamePasswordCredentials cred = new UsernamePasswordCredentials(
105: "username", "password");
106: AuthScheme authscheme = new DigestScheme();
107: authscheme.processChallenge(challenge);
108: String response = authscheme.authenticate(cred, method);
109: Map table = AuthChallengeParser.extractParams(response);
110: assertEquals("username", table.get("username"));
111: assertEquals("realm1", table.get("realm"));
112: assertEquals("/", table.get("uri"));
113: assertEquals("f2a3f18799759d4f1a1c068b92b573cb", table
114: .get("nonce"));
115: assertEquals("e95a7ddf37c2eab009568b1ed134f89a", table
116: .get("response"));
117: }
118:
119: public void testDigestAuthentication() throws Exception {
120: String challenge = "Digest realm=\"realm1\", nonce=\"f2a3f18799759d4f1a1c068b92b573cb\"";
121: UsernamePasswordCredentials cred = new UsernamePasswordCredentials(
122: "username", "password");
123: FakeHttpMethod method = new FakeHttpMethod("/");
124: AuthScheme authscheme = new DigestScheme();
125: authscheme.processChallenge(challenge);
126: String response = authscheme.authenticate(cred, method);
127: Map table = AuthChallengeParser.extractParams(response);
128: assertEquals("username", table.get("username"));
129: assertEquals("realm1", table.get("realm"));
130: assertEquals("/", table.get("uri"));
131: assertEquals("f2a3f18799759d4f1a1c068b92b573cb", table
132: .get("nonce"));
133: assertEquals("e95a7ddf37c2eab009568b1ed134f89a", table
134: .get("response"));
135: }
136:
137: public void testDigestAuthenticationWithQueryStringInDigestURI()
138: throws Exception {
139: String challenge = "Digest realm=\"realm1\", nonce=\"f2a3f18799759d4f1a1c068b92b573cb\"";
140: UsernamePasswordCredentials cred = new UsernamePasswordCredentials(
141: "username", "password");
142: FakeHttpMethod method = new FakeHttpMethod("/");
143: method.setQueryString("param=value");
144: AuthScheme authscheme = new DigestScheme();
145: authscheme.processChallenge(challenge);
146: String response = authscheme.authenticate(cred, method);
147: Map table = AuthChallengeParser.extractParams(response);
148: assertEquals("username", table.get("username"));
149: assertEquals("realm1", table.get("realm"));
150: assertEquals("/?param=value", table.get("uri"));
151: assertEquals("f2a3f18799759d4f1a1c068b92b573cb", table
152: .get("nonce"));
153: assertEquals("a847f58f5fef0bc087bcb9c3eb30e042", table
154: .get("response"));
155: }
156:
157: public void testDigestAuthenticationWithMultipleRealms()
158: throws Exception {
159: String challenge1 = "Digest realm=\"realm1\", nonce=\"abcde\"";
160: String challenge2 = "Digest realm=\"realm2\", nonce=\"123546\"";
161: UsernamePasswordCredentials cred = new UsernamePasswordCredentials(
162: "username", "password");
163: UsernamePasswordCredentials cred2 = new UsernamePasswordCredentials(
164: "uname2", "password2");
165:
166: FakeHttpMethod method = new FakeHttpMethod("/");
167: AuthScheme authscheme1 = new DigestScheme();
168: authscheme1.processChallenge(challenge1);
169: String response1 = authscheme1.authenticate(cred, method);
170: Map table = AuthChallengeParser.extractParams(response1);
171: assertEquals("username", table.get("username"));
172: assertEquals("realm1", table.get("realm"));
173: assertEquals("/", table.get("uri"));
174: assertEquals("abcde", table.get("nonce"));
175: assertEquals("786f500303eac1478f3c2865e676ed68", table
176: .get("response"));
177:
178: AuthScheme authscheme2 = new DigestScheme();
179: authscheme2.processChallenge(challenge2);
180: String response2 = authscheme2.authenticate(cred2, method);
181: table = AuthChallengeParser.extractParams(response2);
182: assertEquals("uname2", table.get("username"));
183: assertEquals("realm2", table.get("realm"));
184: assertEquals("/", table.get("uri"));
185: assertEquals("123546", table.get("nonce"));
186: assertEquals("0283edd9ef06a38b378b3b74661391e9", table
187: .get("response"));
188: }
189:
190: /**
191: * Test digest authentication using the MD5-sess algorithm.
192: */
193: public void testDigestAuthenticationMD5Sess() throws Exception {
194: // Example using Digest auth with MD5-sess
195:
196: String realm = "realm";
197: String username = "username";
198: String password = "password";
199: String nonce = "e273f1776275974f1a120d8b92c5b3cb";
200:
201: String challenge = "Digest realm=\"" + realm + "\", "
202: + "nonce=\"" + nonce + "\", "
203: + "opaque=\"SomeString\", " + "stale=false, "
204: + "algorithm=MD5-sess, " + "qop=\"auth,auth-int\""; // we pass both but expect auth to be used
205:
206: UsernamePasswordCredentials cred = new UsernamePasswordCredentials(
207: username, password);
208: FakeHttpMethod method = new FakeHttpMethod("/");
209:
210: AuthScheme authscheme = new DigestScheme();
211: authscheme.processChallenge(challenge);
212: String response = authscheme.authenticate(cred, method);
213: assertTrue(response.indexOf("nc=00000001") > 0); // test for quotes
214: assertTrue(response.indexOf("qop=auth") > 0); // test for quotes
215: Map table = AuthChallengeParser.extractParams(response);
216: assertEquals(username, table.get("username"));
217: assertEquals(realm, table.get("realm"));
218: assertEquals("MD5-sess", table.get("algorithm"));
219: assertEquals("/", table.get("uri"));
220: assertEquals(nonce, table.get("nonce"));
221: assertEquals(1, Integer.parseInt((String) table.get("nc"), 16));
222: assertTrue(null != table.get("cnonce"));
223: assertEquals("SomeString", table.get("opaque"));
224: assertEquals("auth", table.get("qop"));
225: //@TODO: add better check
226: assertTrue(null != table.get("response"));
227: }
228:
229: /**
230: * Test digest authentication using the MD5-sess algorithm.
231: */
232: public void testDigestAuthenticationMD5SessNoQop() throws Exception {
233: // Example using Digest auth with MD5-sess
234:
235: String realm = "realm";
236: String username = "username";
237: String password = "password";
238: String nonce = "e273f1776275974f1a120d8b92c5b3cb";
239:
240: String challenge = "Digest realm=\"" + realm + "\", "
241: + "nonce=\"" + nonce + "\", "
242: + "opaque=\"SomeString\", " + "stale=false, "
243: + "algorithm=MD5-sess";
244:
245: UsernamePasswordCredentials cred = new UsernamePasswordCredentials(
246: username, password);
247: FakeHttpMethod method = new FakeHttpMethod("/");
248:
249: AuthScheme authscheme = new DigestScheme();
250: authscheme.processChallenge(challenge);
251: String response = authscheme.authenticate(cred, method);
252:
253: Map table = AuthChallengeParser.extractParams(response);
254: assertEquals(username, table.get("username"));
255: assertEquals(realm, table.get("realm"));
256: assertEquals("MD5-sess", table.get("algorithm"));
257: assertEquals("/", table.get("uri"));
258: assertEquals(nonce, table.get("nonce"));
259: assertTrue(null == table.get("nc"));
260: assertEquals("SomeString", table.get("opaque"));
261: assertTrue(null == table.get("qop"));
262: //@TODO: add better check
263: assertTrue(null != table.get("response"));
264: }
265:
266: /**
267: * Test digest authentication with invalud qop value
268: */
269: public void testDigestAuthenticationMD5SessInvalidQop()
270: throws Exception {
271: // Example using Digest auth with MD5-sess
272:
273: String realm = "realm";
274: String username = "username";
275: String password = "password";
276: String nonce = "e273f1776275974f1a120d8b92c5b3cb";
277:
278: String challenge = "Digest realm=\"" + realm + "\", "
279: + "nonce=\"" + nonce + "\", "
280: + "opaque=\"SomeString\", " + "stale=false, "
281: + "algorithm=MD5-sess, " + "qop=\"jakarta\""; // jakarta is an invalid qop value
282:
283: UsernamePasswordCredentials cred = new UsernamePasswordCredentials(
284: username, password);
285: try {
286: AuthScheme authscheme = new DigestScheme();
287: authscheme.processChallenge(challenge);
288: fail("MalformedChallengeException exception expected due to invalid qop value");
289: } catch (MalformedChallengeException e) {
290: }
291: }
292:
293: private class StaleNonceService implements HttpService {
294:
295: public StaleNonceService() {
296: super ();
297: }
298:
299: public boolean process(final SimpleRequest request,
300: final SimpleResponse response) throws IOException {
301: RequestLine requestLine = request.getRequestLine();
302: HttpVersion ver = requestLine.getHttpVersion();
303: Header auth = request.getFirstHeader("Authorization");
304: if (auth == null) {
305: response.setStatusLine(ver, HttpStatus.SC_UNAUTHORIZED);
306: response.addHeader(new Header("WWW-Authenticate",
307: "Digest realm=\"realm1\", nonce=\"ABC123\""));
308: response.setBodyString("Authorization required");
309: return true;
310: } else {
311: Map table = AuthChallengeParser.extractParams(auth
312: .getValue());
313: String nonce = (String) table.get("nonce");
314: if (nonce.equals("ABC123")) {
315: response.setStatusLine(ver,
316: HttpStatus.SC_UNAUTHORIZED);
317: response
318: .addHeader(new Header("WWW-Authenticate",
319: "Digest realm=\"realm1\", nonce=\"321CBA\", stale=\"true\""));
320: response.setBodyString("Authorization required");
321: return true;
322: } else {
323: response.setStatusLine(ver, HttpStatus.SC_OK);
324: response.setBodyString("Authorization successful");
325: return true;
326: }
327: }
328: }
329: }
330:
331: public void testDigestAuthenticationWithStaleNonce()
332: throws Exception {
333: // configure the server
334: SimpleHttpServer server = new SimpleHttpServer(); // use arbitrary port
335: server.setTestname(getName());
336: server.setHttpService(new StaleNonceService());
337:
338: // configure the client
339: HttpClient client = new HttpClient();
340: client.getHostConfiguration().setHost(server.getLocalAddress(),
341: server.getLocalPort(), Protocol.getProtocol("http"));
342:
343: client.getState()
344: .setCredentials(
345: AuthScope.ANY,
346: new UsernamePasswordCredentials("username",
347: "password"));
348:
349: FakeHttpMethod httpget = new FakeHttpMethod("/");
350: try {
351: client.executeMethod(httpget);
352: } finally {
353: httpget.releaseConnection();
354: }
355: assertNotNull(httpget.getStatusLine());
356: assertEquals(HttpStatus.SC_OK, httpget.getStatusLine()
357: .getStatusCode());
358: Map table = AuthChallengeParser.extractParams(httpget
359: .getRequestHeader("Authorization").getValue());
360: assertEquals("username", table.get("username"));
361: assertEquals("realm1", table.get("realm"));
362: assertEquals("/", table.get("uri"));
363: assertEquals("321CBA", table.get("nonce"));
364: assertEquals("7f5948eefa115296e9279225041527b3", table
365: .get("response"));
366: server.destroy();
367: }
368:
369: }
|