ClickHouse/base/poco/Net/src/HTTPAuthenticationParams.cpp
Robert Schulze b79ead9c84
Move poco to base/poco/ (#46075)
* Replicate poco into base/poco/

* De-register poco submodule

* Build poco from ClickHouse

* Exclude poco from stylecheck

* Exclude poco from whitespace check

* Exclude poco from typo check

* Remove x bit from sources/headers (the style check complained)

* Exclude poco from duplicate include check

* Fix fasttest

* Remove contrib/poco-cmake/*

* Simplify poco build descriptions

* Remove poco stuff not used by ClickHouse

* Glob poco sources

* Exclude poco from clang-tidy
2023-02-08 12:04:11 +01:00

317 lines
6.1 KiB
C++

//
// HTTPAuthenticationParams.cpp
//
// Library: Net
// Package: HTTP
// Module: HTTPAuthenticationParams
//
// Copyright (c) 2011, Anton V. Yabchinskiy (arn at bestmx dot ru).
// Copyright (c) 2012, Applied Informatics Software Engineering GmbH.
// and Contributors.
//
// SPDX-License-Identifier: BSL-1.0
//
#include "Poco/Exception.h"
#include "Poco/Net/HTTPAuthenticationParams.h"
#include "Poco/Net/HTTPRequest.h"
#include "Poco/Net/HTTPResponse.h"
#include "Poco/Net/NetException.h"
#include "Poco/String.h"
#include "Poco/Ascii.h"
using Poco::icompare;
using Poco::Ascii;
namespace
{
bool mustBeQuoted(const std::string& name)
{
return
icompare(name, "cnonce") == 0 ||
icompare(name, "domain") == 0 ||
icompare(name, "nonce") == 0 ||
icompare(name, "opaque") == 0 ||
icompare(name, "qop") == 0 ||
icompare(name, "realm") == 0 ||
icompare(name, "response") == 0 ||
icompare(name, "uri") == 0 ||
icompare(name, "username") == 0;
}
void formatParameter(std::string& result, const std::string& name, const std::string& value)
{
result += name;
result += '=';
if (mustBeQuoted(name))
{
result += '"';
result += value;
result += '"';
}
else
{
result += value;
}
}
}
namespace Poco {
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()
{
}
HTTPAuthenticationParams::HTTPAuthenticationParams(const std::string& authInfo)
{
fromAuthInfo(authInfo);
}
HTTPAuthenticationParams::HTTPAuthenticationParams(const HTTPRequest& request)
{
fromRequest(request);
}
HTTPAuthenticationParams::HTTPAuthenticationParams(const HTTPResponse& response, const std::string& header)
{
fromResponse(response, header);
}
HTTPAuthenticationParams::~HTTPAuthenticationParams()
{
}
HTTPAuthenticationParams& HTTPAuthenticationParams::operator = (const HTTPAuthenticationParams& authParams)
{
NameValueCollection::operator = (authParams);
return *this;
}
void HTTPAuthenticationParams::fromAuthInfo(const std::string& authInfo)
{
parse(authInfo.begin(), authInfo.end());
}
void HTTPAuthenticationParams::fromRequest(const HTTPRequest& request)
{
std::string scheme;
std::string authInfo;
request.getCredentials(scheme, authInfo);
if (icompare(scheme, "Digest") != 0)
throw InvalidArgumentException("Could not parse non-Digest authentication information", scheme);
fromAuthInfo(authInfo);
}
void HTTPAuthenticationParams::fromResponse(const HTTPResponse& response, const std::string& header)
{
NameValueCollection::ConstIterator it = response.find(header);
if (it == response.end())
throw NotAuthenticatedException("HTTP response has no authentication header");
bool found = false;
while (!found && it != response.end() && icompare(it->first, header) == 0)
{
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");
}
const std::string& HTTPAuthenticationParams::getRealm() const
{
return get(REALM);
}
void HTTPAuthenticationParams::setRealm(const std::string& realm)
{
set(REALM, realm);
}
std::string HTTPAuthenticationParams::toString() const
{
ConstIterator iter = begin();
std::string result;
if (iter != end())
{
formatParameter(result, iter->first, iter->second);
++iter;
}
for (; iter != end(); ++iter)
{
result.append(", ");
formatParameter(result, iter->first, iter->second);
}
return result;
}
void HTTPAuthenticationParams::parse(std::string::const_iterator first, std::string::const_iterator last)
{
enum State
{
STATE_INITIAL = 0x0100,
STATE_FINAL = 0x0200,
STATE_SPACE = STATE_INITIAL | 0,
STATE_TOKEN = 1,
STATE_EQUALS = 2,
STATE_VALUE = STATE_FINAL | 3,
STATE_VALUE_QUOTED = 4,
STATE_VALUE_ESCAPE = 5,
STATE_COMMA = STATE_FINAL | 6
};
int state = STATE_SPACE;
std::string token;
std::string value;
for (std::string::const_iterator it = first; it != last; ++it)
{
switch (state)
{
case STATE_SPACE:
if (Ascii::isAlphaNumeric(*it) || *it == '_' || *it == '-')
{
token += *it;
state = STATE_TOKEN;
}
else if (Ascii::isSpace(*it))
{
// Skip
}
else throw SyntaxException("Invalid authentication information");
break;
case STATE_TOKEN:
if (*it == '=')
{
state = STATE_EQUALS;
}
else if (Ascii::isAlphaNumeric(*it) || *it == '_' || *it == '-')
{
token += *it;
}
else throw SyntaxException("Invalid authentication information");
break;
case STATE_EQUALS:
if (Ascii::isAlphaNumeric(*it) || *it == '_')
{
value += *it;
state = STATE_VALUE;
}
else if (*it == '"')
{
state = STATE_VALUE_QUOTED;
}
else throw SyntaxException("Invalid authentication information");
break;
case STATE_VALUE_QUOTED:
if (*it == '\\')
{
state = STATE_VALUE_ESCAPE;
}
else if (*it == '"')
{
add(token, value);
token.clear();
value.clear();
state = STATE_COMMA;
}
else
{
value += *it;
}
break;
case STATE_VALUE_ESCAPE:
value += *it;
state = STATE_VALUE_QUOTED;
break;
case STATE_VALUE:
if (Ascii::isSpace(*it))
{
add(token, value);
token.clear();
value.clear();
state = STATE_COMMA;
}
else if (*it == ',')
{
add(token, value);
token.clear();
value.clear();
state = STATE_SPACE;
}
else
{
value += *it;
}
break;
case STATE_COMMA:
if (*it == ',')
{
state = STATE_SPACE;
}
else if (Ascii::isSpace(*it))
{
// Skip
}
else throw SyntaxException("Invalid authentication information");
break;
}
}
if (state == STATE_VALUE)
add(token, value);
if (!(state & STATE_FINAL))
throw SyntaxException("Invalid authentication information");
}
} } // namespace Poco::Net