fixed GH #478: HTTPCredentials and HTTPAuthenticationParams support multiple WWW-Authenticate headers

This commit is contained in:
Guenter Obiltschnig
2014-11-19 21:25:36 +01:00
parent b8503e82e0
commit 88b203f483
8 changed files with 72 additions and 22 deletions

View File

@@ -46,7 +46,7 @@ public:
explicit HTTPAuthenticationParams(const HTTPRequest& request); explicit HTTPAuthenticationParams(const HTTPRequest& request);
/// See fromRequest() documentation. /// See fromRequest() documentation.
explicit HTTPAuthenticationParams(const HTTPResponse& response); HTTPAuthenticationParams(const HTTPResponse& response, const std::string& header = WWW_AUTHENTICATE);
/// See fromResponse() documentation. /// See fromResponse() documentation.
virtual ~HTTPAuthenticationParams(); virtual ~HTTPAuthenticationParams();
@@ -68,7 +68,7 @@ public:
/// Throws a InvalidArgumentException if authentication scheme is /// Throws a InvalidArgumentException if authentication scheme is
/// unknown or invalid. /// 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 /// Extracts authentication information from the response and creates
/// HTTPAuthenticationParams by parsing it. /// HTTPAuthenticationParams by parsing it.
/// ///
@@ -91,6 +91,8 @@ public:
/// request or response authentication header. /// request or response authentication header.
static const std::string REALM; static const std::string REALM;
static const std::string WWW_AUTHENTICATE;
static const std::string PROXY_AUTHENTICATE;
private: private:
void parse(std::string::const_iterator first, std::string::const_iterator last); void parse(std::string::const_iterator first, std::string::const_iterator last);

View File

@@ -52,6 +52,9 @@ public:
~HTTPDigestCredentials(); ~HTTPDigestCredentials();
/// Destroys the HTTPDigestCredentials. /// Destroys the HTTPDigestCredentials.
void reset();
/// Resets the HTTPDigestCredentials object to a clean state.
void setUsername(const std::string& username); void setUsername(const std::string& username);
/// Sets the username. /// Sets the username.

View File

@@ -68,6 +68,8 @@ namespace Net {
const std::string HTTPAuthenticationParams::REALM("realm"); const std::string HTTPAuthenticationParams::REALM("realm");
const std::string HTTPAuthenticationParams::WWW_AUTHENTICATE("WWW-Authenticate");
const std::string HTTPAuthenticationParams::PROXY_AUTHENTICATE("Proxy-Authenticate");
HTTPAuthenticationParams::HTTPAuthenticationParams() 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"); throw NotAuthenticatedException("HTTP response has no authentication header");
const std::string& header = response.get("WWW-Authenticate"); bool found = false;
while (!found && it != response.end() && icompare(it->first, header) == 0)
if (icompare(header, 0, 6, "Basic ") == 0)
{ {
parse(header.begin() + 6, header.end()); 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;
} }
else if (icompare(header, 0, 7, "Digest ") == 0) if (!found) throw NotAuthenticatedException("No Basic or Digest authentication header found");
{
parse(header.begin() + 7, header.end());
}
else throw InvalidArgumentException("Invalid authentication scheme", header);
} }

View File

@@ -57,7 +57,7 @@ void HTTPCredentials::fromUserInfo(const std::string& userInfo)
extractCredentials(userInfo, username, password); extractCredentials(userInfo, username, password);
setUsername(username); setUsername(username);
setPassword(password); setPassword(password);
// TODO: Reset digest state? _digest.reset();
} }
@@ -69,13 +69,13 @@ void HTTPCredentials::fromURI(const URI& uri)
extractCredentials(uri, username, password); extractCredentials(uri, username, password);
setUsername(username); setUsername(username);
setPassword(password); setPassword(password);
// TODO: Reset digest state? _digest.reset();
} }
void HTTPCredentials::authenticate(HTTPRequest& request, const HTTPResponse& response) 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)) if (isBasicCredentials(iter->second))
{ {
@@ -111,7 +111,7 @@ void HTTPCredentials::updateAuthInfo(HTTPRequest& request)
void HTTPCredentials::proxyAuthenticate(HTTPRequest& request, const HTTPResponse& response) 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)) if (isBasicCredentials(iter->second))
{ {

View File

@@ -104,6 +104,13 @@ HTTPDigestCredentials::~HTTPDigestCredentials()
} }
void HTTPDigestCredentials::reset()
{
_requestAuthParams.clear();
_nc.clear();
}
void HTTPDigestCredentials::setUsername(const std::string& username) void HTTPDigestCredentials::setUsername(const std::string& username)
{ {
_username = username; _username = username;
@@ -138,7 +145,7 @@ void HTTPDigestCredentials::updateAuthInfo(HTTPRequest& request)
void HTTPDigestCredentials::proxyAuthenticate(HTTPRequest& request, const HTTPResponse& response) void HTTPDigestCredentials::proxyAuthenticate(HTTPRequest& request, const HTTPResponse& response)
{ {
proxyAuthenticate(request, HTTPAuthenticationParams(response)); proxyAuthenticate(request, HTTPAuthenticationParams(response, HTTPAuthenticationParams::PROXY_AUTHENTICATE));
} }

View File

@@ -259,5 +259,4 @@ void HTTPRequest::setCredentials(const std::string& header, const std::string& s
} }
} } // namespace Poco::Net } } // namespace Poco::Net

View File

@@ -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() void HTTPCredentialsTest::testDigestCredentials()
{ {
HTTPDigestCredentials creds("user", "s3cr3t"); 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() void HTTPCredentialsTest::testProxyCredentialsDigest()
{ {
HTTPCredentials creds("user", "s3cr3t"); HTTPCredentials creds("user", "s3cr3t");
@@ -299,11 +325,13 @@ CppUnit::Test* HTTPCredentialsTest::suite()
CppUnit_addTest(pSuite, HTTPCredentialsTest, testProxyBasicCredentials); CppUnit_addTest(pSuite, HTTPCredentialsTest, testProxyBasicCredentials);
CppUnit_addTest(pSuite, HTTPCredentialsTest, testBadCredentials); CppUnit_addTest(pSuite, HTTPCredentialsTest, testBadCredentials);
CppUnit_addTest(pSuite, HTTPCredentialsTest, testAuthenticationParams); CppUnit_addTest(pSuite, HTTPCredentialsTest, testAuthenticationParams);
CppUnit_addTest(pSuite, HTTPCredentialsTest, testAuthenticationParamsMultipleHeaders);
CppUnit_addTest(pSuite, HTTPCredentialsTest, testDigestCredentials); CppUnit_addTest(pSuite, HTTPCredentialsTest, testDigestCredentials);
CppUnit_addTest(pSuite, HTTPCredentialsTest, testDigestCredentialsQoP); CppUnit_addTest(pSuite, HTTPCredentialsTest, testDigestCredentialsQoP);
CppUnit_addTest(pSuite, HTTPCredentialsTest, testCredentialsBasic); CppUnit_addTest(pSuite, HTTPCredentialsTest, testCredentialsBasic);
CppUnit_addTest(pSuite, HTTPCredentialsTest, testProxyCredentialsBasic); CppUnit_addTest(pSuite, HTTPCredentialsTest, testProxyCredentialsBasic);
CppUnit_addTest(pSuite, HTTPCredentialsTest, testCredentialsDigest); CppUnit_addTest(pSuite, HTTPCredentialsTest, testCredentialsDigest);
CppUnit_addTest(pSuite, HTTPCredentialsTest, testCredentialsDigestMultipleHeaders);
CppUnit_addTest(pSuite, HTTPCredentialsTest, testProxyCredentialsDigest); CppUnit_addTest(pSuite, HTTPCredentialsTest, testProxyCredentialsDigest);
CppUnit_addTest(pSuite, HTTPCredentialsTest, testExtractCredentials); CppUnit_addTest(pSuite, HTTPCredentialsTest, testExtractCredentials);
CppUnit_addTest(pSuite, HTTPCredentialsTest, testVerifyAuthInfo); CppUnit_addTest(pSuite, HTTPCredentialsTest, testVerifyAuthInfo);

View File

@@ -30,11 +30,13 @@ public:
void testProxyBasicCredentials(); void testProxyBasicCredentials();
void testBadCredentials(); void testBadCredentials();
void testAuthenticationParams(); void testAuthenticationParams();
void testAuthenticationParamsMultipleHeaders();
void testDigestCredentials(); void testDigestCredentials();
void testDigestCredentialsQoP(); void testDigestCredentialsQoP();
void testCredentialsBasic(); void testCredentialsBasic();
void testProxyCredentialsBasic(); void testProxyCredentialsBasic();
void testCredentialsDigest(); void testCredentialsDigest();
void testCredentialsDigestMultipleHeaders();
void testProxyCredentialsDigest(); void testProxyCredentialsDigest();
void testExtractCredentials(); void testExtractCredentials();
void testVerifyAuthInfo(); void testVerifyAuthInfo();