mirror of
https://github.com/ClickHouse/ClickHouse.git
synced 2024-11-22 23:52:03 +00:00
Move some part of the Authentication class to header to allow using in the parser.
This commit is contained in:
parent
1e8f04b571
commit
291b7c277a
@ -1,166 +1,18 @@
|
||||
#include <Access/Authentication.h>
|
||||
#include <Common/Exception.h>
|
||||
#include <common/StringRef.h>
|
||||
#include <Core/Defines.h>
|
||||
#include <Poco/SHA1Engine.h>
|
||||
#include <boost/algorithm/hex.hpp>
|
||||
#include "config_core.h"
|
||||
#if USE_SSL
|
||||
# include <openssl/sha.h>
|
||||
#endif
|
||||
|
||||
|
||||
namespace DB
|
||||
{
|
||||
namespace ErrorCodes
|
||||
{
|
||||
extern const int SUPPORT_IS_DISABLED;
|
||||
extern const int REQUIRED_PASSWORD;
|
||||
extern const int WRONG_PASSWORD;
|
||||
extern const int BAD_ARGUMENTS;
|
||||
extern const int LOGICAL_ERROR;
|
||||
}
|
||||
|
||||
|
||||
namespace
|
||||
{
|
||||
using Digest = Authentication::Digest;
|
||||
|
||||
Digest encodePlainText(const StringRef & text)
|
||||
{
|
||||
return Digest(text.data, text.data + text.size);
|
||||
}
|
||||
|
||||
Digest encodeSHA256(const StringRef & text)
|
||||
{
|
||||
#if USE_SSL
|
||||
Digest hash;
|
||||
hash.resize(32);
|
||||
SHA256_CTX ctx;
|
||||
SHA256_Init(&ctx);
|
||||
SHA256_Update(&ctx, reinterpret_cast<const UInt8 *>(text.data), text.size);
|
||||
SHA256_Final(hash.data(), &ctx);
|
||||
return hash;
|
||||
#else
|
||||
UNUSED(text);
|
||||
throw DB::Exception("SHA256 passwords support is disabled, because ClickHouse was built without SSL library", DB::ErrorCodes::SUPPORT_IS_DISABLED);
|
||||
#endif
|
||||
}
|
||||
|
||||
Digest encodeSHA1(const StringRef & text)
|
||||
{
|
||||
Poco::SHA1Engine engine;
|
||||
engine.update(text.data, text.size);
|
||||
return engine.digest();
|
||||
}
|
||||
|
||||
Digest encodeSHA1(const Digest & text)
|
||||
{
|
||||
return encodeSHA1(StringRef{reinterpret_cast<const char *>(text.data()), text.size()});
|
||||
}
|
||||
|
||||
Digest encodeDoubleSHA1(const StringRef & text)
|
||||
{
|
||||
return encodeSHA1(encodeSHA1(text));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Authentication::Authentication(Authentication::Type type_)
|
||||
: type(type_)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
void Authentication::setPassword(const String & password_)
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case NO_PASSWORD:
|
||||
throw Exception("Cannot specify password for the 'NO_PASSWORD' authentication type", ErrorCodes::LOGICAL_ERROR);
|
||||
|
||||
case PLAINTEXT_PASSWORD:
|
||||
setPasswordHashBinary(encodePlainText(password_));
|
||||
return;
|
||||
|
||||
case SHA256_PASSWORD:
|
||||
setPasswordHashBinary(encodeSHA256(password_));
|
||||
return;
|
||||
|
||||
case DOUBLE_SHA1_PASSWORD:
|
||||
setPasswordHashBinary(encodeDoubleSHA1(password_));
|
||||
return;
|
||||
}
|
||||
throw Exception("Unknown authentication type: " + std::to_string(static_cast<int>(type)), ErrorCodes::LOGICAL_ERROR);
|
||||
}
|
||||
|
||||
|
||||
String Authentication::getPassword() const
|
||||
{
|
||||
if (type != PLAINTEXT_PASSWORD)
|
||||
throw Exception("Cannot decode the password", ErrorCodes::LOGICAL_ERROR);
|
||||
return String(password_hash.data(), password_hash.data() + password_hash.size());
|
||||
}
|
||||
|
||||
|
||||
void Authentication::setPasswordHashHex(const String & hash)
|
||||
{
|
||||
Digest digest;
|
||||
digest.resize(hash.size() / 2);
|
||||
boost::algorithm::unhex(hash.begin(), hash.end(), digest.data());
|
||||
setPasswordHashBinary(digest);
|
||||
}
|
||||
|
||||
|
||||
String Authentication::getPasswordHashHex() const
|
||||
{
|
||||
String hex;
|
||||
hex.resize(password_hash.size() * 2);
|
||||
boost::algorithm::hex(password_hash.begin(), password_hash.end(), hex.data());
|
||||
return hex;
|
||||
}
|
||||
|
||||
|
||||
void Authentication::setPasswordHashBinary(const Digest & hash)
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case NO_PASSWORD:
|
||||
throw Exception("Cannot specify password for the 'NO_PASSWORD' authentication type", ErrorCodes::LOGICAL_ERROR);
|
||||
|
||||
case PLAINTEXT_PASSWORD:
|
||||
{
|
||||
password_hash = hash;
|
||||
return;
|
||||
}
|
||||
|
||||
case SHA256_PASSWORD:
|
||||
{
|
||||
if (hash.size() != 32)
|
||||
throw Exception(
|
||||
"Password hash for the 'SHA256_PASSWORD' authentication type has length " + std::to_string(hash.size())
|
||||
+ " but must be exactly 32 bytes.",
|
||||
ErrorCodes::BAD_ARGUMENTS);
|
||||
password_hash = hash;
|
||||
return;
|
||||
}
|
||||
|
||||
case DOUBLE_SHA1_PASSWORD:
|
||||
{
|
||||
if (hash.size() != 20)
|
||||
throw Exception(
|
||||
"Password hash for the 'DOUBLE_SHA1_PASSWORD' authentication type has length " + std::to_string(hash.size())
|
||||
+ " but must be exactly 20 bytes.",
|
||||
ErrorCodes::BAD_ARGUMENTS);
|
||||
password_hash = hash;
|
||||
return;
|
||||
}
|
||||
}
|
||||
throw Exception("Unknown authentication type: " + std::to_string(static_cast<int>(type)), ErrorCodes::LOGICAL_ERROR);
|
||||
}
|
||||
|
||||
|
||||
Digest Authentication::getPasswordDoubleSHA1() const
|
||||
Authentication::Digest Authentication::getPasswordDoubleSHA1() const
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
@ -198,12 +50,12 @@ bool Authentication::isCorrectPassword(const String & password_) const
|
||||
|
||||
case PLAINTEXT_PASSWORD:
|
||||
{
|
||||
if (password_ == StringRef{reinterpret_cast<const char *>(password_hash.data()), password_hash.size()})
|
||||
if (password_ == std::string_view{reinterpret_cast<const char *>(password_hash.data()), password_hash.size()})
|
||||
return true;
|
||||
|
||||
// For compatibility with MySQL clients which support only native authentication plugin, SHA1 can be passed instead of password.
|
||||
auto password_sha1 = encodeSHA1(password_hash);
|
||||
return password_ == StringRef{reinterpret_cast<const char *>(password_sha1.data()), password_sha1.size()};
|
||||
return password_ == std::string_view{reinterpret_cast<const char *>(password_sha1.data()), password_sha1.size()};
|
||||
}
|
||||
|
||||
case SHA256_PASSWORD:
|
||||
@ -234,10 +86,5 @@ void Authentication::checkPassword(const String & password_, const String & user
|
||||
throw Exception("Wrong password" + info_about_user_name(), ErrorCodes::WRONG_PASSWORD);
|
||||
}
|
||||
|
||||
|
||||
bool operator ==(const Authentication & lhs, const Authentication & rhs)
|
||||
{
|
||||
return (lhs.type == rhs.type) && (lhs.password_hash == rhs.password_hash);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,10 +1,22 @@
|
||||
#pragma once
|
||||
|
||||
#include <Core/Types.h>
|
||||
#include <Common/Exception.h>
|
||||
#include <Common/OpenSSLHelpers.h>
|
||||
#include <Poco/SHA1Engine.h>
|
||||
#include <boost/algorithm/hex.hpp>
|
||||
|
||||
|
||||
namespace DB
|
||||
{
|
||||
namespace ErrorCodes
|
||||
{
|
||||
extern const int SUPPORT_IS_DISABLED;
|
||||
extern const int BAD_ARGUMENTS;
|
||||
extern const int LOGICAL_ERROR;
|
||||
}
|
||||
|
||||
|
||||
/// Authentication type and encrypted password for checking when an user logins.
|
||||
class Authentication
|
||||
{
|
||||
@ -27,7 +39,7 @@ public:
|
||||
|
||||
using Digest = std::vector<UInt8>;
|
||||
|
||||
Authentication(Authentication::Type type = NO_PASSWORD);
|
||||
Authentication(Authentication::Type type_ = NO_PASSWORD) : type(type_) {}
|
||||
Authentication(const Authentication & src) = default;
|
||||
Authentication & operator =(const Authentication & src) = default;
|
||||
Authentication(Authentication && src) = default;
|
||||
@ -36,17 +48,19 @@ public:
|
||||
Type getType() const { return type; }
|
||||
|
||||
/// Sets the password and encrypt it using the authentication type set in the constructor.
|
||||
void setPassword(const String & password);
|
||||
void setPassword(const String & password_);
|
||||
|
||||
/// Returns the password. Allowed to use only for Type::PLAINTEXT_PASSWORD.
|
||||
String getPassword() const;
|
||||
|
||||
/// Sets the password as a string of hexadecimal digits.
|
||||
void setPasswordHashHex(const String & hash);
|
||||
|
||||
String getPasswordHashHex() const;
|
||||
|
||||
/// Sets the password in binary form.
|
||||
void setPasswordHashBinary(const Digest & hash);
|
||||
|
||||
const Digest & getPasswordHashBinary() const { return password_hash; }
|
||||
|
||||
/// Returns SHA1(SHA1(password)) used by MySQL compatibility server for authentication.
|
||||
@ -60,11 +74,124 @@ public:
|
||||
/// `user_name` is only used for generating an error message if the password is incorrect.
|
||||
void checkPassword(const String & password, const String & user_name = String()) const;
|
||||
|
||||
friend bool operator ==(const Authentication & lhs, const Authentication & rhs);
|
||||
friend bool operator ==(const Authentication & lhs, const Authentication & rhs) { return (lhs.type == rhs.type) && (lhs.password_hash == rhs.password_hash); }
|
||||
friend bool operator !=(const Authentication & lhs, const Authentication & rhs) { return !(lhs == rhs); }
|
||||
|
||||
private:
|
||||
static Digest encodePlainText(const std::string_view & text) { return Digest(text.data(), text.data() + text.size()); }
|
||||
static Digest encodeSHA256(const std::string_view & text);
|
||||
static Digest encodeSHA1(const std::string_view & text);
|
||||
static Digest encodeSHA1(const Digest & text) { return encodeSHA1(std::string_view{reinterpret_cast<const char *>(text.data()), text.size()}); }
|
||||
static Digest encodeDoubleSHA1(const std::string_view & text) { return encodeSHA1(encodeSHA1(text)); }
|
||||
|
||||
Type type = Type::NO_PASSWORD;
|
||||
Digest password_hash;
|
||||
};
|
||||
|
||||
|
||||
inline Authentication::Digest Authentication::encodeSHA256(const std::string_view & text [[maybe_unused]])
|
||||
{
|
||||
#if USE_SSL
|
||||
Digest hash;
|
||||
hash.resize(32);
|
||||
::DB::encodeSHA256(text, hash.data());
|
||||
return hash;
|
||||
#else
|
||||
throw DB::Exception(
|
||||
"SHA256 passwords support is disabled, because ClickHouse was built without SSL library",
|
||||
DB::ErrorCodes::SUPPORT_IS_DISABLED);
|
||||
#endif
|
||||
}
|
||||
|
||||
inline Authentication::Digest Authentication::encodeSHA1(const std::string_view & text)
|
||||
{
|
||||
Poco::SHA1Engine engine;
|
||||
engine.update(text.data(), text.size());
|
||||
return engine.digest();
|
||||
}
|
||||
|
||||
|
||||
inline void Authentication::setPassword(const String & password_)
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case NO_PASSWORD:
|
||||
throw Exception("Cannot specify password for the 'NO_PASSWORD' authentication type", ErrorCodes::LOGICAL_ERROR);
|
||||
|
||||
case PLAINTEXT_PASSWORD:
|
||||
return setPasswordHashBinary(encodePlainText(password_));
|
||||
|
||||
case SHA256_PASSWORD:
|
||||
return setPasswordHashBinary(encodeSHA256(password_));
|
||||
|
||||
case DOUBLE_SHA1_PASSWORD:
|
||||
return setPasswordHashBinary(encodeDoubleSHA1(password_));
|
||||
}
|
||||
throw Exception("Unknown authentication type: " + std::to_string(static_cast<int>(type)), ErrorCodes::LOGICAL_ERROR);
|
||||
}
|
||||
|
||||
|
||||
inline String Authentication::getPassword() const
|
||||
{
|
||||
if (type != PLAINTEXT_PASSWORD)
|
||||
throw Exception("Cannot decode the password", ErrorCodes::LOGICAL_ERROR);
|
||||
return String(password_hash.data(), password_hash.data() + password_hash.size());
|
||||
}
|
||||
|
||||
|
||||
inline void Authentication::setPasswordHashHex(const String & hash)
|
||||
{
|
||||
Digest digest;
|
||||
digest.resize(hash.size() / 2);
|
||||
boost::algorithm::unhex(hash.begin(), hash.end(), digest.data());
|
||||
setPasswordHashBinary(digest);
|
||||
}
|
||||
|
||||
inline String Authentication::getPasswordHashHex() const
|
||||
{
|
||||
String hex;
|
||||
hex.resize(password_hash.size() * 2);
|
||||
boost::algorithm::hex(password_hash.begin(), password_hash.end(), hex.data());
|
||||
return hex;
|
||||
}
|
||||
|
||||
|
||||
inline void Authentication::setPasswordHashBinary(const Digest & hash)
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case NO_PASSWORD:
|
||||
throw Exception("Cannot specify password for the 'NO_PASSWORD' authentication type", ErrorCodes::LOGICAL_ERROR);
|
||||
|
||||
case PLAINTEXT_PASSWORD:
|
||||
{
|
||||
password_hash = hash;
|
||||
return;
|
||||
}
|
||||
|
||||
case SHA256_PASSWORD:
|
||||
{
|
||||
if (hash.size() != 32)
|
||||
throw Exception(
|
||||
"Password hash for the 'SHA256_PASSWORD' authentication type has length " + std::to_string(hash.size())
|
||||
+ " but must be exactly 32 bytes.",
|
||||
ErrorCodes::BAD_ARGUMENTS);
|
||||
password_hash = hash;
|
||||
return;
|
||||
}
|
||||
|
||||
case DOUBLE_SHA1_PASSWORD:
|
||||
{
|
||||
if (hash.size() != 20)
|
||||
throw Exception(
|
||||
"Password hash for the 'DOUBLE_SHA1_PASSWORD' authentication type has length " + std::to_string(hash.size())
|
||||
+ " but must be exactly 20 bytes.",
|
||||
ErrorCodes::BAD_ARGUMENTS);
|
||||
password_hash = hash;
|
||||
return;
|
||||
}
|
||||
}
|
||||
throw Exception("Unknown authentication type: " + std::to_string(static_cast<int>(type)), ErrorCodes::LOGICAL_ERROR);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -3,11 +3,20 @@
|
||||
#include "OpenSSLHelpers.h"
|
||||
#include <ext/scope_guard.h>
|
||||
#include <openssl/err.h>
|
||||
#include <openssl/sha.h>
|
||||
|
||||
namespace DB
|
||||
{
|
||||
#pragma GCC diagnostic warning "-Wold-style-cast"
|
||||
|
||||
void encodeSHA256(const std::string_view & text, unsigned char * out)
|
||||
{
|
||||
SHA256_CTX ctx;
|
||||
SHA256_Init(&ctx);
|
||||
SHA256_Update(&ctx, reinterpret_cast<const UInt8 *>(text.data()), text.size());
|
||||
SHA256_Final(out, &ctx);
|
||||
}
|
||||
|
||||
String getOpenSSLErrors()
|
||||
{
|
||||
BIO * mem = BIO_new(BIO_s_mem());
|
||||
|
@ -7,6 +7,8 @@
|
||||
|
||||
namespace DB
|
||||
{
|
||||
/// Encodes `text` and puts the result to `out` which must be at least 32 bytes long.
|
||||
void encodeSHA256(const std::string_view & text, unsigned char * out);
|
||||
|
||||
/// Returns concatenation of error strings for all errors that OpenSSL has recorded, emptying the error queue.
|
||||
String getOpenSSLErrors();
|
||||
|
Loading…
Reference in New Issue
Block a user