mirror of
https://github.com/pocoproject/poco.git
synced 2025-01-31 14:39:53 +01:00
HTTPDigestCredentials added support for RFC7616 algorithms (#3026)
This commit is contained in:
parent
1f587cfd3b
commit
fe59436763
@ -38,10 +38,12 @@ class Foundation_API SHA2Engine: public DigestEngine
|
||||
public:
|
||||
enum ALGORITHM
|
||||
{
|
||||
SHA_224 = 224,
|
||||
SHA_256 = 256,
|
||||
SHA_384 = 384,
|
||||
SHA_512 = 512
|
||||
SHA_224 = 1,
|
||||
SHA_256,
|
||||
SHA_384,
|
||||
SHA_512,
|
||||
SHA_512_224,
|
||||
SHA_512_256
|
||||
};
|
||||
|
||||
SHA2Engine(ALGORITHM algorithm = SHA_256);
|
||||
|
@ -41,7 +41,6 @@ typedef struct
|
||||
Poco::UInt64 state64[8];
|
||||
} state;
|
||||
|
||||
SHA2Engine::ALGORITHM size;
|
||||
unsigned char buffer[128];
|
||||
} HASHCONTEXT;
|
||||
|
||||
@ -274,7 +273,7 @@ void SHA2Engine::updateImpl(const void* buffer_, std::size_t count)
|
||||
Poco::UInt32 left = 0;
|
||||
HASHCONTEXT* pContext = (HASHCONTEXT*)_context;
|
||||
unsigned char* data = (unsigned char*)buffer_;
|
||||
if (pContext->size > SHA_256)
|
||||
if (_algorithm > SHA_256)
|
||||
{
|
||||
left = (Poco::UInt32)(pContext->total.total64[0] & 0x7F);
|
||||
size_t fill = 128 - left;
|
||||
@ -323,7 +322,31 @@ void SHA2Engine::updateImpl(const void* buffer_, std::size_t count)
|
||||
|
||||
std::size_t SHA2Engine::digestLength() const
|
||||
{
|
||||
return (size_t)((int)_algorithm / 8);
|
||||
size_t result = 0;
|
||||
|
||||
switch (_algorithm)
|
||||
{
|
||||
case SHA_224:
|
||||
result = 224;
|
||||
break;
|
||||
case SHA_256:
|
||||
result = 256;
|
||||
break;
|
||||
case SHA_384:
|
||||
result = 384;
|
||||
break;
|
||||
case SHA_512:
|
||||
result = 512;
|
||||
break;
|
||||
case SHA_512_224:
|
||||
result = 224;
|
||||
break;
|
||||
case SHA_512_256:
|
||||
result = 256;
|
||||
break;
|
||||
}
|
||||
|
||||
return result / 8;
|
||||
}
|
||||
|
||||
|
||||
@ -332,7 +355,6 @@ void SHA2Engine::reset()
|
||||
if (_context != NULL) free(_context);
|
||||
_context = calloc(1, sizeof(HASHCONTEXT));
|
||||
HASHCONTEXT* pContext = (HASHCONTEXT*)_context;
|
||||
pContext->size = _algorithm;
|
||||
if (_algorithm == SHA_224)
|
||||
{
|
||||
pContext->state.state32[0] = 0xC1059ED8;
|
||||
@ -366,7 +388,7 @@ void SHA2Engine::reset()
|
||||
pContext->state.state64[6] = UL64(0xDB0C2E0D64F98FA7);
|
||||
pContext->state.state64[7] = UL64(0x47B5481DBEFA4FA4);
|
||||
}
|
||||
else
|
||||
else if (_algorithm == SHA_512)
|
||||
{
|
||||
pContext->state.state64[0] = UL64(0x6A09E667F3BCC908);
|
||||
pContext->state.state64[1] = UL64(0xBB67AE8584CAA73B);
|
||||
@ -377,6 +399,27 @@ void SHA2Engine::reset()
|
||||
pContext->state.state64[6] = UL64(0x1F83D9ABFB41BD6B);
|
||||
pContext->state.state64[7] = UL64(0x5BE0CD19137E2179);
|
||||
}
|
||||
else if (_algorithm == SHA_512_224)
|
||||
{
|
||||
pContext->state.state64[0] = UL64(0x8C3D37C819544DA2);
|
||||
pContext->state.state64[1] = UL64(0x73E1996689DCD4D6);
|
||||
pContext->state.state64[2] = UL64(0x1DFAB7AE32FF9C82);
|
||||
pContext->state.state64[3] = UL64(0x679DD514582F9FCF);
|
||||
pContext->state.state64[4] = UL64(0x0F6D2B697BD44DA8);
|
||||
pContext->state.state64[5] = UL64(0x77E36F7304C48942);
|
||||
pContext->state.state64[6] = UL64(0x3F9D85A86A1D36C8);
|
||||
pContext->state.state64[7] = UL64(0x1112E6AD91D692A1);
|
||||
} else
|
||||
{
|
||||
pContext->state.state64[0] = UL64(0x22312194FC2BF72C);
|
||||
pContext->state.state64[1] = UL64(0x9F555FA3C84C64C2);
|
||||
pContext->state.state64[2] = UL64(0x2393B86B6F53B151);
|
||||
pContext->state.state64[3] = UL64(0x963877195940EABD);
|
||||
pContext->state.state64[4] = UL64(0x96283EE2A88EFFE3);
|
||||
pContext->state.state64[5] = UL64(0xBE5E1E2553863992);
|
||||
pContext->state.state64[6] = UL64(0x2B0199FC2C85B8AA);
|
||||
pContext->state.state64[7] = UL64(0x0EB72DDC81C52CA2);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -388,7 +431,8 @@ const DigestEngine::Digest& SHA2Engine::digest()
|
||||
size_t last, padn;
|
||||
unsigned char hash[64];
|
||||
memset(hash, 0, 64);
|
||||
if (pContext->size > SHA_256)
|
||||
|
||||
if (_algorithm > SHA_256)
|
||||
{
|
||||
unsigned char msglen[16];
|
||||
Poco::UInt64 high = (pContext->total.total64[0] >> 61) | (pContext->total.total64[1] << 3);
|
||||
@ -405,7 +449,7 @@ const DigestEngine::Digest& SHA2Engine::digest()
|
||||
PUT_UINT64(pContext->state.state64[3], hash, 24);
|
||||
PUT_UINT64(pContext->state.state64[4], hash, 32);
|
||||
PUT_UINT64(pContext->state.state64[5], hash, 40);
|
||||
if (pContext->size > SHA_384)
|
||||
if (_algorithm > SHA_384)
|
||||
{
|
||||
PUT_UINT64(pContext->state.state64[6], hash, 48);
|
||||
PUT_UINT64(pContext->state.state64[7], hash, 56);
|
||||
@ -429,7 +473,7 @@ const DigestEngine::Digest& SHA2Engine::digest()
|
||||
PUT_UINT32(pContext->state.state32[4], hash, 16);
|
||||
PUT_UINT32(pContext->state.state32[5], hash, 20);
|
||||
PUT_UINT32(pContext->state.state32[6], hash, 24);
|
||||
if (pContext->size > SHA_224) PUT_UINT32(pContext->state.state32[7], hash, 28);
|
||||
if (_algorithm > SHA_224) PUT_UINT32(pContext->state.state32[7], hash, 28);
|
||||
}
|
||||
_digest.insert(_digest.begin(), hash, hash + digestLength());
|
||||
reset();
|
||||
|
@ -36,6 +36,9 @@ void SHA2EngineTest::testSHA224()
|
||||
{
|
||||
SHA2Engine engine(SHA2Engine::SHA_224);
|
||||
|
||||
engine.update("");
|
||||
assertTrue (DigestEngine::digestToHex(engine.digest()) == "d14a028c2a3a2bc9476102bb288234c415a2b01f828ea62ac5b3e42f");
|
||||
|
||||
engine.update("abc");
|
||||
assertTrue (DigestEngine::digestToHex(engine.digest()) == "23097d223405d8228642a477bda255b32aadbce4bda0b3f7e36c9da7");
|
||||
|
||||
@ -55,6 +58,9 @@ void SHA2EngineTest::testSHA256()
|
||||
{
|
||||
SHA2Engine engine(SHA2Engine::SHA_256);
|
||||
|
||||
engine.update("");
|
||||
assertTrue (DigestEngine::digestToHex(engine.digest()) == "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855");
|
||||
|
||||
engine.update("abc");
|
||||
assertTrue (DigestEngine::digestToHex(engine.digest()) == "ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad");
|
||||
|
||||
@ -74,6 +80,9 @@ void SHA2EngineTest::testSHA384()
|
||||
{
|
||||
SHA2Engine engine(SHA2Engine::SHA_384);
|
||||
|
||||
engine.update("");
|
||||
assertTrue (DigestEngine::digestToHex(engine.digest()) == "38b060a751ac96384cd9327eb1b1e36a21fdb71114be07434c0cc7bf63f6e1da274edebfe76f65fbd51ad2f14898b95b");
|
||||
|
||||
engine.update("abc");
|
||||
assertTrue (DigestEngine::digestToHex(engine.digest()) == "cb00753f45a35e8bb5a03d699ac65007272c32ab0eded1631a8b605a43ff5bed8086072ba1e7cc2358baeca134c825a7");
|
||||
|
||||
@ -93,6 +102,9 @@ void SHA2EngineTest::testSHA512()
|
||||
{
|
||||
SHA2Engine engine(SHA2Engine::SHA_512);
|
||||
|
||||
engine.update("");
|
||||
assertTrue (DigestEngine::digestToHex(engine.digest()) == "cf83e1357eefb8bdf1542850d66d8007d620e4050b5715dc83f4a921d36ce9ce47d0d13c5d85f2b0ff8318d2877eec2f63b931bd47417a81a538327af927da3e");
|
||||
|
||||
engine.update("abc");
|
||||
assertTrue (DigestEngine::digestToHex(engine.digest()) == "ddaf35a193617abacc417349ae20413112e6fa4e89a97ea20a9eeee64b55d39a2192992a274fc1a836ba3c23a3feebbd454d4423643ce80e2a9ac94fa54ca49f");
|
||||
|
||||
@ -107,6 +119,47 @@ void SHA2EngineTest::testSHA512()
|
||||
assertTrue (DigestEngine::digestToHex(engine.digest()) == "e718483d0ce769644e2e42c7bc15b4638e1f98b13b2044285632a803afa973ebde0ff244877ea60a4cb0432ce577c31beb009c5c2c49aa2e4eadb217ad8cc09b");
|
||||
}
|
||||
|
||||
void SHA2EngineTest::testSHA512_224()
|
||||
{
|
||||
SHA2Engine engine(SHA2Engine::SHA_512_224);
|
||||
|
||||
engine.update("");
|
||||
assertTrue (DigestEngine::digestToHex(engine.digest()) == "6ed0dd02806fa89e25de060c19d3ac86cabb87d6a0ddd05c333b84f4");
|
||||
|
||||
engine.update("abc");
|
||||
assertTrue (DigestEngine::digestToHex(engine.digest()) == "4634270f707b6a54daae7530460842e20e37ed265ceee9a43e8924aa");
|
||||
|
||||
engine.update("abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq");
|
||||
assertTrue (DigestEngine::digestToHex(engine.digest()) == "e5302d6d54bb242275d1e7622d68df6eb02dedd13f564c13dbda2174");
|
||||
|
||||
engine.update("abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu");
|
||||
assertTrue (DigestEngine::digestToHex(engine.digest()) == "23fec5bb94d60b23308192640b0c453335d664734fe40e7268674af9");
|
||||
|
||||
for (int i = 0; i < 1000000; ++i)
|
||||
engine.update('a');
|
||||
assertTrue (DigestEngine::digestToHex(engine.digest()) == "37ab331d76f0d36de422bd0edeb22a28accd487b7a8453ae965dd287");
|
||||
}
|
||||
|
||||
void SHA2EngineTest::testSHA512_256()
|
||||
{
|
||||
SHA2Engine engine(SHA2Engine::SHA_512_256);
|
||||
|
||||
engine.update("");
|
||||
assertTrue (DigestEngine::digestToHex(engine.digest()) == "c672b8d1ef56ed28ab87c3622c5114069bdd3ad7b8f9737498d0c01ecef0967a");
|
||||
|
||||
engine.update("abc");
|
||||
assertTrue (DigestEngine::digestToHex(engine.digest()) == "53048e2681941ef99b2e29b76b4c7dabe4c2d0c634fc6d46e0e2f13107e7af23");
|
||||
|
||||
engine.update("abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq");
|
||||
assertTrue (DigestEngine::digestToHex(engine.digest()) == "bde8e1f9f19bb9fd3406c90ec6bc47bd36d8ada9f11880dbc8a22a7078b6a461");
|
||||
|
||||
engine.update("abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu");
|
||||
assertTrue (DigestEngine::digestToHex(engine.digest()) == "3928e184fb8690f840da3988121d31be65cb9d3ef83ee6146feac861e19b563a");
|
||||
|
||||
for (int i = 0; i < 1000000; ++i)
|
||||
engine.update('a');
|
||||
assertTrue (DigestEngine::digestToHex(engine.digest()) == "9a59a052930187a97038cae692f30708aa6491923ef5194394dc68d56c74fb21");
|
||||
}
|
||||
|
||||
void SHA2EngineTest::setUp()
|
||||
{
|
||||
@ -126,6 +179,7 @@ CppUnit::Test* SHA2EngineTest::suite()
|
||||
CppUnit_addTest(pSuite, SHA2EngineTest, testSHA256);
|
||||
CppUnit_addTest(pSuite, SHA2EngineTest, testSHA384);
|
||||
CppUnit_addTest(pSuite, SHA2EngineTest, testSHA512);
|
||||
|
||||
CppUnit_addTest(pSuite, SHA2EngineTest, testSHA512_224);
|
||||
CppUnit_addTest(pSuite, SHA2EngineTest, testSHA512_256);
|
||||
return pSuite;
|
||||
}
|
||||
|
@ -28,6 +28,8 @@ public:
|
||||
void testSHA256();
|
||||
void testSHA384();
|
||||
void testSHA512();
|
||||
void testSHA512_224();
|
||||
void testSHA512_256();
|
||||
|
||||
void setUp();
|
||||
void tearDown();
|
||||
|
@ -120,6 +120,9 @@ public:
|
||||
/// and HTTPAuthenticationParams by recomputing the response and comparing
|
||||
/// it with what's in the request.
|
||||
|
||||
bool isAlgorithmSupported(const std::string& algorithm) const;
|
||||
/// Check if digest algorithm is supported
|
||||
|
||||
static std::string createNonce();
|
||||
/// Creates a random nonce string.
|
||||
|
||||
@ -133,7 +136,19 @@ private:
|
||||
void updateAuthParams(const HTTPRequest& request);
|
||||
int updateNonceCounter(const std::string& nonce);
|
||||
|
||||
static const std::string DEFAULT_ALGORITHM;
|
||||
class DigestEngineProvider;
|
||||
|
||||
static const std::string MD_5_ALGORITHM;
|
||||
static const std::string MD_5_SESS_ALGORITHM;
|
||||
static const std::string SHA_ALGORITHM;
|
||||
static const std::string SHA_SESS_ALGORITHM;
|
||||
static const std::string SHA_256_ALGORITHM;
|
||||
static const std::string SHA_256_SESS_ALGORITHM;
|
||||
static const std::string SHA_512_256_ALGORITHM;
|
||||
static const std::string SHA_512_256_SESS_ALGORITHM;
|
||||
static const std::string SHA_512_ALGORITHM;
|
||||
static const std::string SHA_512_SESS_ALGORITHM;
|
||||
static const std::vector<std::string> SUPPORTED_ALGORITHMS;
|
||||
static const std::string DEFAULT_QOP;
|
||||
static const std::string NONCE_PARAM;
|
||||
static const std::string REALM_PARAM;
|
||||
|
@ -18,12 +18,15 @@
|
||||
#include "Poco/DateTimeFormatter.h"
|
||||
#include "Poco/Exception.h"
|
||||
#include "Poco/MD5Engine.h"
|
||||
#include "Poco/SHA1Engine.h"
|
||||
#include "Poco/SHA2Engine.h"
|
||||
#include "Poco/Net/HTTPDigestCredentials.h"
|
||||
#include "Poco/Net/HTTPRequest.h"
|
||||
#include "Poco/Net/HTTPResponse.h"
|
||||
#include "Poco/NumberFormatter.h"
|
||||
#include "Poco/StringTokenizer.h"
|
||||
|
||||
#include <iostream>
|
||||
|
||||
namespace
|
||||
{
|
||||
@ -68,7 +71,28 @@ namespace Net {
|
||||
|
||||
|
||||
const std::string HTTPDigestCredentials::SCHEME = "Digest";
|
||||
const std::string HTTPDigestCredentials::DEFAULT_ALGORITHM("MD5");
|
||||
const std::vector<std::string> HTTPDigestCredentials::SUPPORTED_ALGORITHMS = {
|
||||
"MD5",
|
||||
"MD5-sess",
|
||||
"SHA",
|
||||
"SHA-sess",
|
||||
"SHA-256",
|
||||
"SHA-256-sess",
|
||||
"SHA-512-256",
|
||||
"SHA-512-256-sess",
|
||||
"SHA-512",
|
||||
"SHA-512-sess"
|
||||
};
|
||||
const std::string HTTPDigestCredentials::MD_5_ALGORITHM = "MD5";
|
||||
const std::string HTTPDigestCredentials::MD_5_SESS_ALGORITHM = "MD5-sess";
|
||||
const std::string HTTPDigestCredentials::SHA_ALGORITHM = "SHA";
|
||||
const std::string HTTPDigestCredentials::SHA_SESS_ALGORITHM = "SHA-sess";
|
||||
const std::string HTTPDigestCredentials::SHA_256_ALGORITHM = "SHA-256";
|
||||
const std::string HTTPDigestCredentials::SHA_256_SESS_ALGORITHM = "SHA-256-sess";
|
||||
const std::string HTTPDigestCredentials::SHA_512_256_ALGORITHM = "SHA-512-256";
|
||||
const std::string HTTPDigestCredentials::SHA_512_256_SESS_ALGORITHM = "SHA-512-256-sess";
|
||||
const std::string HTTPDigestCredentials::SHA_512_ALGORITHM = "SHA-512";
|
||||
const std::string HTTPDigestCredentials::SHA_512_SESS_ALGORITHM = "SHA-512-sess";
|
||||
const std::string HTTPDigestCredentials::DEFAULT_QOP("");
|
||||
const std::string HTTPDigestCredentials::NONCE_PARAM("nonce");
|
||||
const std::string HTTPDigestCredentials::REALM_PARAM("realm");
|
||||
@ -84,6 +108,44 @@ const std::string HTTPDigestCredentials::NC_PARAM("nc");
|
||||
int HTTPDigestCredentials::_nonceCounter(0);
|
||||
Poco::FastMutex HTTPDigestCredentials::_nonceMutex;
|
||||
|
||||
class HTTPDigestCredentials::DigestEngineProvider {
|
||||
public:
|
||||
DigestEngineProvider(std::string algorithm): _algorithm(algorithm) {
|
||||
_isSessionAlgorithm = _algorithm.find("sess") != std::string::npos;
|
||||
}
|
||||
|
||||
DigestEngine& engine() {
|
||||
if (icompare(_algorithm, SHA_ALGORITHM) == 0 || icompare(_algorithm, SHA_SESS_ALGORITHM) == 0)
|
||||
{
|
||||
return _sha1Engine;
|
||||
}
|
||||
if (icompare(_algorithm, SHA_256_ALGORITHM) == 0 || icompare(_algorithm, SHA_256_SESS_ALGORITHM) == 0)
|
||||
{
|
||||
return _sha256Engine;
|
||||
} else if (icompare(_algorithm, SHA_512_256_ALGORITHM) == 0 || icompare(_algorithm, SHA_512_256_SESS_ALGORITHM) == 0)
|
||||
{
|
||||
return _sha512_256Engine;
|
||||
} else if (icompare(_algorithm, SHA_512_ALGORITHM) == 0 || icompare(_algorithm, SHA_512_SESS_ALGORITHM) == 0)
|
||||
{
|
||||
return _sha512;
|
||||
}
|
||||
else {
|
||||
return _md5Engine;
|
||||
}
|
||||
}
|
||||
|
||||
bool isSessionAlgorithm() {
|
||||
return _isSessionAlgorithm;
|
||||
}
|
||||
private:
|
||||
std::string _algorithm;
|
||||
SHA1Engine _sha1Engine;
|
||||
MD5Engine _md5Engine;
|
||||
SHA2Engine _sha256Engine { SHA2Engine::ALGORITHM::SHA_256 };
|
||||
SHA2Engine _sha512_256Engine { SHA2Engine::ALGORITHM::SHA_512_256 };
|
||||
SHA2Engine _sha512 { SHA2Engine::ALGORITHM::SHA_512 };
|
||||
bool _isSessionAlgorithm;
|
||||
};
|
||||
|
||||
HTTPDigestCredentials::HTTPDigestCredentials()
|
||||
{
|
||||
@ -191,11 +253,6 @@ void HTTPDigestCredentials::createAuthParams(const HTTPRequest& request, const H
|
||||
if (!responseAuthParams.has(NONCE_PARAM) || !responseAuthParams.has(REALM_PARAM))
|
||||
throw InvalidArgumentException("Invalid HTTP authentication parameters");
|
||||
|
||||
const std::string& algorithm = responseAuthParams.get(ALGORITHM_PARAM, DEFAULT_ALGORITHM);
|
||||
|
||||
if (icompare(algorithm, DEFAULT_ALGORITHM) != 0)
|
||||
throw NotImplementedException("Unsupported digest algorithm", algorithm);
|
||||
|
||||
const std::string& nonce = responseAuthParams.get(NONCE_PARAM);
|
||||
const std::string& qop = responseAuthParams.get(QOP_PARAM, DEFAULT_QOP);
|
||||
const std::string& realm = responseAuthParams.getRealm();
|
||||
@ -208,6 +265,10 @@ void HTTPDigestCredentials::createAuthParams(const HTTPRequest& request, const H
|
||||
{
|
||||
_requestAuthParams.set(OPAQUE_PARAM, responseAuthParams.get(OPAQUE_PARAM));
|
||||
}
|
||||
if (responseAuthParams.has(ALGORITHM_PARAM))
|
||||
{
|
||||
_requestAuthParams.set(ALGORITHM_PARAM, responseAuthParams.get(ALGORITHM_PARAM));
|
||||
}
|
||||
|
||||
if (qop.empty())
|
||||
{
|
||||
@ -233,10 +294,8 @@ void HTTPDigestCredentials::createAuthParams(const HTTPRequest& request, const H
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void HTTPDigestCredentials::updateAuthParams(const HTTPRequest& request)
|
||||
{
|
||||
MD5Engine engine;
|
||||
const std::string qop = _requestAuthParams.get(QOP_PARAM, DEFAULT_QOP);
|
||||
const std::string realm = _requestAuthParams.getRealm();
|
||||
const std::string nonce = _requestAuthParams.get(NONCE_PARAM);
|
||||
@ -245,6 +304,11 @@ void HTTPDigestCredentials::updateAuthParams(const HTTPRequest& request)
|
||||
|
||||
if (qop.empty())
|
||||
{
|
||||
/// Assume that https://tools.ietf.org/html/rfc7616 does not supported
|
||||
/// and still using https://tools.ietf.org/html/rfc2069#section-2.4
|
||||
|
||||
MD5Engine engine;
|
||||
|
||||
const std::string ha1 = digest(engine, _username, realm, _password);
|
||||
const std::string ha2 = digest(engine, request.getMethod(), request.getURI());
|
||||
|
||||
@ -252,13 +316,28 @@ void HTTPDigestCredentials::updateAuthParams(const HTTPRequest& request)
|
||||
}
|
||||
else if (icompare(qop, AUTH_PARAM) == 0)
|
||||
{
|
||||
const std::string cnonce = _requestAuthParams.get(CNONCE_PARAM);
|
||||
const std::string algorithm = _requestAuthParams.get(ALGORITHM_PARAM, MD_5_ALGORITHM);
|
||||
|
||||
const std::string ha1 = digest(engine, _username, realm, _password);
|
||||
const std::string ha2 = digest(engine, request.getMethod(), request.getURI());
|
||||
if (!isAlgorithmSupported(algorithm)) {
|
||||
throw NotImplementedException("Unsupported digest algorithm", algorithm);
|
||||
}
|
||||
|
||||
const std::string cnonce = _requestAuthParams.get(CNONCE_PARAM);
|
||||
const std::string nc = formatNonceCounter(updateNonceCounter(nonce));
|
||||
|
||||
DigestEngineProvider engineProvider(algorithm);
|
||||
DigestEngine &engine = engineProvider.engine();
|
||||
|
||||
std::string ha1 = digest(engine, _username, realm, _password);
|
||||
|
||||
if (engineProvider.isSessionAlgorithm()) {
|
||||
ha1 = digest(engine, ha1, nonce, cnonce);
|
||||
}
|
||||
|
||||
const std::string ha2 = digest(engine, request.getMethod(), request.getURI());
|
||||
|
||||
_requestAuthParams.set(NC_PARAM, nc);
|
||||
_requestAuthParams.set(CNONCE_PARAM, cnonce);
|
||||
_requestAuthParams.set(RESPONSE_PARAM, digest(engine, ha1, nonce, nc, cnonce, qop, ha2));
|
||||
}
|
||||
}
|
||||
@ -277,18 +356,34 @@ bool HTTPDigestCredentials::verifyAuthParams(const HTTPRequest& request, const H
|
||||
const std::string& realm = params.getRealm();
|
||||
const std::string& qop = params.get(QOP_PARAM, DEFAULT_QOP);
|
||||
std::string response;
|
||||
MD5Engine engine;
|
||||
if (qop.empty())
|
||||
{
|
||||
MD5Engine engine;
|
||||
|
||||
const std::string ha1 = digest(engine, _username, realm, _password);
|
||||
const std::string ha2 = digest(engine, request.getMethod(), request.getURI());
|
||||
response = digest(engine, ha1, nonce, ha2);
|
||||
}
|
||||
else if (icompare(qop, AUTH_PARAM) == 0)
|
||||
{
|
||||
const std::string& algorithm = params.get(ALGORITHM_PARAM, MD_5_ALGORITHM);
|
||||
|
||||
if (!isAlgorithmSupported(algorithm)) {
|
||||
throw NotImplementedException("Unsupported digest algorithm", algorithm);
|
||||
}
|
||||
|
||||
DigestEngineProvider engineProvider(algorithm);
|
||||
DigestEngine& engine = engineProvider.engine();
|
||||
|
||||
const std::string& cnonce = params.get(CNONCE_PARAM);
|
||||
const std::string& nc = params.get(NC_PARAM);
|
||||
const std::string ha1 = digest(engine, _username, realm, _password);
|
||||
|
||||
std::string ha1 = digest(engine, _username, realm, _password);
|
||||
|
||||
if (engineProvider.isSessionAlgorithm()) {
|
||||
ha1 = digest(engine, ha1, nonce, cnonce);
|
||||
}
|
||||
|
||||
const std::string ha2 = digest(engine, request.getMethod(), request.getURI());
|
||||
response = digest(engine, ha1, nonce, nc, cnonce, qop, ha2);
|
||||
}
|
||||
@ -309,5 +404,15 @@ int HTTPDigestCredentials::updateNonceCounter(const std::string& nonce)
|
||||
return iter->second;
|
||||
}
|
||||
|
||||
bool HTTPDigestCredentials::isAlgorithmSupported(const std::string& algorithm) const
|
||||
{
|
||||
bool isAlgorithmSupported = std::find_if(std::begin(SUPPORTED_ALGORITHMS),
|
||||
std::end(SUPPORTED_ALGORITHMS),
|
||||
[&algorithm](const std::string& supportedAlgorithm) {
|
||||
return icompare(algorithm, supportedAlgorithm) == 0;
|
||||
}) != std::end(SUPPORTED_ALGORITHMS);
|
||||
|
||||
return isAlgorithmSupported;
|
||||
}
|
||||
|
||||
} } // namespace Poco::Net
|
||||
|
@ -214,6 +214,45 @@ void HTTPCredentialsTest::testDigestCredentialsQoP()
|
||||
assertTrue (params.size() == 9);
|
||||
}
|
||||
|
||||
void HTTPCredentialsTest::testDigestCredentialsQoPSHA256()
|
||||
{
|
||||
HTTPDigestCredentials creds("user", "s3cr3t");
|
||||
HTTPRequest request(HTTPRequest::HTTP_GET, "/digest/");
|
||||
HTTPResponse response;
|
||||
response.set("WWW-Authenticate", "Digest realm=\"TestDigest\", nonce=\"212573bb90170538efad012978ab811f%lu\", opaque=\"opaque\", qop=\"auth,auth-int\", algorithm=SHA-256");
|
||||
creds.authenticate(request, response);
|
||||
|
||||
HTTPAuthenticationParams params(request);
|
||||
assertTrue (params["nonce"] == "212573bb90170538efad012978ab811f%lu");
|
||||
assertTrue (params["realm"] == "TestDigest");
|
||||
assertTrue (params["response"] != "40e4889cfbd0e561f71e3107a2863bc4");
|
||||
assertTrue (params["uri"] == "/digest/");
|
||||
assertTrue (params["username"] == "user");
|
||||
assertTrue (params["opaque"] == "opaque");
|
||||
assertTrue (params["cnonce"] != "");
|
||||
assertTrue (params["nc"] == "00000001");
|
||||
assertTrue (params["qop"] == "auth");
|
||||
assertTrue (params["algorithm"] == "SHA-256");
|
||||
assertTrue (params.size() == 10);
|
||||
|
||||
std::string cnonce = params["cnonce"];
|
||||
std::string aresp = params["response"];
|
||||
|
||||
params.clear();
|
||||
|
||||
creds.updateAuthInfo(request);
|
||||
params.fromRequest(request);
|
||||
assertTrue (params["nonce"] == "212573bb90170538efad012978ab811f%lu");
|
||||
assertTrue (params["realm"] == "TestDigest");
|
||||
assertTrue (params["response"] != aresp);
|
||||
assertTrue (params["uri"] == "/digest/");
|
||||
assertTrue (params["username"] == "user");
|
||||
assertTrue (params["opaque"] == "opaque");
|
||||
assertTrue (params["cnonce"] == cnonce);
|
||||
assertTrue (params["nc"] == "00000002");
|
||||
assertTrue (params["qop"] == "auth");
|
||||
assertTrue (params.size() == 10);
|
||||
}
|
||||
|
||||
void HTTPCredentialsTest::testCredentialsBasic()
|
||||
{
|
||||
@ -311,6 +350,43 @@ void HTTPCredentialsTest::testVerifyAuthInfoQoP()
|
||||
assertTrue (!creds.verifyAuthInfo(request));
|
||||
}
|
||||
|
||||
void HTTPCredentialsTest::testVerifyAuthInfoQoPSHA256() {
|
||||
HTTPDigestCredentials sha256Creds("user", "s3cr3t");
|
||||
HTTPRequest sha256Request(HTTPRequest::HTTP_GET, "/digest/");
|
||||
HTTPResponse sha256Response;
|
||||
sha256Response.set("WWW-Authenticate", "Digest realm=\"TestDigest\", nonce=\"212573bb90170538efad012978ab811f%lu\", opaque=\"opaque\", qop=\"auth,auth-int\", algorithm=SHA-256");
|
||||
sha256Creds.authenticate(sha256Request, sha256Response);
|
||||
assertTrue (sha256Creds.verifyAuthInfo(sha256Request));
|
||||
|
||||
sha256Request.set("Authorization", "Digest cnonce=\"f9c80ffd1c3bc4ee47ed92b704ba75a4\", nc=00000001, nonce=\"212573bb90170538efad012978ab811f%lu\", opaque=\"opaque\", qop=\"auth\", realm=\"TestDigest\", response=\"ff0e90b9aa019120ea0ed6e23ce95d9a\", uri=\"/digest/\", username=\"user\", algorithm=SHA-256");
|
||||
assertTrue (!sha256Creds.verifyAuthInfo(sha256Request));
|
||||
|
||||
HTTPDigestCredentials sha256SessCreds("user", "s3cr3t");
|
||||
HTTPRequest sha256SessRequest(HTTPRequest::HTTP_GET, "/digest/");
|
||||
HTTPResponse sha256SessResponse;
|
||||
sha256SessResponse.set("WWW-Authenticate", "Digest realm=\"TestDigest\", nonce=\"212573bb90170538efad012978ab811f%lu\", opaque=\"opaque\", qop=\"auth,auth-int\", algorithm=SHA-256-sess");
|
||||
sha256SessCreds.authenticate(sha256SessRequest, sha256SessResponse);
|
||||
assertTrue (sha256SessCreds.verifyAuthInfo(sha256SessRequest));
|
||||
|
||||
sha256SessRequest.set("Authorization", "Digest cnonce=\"f9c80ffd1c3bc4ee47ed92b704ba75a4\", nc=00000001, nonce=\"212573bb90170538efad012978ab811f%lu\", opaque=\"opaque\", qop=\"auth\", realm=\"TestDigest\", response=\"ff0e90b9aa019120ea0ed6e23ce95d9a\", uri=\"/digest/\", username=\"user\", algorithm=SHA-256-sess");
|
||||
assertTrue (!sha256SessCreds.verifyAuthInfo(sha256SessRequest));
|
||||
}
|
||||
|
||||
void HTTPCredentialsTest::testIsAlgorithmSupported() {
|
||||
HTTPDigestCredentials sha256Creds("user", "s3cr3t");
|
||||
|
||||
assertTrue (sha256Creds.isAlgorithmSupported("MD5"));
|
||||
assertTrue (sha256Creds.isAlgorithmSupported("MD5-sess"));
|
||||
assertTrue (sha256Creds.isAlgorithmSupported("SHA"));
|
||||
assertTrue (sha256Creds.isAlgorithmSupported("SHA-sess"));
|
||||
assertTrue (sha256Creds.isAlgorithmSupported("SHA-256"));
|
||||
assertTrue (sha256Creds.isAlgorithmSupported("SHA-256-sess"));
|
||||
assertTrue (sha256Creds.isAlgorithmSupported("SHA-512-256"));
|
||||
assertTrue (sha256Creds.isAlgorithmSupported("SHA-512-256-sess"));
|
||||
assertTrue (sha256Creds.isAlgorithmSupported("SHA-512"));
|
||||
assertTrue (sha256Creds.isAlgorithmSupported("SHA-512-sess"));
|
||||
assertFalse (sha256Creds.isAlgorithmSupported("random_algorithm"));
|
||||
}
|
||||
|
||||
void HTTPCredentialsTest::setUp()
|
||||
{
|
||||
@ -333,6 +409,7 @@ CppUnit::Test* HTTPCredentialsTest::suite()
|
||||
CppUnit_addTest(pSuite, HTTPCredentialsTest, testAuthenticationParamsMultipleHeaders);
|
||||
CppUnit_addTest(pSuite, HTTPCredentialsTest, testDigestCredentials);
|
||||
CppUnit_addTest(pSuite, HTTPCredentialsTest, testDigestCredentialsQoP);
|
||||
CppUnit_addTest(pSuite, HTTPCredentialsTest, testDigestCredentialsQoPSHA256);
|
||||
CppUnit_addTest(pSuite, HTTPCredentialsTest, testCredentialsBasic);
|
||||
CppUnit_addTest(pSuite, HTTPCredentialsTest, testProxyCredentialsBasic);
|
||||
CppUnit_addTest(pSuite, HTTPCredentialsTest, testCredentialsDigest);
|
||||
@ -341,6 +418,8 @@ CppUnit::Test* HTTPCredentialsTest::suite()
|
||||
CppUnit_addTest(pSuite, HTTPCredentialsTest, testExtractCredentials);
|
||||
CppUnit_addTest(pSuite, HTTPCredentialsTest, testVerifyAuthInfo);
|
||||
CppUnit_addTest(pSuite, HTTPCredentialsTest, testVerifyAuthInfoQoP);
|
||||
CppUnit_addTest(pSuite, HTTPCredentialsTest, testVerifyAuthInfoQoPSHA256);
|
||||
CppUnit_addTest(pSuite, HTTPCredentialsTest, testIsAlgorithmSupported);
|
||||
|
||||
return pSuite;
|
||||
}
|
||||
|
@ -31,6 +31,7 @@ public:
|
||||
void testAuthenticationParamsMultipleHeaders();
|
||||
void testDigestCredentials();
|
||||
void testDigestCredentialsQoP();
|
||||
void testDigestCredentialsQoPSHA256();
|
||||
void testCredentialsBasic();
|
||||
void testProxyCredentialsBasic();
|
||||
void testCredentialsDigest();
|
||||
@ -39,6 +40,8 @@ public:
|
||||
void testExtractCredentials();
|
||||
void testVerifyAuthInfo();
|
||||
void testVerifyAuthInfoQoP();
|
||||
void testVerifyAuthInfoQoPSHA256();
|
||||
void testIsAlgorithmSupported();
|
||||
|
||||
void setUp();
|
||||
void tearDown();
|
||||
|
Loading…
x
Reference in New Issue
Block a user