Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions src/Access/AccessEntityIO.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,16 @@ String serializeAccessEntity(const IAccessEntity & entity)
for (const ASTPtr & query : queries)
{
formatAST(*query, buf, false, true);
if (const User * user = typeid_cast<const User *>(&entity))
{
if(user->auth_data.getSaltEnabledStatus())
{
std::string strSalt = " '";
strSalt += user->auth_data.getSalt();
strSalt+="'";
buf.write(strSalt.c_str(), strSalt.length());
}
}
buf.write(";\n", 2);
}
return buf.str();
Expand Down Expand Up @@ -121,6 +131,9 @@ AccessEntityPtr deserializeAccessEntity(const String & definition, const String
throw Exception("Two access entities attached in " + path, ErrorCodes::INCORRECT_ACCESS_ENTITY_DEFINITION);
res = user = std::make_unique<User>();
InterpreterCreateUserQuery::updateUserFromQuery(*user, *create_user_query);

if(user->auth_data.getSaltEnabledStatus())
user->auth_data.setPassword(user->auth_data.getPassword() + user->auth_data.getSalt());
}
else if (auto * create_role_query = query->as<ASTCreateRoleQuery>())
{
Expand Down
41 changes: 35 additions & 6 deletions src/Access/Authentication.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -26,14 +26,33 @@ namespace
return (Util::stringToDigest(password) == password_plaintext);
}

bool checkPasswordDoubleSHA1(const std::string_view & password, const Digest & password_double_sha1)
bool checkPasswordDoubleSHA1(const std::string_view & password, const Digest & password_double_sha1, bool isSaltEnabled, const String &salt)
{
return (Util::encodeDoubleSHA1(password) == password_double_sha1);
if(isSaltEnabled)
{
auto salt_password = salt + std::string(password);
return Util::encodeDoubleSHA1(salt_password) == password_double_sha1;
}
else
{
return Util::encodeDoubleSHA1(password) == password_double_sha1;
}
}

bool checkPasswordSHA256(const std::string_view & password, const Digest & password_sha256)
bool checkPasswordSHA256(const std::string_view & password, const Digest & password_sha256, bool isSaltEnabled, const String &salt)
{
return Util::encodeSHA256(password) == password_sha256;
if(isSaltEnabled)
{
std::vector<uint8_t> salt_password = Util::encodeSHA256(password);
for(auto i : salt)
salt_password.push_back(i);

return salt_password == password_sha256;
}
else
{
return Util::encodeSHA256(password) == password_sha256;
}
}

bool checkPasswordDoubleSHA1MySQL(const std::string_view & scramble, const std::string_view & scrambled_password, const Digest & password_double_sha1)
Expand Down Expand Up @@ -81,6 +100,8 @@ bool Authentication::areCredentialsValid(const Credentials & credentials, const
case AuthenticationType::PLAINTEXT_PASSWORD:
case AuthenticationType::SHA256_PASSWORD:
case AuthenticationType::DOUBLE_SHA1_PASSWORD:
case AuthenticationType::SHA256_PASSWORD_SALT:
case AuthenticationType::DOUBLE_SHA1_PASSWORD_SALT:
case AuthenticationType::LDAP:
throw Authentication::Require<BasicCredentials>("ClickHouse Basic Authentication");

Expand All @@ -106,6 +127,8 @@ bool Authentication::areCredentialsValid(const Credentials & credentials, const
return checkPasswordDoubleSHA1MySQL(mysql_credentials->getScramble(), mysql_credentials->getScrambledPassword(), auth_data.getPasswordHashBinary());

case AuthenticationType::SHA256_PASSWORD:
case AuthenticationType::SHA256_PASSWORD_SALT:
case AuthenticationType::DOUBLE_SHA1_PASSWORD_SALT:
case AuthenticationType::LDAP:
case AuthenticationType::KERBEROS:
throw Authentication::Require<BasicCredentials>("ClickHouse Basic Authentication");
Expand All @@ -126,10 +149,16 @@ bool Authentication::areCredentialsValid(const Credentials & credentials, const
return checkPasswordPlainText(basic_credentials->getPassword(), auth_data.getPasswordHashBinary());

case AuthenticationType::SHA256_PASSWORD:
return checkPasswordSHA256(basic_credentials->getPassword(), auth_data.getPasswordHashBinary());
return checkPasswordSHA256(basic_credentials->getPassword(), auth_data.getPasswordHashBinary(), auth_data.getSaltEnabledStatus(), auth_data.getSalt());

case AuthenticationType::DOUBLE_SHA1_PASSWORD:
return checkPasswordDoubleSHA1(basic_credentials->getPassword(), auth_data.getPasswordHashBinary());
return checkPasswordDoubleSHA1(basic_credentials->getPassword(), auth_data.getPasswordHashBinary(), auth_data.getSaltEnabledStatus(), auth_data.getSalt());

case AuthenticationType::SHA256_PASSWORD_SALT:
return checkPasswordSHA256(basic_credentials->getPassword(), auth_data.getPasswordHashBinary(), auth_data.getSaltEnabledStatus(), auth_data.getSalt());

case AuthenticationType::DOUBLE_SHA1_PASSWORD_SALT:
return checkPasswordDoubleSHA1(basic_credentials->getPassword(), auth_data.getPasswordHashBinary(), auth_data.getSaltEnabledStatus(), auth_data.getSalt());

case AuthenticationType::LDAP:
return external_authenticators.checkLDAPCredentials(auth_data.getLDAPServerName(), *basic_credentials);
Expand Down
68 changes: 67 additions & 1 deletion src/Access/Common/AuthenticationData.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,16 @@ const AuthenticationTypeInfo & AuthenticationTypeInfo::get(AuthenticationType ty
static const auto info = make_info("DOUBLE_SHA1_PASSWORD");
return info;
}
case AuthenticationType::SHA256_PASSWORD_SALT:
{
static const auto info = make_info("SHA256_PASSWORD_SALT");
return info;
}
case AuthenticationType::DOUBLE_SHA1_PASSWORD_SALT:
{
static const auto info = make_info("DOUBLE_SHA1_PASSWORD_SALT");
return info;
}
case AuthenticationType::LDAP:
{
static const auto info = make_info("LDAP");
Expand All @@ -59,6 +69,7 @@ const AuthenticationTypeInfo & AuthenticationTypeInfo::get(AuthenticationType ty
static const auto info = make_info("KERBEROS");
return info;
}

case AuthenticationType::MAX:
break;
}
Expand Down Expand Up @@ -104,9 +115,11 @@ void AuthenticationData::setPassword(const String & password_)
return setPasswordHashBinary(Util::stringToDigest(password_));

case AuthenticationType::SHA256_PASSWORD:
case AuthenticationType::SHA256_PASSWORD_SALT:
return setPasswordHashBinary(Util::encodeSHA256(password_));

case AuthenticationType::DOUBLE_SHA1_PASSWORD:
case AuthenticationType::DOUBLE_SHA1_PASSWORD_SALT:
return setPasswordHashBinary(Util::encodeDoubleSHA1(password_));

case AuthenticationType::NO_PASSWORD:
Expand All @@ -128,6 +141,12 @@ String AuthenticationData::getPassword() const
return String(password_hash.data(), password_hash.data() + password_hash.size());
}

String AuthenticationData::getSalt() const
{
//if (type != AuthenticationType::PLAINTEXT_PASSWORD)
// throw Exception("Cannot decode the password", ErrorCodes::LOGICAL_ERROR);
return String(salt.data(), salt.data() + salt.size());
}

void AuthenticationData::setPasswordHashHex(const String & hash)
{
Expand All @@ -146,7 +165,6 @@ void AuthenticationData::setPasswordHashHex(const String & hash)
setPasswordHashBinary(digest);
}


String AuthenticationData::getPasswordHashHex() const
{
if (type == AuthenticationType::LDAP || type == AuthenticationType::KERBEROS)
Expand Down Expand Up @@ -179,6 +197,11 @@ void AuthenticationData::setPasswordHashBinary(const Digest & hash)
password_hash = hash;
return;
}
case AuthenticationType::SHA256_PASSWORD_SALT:
{
password_hash = hash;
return;
}

case AuthenticationType::DOUBLE_SHA1_PASSWORD:
{
Expand All @@ -190,6 +213,11 @@ void AuthenticationData::setPasswordHashBinary(const Digest & hash)
password_hash = hash;
return;
}
case AuthenticationType::DOUBLE_SHA1_PASSWORD_SALT:
{
password_hash = hash;
return;
}

case AuthenticationType::NO_PASSWORD:
case AuthenticationType::LDAP:
Expand All @@ -202,4 +230,42 @@ void AuthenticationData::setPasswordHashBinary(const Digest & hash)
throw Exception("setPasswordHashBinary(): authentication type " + toString(type) + " not supported", ErrorCodes::NOT_IMPLEMENTED);
}

void AuthenticationData::setSaltHashBinary(const Digest & salt_hash)
{
switch (type)
{
case AuthenticationType::SHA256_PASSWORD_SALT:
case AuthenticationType::DOUBLE_SHA1_PASSWORD_SALT:
{
salt = salt_hash;
return;
}

default:
throw Exception("Cannot specify salt binary hash for authentication type " + toString(type), ErrorCodes::LOGICAL_ERROR);
}
}

void AuthenticationData::setSalt(const String & salt_)
{
switch (type)
{
case AuthenticationType::SHA256_PASSWORD_SALT:
//(salt = salt_); Util::encodeSHA256(salt_);//.data();
//return;
return setSaltHashBinary(Util::encodeSHA256(salt_));
case AuthenticationType::DOUBLE_SHA1_PASSWORD_SALT:
//salt = salt_;
//return;
return setSaltHashBinary(Util::encodeDoubleSHA1(salt_));
default:
throw Exception("setSalt(): authentication type " + toString(type) + " not supported", ErrorCodes::NOT_IMPLEMENTED);
}
}

void AuthenticationData::setSaltEnableStatus(bool enableSalt)
{
isSaltEnabled = enableSalt;
}

}
18 changes: 18 additions & 0 deletions src/Access/Common/AuthenticationData.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,12 @@ enum class AuthenticationType
/// This kind of hash is used by the `mysql_native_password` authentication plugin.
DOUBLE_SHA1_PASSWORD,

///Password hash with salt
SHA256_PASSWORD_SALT,

///Double Sha Password hash with salt
DOUBLE_SHA1_PASSWORD_SALT,

/// Password is checked by a [remote] LDAP server. Connection will be made at each authentication attempt.
LDAP,

Expand Down Expand Up @@ -71,6 +77,16 @@ class AuthenticationData
void setPasswordHashBinary(const Digest & hash);
const Digest & getPasswordHashBinary() const { return password_hash; }

/// Sets the salt in String form.
void setSalt(const String & salt);
void setSaltHashBinary(const Digest & salt_hash);
const Digest& getSaltHashBinary() const { return salt; }
String getSalt() const;

/// Sets the salt in String form.
void setSaltEnableStatus(bool enableSalt);// { isSaltEnabled = enableSalt; }
const bool & getSaltEnabledStatus() const { return isSaltEnabled; }

/// Sets the server name for authentication type LDAP.
const String & getLDAPServerName() const { return ldap_server_name; }
void setLDAPServerName(const String & name) { ldap_server_name = name; }
Expand All @@ -97,6 +113,8 @@ class AuthenticationData
Digest password_hash;
String ldap_server_name;
String kerberos_realm;
Digest salt;
bool isSaltEnabled;
};

}
20 changes: 17 additions & 3 deletions src/Access/IAccessStorage.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,18 @@
#include <Common/quoteString.h>
#include <IO/WriteHelpers.h>
#include <Poco/UUIDGenerator.h>
#include <Poco/PBKDF2Engine.h>
#include "Poco/HMACEngine.h"
#include "Poco/SHA1Engine.h"
#include <Poco/Logger.h>
#include <base/FnTraits.h>
#include <boost/algorithm/string/join.hpp>
#include <boost/algorithm/string/replace.hpp>

#include <iostream>

namespace DB
{

namespace ErrorCodes
{
extern const int ACCESS_ENTITY_ALREADY_EXISTS;
Expand All @@ -25,9 +29,9 @@ namespace ErrorCodes
extern const int LOGICAL_ERROR;
}


namespace
{

String outputID(const UUID & id)
{
return "ID(" + toString(id) + ")";
Expand Down Expand Up @@ -472,7 +476,7 @@ UUID IAccessStorage::loginImpl(
{
if (!isAddressAllowedImpl(*user, address))
throwAddressNotAllowed(address);

if (!areCredentialsValidImpl(*user, credentials, external_authenticators))
throwInvalidCredentials();

Expand Down Expand Up @@ -524,6 +528,16 @@ UUID IAccessStorage::generateRandomID()
return id;
}

void IAccessStorage::generateSaltDiget(std::string &num)
{
std::string p("Password");
std::string s("salt");
Poco::PBKDF2Engine<Poco::HMACEngine<Poco::SHA1Engine> > pbkdf2(s, 4096, 25);
pbkdf2.update(p);
std::string dk = Poco::DigestEngine::digestToHex(pbkdf2.digest());

num=std::move(dk);
}

Poco::Logger * IAccessStorage::getLogger() const
{
Expand Down
8 changes: 4 additions & 4 deletions src/Access/IAccessStorage.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@
#include <optional>
#include <vector>
#include <atomic>


#include <unordered_map>
#include <map>
namespace Poco { class Logger; }
namespace Poco::Net { class IPAddress; }

Expand Down Expand Up @@ -149,7 +149,6 @@ class IAccessStorage
/// Returns the ID of a user who has logged in (maybe on another node).
/// The function assumes that the password has been already checked somehow, so we can skip checking it now.
UUID getIDOfLoggedUser(const String & user_name) const;

protected:
virtual std::optional<UUID> findImpl(AccessEntityType type, const String & name) const = 0;
virtual std::vector<UUID> findAllImpl(AccessEntityType type) const = 0;
Expand All @@ -170,6 +169,7 @@ class IAccessStorage
virtual UUID getIDOfLoggedUserImpl(const String & user_name) const;

static UUID generateRandomID();
void generateSaltDiget(std::string &);
Poco::Logger * getLogger() const;
static String formatEntityTypeWithName(AccessEntityType type, const String & name) { return AccessEntityTypeInfo::get(type).formatEntityNameWithType(name); }
[[noreturn]] void throwNotFound(const UUID & id) const;
Expand All @@ -189,7 +189,7 @@ class IAccessStorage
using Notification = std::tuple<OnChangedHandler, UUID, AccessEntityPtr>;
using Notifications = std::vector<Notification>;
static void notify(const Notifications & notifications);

private:
AccessEntityPtr tryReadBase(const UUID & id) const;

Expand Down
22 changes: 21 additions & 1 deletion src/Interpreters/Access/InterpreterCreateUserQuery.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,10 @@
#include <Interpreters/Context.h>
#include <Interpreters/executeDDLQueryOnCluster.h>
#include <boost/range/algorithm/copy.hpp>

#include <pcg_random.hpp>
#include <Common/randomSeed.h>
#include "Common/OpenSSLHelpers.h"
#include <memory>

namespace DB
{
Expand All @@ -33,6 +36,23 @@ namespace

if (query.auth_data)
user.auth_data = *query.auth_data;

user.auth_data.setSaltEnableStatus(false);

if (query.auth_data->getType() == AuthenticationType::SHA256_PASSWORD_SALT
|| query.auth_data->getType() == AuthenticationType::DOUBLE_SHA1_PASSWORD_SALT)
{
//generate and add salt here
pcg64_fast rng(randomSeed());
UInt64 rand = rng();
String salt = encodeSHA256(&rand, sizeof(rand));
user.auth_data.setSalt(salt);
std::vector<uint8_t> password = user.auth_data.getPasswordHashBinary();
std::vector<uint8_t> salt_hash = user.auth_data.getSaltHashBinary();
password.insert(password.end(), salt_hash.begin(), salt_hash.end());
user.auth_data.setPasswordHashBinary(password);
user.auth_data.setSaltEnableStatus(true);
}

if (override_name && !override_name->host_pattern.empty())
{
Expand Down
Loading