You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@hc.apache.org by ol...@apache.org on 2011/08/16 17:13:37 UTC
svn commit: r1158320 - in /httpcomponents/httpclient/trunk/httpclient/src:
main/java/org/apache/http/impl/auth/ test/java/org/apache/http/impl/auth/
Author: olegk
Date: Tue Aug 16 15:13:36 2011
New Revision: 1158320
URL: http://svn.apache.org/viewvc?rev=1158320&view=rev
Log:
Support for auth-int qop (quality of protection) option in Digest auth scheme
Added:
httpcomponents/httpclient/trunk/httpclient/src/main/java/org/apache/http/impl/auth/HttpEntityDigester.java (with props)
Modified:
httpcomponents/httpclient/trunk/httpclient/src/main/java/org/apache/http/impl/auth/BasicScheme.java
httpcomponents/httpclient/trunk/httpclient/src/main/java/org/apache/http/impl/auth/DigestScheme.java
httpcomponents/httpclient/trunk/httpclient/src/main/java/org/apache/http/impl/auth/RFC2617Scheme.java
httpcomponents/httpclient/trunk/httpclient/src/test/java/org/apache/http/impl/auth/TestBasicScheme.java
httpcomponents/httpclient/trunk/httpclient/src/test/java/org/apache/http/impl/auth/TestDigestScheme.java
httpcomponents/httpclient/trunk/httpclient/src/test/java/org/apache/http/impl/auth/TestRFC2617Scheme.java
Modified: httpcomponents/httpclient/trunk/httpclient/src/main/java/org/apache/http/impl/auth/BasicScheme.java
URL: http://svn.apache.org/viewvc/httpcomponents/httpclient/trunk/httpclient/src/main/java/org/apache/http/impl/auth/BasicScheme.java?rev=1158320&r1=1158319&r2=1158320&view=diff
==============================================================================
--- httpcomponents/httpclient/trunk/httpclient/src/main/java/org/apache/http/impl/auth/BasicScheme.java (original)
+++ httpcomponents/httpclient/trunk/httpclient/src/main/java/org/apache/http/impl/auth/BasicScheme.java Tue Aug 16 15:13:36 2011
@@ -38,6 +38,8 @@ import org.apache.http.auth.InvalidCrede
import org.apache.http.auth.MalformedChallengeException;
import org.apache.http.auth.params.AuthParams;
import org.apache.http.message.BufferedHeader;
+import org.apache.http.protocol.BasicHttpContext;
+import org.apache.http.protocol.HttpContext;
import org.apache.http.util.CharArrayBuffer;
import org.apache.http.util.EncodingUtils;
@@ -109,6 +111,12 @@ public class BasicScheme extends RFC2617
return false;
}
+ @Deprecated
+ public Header authenticate(
+ final Credentials credentials, final HttpRequest request) throws AuthenticationException {
+ return authenticate(credentials, request, new BasicHttpContext());
+ }
+
/**
* Produces basic authorization header for the given set of {@link Credentials}.
*
@@ -121,9 +129,11 @@ public class BasicScheme extends RFC2617
*
* @return a basic authorization string
*/
+ @Override
public Header authenticate(
final Credentials credentials,
- final HttpRequest request) throws AuthenticationException {
+ final HttpRequest request,
+ final HttpContext context) throws AuthenticationException {
if (credentials == null) {
throw new IllegalArgumentException("Credentials may not be null");
Modified: httpcomponents/httpclient/trunk/httpclient/src/main/java/org/apache/http/impl/auth/DigestScheme.java
URL: http://svn.apache.org/viewvc/httpcomponents/httpclient/trunk/httpclient/src/main/java/org/apache/http/impl/auth/DigestScheme.java?rev=1158320&r1=1158319&r2=1158320&view=diff
==============================================================================
--- httpcomponents/httpclient/trunk/httpclient/src/main/java/org/apache/http/impl/auth/DigestScheme.java (original)
+++ httpcomponents/httpclient/trunk/httpclient/src/main/java/org/apache/http/impl/auth/DigestScheme.java Tue Aug 16 15:13:36 2011
@@ -26,17 +26,22 @@
package org.apache.http.impl.auth;
+import java.io.IOException;
import java.security.MessageDigest;
import java.security.SecureRandom;
import java.util.ArrayList;
import java.util.Formatter;
+import java.util.HashSet;
import java.util.List;
import java.util.Locale;
+import java.util.Set;
import java.util.StringTokenizer;
import org.apache.http.annotation.NotThreadSafe;
import org.apache.http.Header;
+import org.apache.http.HttpEntity;
+import org.apache.http.HttpEntityEnclosingRequest;
import org.apache.http.HttpRequest;
import org.apache.http.auth.AuthenticationException;
import org.apache.http.auth.Credentials;
@@ -46,6 +51,8 @@ import org.apache.http.auth.params.AuthP
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.message.BasicHeaderValueFormatter;
import org.apache.http.message.BufferedHeader;
+import org.apache.http.protocol.BasicHttpContext;
+import org.apache.http.protocol.HttpContext;
import org.apache.http.util.CharArrayBuffer;
import org.apache.http.util.EncodingUtils;
@@ -122,13 +129,6 @@ public class DigestScheme extends RFC261
public void processChallenge(
final Header header) throws MalformedChallengeException {
super.processChallenge(header);
-
- if (getParameter("realm") == null) {
- throw new MalformedChallengeException("missing realm in challenge");
- }
- if (getParameter("nonce") == null) {
- throw new MalformedChallengeException("missing nonce in challenge");
- }
this.complete = true;
}
@@ -169,6 +169,12 @@ public class DigestScheme extends RFC261
getParameters().put(name, value);
}
+ @Deprecated
+ public Header authenticate(
+ final Credentials credentials, final HttpRequest request) throws AuthenticationException {
+ return authenticate(credentials, request, new BasicHttpContext());
+ }
+
/**
* Produces a digest authorization string for the given set of
* {@link Credentials}, method name and URI.
@@ -183,9 +189,11 @@ public class DigestScheme extends RFC261
*
* @return a digest authorization string
*/
+ @Override
public Header authenticate(
final Credentials credentials,
- final HttpRequest request) throws AuthenticationException {
+ final HttpRequest request,
+ final HttpContext context) throws AuthenticationException {
if (credentials == null) {
throw new IllegalArgumentException("Credentials may not be null");
@@ -193,7 +201,12 @@ public class DigestScheme extends RFC261
if (request == null) {
throw new IllegalArgumentException("HTTP request may not be null");
}
-
+ if (getParameter("realm") == null) {
+ throw new AuthenticationException("missing realm in challenge");
+ }
+ if (getParameter("nonce") == null) {
+ throw new AuthenticationException("missing nonce in challenge");
+ }
// Add method name and request-URI to the parameter map
getParameters().put("methodname", request.getRequestLine().getMethod());
getParameters().put("uri", request.getRequestLine().getUri());
@@ -202,7 +215,7 @@ public class DigestScheme extends RFC261
charset = AuthParams.getCredentialCharset(request.getParams());
getParameters().put("charset", charset);
}
- return createDigestHeader(credentials);
+ return createDigestHeader(credentials, request);
}
private static MessageDigest createMessageDigest(
@@ -224,34 +237,28 @@ public class DigestScheme extends RFC261
* @return The digest-response as String.
*/
private Header createDigestHeader(
- final Credentials credentials) throws AuthenticationException {
+ final Credentials credentials,
+ final HttpRequest request) throws AuthenticationException {
String uri = getParameter("uri");
String realm = getParameter("realm");
String nonce = getParameter("nonce");
String opaque = getParameter("opaque");
String method = getParameter("methodname");
String algorithm = getParameter("algorithm");
- if (uri == null) {
- throw new IllegalStateException("URI may not be null");
- }
- if (realm == null) {
- throw new IllegalStateException("Realm may not be null");
- }
- if (nonce == null) {
- throw new IllegalStateException("Nonce may not be null");
- }
- //TODO: add support for QOP_INT
+ Set<String> qopset = new HashSet<String>(8);
int qop = QOP_UNKNOWN;
String qoplist = getParameter("qop");
if (qoplist != null) {
StringTokenizer tok = new StringTokenizer(qoplist, ",");
while (tok.hasMoreTokens()) {
String variant = tok.nextToken().trim();
- if (variant.equals("auth")) {
- qop = QOP_AUTH;
- break;
- }
+ qopset.add(variant.toLowerCase(Locale.US));
+ }
+ if (request instanceof HttpEntityEnclosingRequest && qopset.contains("auth-int")) {
+ qop = QOP_AUTH_INT;
+ } else if (qopset.contains("auth")) {
+ qop = QOP_AUTH;
}
} else {
qop = QOP_MISSING;
@@ -265,7 +272,6 @@ public class DigestScheme extends RFC261
if (algorithm == null) {
algorithm = "MD5";
}
- // If an charset is not specified, default to ISO-8859-1.
String charset = getParameter("charset");
if (charset == null) {
charset = "ISO-8859-1";
@@ -331,8 +337,31 @@ public class DigestScheme extends RFC261
a2 = method + ':' + uri;
} else if (qop == QOP_AUTH_INT) {
// Method ":" digest-uri-value ":" H(entity-body)
- //TODO: calculate entity hash if entity is repeatable
- throw new AuthenticationException("qop-int method is not suppported");
+ HttpEntity entity = null;
+ if (request instanceof HttpEntityEnclosingRequest) {
+ entity = ((HttpEntityEnclosingRequest) request).getEntity();
+ }
+ if (entity != null && !entity.isRepeatable()) {
+ // If the entity is not repeatable, try falling back onto QOP_AUTH
+ if (qopset.contains("auth")) {
+ qop = QOP_AUTH;
+ a2 = method + ':' + uri;
+ } else {
+ throw new AuthenticationException("Qop auth-int cannot be used with " +
+ "a non-repeatable entity");
+ }
+ } else {
+ HttpEntityDigester entityDigester = new HttpEntityDigester(digester);
+ try {
+ if (entity != null) {
+ entity.writeTo(entityDigester);
+ }
+ entityDigester.close();
+ } catch (IOException ex) {
+ throw new AuthenticationException("I/O error reading entity content", ex);
+ }
+ a2 = method + ':' + uri + ':' + encode(entityDigester.getDigest());
+ }
} else {
a2 = method + ':' + uri;
}
@@ -413,7 +442,7 @@ public class DigestScheme extends RFC261
* @param binaryData array containing the digest
* @return encoded MD5, or <CODE>null</CODE> if encoding failed
*/
- private static String encode(byte[] binaryData) {
+ static String encode(byte[] binaryData) {
int n = binaryData.length;
char[] buffer = new char[n * 2];
for (int i = 0; i < n; i++) {
Added: httpcomponents/httpclient/trunk/httpclient/src/main/java/org/apache/http/impl/auth/HttpEntityDigester.java
URL: http://svn.apache.org/viewvc/httpcomponents/httpclient/trunk/httpclient/src/main/java/org/apache/http/impl/auth/HttpEntityDigester.java?rev=1158320&view=auto
==============================================================================
--- httpcomponents/httpclient/trunk/httpclient/src/main/java/org/apache/http/impl/auth/HttpEntityDigester.java (added)
+++ httpcomponents/httpclient/trunk/httpclient/src/main/java/org/apache/http/impl/auth/HttpEntityDigester.java Tue Aug 16 15:13:36 2011
@@ -0,0 +1,75 @@
+/*
+ * ====================================================================
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.http.impl.auth;
+
+import java.io.IOException;
+import java.io.OutputStream;
+import java.security.MessageDigest;
+
+class HttpEntityDigester extends OutputStream {
+
+ private final MessageDigest digester;
+ private boolean closed;
+ private byte[] digest;
+
+ HttpEntityDigester(final MessageDigest digester) {
+ super();
+ this.digester = digester;
+ this.digester.reset();
+ }
+
+ @Override
+ public void write(int b) throws IOException {
+ if (this.closed) {
+ throw new IOException("Stream has been already closed");
+ }
+ this.digester.update((byte) b);
+ }
+
+ @Override
+ public void write(byte[] b, int off, int len) throws IOException {
+ if (this.closed) {
+ throw new IOException("Stream has been already closed");
+ }
+ this.digester.update(b, off, len);
+ }
+
+ @Override
+ public void close() throws IOException {
+ if (this.closed) {
+ return;
+ }
+ this.closed = true;
+ this.digest = this.digester.digest();
+ super.close();
+ }
+
+ public byte[] getDigest() {
+ return this.digest;
+ }
+
+}
Propchange: httpcomponents/httpclient/trunk/httpclient/src/main/java/org/apache/http/impl/auth/HttpEntityDigester.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: httpcomponents/httpclient/trunk/httpclient/src/main/java/org/apache/http/impl/auth/HttpEntityDigester.java
------------------------------------------------------------------------------
svn:keywords = Date Revision
Propchange: httpcomponents/httpclient/trunk/httpclient/src/main/java/org/apache/http/impl/auth/HttpEntityDigester.java
------------------------------------------------------------------------------
svn:mime-type = text/plain
Modified: httpcomponents/httpclient/trunk/httpclient/src/main/java/org/apache/http/impl/auth/RFC2617Scheme.java
URL: http://svn.apache.org/viewvc/httpcomponents/httpclient/trunk/httpclient/src/main/java/org/apache/http/impl/auth/RFC2617Scheme.java?rev=1158320&r1=1158319&r2=1158320&view=diff
==============================================================================
--- httpcomponents/httpclient/trunk/httpclient/src/main/java/org/apache/http/impl/auth/RFC2617Scheme.java (original)
+++ httpcomponents/httpclient/trunk/httpclient/src/main/java/org/apache/http/impl/auth/RFC2617Scheme.java Tue Aug 16 15:13:36 2011
@@ -52,13 +52,14 @@ public abstract class RFC2617Scheme exte
/**
* Authentication parameter map.
*/
- private Map<String, String> params;
+ private final Map<String, String> params;
/**
* Default constructor for RFC2617 compliant authentication schemes.
*/
public RFC2617Scheme() {
super();
+ this.params = new HashMap<String, String>();
}
@Override
@@ -70,8 +71,7 @@ public abstract class RFC2617Scheme exte
if (elements.length == 0) {
throw new MalformedChallengeException("Authentication challenge is empty");
}
-
- this.params = new HashMap<String, String>(elements.length);
+ this.params.clear();
for (HeaderElement element : elements) {
this.params.put(element.getName(), element.getValue());
}
@@ -83,9 +83,6 @@ public abstract class RFC2617Scheme exte
* @return the map of authentication parameters
*/
protected Map<String, String> getParameters() {
- if (this.params == null) {
- this.params = new HashMap<String, String>();
- }
return this.params;
}
@@ -98,9 +95,6 @@ public abstract class RFC2617Scheme exte
*/
public String getParameter(final String name) {
if (name == null) {
- throw new IllegalArgumentException("Parameter name may not be null");
- }
- if (this.params == null) {
return null;
}
return this.params.get(name.toLowerCase(Locale.ENGLISH));
Modified: httpcomponents/httpclient/trunk/httpclient/src/test/java/org/apache/http/impl/auth/TestBasicScheme.java
URL: http://svn.apache.org/viewvc/httpcomponents/httpclient/trunk/httpclient/src/test/java/org/apache/http/impl/auth/TestBasicScheme.java?rev=1158320&r1=1158319&r2=1158320&view=diff
==============================================================================
--- httpcomponents/httpclient/trunk/httpclient/src/test/java/org/apache/http/impl/auth/TestBasicScheme.java (original)
+++ httpcomponents/httpclient/trunk/httpclient/src/test/java/org/apache/http/impl/auth/TestBasicScheme.java Tue Aug 16 15:13:36 2011
@@ -35,6 +35,8 @@ import org.apache.http.auth.MalformedCha
import org.apache.http.auth.UsernamePasswordCredentials;
import org.apache.http.message.BasicHeader;
import org.apache.http.message.BasicHttpRequest;
+import org.apache.http.protocol.BasicHttpContext;
+import org.apache.http.protocol.HttpContext;
import org.apache.http.util.EncodingUtils;
import org.junit.Assert;
import org.junit.Test;
@@ -76,7 +78,8 @@ public class TestBasicScheme {
authscheme.processChallenge(challenge);
HttpRequest request = new BasicHttpRequest("GET", "/");
- Header authResponse = authscheme.authenticate(creds, request);
+ HttpContext context = new BasicHttpContext();
+ Header authResponse = authscheme.authenticate(creds, request, context);
String expected = "Basic " + EncodingUtils.getAsciiString(
Base64.encodeBase64(EncodingUtils.getAsciiBytes("testuser:testpass")));
@@ -98,7 +101,8 @@ public class TestBasicScheme {
authscheme.processChallenge(challenge);
HttpRequest request = new BasicHttpRequest("GET", "/");
- Header authResponse = authscheme.authenticate(creds, request);
+ HttpContext context = new BasicHttpContext();
+ Header authResponse = authscheme.authenticate(creds, request, context);
String expected = "Basic " + EncodingUtils.getAsciiString(
Base64.encodeBase64(EncodingUtils.getAsciiBytes("testuser:testpass")));
Modified: httpcomponents/httpclient/trunk/httpclient/src/test/java/org/apache/http/impl/auth/TestDigestScheme.java
URL: http://svn.apache.org/viewvc/httpcomponents/httpclient/trunk/httpclient/src/test/java/org/apache/http/impl/auth/TestDigestScheme.java?rev=1158320&r1=1158319&r2=1158320&view=diff
==============================================================================
--- httpcomponents/httpclient/trunk/httpclient/src/test/java/org/apache/http/impl/auth/TestDigestScheme.java (original)
+++ httpcomponents/httpclient/trunk/httpclient/src/test/java/org/apache/http/impl/auth/TestDigestScheme.java Tue Aug 16 15:13:36 2011
@@ -26,11 +26,15 @@
package org.apache.http.impl.auth;
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.security.MessageDigest;
import java.util.HashMap;
import java.util.Map;
import org.apache.http.Header;
import org.apache.http.HeaderElement;
+import org.apache.http.HttpEntityEnclosingRequest;
import org.apache.http.HttpRequest;
import org.apache.http.auth.AuthScheme;
import org.apache.http.auth.AuthenticationException;
@@ -38,9 +42,15 @@ import org.apache.http.auth.Credentials;
import org.apache.http.auth.AUTH;
import org.apache.http.auth.MalformedChallengeException;
import org.apache.http.auth.UsernamePasswordCredentials;
+import org.apache.http.entity.InputStreamEntity;
+import org.apache.http.entity.StringEntity;
import org.apache.http.message.BasicHeader;
import org.apache.http.message.BasicHeaderValueParser;
+import org.apache.http.message.BasicHttpEntityEnclosingRequest;
import org.apache.http.message.BasicHttpRequest;
+import org.apache.http.protocol.BasicHttpContext;
+import org.apache.http.protocol.HTTP;
+import org.apache.http.protocol.HttpContext;
import org.junit.Assert;
import org.junit.Test;
@@ -50,14 +60,14 @@ import org.junit.Test;
public class TestDigestScheme {
@Test(expected=MalformedChallengeException.class)
- public void testDigestAuthenticationWithNoRealm() throws Exception {
+ public void testDigestAuthenticationEmptyChallenge1() throws Exception {
Header authChallenge = new BasicHeader(AUTH.WWW_AUTH, "Digest");
AuthScheme authscheme = new DigestScheme();
authscheme.processChallenge(authChallenge);
}
@Test(expected=MalformedChallengeException.class)
- public void testDigestAuthenticationWithNoRealm2() throws Exception {
+ public void testDigestAuthenticationEmptyChallenge2() throws Exception {
Header authChallenge = new BasicHeader(AUTH.WWW_AUTH, "Digest ");
AuthScheme authscheme = new DigestScheme();
authscheme.processChallenge(authChallenge);
@@ -70,8 +80,11 @@ public class TestDigestScheme {
HttpRequest request = new BasicHttpRequest("Simple", "/");
Credentials cred = new UsernamePasswordCredentials("username","password");
DigestScheme authscheme = new DigestScheme();
+ HttpContext context = new BasicHttpContext();
authscheme.processChallenge(authChallenge);
- Header authResponse = authscheme.authenticate(cred, request);
+ Header authResponse = authscheme.authenticate(cred, request, context);
+ Assert.assertTrue(authscheme.isComplete());
+ Assert.assertFalse(authscheme.isConnectionBased());
Map<String, String> table = parseAuthResponse(authResponse);
Assert.assertEquals("username", table.get("username"));
@@ -88,8 +101,9 @@ public class TestDigestScheme {
HttpRequest request = new BasicHttpRequest("Simple", "/");
Credentials cred = new UsernamePasswordCredentials("username","password");
DigestScheme authscheme = new DigestScheme();
+ HttpContext context = new BasicHttpContext();
authscheme.processChallenge(authChallenge);
- Header authResponse = authscheme.authenticate(cred, request);
+ Header authResponse = authscheme.authenticate(cred, request, context);
Map<String, String> table = parseAuthResponse(authResponse);
Assert.assertEquals("username", table.get("username"));
@@ -100,6 +114,47 @@ public class TestDigestScheme {
}
@Test
+ public void testDigestAuthenticationInvalidInput() throws Exception {
+ String challenge = "Digest realm=\"realm1\", nonce=\"f2a3f18799759d4f1a1c068b92b573cb\"";
+ Header authChallenge = new BasicHeader(AUTH.WWW_AUTH, challenge);
+ HttpRequest request = new BasicHttpRequest("Simple", "/");
+ Credentials cred = new UsernamePasswordCredentials("username","password");
+ DigestScheme authscheme = new DigestScheme();
+ HttpContext context = new BasicHttpContext();
+ authscheme.processChallenge(authChallenge);
+ try {
+ authscheme.authenticate(null, request, context);
+ Assert.fail("IllegalArgumentException should have been thrown");
+ } catch (IllegalArgumentException ex) {
+ }
+ try {
+ authscheme.authenticate(cred, null, context);
+ Assert.fail("IllegalArgumentException should have been thrown");
+ } catch (IllegalArgumentException ex) {
+ }
+ }
+
+ @Test
+ public void testDigestAuthenticationOverrideParameter() throws Exception {
+ String challenge = "Digest realm=\"realm1\", nonce=\"f2a3f18799759d4f1a1c068b92b573cb\"";
+ Header authChallenge = new BasicHeader(AUTH.WWW_AUTH, challenge);
+ HttpRequest request = new BasicHttpRequest("Simple", "/");
+ Credentials cred = new UsernamePasswordCredentials("username","password");
+ DigestScheme authscheme = new DigestScheme();
+ HttpContext context = new BasicHttpContext();
+ authscheme.processChallenge(authChallenge);
+ authscheme.overrideParamter("realm", "other realm");
+ Header authResponse = authscheme.authenticate(cred, request, context);
+
+ Map<String, String> table = parseAuthResponse(authResponse);
+ Assert.assertEquals("username", table.get("username"));
+ Assert.assertEquals("other realm", table.get("realm"));
+ Assert.assertEquals("/", table.get("uri"));
+ Assert.assertEquals("f2a3f18799759d4f1a1c068b92b573cb", table.get("nonce"));
+ Assert.assertEquals("3f211de10463cbd055ab4cd9c5158eac", table.get("response"));
+ }
+
+ @Test
public void testDigestAuthenticationWithSHA() throws Exception {
String challenge = "Digest realm=\"realm1\", " +
"nonce=\"f2a3f18799759d4f1a1c068b92b573cb\", " +
@@ -107,9 +162,10 @@ public class TestDigestScheme {
Header authChallenge = new BasicHeader(AUTH.WWW_AUTH, challenge);
HttpRequest request = new BasicHttpRequest("Simple", "/");
Credentials cred = new UsernamePasswordCredentials("username","password");
+ HttpContext context = new BasicHttpContext();
DigestScheme authscheme = new DigestScheme();
authscheme.processChallenge(authChallenge);
- Header authResponse = authscheme.authenticate(cred, request);
+ Header authResponse = authscheme.authenticate(cred, request, context);
Map<String, String> table = parseAuthResponse(authResponse);
Assert.assertEquals("username", table.get("username"));
@@ -125,9 +181,10 @@ public class TestDigestScheme {
Header authChallenge = new BasicHeader(AUTH.WWW_AUTH, challenge);
HttpRequest request = new BasicHttpRequest("Simple", "/?param=value");
Credentials cred = new UsernamePasswordCredentials("username","password");
+ HttpContext context = new BasicHttpContext();
DigestScheme authscheme = new DigestScheme();
authscheme.processChallenge(authChallenge);
- Header authResponse = authscheme.authenticate(cred, request);
+ Header authResponse = authscheme.authenticate(cred, request, context);
Map<String, String> table = parseAuthResponse(authResponse);
Assert.assertEquals("username", table.get("username"));
@@ -146,9 +203,10 @@ public class TestDigestScheme {
Header authChallenge = new BasicHeader(AUTH.WWW_AUTH, challenge1);
HttpRequest request = new BasicHttpRequest("Simple", "/");
+ HttpContext context = new BasicHttpContext();
DigestScheme authscheme = new DigestScheme();
authscheme.processChallenge(authChallenge);
- Header authResponse = authscheme.authenticate(cred, request);
+ Header authResponse = authscheme.authenticate(cred, request, context);
Map<String, String> table = parseAuthResponse(authResponse);
Assert.assertEquals("username", table.get("username"));
@@ -160,7 +218,7 @@ public class TestDigestScheme {
authChallenge = new BasicHeader(AUTH.WWW_AUTH, challenge2);
DigestScheme authscheme2 = new DigestScheme();
authscheme2.processChallenge(authChallenge);
- authResponse = authscheme2.authenticate(cred2, request);
+ authResponse = authscheme2.authenticate(cred2, request, context);
table = parseAuthResponse(authResponse);
Assert.assertEquals("uname2", table.get("username"));
@@ -170,6 +228,32 @@ public class TestDigestScheme {
Assert.assertEquals("0283edd9ef06a38b378b3b74661391e9", table.get("response"));
}
+ @Test(expected=AuthenticationException.class)
+ public void testDigestAuthenticationNoRealm() throws Exception {
+ String challenge = "Digest no-realm=\"realm1\", nonce=\"f2a3f18799759d4f1a1c068b92b573cb\"";
+ Header authChallenge = new BasicHeader(AUTH.WWW_AUTH, challenge);
+ HttpContext context = new BasicHttpContext();
+ DigestScheme authscheme = new DigestScheme();
+ authscheme.processChallenge(authChallenge);
+
+ Credentials cred = new UsernamePasswordCredentials("username","password");
+ HttpRequest request = new BasicHttpRequest("Simple", "/");
+ authscheme.authenticate(cred, request, context);
+ }
+
+ @Test(expected=AuthenticationException.class)
+ public void testDigestAuthenticationNoNonce() throws Exception {
+ String challenge = "Digest realm=\"realm1\", no-nonce=\"f2a3f18799759d4f1a1c068b92b573cb\"";
+ Header authChallenge = new BasicHeader(AUTH.WWW_AUTH, challenge);
+ HttpContext context = new BasicHttpContext();
+ DigestScheme authscheme = new DigestScheme();
+ authscheme.processChallenge(authChallenge);
+
+ Credentials cred = new UsernamePasswordCredentials("username","password");
+ HttpRequest request = new BasicHttpRequest("Simple", "/");
+ authscheme.authenticate(cred, request, context);
+ }
+
/**
* Test digest authentication using the MD5-sess algorithm.
*/
@@ -193,10 +277,11 @@ public class TestDigestScheme {
Credentials cred = new UsernamePasswordCredentials(username, password);
HttpRequest request = new BasicHttpRequest("Simple", "/");
+ HttpContext context = new BasicHttpContext();
DigestScheme authscheme = new DigestScheme();
authscheme.processChallenge(authChallenge);
- Header authResponse = authscheme.authenticate(cred, request);
+ Header authResponse = authscheme.authenticate(cred, request, context);
String response = authResponse.getValue();
Assert.assertTrue(response.indexOf("nc=00000001") > 0); // test for quotes
@@ -239,10 +324,11 @@ public class TestDigestScheme {
Credentials cred = new UsernamePasswordCredentials(username, password);
HttpRequest request = new BasicHttpRequest("Simple", "/");
+ HttpContext context = new BasicHttpContext();
DigestScheme authscheme = new DigestScheme();
authscheme.processChallenge(authChallenge);
- Header authResponse = authscheme.authenticate(cred, request);
+ Header authResponse = authscheme.authenticate(cred, request, context);
Map<String, String> table = parseAuthResponse(authResponse);
Assert.assertEquals(username, table.get("username"));
@@ -283,7 +369,8 @@ public class TestDigestScheme {
Credentials cred = new UsernamePasswordCredentials(username, password);
HttpRequest request = new BasicHttpRequest("Simple", "/");
- authscheme.authenticate(cred, request);
+ HttpContext context = new BasicHttpContext();
+ authscheme.authenticate(cred, request, context);
}
/**
@@ -312,7 +399,8 @@ public class TestDigestScheme {
Credentials cred = new UsernamePasswordCredentials(username, password);
HttpRequest request = new BasicHttpRequest("Simple", "/");
- authscheme.authenticate(cred, request);
+ HttpContext context = new BasicHttpContext();
+ authscheme.authenticate(cred, request, context);
}
@Test
@@ -346,24 +434,25 @@ public class TestDigestScheme {
Header authChallenge1 = new BasicHeader(AUTH.WWW_AUTH, challenge1);
HttpRequest request = new BasicHttpRequest("GET", "/");
Credentials cred = new UsernamePasswordCredentials("username","password");
+ HttpContext context = new BasicHttpContext();
DigestScheme authscheme = new DigestScheme();
authscheme.processChallenge(authChallenge1);
- Header authResponse1 = authscheme.authenticate(cred, request);
+ Header authResponse1 = authscheme.authenticate(cred, request, context);
Map<String, String> table1 = parseAuthResponse(authResponse1);
Assert.assertEquals("00000001", table1.get("nc"));
- Header authResponse2 = authscheme.authenticate(cred, request);
+ Header authResponse2 = authscheme.authenticate(cred, request, context);
Map<String, String> table2 = parseAuthResponse(authResponse2);
Assert.assertEquals("00000002", table2.get("nc"));
String challenge2 = "Digest realm=\"realm1\", nonce=\"f2a3f18799759d4f1a1c068b92b573cb\", qop=auth";
Header authChallenge2 = new BasicHeader(AUTH.WWW_AUTH, challenge2);
authscheme.processChallenge(authChallenge2);
- Header authResponse3 = authscheme.authenticate(cred, request);
+ Header authResponse3 = authscheme.authenticate(cred, request, context);
Map<String, String> table3 = parseAuthResponse(authResponse3);
Assert.assertEquals("00000003", table3.get("nc"));
String challenge3 = "Digest realm=\"realm1\", nonce=\"e273f1776275974f1a120d8b92c5b3cb\", qop=auth";
Header authChallenge3 = new BasicHeader(AUTH.WWW_AUTH, challenge3);
authscheme.processChallenge(authChallenge3);
- Header authResponse4 = authscheme.authenticate(cred, request);
+ Header authResponse4 = authscheme.authenticate(cred, request, context);
Map<String, String> table4 = parseAuthResponse(authResponse4);
Assert.assertEquals("00000001", table4.get("nc"));
}
@@ -375,15 +464,16 @@ public class TestDigestScheme {
Header authChallenge1 = new BasicHeader(AUTH.WWW_AUTH, challenge1);
HttpRequest request = new BasicHttpRequest("GET", "/");
Credentials cred = new UsernamePasswordCredentials("username","password");
+ HttpContext context = new BasicHttpContext();
DigestScheme authscheme = new DigestScheme();
authscheme.processChallenge(authChallenge1);
- Header authResponse1 = authscheme.authenticate(cred, request);
+ Header authResponse1 = authscheme.authenticate(cred, request, context);
Map<String, String> table1 = parseAuthResponse(authResponse1);
Assert.assertEquals("00000001", table1.get("nc"));
String cnonce1 = authscheme.getCnonce();
String sessionKey1 = authscheme.getA1();
- Header authResponse2 = authscheme.authenticate(cred, request);
+ Header authResponse2 = authscheme.authenticate(cred, request, context);
Map<String, String> table2 = parseAuthResponse(authResponse2);
Assert.assertEquals("00000002", table2.get("nc"));
String cnonce2 = authscheme.getCnonce();
@@ -396,7 +486,7 @@ public class TestDigestScheme {
"charset=utf-8, realm=\"subnet.domain.com\"";
Header authChallenge2 = new BasicHeader(AUTH.WWW_AUTH, challenge2);
authscheme.processChallenge(authChallenge2);
- Header authResponse3 = authscheme.authenticate(cred, request);
+ Header authResponse3 = authscheme.authenticate(cred, request, context);
Map<String, String> table3 = parseAuthResponse(authResponse3);
Assert.assertEquals("00000003", table3.get("nc"));
@@ -410,7 +500,7 @@ public class TestDigestScheme {
"charset=utf-8, realm=\"subnet.domain.com\"";
Header authChallenge3 = new BasicHeader(AUTH.WWW_AUTH, challenge3);
authscheme.processChallenge(authChallenge3);
- Header authResponse4 = authscheme.authenticate(cred, request);
+ Header authResponse4 = authscheme.authenticate(cred, request, context);
Map<String, String> table4 = parseAuthResponse(authResponse4);
Assert.assertEquals("00000001", table4.get("nc"));
@@ -420,4 +510,113 @@ public class TestDigestScheme {
Assert.assertFalse(cnonce1.equals(cnonce4));
Assert.assertFalse(sessionKey1.equals(sessionKey4));
}
+
+ @Test
+ public void testHttpEntityDigest() throws Exception {
+ HttpEntityDigester digester = new HttpEntityDigester(MessageDigest.getInstance("MD5"));
+ Assert.assertNull(digester.getDigest());
+ digester.write('a');
+ digester.write('b');
+ digester.write('c');
+ digester.write(0xe4);
+ digester.write(0xf6);
+ digester.write(0xfc);
+ digester.write(new byte[] { 'a', 'b', 'c'});
+ Assert.assertNull(digester.getDigest());
+ digester.close();
+ Assert.assertEquals("acd2b59cd01c7737d8069015584c6cac", DigestScheme.encode(digester.getDigest()));
+ try {
+ digester.write('a');
+ Assert.fail("IOException should have been thrown");
+ } catch (IOException ex) {
+ }
+ try {
+ digester.write(new byte[] { 'a', 'b', 'c'});
+ Assert.fail("IOException should have been thrown");
+ } catch (IOException ex) {
+ }
+ }
+
+ @Test
+ public void testDigestAuthenticationQopAuthInt() throws Exception {
+ String challenge = "Digest realm=\"realm1\", nonce=\"f2a3f18799759d4f1a1c068b92b573cb\", " +
+ "qop=\"auth,auth-int\"";
+ Header authChallenge = new BasicHeader(AUTH.WWW_AUTH, challenge);
+ HttpEntityEnclosingRequest request = new BasicHttpEntityEnclosingRequest("Post", "/");
+ request.setEntity(new StringEntity("abc\u00e4\u00f6\u00fcabc", HTTP.DEFAULT_CONTENT_CHARSET));
+ Credentials cred = new UsernamePasswordCredentials("username","password");
+ DigestScheme authscheme = new DigestScheme();
+ HttpContext context = new BasicHttpContext();
+ authscheme.processChallenge(authChallenge);
+ Header authResponse = authscheme.authenticate(cred, request, context);
+
+ Assert.assertEquals("Post:/:acd2b59cd01c7737d8069015584c6cac", authscheme.getA2());
+
+ Map<String, String> table = parseAuthResponse(authResponse);
+ Assert.assertEquals("username", table.get("username"));
+ Assert.assertEquals("realm1", table.get("realm"));
+ Assert.assertEquals("/", table.get("uri"));
+ Assert.assertEquals("auth-int", table.get("qop"));
+ Assert.assertEquals("f2a3f18799759d4f1a1c068b92b573cb", table.get("nonce"));
+ }
+
+ @Test
+ public void testDigestAuthenticationQopAuthIntNullEntity() throws Exception {
+ String challenge = "Digest realm=\"realm1\", nonce=\"f2a3f18799759d4f1a1c068b92b573cb\", " +
+ "qop=\"auth,auth-int\"";
+ Header authChallenge = new BasicHeader(AUTH.WWW_AUTH, challenge);
+ HttpRequest request = new BasicHttpEntityEnclosingRequest("Post", "/");
+ Credentials cred = new UsernamePasswordCredentials("username","password");
+ DigestScheme authscheme = new DigestScheme();
+ HttpContext context = new BasicHttpContext();
+ authscheme.processChallenge(authChallenge);
+ Header authResponse = authscheme.authenticate(cred, request, context);
+
+ Assert.assertEquals("Post:/:d41d8cd98f00b204e9800998ecf8427e", authscheme.getA2());
+
+ Map<String, String> table = parseAuthResponse(authResponse);
+ Assert.assertEquals("username", table.get("username"));
+ Assert.assertEquals("realm1", table.get("realm"));
+ Assert.assertEquals("/", table.get("uri"));
+ Assert.assertEquals("auth-int", table.get("qop"));
+ Assert.assertEquals("f2a3f18799759d4f1a1c068b92b573cb", table.get("nonce"));
+ }
+
+ @Test
+ public void testDigestAuthenticationQopAuthOrAuthIntNonRepeatableEntity() throws Exception {
+ String challenge = "Digest realm=\"realm1\", nonce=\"f2a3f18799759d4f1a1c068b92b573cb\", " +
+ "qop=\"auth,auth-int\"";
+ Header authChallenge = new BasicHeader(AUTH.WWW_AUTH, challenge);
+ HttpEntityEnclosingRequest request = new BasicHttpEntityEnclosingRequest("Post", "/");
+ request.setEntity(new InputStreamEntity(new ByteArrayInputStream(new byte[] {'a'}), -1));
+ Credentials cred = new UsernamePasswordCredentials("username","password");
+ DigestScheme authscheme = new DigestScheme();
+ HttpContext context = new BasicHttpContext();
+ authscheme.processChallenge(authChallenge);
+ Header authResponse = authscheme.authenticate(cred, request, context);
+
+ Assert.assertEquals("Post:/", authscheme.getA2());
+
+ Map<String, String> table = parseAuthResponse(authResponse);
+ Assert.assertEquals("username", table.get("username"));
+ Assert.assertEquals("realm1", table.get("realm"));
+ Assert.assertEquals("/", table.get("uri"));
+ Assert.assertEquals("auth", table.get("qop"));
+ Assert.assertEquals("f2a3f18799759d4f1a1c068b92b573cb", table.get("nonce"));
+ }
+
+ @Test(expected=AuthenticationException.class)
+ public void testDigestAuthenticationQopIntOnlyNonRepeatableEntity() throws Exception {
+ String challenge = "Digest realm=\"realm1\", nonce=\"f2a3f18799759d4f1a1c068b92b573cb\", " +
+ "qop=\"auth-int\"";
+ Header authChallenge = new BasicHeader(AUTH.WWW_AUTH, challenge);
+ HttpEntityEnclosingRequest request = new BasicHttpEntityEnclosingRequest("Post", "/");
+ request.setEntity(new InputStreamEntity(new ByteArrayInputStream(new byte[] {'a'}), -1));
+ Credentials cred = new UsernamePasswordCredentials("username","password");
+ DigestScheme authscheme = new DigestScheme();
+ HttpContext context = new BasicHttpContext();
+ authscheme.processChallenge(authChallenge);
+ authscheme.authenticate(cred, request, context);
+ }
+
}
Modified: httpcomponents/httpclient/trunk/httpclient/src/test/java/org/apache/http/impl/auth/TestRFC2617Scheme.java
URL: http://svn.apache.org/viewvc/httpcomponents/httpclient/trunk/httpclient/src/test/java/org/apache/http/impl/auth/TestRFC2617Scheme.java?rev=1158320&r1=1158319&r2=1158320&view=diff
==============================================================================
--- httpcomponents/httpclient/trunk/httpclient/src/test/java/org/apache/http/impl/auth/TestRFC2617Scheme.java (original)
+++ httpcomponents/httpclient/trunk/httpclient/src/test/java/org/apache/http/impl/auth/TestRFC2617Scheme.java Tue Aug 16 15:13:36 2011
@@ -73,11 +73,13 @@ public class TestRFC2617Scheme {
authscheme.processChallenge(header);
Assert.assertEquals("test", authscheme.getSchemeName());
+ Assert.assertEquals("test", authscheme.toString());
Assert.assertEquals("realm1", authscheme.getParameter("realm"));
Assert.assertEquals(null, authscheme.getParameter("test"));
Assert.assertEquals("stuff", authscheme.getParameter("test1"));
Assert.assertEquals("stuff, stuff", authscheme.getParameter("test2"));
Assert.assertEquals("\"crap", authscheme.getParameter("test3"));
+ Assert.assertEquals(null, authscheme.getParameter(null));
}
@Test
@@ -87,12 +89,23 @@ public class TestRFC2617Scheme {
buffer.append(" WWW-Authenticate: Test realm=\"realm1\"");
Header header = new BufferedHeader(buffer);
+
authscheme.processChallenge(header);
Assert.assertEquals("test", authscheme.getSchemeName());
Assert.assertEquals("realm1", authscheme.getParameter("realm"));
}
+ @Test
+ public void testNullHeader() throws Exception {
+ TestAuthScheme authscheme = new TestAuthScheme();
+ try {
+ authscheme.processChallenge(null);
+ Assert.fail("IllegalArgumentException should have been thrown");
+ } catch (IllegalArgumentException ex) {
+ }
+ }
+
@Test(expected=MalformedChallengeException.class)
public void testInvalidHeader() throws Exception {
TestAuthScheme authscheme = new TestAuthScheme();
@@ -101,6 +114,13 @@ public class TestRFC2617Scheme {
}
@Test(expected=MalformedChallengeException.class)
+ public void testInvalidSchemeName() throws Exception {
+ TestAuthScheme authscheme = new TestAuthScheme();
+ Header header = new BasicHeader(AUTH.WWW_AUTH, "Not-a-Test realm=\"realm1\"");
+ authscheme.processChallenge(header);
+ }
+
+ @Test(expected=MalformedChallengeException.class)
public void testEmptyHeader() throws Exception {
TestAuthScheme authscheme = new TestAuthScheme();
Header header = new BasicHeader(AUTH.WWW_AUTH, "Test ");