summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRolf Eike Beer <kde@opensource.sf-tec.de>2011-07-28 13:09:40 (GMT)
committerRolf Eike Beer <kde@opensource.sf-tec.de>2011-08-02 06:27:09 (GMT)
commit93fd96d12cc8eeb1a1ab1918cd34c8c37abbbaac (patch)
tree6f7c75b0fffe842996785ac003067b44b09012a5
parent58cb098864ac415cfd0486dbacb49927d92e00fc (diff)
make quoting and empty fields work in HTTP authentication headers
CCMAIL:adawit@kde.org
-rw-r--r--kioslave/http/httpauthentication.cpp76
-rw-r--r--kioslave/http/tests/httpauthenticationtest.cpp25
2 files changed, 71 insertions, 30 deletions
diff --git a/kioslave/http/httpauthentication.cpp b/kioslave/http/httpauthentication.cpp
index 42c9629..cfb733c 100644
--- a/kioslave/http/httpauthentication.cpp
+++ b/kioslave/http/httpauthentication.cpp
@@ -77,8 +77,8 @@ static QList<QByteArray> parseChallenge(const QByteArray &ba, QByteArray *scheme
while (end < len) {
start = end;
- // parse key
- while (start < len && isWhiteSpace(b[start])) {
+ // parse key, skip empty fields
+ while (start < len && (isWhiteSpace(b[start]) || b[start] == ',')) {
start++;
}
end = start;
@@ -107,41 +107,63 @@ static QList<QByteArray> parseChallenge(const QByteArray &ba, QByteArray *scheme
while (start < len && isWhiteSpace(b[start])) {
start++;
}
- if (start + 1 < len && b[start] == '"') {
+ if (b[start] == '"') {
+ bool hasBs = false;
+ bool hasErr = false;
+
end = ++start;
- while (start + 1 < len && b[start] == '\\' && b[start+1] == '"') {
- start += 2;
- end = start;
- }
- //quoted string
- while (end < len && b[end] != '"') {
- end++;
- }
- pos = end; // save the end position
- if (end-1 > start && b[end-1] == '\\') {
- end--; // ignore escape char
+
+ while (end < len) {
+ if (b[end] == '\\') {
+ if (++end + 1 >= len) {
+ hasErr = true;
+ break;
+ } else {
+ hasBs = true;
+ end++;
+ }
+ } else if (b[end] == '"') {
+ break;
+ } else {
+ end++;
+ }
}
- values.append(QByteArray(b + start, end - start));
- end = pos; // restore the end position
- //the quoted string has ended, but only a comma ends a key-value pair
- while (end < len && b[end] != ',') {
- end++;
+ if (hasErr || (end == len)) {
+ // remove the key we already inserted
+ kDebug(7113) << "error in quoted text for key" << values.last();
+ values.removeLast();
+ break;
+ }
+
+ QByteArray value = QByteArray(b + start, end - start);
+ if (hasBs) {
+ // skip over the next character, it might be an escaped backslash
+ int i = -1;
+ while ( (i = value.indexOf('\\', i + 1)) >= 0 ) {
+ value.remove(i, 1);
+ }
}
+
+ values.append(value);
+ end++;
} else {
end = start;
//unquoted string
- while (end < len && b[end] != ',') {
+ while (end < len && b[end] != ',' && !isWhiteSpace(b[end])) {
end++;
}
- pos = end; // save the end position
- while (end - 1 > start && isWhiteSpace(b[end - 1])) { // trim whitespace
- end--;
- }
values.append(QByteArray(b + start, end - start));
- end = pos; // restore the end position
}
- // end may point beyond the buffer already here
- end++; // skip comma
+
+ //the quoted string has ended, but only a comma ends a key-value pair
+ while (end < len && isWhiteSpace(b[end]))
+ end++;
+
+ // garbage
+ if (end < len && b[end] != ',') {
+ kDebug(7113) << "unexpected character" << b[end] << "found in WWW-authentication header where token boundary (,) was expected";
+ break;
+ }
}
// ensure every key has a value
// WARNING: Do not remove the > 1 check or parsing a Type 1 NTLM
diff --git a/kioslave/http/tests/httpauthenticationtest.cpp b/kioslave/http/tests/httpauthenticationtest.cpp
index 627f1cc..4b90004 100644
--- a/kioslave/http/tests/httpauthenticationtest.cpp
+++ b/kioslave/http/tests/httpauthenticationtest.cpp
@@ -89,11 +89,30 @@ void HTTPAuthenticationTest::testHeaderParsing()
// Tests cases from http://greenbytes.de/tech/tc/httpauth/
testAuthHeaderFormats("Basic realm=\"foo\"", "Basic", toByteArrayList("realm,foo"));
testAuthHeaderFormats("Basic realm=foo", "Basic", toByteArrayList("realm,foo"));
+ // missing comma between fields
+ testAuthHeaderFormats("Basic realm=foo bar=baz", "Basic", toByteArrayList("realm,foo"));
+ // missing comma between fields
+ testAuthHeaderFormats("Basic realm=\"foo\" bar=baz", "Basic", toByteArrayList("realm,foo"));
+ // empty fields
+ testAuthHeaderFormats("Basic realm=foo , , , ,, bar=\"baz\"\t,", "Basic", toByteArrayList("realm,foo,bar,baz"));
testAuthHeaderFormats("Basic", "Basic", QList<QByteArray>());
testAuthHeaderFormats("Basic realm = \"foo\"", "Basic", toByteArrayList("realm,foo"));
- // FIXME: Deal with quoted and escaped values...
- //testAuthHeaderFormats("Basic realm=\"\\f\\o\\o\"", "Basic", toByteArrayList("realm,foo"));
- testAuthHeaderFormats("Basic realm=\"\\\"foo\\\"\"", "Basic", toByteArrayList("realm,foo"));
+ // only opening quote
+ testAuthHeaderFormats("Basic realm=\"", "Basic", QList<QByteArray>());
+ // every character needlessly quoted
+ testAuthHeaderFormats("Basic realm=\"\\f\\o\\o\"", "Basic", toByteArrayList("realm,foo"));
+ // quotes around text
+ testAuthHeaderFormats("Basic realm=\"\\\"foo\\\"\"", "Basic", toByteArrayList("realm,\"foo\""));
+ // quotes around text, every character needlessly quoted
+ testAuthHeaderFormats("Basic realm=\"\\\"\\f\\o\\o\\\"\"", "Basic", toByteArrayList("realm,\"foo\""));
+ // quotes around text, quoted backslashes
+ testAuthHeaderFormats("Basic realm=\"\\\"foo\\\\\\\\\"", "Basic", toByteArrayList("realm,\"foo\\\\"));
+ // quotes around text, quoted backslashes, quote hidden behind them
+ testAuthHeaderFormats("Basic realm=\"\\\"foo\\\\\\\"\"", "Basic", toByteArrayList("realm,\"foo\\\""));
+ // invalid quoted text
+ testAuthHeaderFormats("Basic realm=\"\\\"foo\\\\\\\"", "Basic", QList<QByteArray>());
+ // ends in backslash without quoted value
+ testAuthHeaderFormats("Basic realm=\"\\\"foo\\\\\\", "Basic", QList<QByteArray>());
testAuthHeaderFormats("Basic realm=\"foo\", bar=\"xyz\"", "Basic", toByteArrayList("realm,foo,bar,xyz"));
testAuthHeaderFormats("Basic bar=\"xyz\", realm=\"foo\"", "Basic", toByteArrayList("bar,xyz,realm,foo"));
testAuthHeaderFormats("bAsic bar\t =\t\"baz\", realm =\t\"foo\"", "bAsic", toByteArrayList("bar,baz,realm,foo"));