diff --git a/Net/include/Poco/Net/HTTPAuthenticationParams.h b/Net/include/Poco/Net/HTTPAuthenticationParams.h index f5afa5a1c..11f6af1ef 100644 --- a/Net/include/Poco/Net/HTTPAuthenticationParams.h +++ b/Net/include/Poco/Net/HTTPAuthenticationParams.h @@ -46,7 +46,7 @@ public: explicit HTTPAuthenticationParams(const HTTPRequest& request); /// See fromRequest() documentation. - explicit HTTPAuthenticationParams(const HTTPResponse& response); + HTTPAuthenticationParams(const HTTPResponse& response, const std::string& header = WWW_AUTHENTICATE); /// See fromResponse() documentation. virtual ~HTTPAuthenticationParams(); @@ -68,7 +68,7 @@ public: /// Throws a InvalidArgumentException if authentication scheme is /// unknown or invalid. - void fromResponse(const HTTPResponse& response); + void fromResponse(const HTTPResponse& response, const std::string& header = WWW_AUTHENTICATE); /// Extracts authentication information from the response and creates /// HTTPAuthenticationParams by parsing it. /// @@ -91,6 +91,8 @@ public: /// request or response authentication header. static const std::string REALM; + static const std::string WWW_AUTHENTICATE; + static const std::string PROXY_AUTHENTICATE; private: void parse(std::string::const_iterator first, std::string::const_iterator last); diff --git a/Net/include/Poco/Net/HTTPDigestCredentials.h b/Net/include/Poco/Net/HTTPDigestCredentials.h index cde91ec72..709077d3f 100644 --- a/Net/include/Poco/Net/HTTPDigestCredentials.h +++ b/Net/include/Poco/Net/HTTPDigestCredentials.h @@ -52,6 +52,9 @@ public: ~HTTPDigestCredentials(); /// Destroys the HTTPDigestCredentials. + void reset(); + /// Resets the HTTPDigestCredentials object to a clean state. + void setUsername(const std::string& username); /// Sets the username. diff --git a/Net/src/HTTPAuthenticationParams.cpp b/Net/src/HTTPAuthenticationParams.cpp index b7a89834a..29ed198a0 100644 --- a/Net/src/HTTPAuthenticationParams.cpp +++ b/Net/src/HTTPAuthenticationParams.cpp @@ -68,6 +68,8 @@ namespace Net { const std::string HTTPAuthenticationParams::REALM("realm"); +const std::string HTTPAuthenticationParams::WWW_AUTHENTICATE("WWW-Authenticate"); +const std::string HTTPAuthenticationParams::PROXY_AUTHENTICATE("Proxy-Authenticate"); HTTPAuthenticationParams::HTTPAuthenticationParams() @@ -87,9 +89,9 @@ HTTPAuthenticationParams::HTTPAuthenticationParams(const HTTPRequest& request) } -HTTPAuthenticationParams::HTTPAuthenticationParams(const HTTPResponse& response) +HTTPAuthenticationParams::HTTPAuthenticationParams(const HTTPResponse& response, const std::string& header) { - fromResponse(response); + fromResponse(response, header); } @@ -126,22 +128,29 @@ void HTTPAuthenticationParams::fromRequest(const HTTPRequest& request) } -void HTTPAuthenticationParams::fromResponse(const HTTPResponse& response) +void HTTPAuthenticationParams::fromResponse(const HTTPResponse& response, const std::string& header) { - if (!response.has("WWW-Authenticate")) + NameValueCollection::ConstIterator it = response.find(header); + if (it == response.end()) throw NotAuthenticatedException("HTTP response has no authentication header"); - const std::string& header = response.get("WWW-Authenticate"); - - if (icompare(header, 0, 6, "Basic ") == 0) + bool found = false; + while (!found && it != response.end() && icompare(it->first, header) == 0) { - parse(header.begin() + 6, header.end()); - } - else if (icompare(header, 0, 7, "Digest ") == 0) - { - parse(header.begin() + 7, header.end()); - } - else throw InvalidArgumentException("Invalid authentication scheme", header); + const std::string& header = it->second; + if (icompare(header, 0, 6, "Basic ") == 0) + { + parse(header.begin() + 6, header.end()); + found = true; + } + else if (icompare(header, 0, 7, "Digest ") == 0) + { + parse(header.begin() + 7, header.end()); + found = true; + } + ++it; + } + if (!found) throw NotAuthenticatedException("No Basic or Digest authentication header found"); } diff --git a/Net/src/HTTPCredentials.cpp b/Net/src/HTTPCredentials.cpp index 4b576ffc6..78643912d 100644 --- a/Net/src/HTTPCredentials.cpp +++ b/Net/src/HTTPCredentials.cpp @@ -57,7 +57,7 @@ void HTTPCredentials::fromUserInfo(const std::string& userInfo) extractCredentials(userInfo, username, password); setUsername(username); setPassword(password); - // TODO: Reset digest state? + _digest.reset(); } @@ -69,13 +69,13 @@ void HTTPCredentials::fromURI(const URI& uri) extractCredentials(uri, username, password); setUsername(username); setPassword(password); - // TODO: Reset digest state? + _digest.reset(); } void HTTPCredentials::authenticate(HTTPRequest& request, const HTTPResponse& response) { - for (HTTPResponse::ConstIterator iter = response.find("WWW-Authenticate"); iter != response.end(); ++iter) + for (HTTPResponse::ConstIterator iter = response.find(HTTPAuthenticationParams::WWW_AUTHENTICATE); iter != response.end(); ++iter) { if (isBasicCredentials(iter->second)) { @@ -111,7 +111,7 @@ void HTTPCredentials::updateAuthInfo(HTTPRequest& request) void HTTPCredentials::proxyAuthenticate(HTTPRequest& request, const HTTPResponse& response) { - for (HTTPResponse::ConstIterator iter = response.find("Proxy-Authenticate"); iter != response.end(); ++iter) + for (HTTPResponse::ConstIterator iter = response.find(HTTPAuthenticationParams::PROXY_AUTHENTICATE); iter != response.end(); ++iter) { if (isBasicCredentials(iter->second)) { diff --git a/Net/src/HTTPDigestCredentials.cpp b/Net/src/HTTPDigestCredentials.cpp index 94971db57..1ca2a7a38 100644 --- a/Net/src/HTTPDigestCredentials.cpp +++ b/Net/src/HTTPDigestCredentials.cpp @@ -104,6 +104,13 @@ HTTPDigestCredentials::~HTTPDigestCredentials() } +void HTTPDigestCredentials::reset() +{ + _requestAuthParams.clear(); + _nc.clear(); +} + + void HTTPDigestCredentials::setUsername(const std::string& username) { _username = username; @@ -138,7 +145,7 @@ void HTTPDigestCredentials::updateAuthInfo(HTTPRequest& request) void HTTPDigestCredentials::proxyAuthenticate(HTTPRequest& request, const HTTPResponse& response) { - proxyAuthenticate(request, HTTPAuthenticationParams(response)); + proxyAuthenticate(request, HTTPAuthenticationParams(response, HTTPAuthenticationParams::PROXY_AUTHENTICATE)); } diff --git a/Net/src/HTTPRequest.cpp b/Net/src/HTTPRequest.cpp index ac568f94c..653b47e9e 100644 --- a/Net/src/HTTPRequest.cpp +++ b/Net/src/HTTPRequest.cpp @@ -259,5 +259,4 @@ void HTTPRequest::setCredentials(const std::string& header, const std::string& s } - } } // namespace Poco::Net diff --git a/Net/testsuite/src/HTTPCredentialsTest.cpp b/Net/testsuite/src/HTTPCredentialsTest.cpp index 5186b9467..d91351e3c 100644 --- a/Net/testsuite/src/HTTPCredentialsTest.cpp +++ b/Net/testsuite/src/HTTPCredentialsTest.cpp @@ -145,6 +145,19 @@ void HTTPCredentialsTest::testAuthenticationParams() } +void HTTPCredentialsTest::testAuthenticationParamsMultipleHeaders() +{ + HTTPResponse response; + response.add("WWW-Authenticate", "Unsupported realm=\"TestUnsupported\""); + response.add("WWW-Authenticate", "Digest realm=\"TestDigest\", nonce=\"212573bb90170538efad012978ab811f%lu\""); + HTTPAuthenticationParams params(response); + + assert (params["realm"] == "TestDigest"); + assert (params["nonce"] == "212573bb90170538efad012978ab811f%lu"); + assert (params.size() == 2); +} + + void HTTPCredentialsTest::testDigestCredentials() { HTTPDigestCredentials creds("user", "s3cr3t"); @@ -231,6 +244,19 @@ void HTTPCredentialsTest::testCredentialsDigest() } +void HTTPCredentialsTest::testCredentialsDigestMultipleHeaders() +{ + HTTPCredentials creds("user", "s3cr3t"); + HTTPRequest request(HTTPRequest::HTTP_GET, "/digest/"); + HTTPResponse response; + response.add("WWW-Authenticate", "Unsupported realm=\"TestUnsupported\""); + response.add("WWW-Authenticate", "Digest realm=\"TestDigest\", nonce=\"212573bb90170538efad012978ab811f%lu\""); + creds.authenticate(request, response); + std::string auth = request.get("Authorization"); + assert (auth == "Digest username=\"user\", nonce=\"212573bb90170538efad012978ab811f%lu\", realm=\"TestDigest\", uri=\"/digest/\", response=\"40e4889cfbd0e561f71e3107a2863bc4\""); +} + + void HTTPCredentialsTest::testProxyCredentialsDigest() { HTTPCredentials creds("user", "s3cr3t"); @@ -299,11 +325,13 @@ CppUnit::Test* HTTPCredentialsTest::suite() CppUnit_addTest(pSuite, HTTPCredentialsTest, testProxyBasicCredentials); CppUnit_addTest(pSuite, HTTPCredentialsTest, testBadCredentials); CppUnit_addTest(pSuite, HTTPCredentialsTest, testAuthenticationParams); + CppUnit_addTest(pSuite, HTTPCredentialsTest, testAuthenticationParamsMultipleHeaders); CppUnit_addTest(pSuite, HTTPCredentialsTest, testDigestCredentials); CppUnit_addTest(pSuite, HTTPCredentialsTest, testDigestCredentialsQoP); CppUnit_addTest(pSuite, HTTPCredentialsTest, testCredentialsBasic); CppUnit_addTest(pSuite, HTTPCredentialsTest, testProxyCredentialsBasic); CppUnit_addTest(pSuite, HTTPCredentialsTest, testCredentialsDigest); + CppUnit_addTest(pSuite, HTTPCredentialsTest, testCredentialsDigestMultipleHeaders); CppUnit_addTest(pSuite, HTTPCredentialsTest, testProxyCredentialsDigest); CppUnit_addTest(pSuite, HTTPCredentialsTest, testExtractCredentials); CppUnit_addTest(pSuite, HTTPCredentialsTest, testVerifyAuthInfo); diff --git a/Net/testsuite/src/HTTPCredentialsTest.h b/Net/testsuite/src/HTTPCredentialsTest.h index 94f85099f..4f0d3ac8a 100644 --- a/Net/testsuite/src/HTTPCredentialsTest.h +++ b/Net/testsuite/src/HTTPCredentialsTest.h @@ -30,11 +30,13 @@ public: void testProxyBasicCredentials(); void testBadCredentials(); void testAuthenticationParams(); + void testAuthenticationParamsMultipleHeaders(); void testDigestCredentials(); void testDigestCredentialsQoP(); void testCredentialsBasic(); void testProxyCredentialsBasic(); void testCredentialsDigest(); + void testCredentialsDigestMultipleHeaders(); void testProxyCredentialsDigest(); void testExtractCredentials(); void testVerifyAuthInfo();