Author: jmsnell Date: Wed Dec 21 23:56:54 2011 New Revision: 1221958 URL: http://svn.apache.org/viewvc?rev=1221958&view=rev Log: Test cases and fixes..
We're now passing all of the test cases described here: http://greenbytes.de/tech/tc/httpauth/ Modified: abdera/abdera2/common/src/main/java/org/apache/abdera2/common/http/Authentication.java abdera/abdera2/common/src/main/java/org/apache/abdera2/common/http/Preference.java abdera/abdera2/test/src/main/java/org/apache/abdera2/test/common/http/AuthenticationTest.java Modified: abdera/abdera2/common/src/main/java/org/apache/abdera2/common/http/Authentication.java URL: http://svn.apache.org/viewvc/abdera/abdera2/common/src/main/java/org/apache/abdera2/common/http/Authentication.java?rev=1221958&r1=1221957&r2=1221958&view=diff ============================================================================== --- abdera/abdera2/common/src/main/java/org/apache/abdera2/common/http/Authentication.java (original) +++ abdera/abdera2/common/src/main/java/org/apache/abdera2/common/http/Authentication.java Wed Dec 21 23:56:54 2011 @@ -59,10 +59,10 @@ public class Authentication implements I private final static String TOKEN = "[\\!\\#\\$\\%\\&\\'\\*\\+\\-\\.\\^\\_\\`\\|\\~a-zA-Z0-9]+"; private final static String B64 = "([a-zA-Z0-9\\-\\.\\_\\~\\+\\/]+\\=*)"; - private final static String PARAM = TOKEN+"\\s*={1}\\s*(?:(?:\"[^\"]+\")|(?:"+TOKEN+"))"; - private final static String PARAMS = "(" + PARAM + "(?:\\s*,\\s*"+PARAM+")*)"; + private final static String PARAM = TOKEN+"\\s*=\\s*(?:(?:\"(?:(?:\\Q\\\"\\E)|[^\"])*\")|(?:"+TOKEN+"))"; + private final static String PARAMS = "\\s*,?\\s*(" + PARAM + "(?:\\s*,\\s*(?:"+PARAM+")?)*)"; private final static String B64orPARAM = "(?:" + PARAMS + "|" + B64 + ")"; - private final static String PATTERN = "("+TOKEN+")(?:\\s+" + B64orPARAM + ")?"; + private final static String PATTERN = "("+TOKEN+")(?:\\s*" + B64orPARAM + ")?"; private final static Pattern pattern = Pattern.compile(PATTERN); private final static Pattern param = @@ -91,6 +91,13 @@ public class Authentication implements I } }; + public static String unescape(String quoted) { + StringBuilder buf = new StringBuilder(); + for (char c : quoted.toCharArray()) + if (c != '\\') buf.append(c); + return buf.toString(); + } + public static Iterable<Authentication> parse(String challenge) { checkNotNull(challenge); List<Authentication> challenges = new ArrayList<Authentication>(); @@ -98,6 +105,7 @@ public class Authentication implements I while (matcher.find()) { String scheme = matcher.group(1); String params = matcher.group(2); + params = params != null ? params.replaceAll(",\\s*,", ",").replaceAll(",\\s*,", ",") : null; String b64token = matcher.group(3); Authentication.Builder auth = make() @@ -111,7 +119,7 @@ public class Authentication implements I String name = ps[0]; if (name.charAt(name.length()-1)=='*') name = name.substring(0,name.length()-1); - auth.param(name, Codec.decode(unquote(ps[1]))); + auth.param(name, Codec.decode(unquote(unescape(ps[1])))); } } challenges.add(auth.get()); Modified: abdera/abdera2/common/src/main/java/org/apache/abdera2/common/http/Preference.java URL: http://svn.apache.org/viewvc/abdera/abdera2/common/src/main/java/org/apache/abdera2/common/http/Preference.java?rev=1221958&r1=1221957&r2=1221958&view=diff ============================================================================== --- abdera/abdera2/common/src/main/java/org/apache/abdera2/common/http/Preference.java (original) +++ abdera/abdera2/common/src/main/java/org/apache/abdera2/common/http/Preference.java Wed Dec 21 23:56:54 2011 @@ -343,7 +343,7 @@ public class Preference implements Seria } private final static String TOKEN = "[\\!\\#\\$\\%\\&\\'\\*\\+\\-\\.\\^\\_\\`\\|\\~a-zA-Z0-9]+"; - private final static String PREF = TOKEN+"(?:\\s*=\\s*(?:(?:\"[^\"]+\")|(?:"+TOKEN+"))?)?"; + private final static String PREF = TOKEN+"(?:\\s*=\\s*(?:(?:\"(?:(?:\\Q\\\"\\E)|[^\"])*\")|(?:"+TOKEN+"))?)?"; private final static String PARAMS = "(?:\\s*;\\s*" + PREF + ")*"; private final static String PATTERN = "("+PREF+")(" + PARAMS + ")"; @@ -364,7 +364,7 @@ public class Preference implements Seria String[] ps = pref.split("\\s*\\*?=\\s*", 2); token = ps[0].trim(); if (ps.length == 2) - tokenval = Codec.decode(CharUtils.unquote(ps[1])); + tokenval = Codec.decode(CharUtils.unquote(Authentication.unescape(ps[1]))); } Preference.Builder maker = @@ -375,7 +375,7 @@ public class Preference implements Seria String p = mparams.group(1); String[] ps = p.split("\\s*\\*?=\\s*", 2); if (ps.length == 2) - maker.param(ps[0], Codec.decode(CharUtils.unquote(ps[1]))); + maker.param(ps[0], Codec.decode(CharUtils.unquote(Authentication.unescape(ps[1])))); else maker.param(ps[0]); } } Modified: abdera/abdera2/test/src/main/java/org/apache/abdera2/test/common/http/AuthenticationTest.java URL: http://svn.apache.org/viewvc/abdera/abdera2/test/src/main/java/org/apache/abdera2/test/common/http/AuthenticationTest.java?rev=1221958&r1=1221957&r2=1221958&view=diff ============================================================================== --- abdera/abdera2/test/src/main/java/org/apache/abdera2/test/common/http/AuthenticationTest.java (original) +++ abdera/abdera2/test/src/main/java/org/apache/abdera2/test/common/http/AuthenticationTest.java Wed Dec 21 23:56:54 2011 @@ -2,12 +2,16 @@ package org.apache.abdera2.test.common.h import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; +import static org.junit.Assert.assertThat; +import static org.hamcrest.CoreMatchers.*; import java.util.Iterator; import org.apache.abdera2.common.http.Authentication; import org.junit.Test; +import com.google.common.collect.Iterables; + public class AuthenticationTest { @Test @@ -36,4 +40,212 @@ public class AuthenticationTest { assertEquals("foo",auth.getParam("c")); } + @Test + public void simplebasic() { + Iterable<Authentication> ia = Authentication.parse("Basic realm=\"foo\""); + Authentication auth = ia.iterator().next(); + assertEquals("basic",auth.getScheme()); + assertTrue(auth.hasParam("realm")); + assertEquals("foo",auth.getParam("realm")); + } + + @Test + public void simplebasictok() { + Iterable<Authentication> ia = Authentication.parse("Basic realm=foo"); + Authentication auth = ia.iterator().next(); + assertEquals("basic",auth.getScheme()); + assertTrue(auth.hasParam("realm")); + assertEquals("foo",auth.getParam("realm")); + } + + @Test + public void simplebasiccomma() { + Iterable<Authentication> ia = Authentication.parse("Basic , realm=foo"); + Authentication auth = ia.iterator().next(); + assertEquals("basic",auth.getScheme()); + assertTrue(auth.hasParam("realm")); + assertEquals("foo",auth.getParam("realm")); + } + + @Test + public void simplebasiccomma2() { + // technically this is invalid, but trying to be liberal in what we accept + Iterable<Authentication> ia = Authentication.parse("Basic, realm=foo"); + Authentication auth = ia.iterator().next(); + assertEquals("basic",auth.getScheme()); + assertTrue(auth.hasParam("realm")); + assertEquals("foo",auth.getParam("realm")); + } + + @Test + public void simplebasicnorealm() { + // technically this is invalid, but trying to be liberal in what we accept.. it's useless without a realm tho + Iterable<Authentication> ia = Authentication.parse("Basic"); + Authentication auth = ia.iterator().next(); + assertEquals("basic",auth.getScheme()); + } + + @Test(expected=IllegalArgumentException.class) + public void simplebasic2realms() { + // can't have duplicated parameters + Authentication.parse("Basic realm=\"foo\", realm=\"bar\""); + } + + @Test + public void simplebasicwsrealm() { + // technically this is invalid, but trying to be liberal in what we accept + Iterable<Authentication> ia = Authentication.parse("Basic realm = \"foo\" "); + Authentication auth = ia.iterator().next(); + assertEquals("basic",auth.getScheme()); + assertTrue(auth.hasParam("realm")); + assertEquals("foo",auth.getParam("realm")); + } + + @Test + public void simplebasicrealmsqc() { + // technically this is invalid, but trying to be liberal in what we accept + Iterable<Authentication> ia = Authentication.parse("Basic realm = \"\\f\\o\\o\" "); + Authentication auth = ia.iterator().next(); + assertEquals("basic",auth.getScheme()); + assertTrue(auth.hasParam("realm")); + assertEquals("foo",auth.getParam("realm")); + } + + @Test + public void simplebasicrealmsqc2() { + // technically this is invalid, but trying to be liberal in what we accept + Iterable<Authentication> ia = Authentication.parse("Basic realm = \"\\\"foo\\\"\" "); + Authentication auth = ia.iterator().next(); + assertEquals("basic",auth.getScheme()); + assertTrue(auth.hasParam("realm")); + assertEquals("\"foo\"",auth.getParam("realm")); + } + + @Test + public void simplebasicnewparam1() { + Iterable<Authentication> ia = Authentication.parse("Basic realm=\"foo\", bar=\"xyz\",, a=b,,,c=d"); + Authentication auth = ia.iterator().next(); + assertEquals("basic",auth.getScheme()); + assertTrue(auth.hasParam("realm")); + assertTrue(auth.hasParam("bar")); + assertTrue(auth.hasParam("a")); + assertTrue(auth.hasParam("c")); + assertEquals("foo",auth.getParam("realm")); + assertEquals("xyz",auth.getParam("bar")); + assertEquals("b",auth.getParam("a")); + assertEquals("d",auth.getParam("c")); + } + + @Test + public void simplebasicnewparam2() { + Iterable<Authentication> ia = Authentication.parse("Basic bar=\"xyz\", realm=\"foo\""); + Authentication auth = ia.iterator().next(); + assertEquals("basic",auth.getScheme()); + assertTrue(auth.hasParam("realm")); + assertTrue(auth.hasParam("bar")); + assertEquals("foo",auth.getParam("realm")); + assertEquals("xyz",auth.getParam("bar")); + } + + @Test + public void simplebasicrealmiso88591() { + Iterable<Authentication> ia = Authentication.parse("Basic realm=\"foo-\u00E4\""); + Authentication auth = ia.iterator().next(); + assertEquals("basic",auth.getScheme()); + assertTrue(auth.hasParam("realm")); + assertEquals("foo-\u00E4",auth.getParam("realm")); + } + + @Test + public void simplebasicrealmutf8() { + Iterable<Authentication> ia = Authentication.parse("Basic realm=\"foo-\u00E4\u00A4\""); + Authentication auth = ia.iterator().next(); + assertEquals("basic",auth.getScheme()); + assertTrue(auth.hasParam("realm")); + assertEquals("foo-\u00E4\u00A4",auth.getParam("realm")); + } + + @Test + public void simplebasicrealmrfc2047() { + Iterable<Authentication> ia = Authentication.parse("Basic realm=\"=?ISO-8859-1?Q?foo-=E4?=\""); + Authentication auth = ia.iterator().next(); + assertEquals("basic",auth.getScheme()); + assertTrue(auth.hasParam("realm")); + assertEquals("foo-\u00E4",auth.getParam("realm")); + } + + @Test + public void multibasicunknown() { + Iterable<Authentication> ia = Authentication.parse("Basic realm=\"basic\", Newauth realm=\"newauth\""); + assertEquals(2,Iterables.size(ia)); + for (Authentication auth : ia) { + assertThat(auth.getScheme(),anyOf(is("basic"),is("newauth"))); + assertEquals(auth.getScheme(), auth.getParam("realm")); + } + } + + @Test + public void multibasicunknown2() { + Iterable<Authentication> ia = Authentication.parse("Newauth realm=\"newauth\", Basic realm=\"basic\""); + assertEquals(2,Iterables.size(ia)); + for (Authentication auth : ia) { + assertThat(auth.getScheme(),anyOf(is("basic"),is("newauth"))); + assertEquals(auth.getScheme(), auth.getParam("realm")); + } + } + + @Test + public void multibasicempty() { + Iterable<Authentication> ia = Authentication.parse(",Basic realm=\"basic\""); + assertEquals(1,Iterables.size(ia)); + Authentication auth = ia.iterator().next(); + assertEquals("basic",auth.getScheme()); + assertTrue(auth.hasParam("realm")); + } + + @Test + public void multibasicqs() { + Iterable<Authentication> ia = Authentication.parse("Newauth realm=\"apps\", type=1, title=\"Login to \\\"apps\\\"\", Basic realm=\"simple\""); + assertEquals(2,Iterables.size(ia)); + for (Authentication auth : ia) { + assertThat(auth.getScheme(),anyOf(is("basic"),is("newauth"))); + if ("basic".equalsIgnoreCase(auth.getScheme())) { + assertEquals("simple",auth.getParam("realm")); + } else if ("newauth".equalsIgnoreCase(auth.getScheme())) { + assertEquals("apps",auth.getParam("realm")); + assertEquals("1",auth.getParam("type")); + assertEquals("Login to \"apps\"", auth.getParam("title")); + } + } + } + + @Test + public void unknown() { + Iterable<Authentication> ia = Authentication.parse("Newauth realm=\"newauth\""); + assertEquals(1,Iterables.size(ia)); + Authentication auth = ia.iterator().next(); + assertEquals("newauth",auth.getScheme()); + assertTrue(auth.hasParam("realm")); + } + + @Test + public void disguisedrealm() { + Iterable<Authentication> ia = Authentication.parse("Basic foo=\"realm=nottherealm\", realm=\"basic\""); + assertEquals(1,Iterables.size(ia)); + Authentication auth = ia.iterator().next(); + assertEquals("basic",auth.getScheme()); + assertTrue(auth.hasParam("realm")); + assertEquals("basic",auth.getParam("realm")); + } + + @Test + public void disguisedrealm2() { + Iterable<Authentication> ia = Authentication.parse("Basic nottherealm=\"nottherealm\", realm=\"basic\""); + assertEquals(1,Iterables.size(ia)); + Authentication auth = ia.iterator().next(); + assertEquals("basic",auth.getScheme()); + assertTrue(auth.hasParam("realm")); + assertEquals("basic",auth.getParam("realm")); + } + }
