mirror of
https://github.com/boostorg/mysql.git
synced 2026-02-15 01:02:17 +00:00
Refactored auth calculation
This commit is contained in:
2
TODO.txt
2
TODO.txt
@@ -1,11 +1,9 @@
|
||||
sha256_password auth plugin
|
||||
Unit tests for auth calculator & refactor
|
||||
Set error_info when there is an auth plugin involved
|
||||
Unknown auth plugin
|
||||
Auth plugin requires SSL
|
||||
Test for an unknown auth plugin
|
||||
Update readme
|
||||
Unit test for auth_more_data
|
||||
Multiresultset
|
||||
Text protocol
|
||||
Binary protocol (stored procedures)
|
||||
|
||||
@@ -1,119 +0,0 @@
|
||||
#ifndef INCLUDE_BOOST_MYSQL_DETAIL_AUTH_AUTH_HPP_
|
||||
#define INCLUDE_BOOST_MYSQL_DETAIL_AUTH_AUTH_HPP_
|
||||
|
||||
#include "boost/mysql/detail/auth/mysql_native_password.hpp"
|
||||
#include "boost/mysql/detail/auth/caching_sha2_password.hpp"
|
||||
#include "boost/mysql/error.hpp"
|
||||
|
||||
namespace boost {
|
||||
namespace mysql {
|
||||
namespace detail {
|
||||
|
||||
class auth_response_calculator
|
||||
{
|
||||
//std::array<std::uint8_t, mysql_native_password::response_length> auth_response_buffer_ {};
|
||||
//std::string_view res_;
|
||||
//bool use_buffer_ {};
|
||||
std::string response_;
|
||||
std::string plugin_name_;
|
||||
|
||||
error_code calculate_impl(
|
||||
std::string_view plugin_name,
|
||||
std::string_view password,
|
||||
std::string_view challenge,
|
||||
bool use_ssl
|
||||
)
|
||||
{
|
||||
plugin_name_ = plugin_name;
|
||||
|
||||
// Blank password: we should just return an empty auth string
|
||||
if (password.empty())
|
||||
{
|
||||
response_ = "";
|
||||
return error_code();
|
||||
}
|
||||
|
||||
if (plugin_name == mysql_native_password::plugin_name)
|
||||
{
|
||||
// Check challenge size
|
||||
if (challenge.size() != mysql_native_password::challenge_length)
|
||||
{
|
||||
return make_error_code(errc::protocol_value_error);
|
||||
}
|
||||
|
||||
// Do the calculation
|
||||
std::array<std::uint8_t, mysql_native_password::response_length> buff;
|
||||
mysql_native_password::compute_auth_string(
|
||||
password,
|
||||
challenge.data(),
|
||||
buff.data()
|
||||
);
|
||||
response_.assign(reinterpret_cast<const char*>(buff.data()), buff.size());
|
||||
return error_code();
|
||||
}
|
||||
else if (plugin_name == "caching_sha2_password")
|
||||
{
|
||||
if (challenge.size() == 1 && challenge[0] == 4)
|
||||
{
|
||||
if (!use_ssl)
|
||||
{
|
||||
return make_error_code(errc::auth_plugin_requires_ssl);
|
||||
}
|
||||
response_ = password;
|
||||
response_.push_back(0);
|
||||
return error_code();
|
||||
}
|
||||
else
|
||||
{
|
||||
// Check challenge size
|
||||
if (challenge.size() != caching_sha2_password::challenge_length)
|
||||
{
|
||||
return make_error_code(errc::protocol_value_error);
|
||||
}
|
||||
|
||||
// Do the calculation
|
||||
std::array<std::uint8_t, caching_sha2_password::response_length> buff;
|
||||
caching_sha2_password::compute_auth_string(
|
||||
password,
|
||||
challenge.data(),
|
||||
buff.data()
|
||||
);
|
||||
response_.assign(reinterpret_cast<const char*>(buff.data()), buff.size());
|
||||
return error_code();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return make_error_code(errc::unknown_auth_plugin);
|
||||
}
|
||||
}
|
||||
public:
|
||||
error_code calculate(
|
||||
std::string_view plugin_name,
|
||||
std::string_view password,
|
||||
std::string_view challenge,
|
||||
bool use_ssl
|
||||
)
|
||||
{
|
||||
auto res = calculate_impl(plugin_name, password, challenge, use_ssl);
|
||||
if (res)
|
||||
{
|
||||
response_.clear();
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
std::string_view response() const noexcept
|
||||
{
|
||||
return response_;
|
||||
}
|
||||
const auto& get_plugin_name() const { return plugin_name_; }
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
#endif /* INCLUDE_BOOST_MYSQL_DETAIL_AUTH_AUTH_HPP_ */
|
||||
53
include/boost/mysql/detail/auth/auth_calculator.hpp
Normal file
53
include/boost/mysql/detail/auth/auth_calculator.hpp
Normal file
@@ -0,0 +1,53 @@
|
||||
#ifndef INCLUDE_BOOST_MYSQL_DETAIL_AUTH_AUTH_CALCULATOR_HPP_
|
||||
#define INCLUDE_BOOST_MYSQL_DETAIL_AUTH_AUTH_CALCULATOR_HPP_
|
||||
|
||||
#include "boost/mysql/error.hpp"
|
||||
#include <array>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
|
||||
namespace boost {
|
||||
namespace mysql {
|
||||
namespace detail {
|
||||
|
||||
struct authentication_plugin
|
||||
{
|
||||
using calculator_signature = error_code (*)(
|
||||
std::string_view password,
|
||||
std::string_view challenge,
|
||||
bool use_ssl,
|
||||
std::string& output
|
||||
);
|
||||
|
||||
std::string_view name;
|
||||
calculator_signature calculator;
|
||||
};
|
||||
|
||||
class auth_calculator
|
||||
{
|
||||
const authentication_plugin* plugin_ {nullptr};
|
||||
std::string response_;
|
||||
|
||||
inline static const authentication_plugin* find_plugin(std::string_view name);
|
||||
public:
|
||||
inline error_code calculate(
|
||||
std::string_view plugin_name,
|
||||
std::string_view password,
|
||||
std::string_view challenge,
|
||||
bool use_ssl
|
||||
);
|
||||
std::string_view response() const noexcept { return response_; }
|
||||
std::string_view plugin_name() const noexcept
|
||||
{
|
||||
assert(plugin_);
|
||||
return plugin_->name;
|
||||
}
|
||||
};
|
||||
|
||||
} // detail
|
||||
} // mysql
|
||||
} // boost
|
||||
|
||||
#include "boost/mysql/detail/auth/impl/auth_calculator.ipp"
|
||||
|
||||
#endif /* INCLUDE_BOOST_MYSQL_DETAIL_AUTH_AUTH_CALCULATOR_HPP_ */
|
||||
@@ -3,25 +3,34 @@
|
||||
|
||||
#include <cstddef>
|
||||
#include <string_view>
|
||||
#include "boost/mysql/error.hpp"
|
||||
|
||||
namespace boost {
|
||||
namespace mysql {
|
||||
namespace detail {
|
||||
namespace caching_sha2_password {
|
||||
|
||||
constexpr const char* plugin_name = "caching_sha2_password";
|
||||
constexpr std::size_t challenge_length = 20;
|
||||
constexpr std::size_t response_length = 32;
|
||||
// Authorization for this plugin may be cleartext password or challenge/response.
|
||||
// The server has a cache that uses when employing challenge/response. When
|
||||
// the server sends a challenge of challenge_length bytes, we should send
|
||||
// the password hashed with the challenge. The server may send a challenge
|
||||
// equals to perform_full_auth, meaning it could not use the cache to
|
||||
// complete the auth. In this case, we should just send the cleartext password.
|
||||
// Doing the latter requires a SSL connection. It is possible to perform full
|
||||
// auth without an SSL connection, but that requires the server public key,
|
||||
// and we do not implement that.
|
||||
inline error_code compute_response(
|
||||
std::string_view password,
|
||||
std::string_view challenge,
|
||||
bool use_ssl,
|
||||
std::string& output
|
||||
);
|
||||
|
||||
// challenge must point to challenge_length bytes of data
|
||||
// output must point to response_length bytes of data
|
||||
inline void compute_auth_string(std::string_view password, const void* challenge, void* output);
|
||||
} // caching_sha2_password
|
||||
} // detail
|
||||
} // mysql
|
||||
} // boost
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#include "boost/mysql/detail/auth/impl/caching_sha2_password.hpp"
|
||||
#include "boost/mysql/detail/auth/impl/caching_sha2_password.ipp"
|
||||
|
||||
#endif /* INCLUDE_BOOST_MYSQL_DETAIL_AUTH_CACHING_SHA2_PASSWORD_HPP_ */
|
||||
|
||||
74
include/boost/mysql/detail/auth/impl/auth_calculator.ipp
Normal file
74
include/boost/mysql/detail/auth/impl/auth_calculator.ipp
Normal file
@@ -0,0 +1,74 @@
|
||||
#ifndef INCLUDE_BOOST_MYSQL_DETAIL_AUTH_IMPL_AUTH_CALCULATOR_IPP_
|
||||
#define INCLUDE_BOOST_MYSQL_DETAIL_AUTH_IMPL_AUTH_CALCULATOR_IPP_
|
||||
|
||||
#include "boost/mysql/detail/auth/mysql_native_password.hpp"
|
||||
#include "boost/mysql/detail/auth/caching_sha2_password.hpp"
|
||||
|
||||
namespace boost {
|
||||
namespace mysql {
|
||||
namespace detail {
|
||||
|
||||
constexpr authentication_plugin mysql_native_password_plugin {
|
||||
"mysql_native_password",
|
||||
&mysql_native_password::compute_response
|
||||
};
|
||||
|
||||
constexpr authentication_plugin caching_sha2_password_plugin {
|
||||
"caching_sha2_password",
|
||||
&caching_sha2_password::compute_response
|
||||
};
|
||||
|
||||
constexpr std::array<const authentication_plugin*, 2> all_authentication_plugins {
|
||||
&mysql_native_password_plugin,
|
||||
&caching_sha2_password_plugin
|
||||
};
|
||||
|
||||
} // detail
|
||||
} // mysql
|
||||
} // boost
|
||||
|
||||
inline const boost::mysql::detail::authentication_plugin*
|
||||
boost::mysql::detail::auth_calculator::find_plugin(
|
||||
std::string_view name
|
||||
)
|
||||
{
|
||||
auto it = std::find_if(
|
||||
all_authentication_plugins.begin(),
|
||||
all_authentication_plugins.end(),
|
||||
[name](const authentication_plugin* plugin) { return plugin->name == name; }
|
||||
);
|
||||
return it == std::end(all_authentication_plugins) ? nullptr : *it;
|
||||
}
|
||||
|
||||
inline boost::mysql::error_code
|
||||
boost::mysql::detail::auth_calculator::calculate(
|
||||
std::string_view plugin_name,
|
||||
std::string_view password,
|
||||
std::string_view challenge,
|
||||
bool use_ssl
|
||||
)
|
||||
{
|
||||
|
||||
plugin_ = find_plugin(plugin_name);
|
||||
if (plugin_)
|
||||
{
|
||||
// Blank password: we should just return an empty auth string
|
||||
if (password.empty())
|
||||
{
|
||||
response_ = "";
|
||||
return error_code();
|
||||
}
|
||||
else
|
||||
{
|
||||
return plugin_->calculator(password, challenge, use_ssl, response_);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return make_error_code(errc::unknown_auth_plugin);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
#endif /* INCLUDE_BOOST_MYSQL_DETAIL_AUTH_IMPL_AUTH_CALCULATOR_IPP_ */
|
||||
@@ -1,10 +1,21 @@
|
||||
#ifndef INCLUDE_BOOST_MYSQL_DETAIL_AUTH_IMPL_CACHING_SHA2_PASSWORD_HPP_
|
||||
#define INCLUDE_BOOST_MYSQL_DETAIL_AUTH_IMPL_CACHING_SHA2_PASSWORD_HPP_
|
||||
#ifndef INCLUDE_BOOST_MYSQL_DETAIL_AUTH_IMPL_CACHING_SHA2_PASSWORD_IPP_
|
||||
#define INCLUDE_BOOST_MYSQL_DETAIL_AUTH_IMPL_CACHING_SHA2_PASSWORD_IPP_
|
||||
|
||||
#include <openssl/sha.h>
|
||||
#include <cstring>
|
||||
|
||||
inline void boost::mysql::detail::caching_sha2_password::compute_auth_string(
|
||||
namespace boost {
|
||||
namespace mysql {
|
||||
namespace detail {
|
||||
namespace caching_sha2_password {
|
||||
|
||||
constexpr std::size_t challenge_length = 20;
|
||||
constexpr std::size_t response_length = 32;
|
||||
constexpr std::string_view perform_full_auth = "\4";
|
||||
|
||||
// challenge must point to challenge_length bytes of data
|
||||
// output must point to response_length bytes of data
|
||||
inline void compute_auth_string(
|
||||
std::string_view password,
|
||||
const void* challenge,
|
||||
void* output
|
||||
@@ -34,6 +45,49 @@ inline void boost::mysql::detail::caching_sha2_password::compute_auth_string(
|
||||
}
|
||||
}
|
||||
|
||||
} // caching_sha2_password
|
||||
} // detail
|
||||
} // mysql
|
||||
} // boost
|
||||
|
||||
|
||||
#endif /* INCLUDE_BOOST_MYSQL_DETAIL_AUTH_IMPL_CACHING_SHA2_PASSWORD_HPP_ */
|
||||
|
||||
inline boost::mysql::error_code
|
||||
boost::mysql::detail::caching_sha2_password::compute_response(
|
||||
std::string_view password,
|
||||
std::string_view challenge,
|
||||
bool use_ssl,
|
||||
std::string& output
|
||||
)
|
||||
{
|
||||
if (challenge == perform_full_auth)
|
||||
{
|
||||
if (!use_ssl)
|
||||
{
|
||||
return make_error_code(errc::auth_plugin_requires_ssl);
|
||||
}
|
||||
output = password;
|
||||
output.push_back(0);
|
||||
return error_code();
|
||||
}
|
||||
else
|
||||
{
|
||||
// Check challenge size
|
||||
if (challenge.size() != challenge_length)
|
||||
{
|
||||
return make_error_code(errc::protocol_value_error);
|
||||
}
|
||||
|
||||
// Do the calculation
|
||||
output.resize(response_length);
|
||||
compute_auth_string(
|
||||
password,
|
||||
challenge.data(),
|
||||
output.data()
|
||||
);
|
||||
return error_code();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#endif /* INCLUDE_BOOST_MYSQL_DETAIL_AUTH_IMPL_CACHING_SHA2_PASSWORD_IPP_ */
|
||||
@@ -4,8 +4,18 @@
|
||||
#include <openssl/sha.h>
|
||||
#include <cstring>
|
||||
|
||||
namespace boost {
|
||||
namespace mysql {
|
||||
namespace detail {
|
||||
namespace mysql_native_password {
|
||||
|
||||
constexpr std::size_t challenge_length = 20;
|
||||
constexpr std::size_t response_length = 20;
|
||||
|
||||
// challenge must point to challenge_length bytes of data
|
||||
// output must point to response_length bytes of data
|
||||
// SHA1( password ) XOR SHA1( "20-bytes random data from server" <concat> SHA1( SHA1( password ) ) )
|
||||
inline void boost::mysql::detail::mysql_native_password::compute_auth_string(
|
||||
inline void compute_auth_string(
|
||||
std::string_view password,
|
||||
const void* challenge,
|
||||
void* output
|
||||
@@ -31,8 +41,36 @@ inline void boost::mysql::detail::mysql_native_password::compute_auth_string(
|
||||
}
|
||||
}
|
||||
|
||||
} // mysql_native_password
|
||||
} // detail
|
||||
} // mysql
|
||||
} // boost
|
||||
|
||||
|
||||
inline boost::mysql::error_code
|
||||
boost::mysql::detail::mysql_native_password::compute_response(
|
||||
std::string_view password,
|
||||
std::string_view challenge,
|
||||
bool, // use_ssl
|
||||
std::string& output
|
||||
)
|
||||
{
|
||||
// Check challenge size
|
||||
if (challenge.size() != challenge_length)
|
||||
{
|
||||
return make_error_code(errc::protocol_value_error);
|
||||
}
|
||||
|
||||
// Do the calculation
|
||||
output.resize(response_length);
|
||||
compute_auth_string(
|
||||
password,
|
||||
challenge.data(),
|
||||
output.data()
|
||||
);
|
||||
return error_code();
|
||||
}
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
@@ -3,20 +3,21 @@
|
||||
|
||||
#include <cstdint>
|
||||
#include <string_view>
|
||||
#include <array>
|
||||
#include "boost/mysql/error.hpp"
|
||||
|
||||
namespace boost {
|
||||
namespace mysql {
|
||||
namespace detail {
|
||||
namespace mysql_native_password {
|
||||
|
||||
constexpr const char* plugin_name = "mysql_native_password";
|
||||
constexpr std::size_t challenge_length = 20;
|
||||
constexpr std::size_t response_length = 20;
|
||||
|
||||
// challenge must point to challenge_length bytes of data
|
||||
// output must point to response_length bytes of data
|
||||
inline void compute_auth_string(std::string_view password, const void* challenge, void* output);
|
||||
// Authorization for this plugin is always challenge (nonce) -> response
|
||||
// (hashed password).
|
||||
inline error_code compute_response(
|
||||
std::string_view password,
|
||||
std::string_view challenge,
|
||||
bool use_ssl,
|
||||
std::string& output
|
||||
);
|
||||
|
||||
|
||||
} // mysql_native_password
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
#include "boost/mysql/detail/network_algorithms/common.hpp"
|
||||
#include "boost/mysql/detail/protocol/capabilities.hpp"
|
||||
#include "boost/mysql/detail/protocol/handshake_messages.hpp"
|
||||
#include "boost/mysql/detail/auth/auth.hpp"
|
||||
#include "boost/mysql/detail/auth/auth_calculator.hpp"
|
||||
#include <boost/asio/yield.hpp>
|
||||
|
||||
namespace boost {
|
||||
@@ -45,6 +45,16 @@ inline error_code deserialize_handshake(
|
||||
return deserialize_message(output, ctx);
|
||||
}
|
||||
|
||||
// When receiving an auth response from the server, several things can happen:
|
||||
// - An OK packet. It means we are done with the auth phase. auth_result::complete.
|
||||
// - An auth switch response. It means we should change the auth plugin,
|
||||
// recalculate the auth response and send it back. auth_result::send_more_data.
|
||||
// - An auth more data. Same as auth switch response, but without changing
|
||||
// the authentication plugin. Also auth_result::send_more_data.
|
||||
// - An auth more data with a challenge equals to fast_auth_complete_challenge.
|
||||
// This means auth is complete and we should wait for an OK packet (auth_result::wait_for_ok).
|
||||
// I have no clue why the server sends this instead of just an OK packet. It
|
||||
// happens just for caching_sha2_password.
|
||||
enum class auth_result
|
||||
{
|
||||
complete,
|
||||
@@ -57,7 +67,7 @@ class handshake_processor
|
||||
{
|
||||
connection_params params_;
|
||||
capabilities negotiated_caps_;
|
||||
auth_response_calculator auth_calc_;
|
||||
auth_calculator auth_calc_;
|
||||
public:
|
||||
handshake_processor(const connection_params& params): params_(params) {};
|
||||
capabilities negotiated_capabilities() const noexcept { return negotiated_caps_; }
|
||||
@@ -125,7 +135,7 @@ public:
|
||||
string_null(params_.username()),
|
||||
string_lenenc(auth_calc_.response()),
|
||||
string_null(params_.database()),
|
||||
string_null(auth_calc_.get_plugin_name())
|
||||
string_null(auth_calc_.plugin_name())
|
||||
};
|
||||
|
||||
// Serialize
|
||||
@@ -183,26 +193,27 @@ public:
|
||||
err = deserialize_message(more_data, ctx);
|
||||
if (err) return err;
|
||||
|
||||
// TODO: refactor this
|
||||
std::string_view data = more_data.auth_plugin_data.value;
|
||||
if (data.size() == 1 && data[0] == 3)
|
||||
std::string_view challenge = more_data.auth_plugin_data.value;
|
||||
if (challenge == fast_auth_complete_challenge)
|
||||
{
|
||||
result = auth_result::wait_for_ok;
|
||||
return error_code();
|
||||
}
|
||||
|
||||
// Compute response
|
||||
auth_switch_response_packet auth_sw_res;
|
||||
err = auth_calc_.calculate(
|
||||
auth_calc_.get_plugin_name(),
|
||||
auth_calc_.plugin_name(),
|
||||
params_.password(),
|
||||
more_data.auth_plugin_data.value,
|
||||
challenge,
|
||||
use_ssl()
|
||||
);
|
||||
if (err) return err;
|
||||
|
||||
auth_sw_res.auth_plugin_data.value = auth_calc_.response();
|
||||
serialize_message(auth_sw_res, negotiated_caps_, buffer);
|
||||
serialize_message(
|
||||
auth_switch_response_packet {string_eof(auth_calc_.response())},
|
||||
negotiated_caps_,
|
||||
buffer
|
||||
);
|
||||
|
||||
result = auth_result::send_more_data;
|
||||
return error_code();
|
||||
|
||||
@@ -64,6 +64,7 @@ constexpr std::uint8_t ok_packet_header = 0x00;
|
||||
constexpr std::uint8_t eof_packet_header = 0xfe;
|
||||
constexpr std::uint8_t auth_switch_request_header = 0xfe;
|
||||
constexpr std::uint8_t auth_more_data_header = 0x01;
|
||||
constexpr std::string_view fast_auth_complete_challenge = "\3";
|
||||
|
||||
// Column flags
|
||||
namespace column_flags
|
||||
|
||||
@@ -17,8 +17,7 @@ endif()
|
||||
# of the runtime penalty (specially considerable in integration tests)
|
||||
add_executable(
|
||||
mysql_unittests
|
||||
unit/detail/auth/mysql_native_password.cpp
|
||||
unit/detail/auth/caching_sha2_password.cpp
|
||||
unit/detail/auth/auth_calculator.cpp
|
||||
unit/detail/protocol/serialization_test_common.cpp
|
||||
unit/detail/protocol/serialization.cpp
|
||||
unit/detail/protocol/common_messages.cpp
|
||||
|
||||
174
test/unit/detail/auth/auth_calculator.cpp
Normal file
174
test/unit/detail/auth/auth_calculator.cpp
Normal file
@@ -0,0 +1,174 @@
|
||||
|
||||
#include "boost/mysql/detail/auth/auth_calculator.hpp"
|
||||
#include "test_common.hpp"
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
using namespace boost::mysql::detail;
|
||||
using namespace boost::mysql::test;
|
||||
using namespace testing;
|
||||
using boost::mysql::error_code;
|
||||
using boost::mysql::errc;
|
||||
|
||||
namespace
|
||||
{
|
||||
|
||||
// mysql_native_password
|
||||
struct MysqlNativePasswordTest : public Test
|
||||
{
|
||||
auth_calculator calc;
|
||||
std::uint8_t challenge_buffer [20] {
|
||||
0x79, 0x64, 0x3d, 0x12, 0x1d, 0x71, 0x74, 0x47,
|
||||
0x5f, 0x48, 0x3e, 0x3e, 0x0b, 0x62, 0x0a, 0x03,
|
||||
0x3d, 0x27, 0x3a, 0x4c
|
||||
}; // Values snooped using Wireshark
|
||||
std::uint8_t expected_buffer [20] {
|
||||
0xf1, 0xb2, 0xfb, 0x1c, 0x8d, 0xe7, 0x5d, 0xb8,
|
||||
0xeb, 0xa8, 0x12, 0x6a, 0xd1, 0x0f, 0xe9, 0xb1,
|
||||
0x10, 0x50, 0xd4, 0x28
|
||||
};
|
||||
std::string_view challenge = makesv(challenge_buffer);
|
||||
std::string_view expected = makesv(expected_buffer);
|
||||
};
|
||||
|
||||
TEST_F(MysqlNativePasswordTest, NonEmptyPasswordSslFalse_ReturnsExpectedHash)
|
||||
{
|
||||
auto err = calc.calculate("mysql_native_password", "root", challenge, false);
|
||||
EXPECT_EQ(err, error_code());
|
||||
EXPECT_EQ(calc.response(), expected);
|
||||
EXPECT_EQ(calc.plugin_name(), "mysql_native_password");
|
||||
}
|
||||
|
||||
TEST_F(MysqlNativePasswordTest, NonEmptyPasswordSslTrue_ReturnsExpectedHash)
|
||||
{
|
||||
auto err = calc.calculate("mysql_native_password", "root", challenge, true);
|
||||
EXPECT_EQ(err, error_code());
|
||||
EXPECT_EQ(calc.response(), expected);
|
||||
EXPECT_EQ(calc.plugin_name(), "mysql_native_password");
|
||||
}
|
||||
|
||||
TEST_F(MysqlNativePasswordTest, EmptyPasswordSslFalse_ReturnsEmpty)
|
||||
{
|
||||
auto err = calc.calculate("mysql_native_password", "", challenge, false);
|
||||
EXPECT_EQ(err, error_code());
|
||||
EXPECT_EQ(calc.response(), "");
|
||||
EXPECT_EQ(calc.plugin_name(), "mysql_native_password");
|
||||
}
|
||||
|
||||
TEST_F(MysqlNativePasswordTest, EmptyPasswordSslTrue_ReturnsEmpty)
|
||||
{
|
||||
auto err = calc.calculate("mysql_native_password", "", challenge, false);
|
||||
EXPECT_EQ(err, error_code());
|
||||
EXPECT_EQ(calc.response(), "");
|
||||
EXPECT_EQ(calc.plugin_name(), "mysql_native_password");
|
||||
}
|
||||
|
||||
TEST_F(MysqlNativePasswordTest, BadChallengeLength_Fail)
|
||||
{
|
||||
EXPECT_EQ((calc.calculate("mysql_native_password", "password", "", true)),
|
||||
make_error_code(errc::protocol_value_error));
|
||||
EXPECT_EQ((calc.calculate("mysql_native_password", "password", "bad_challenge", true)),
|
||||
make_error_code(errc::protocol_value_error));
|
||||
}
|
||||
|
||||
// caching_sha2_password
|
||||
struct CachingSha2PasswordTest : public Test
|
||||
{
|
||||
auth_calculator calc;
|
||||
std::uint8_t challenge_buffer [20] {
|
||||
0x3e, 0x3b, 0x4, 0x55, 0x4, 0x70, 0x16, 0x3a,
|
||||
0x4c, 0x15, 0x35, 0x3, 0x15, 0x76, 0x73, 0x22,
|
||||
0x46, 0x8, 0x18, 0x1
|
||||
}; // Values snooped using the MySQL Python connector
|
||||
std::uint8_t expected_buffer [32] {
|
||||
0xa1, 0xc1, 0xe1, 0xe9, 0x1b, 0xb6, 0x54, 0x4b,
|
||||
0xa7, 0x37, 0x4b, 0x9c, 0x56, 0x6d, 0x69, 0x3e,
|
||||
0x6, 0xca, 0x7, 0x2, 0x98, 0xac, 0xd1, 0x6,
|
||||
0x18, 0xc6, 0x90, 0x38, 0x9d, 0x88, 0xe1, 0x20
|
||||
};
|
||||
std::string_view challenge = makesv(challenge_buffer);
|
||||
std::string_view expected = makesv(expected_buffer);
|
||||
std::string_view cleartext_challenge { "\4" };
|
||||
};
|
||||
|
||||
TEST_F(CachingSha2PasswordTest, NonEmptyPasswordChallengeAuthSslFalse_ReturnsExpectedHash)
|
||||
{
|
||||
auto err = calc.calculate("caching_sha2_password", "hola", challenge, false);
|
||||
EXPECT_EQ(err, error_code());
|
||||
EXPECT_EQ(calc.response(), expected);
|
||||
EXPECT_EQ(calc.plugin_name(), "caching_sha2_password");
|
||||
}
|
||||
|
||||
TEST_F(CachingSha2PasswordTest, NonEmptyPasswordChallengeAuthSslTrue_ReturnsExpectedHash)
|
||||
{
|
||||
auto err = calc.calculate("caching_sha2_password", "hola", challenge, true);
|
||||
EXPECT_EQ(err, error_code());
|
||||
EXPECT_EQ(calc.response(), expected);
|
||||
EXPECT_EQ(calc.plugin_name(), "caching_sha2_password");
|
||||
}
|
||||
|
||||
TEST_F(CachingSha2PasswordTest, NonEmptyPasswordCleartextAuthSslFalse_Fail)
|
||||
{
|
||||
auto err = calc.calculate("caching_sha2_password", "hola", cleartext_challenge, false);
|
||||
EXPECT_EQ(err, make_error_code(errc::auth_plugin_requires_ssl));
|
||||
}
|
||||
|
||||
TEST_F(CachingSha2PasswordTest, NonEmptyPasswordCleartextAuthSslTrue_ReturnsPassword)
|
||||
{
|
||||
auto err = calc.calculate("caching_sha2_password", "hola", cleartext_challenge, true);
|
||||
EXPECT_EQ(err, error_code());
|
||||
EXPECT_EQ(calc.response(), std::string("hola") + '\0');
|
||||
EXPECT_EQ(calc.plugin_name(), "caching_sha2_password");
|
||||
}
|
||||
|
||||
TEST_F(CachingSha2PasswordTest, EmptyPasswordChallengeAuthSslFalse_ReturnsEmpty)
|
||||
{
|
||||
auto err = calc.calculate("caching_sha2_password", "", challenge, false);
|
||||
EXPECT_EQ(err, error_code());
|
||||
EXPECT_EQ(calc.response(), "");
|
||||
EXPECT_EQ(calc.plugin_name(), "caching_sha2_password");
|
||||
}
|
||||
|
||||
TEST_F(CachingSha2PasswordTest, EmptyPasswordChallengeAuthSslTrue_ReturnsEmpty)
|
||||
{
|
||||
auto err = calc.calculate("caching_sha2_password", "", challenge, true);
|
||||
EXPECT_EQ(err, error_code());
|
||||
EXPECT_EQ(calc.response(), "");
|
||||
EXPECT_EQ(calc.plugin_name(), "caching_sha2_password");
|
||||
}
|
||||
|
||||
TEST_F(CachingSha2PasswordTest, EmptyPasswordCleartextAuthSslFalse_ReturnsEmpty)
|
||||
{
|
||||
auto err = calc.calculate("caching_sha2_password", "", cleartext_challenge, false);
|
||||
EXPECT_EQ(err, error_code());
|
||||
EXPECT_EQ(calc.response(), "");
|
||||
EXPECT_EQ(calc.plugin_name(), "caching_sha2_password");
|
||||
}
|
||||
|
||||
TEST_F(CachingSha2PasswordTest, EmptyPasswordCleartextAuthSslTrue_ReturnsEmpty)
|
||||
{
|
||||
auto err = calc.calculate("caching_sha2_password", "", cleartext_challenge, true);
|
||||
EXPECT_EQ(err, error_code());
|
||||
EXPECT_EQ(calc.response(), "");
|
||||
EXPECT_EQ(calc.plugin_name(), "caching_sha2_password");
|
||||
}
|
||||
|
||||
TEST_F(CachingSha2PasswordTest, BadChallengeLength_Fail)
|
||||
{
|
||||
EXPECT_EQ((calc.calculate("caching_sha2_password", "password", "", true)),
|
||||
make_error_code(errc::protocol_value_error));
|
||||
EXPECT_EQ((calc.calculate("caching_sha2_password", "password", "bad_challenge", true)),
|
||||
make_error_code(errc::protocol_value_error));
|
||||
}
|
||||
|
||||
// Bad authentication plugin
|
||||
TEST(AuthCalculator, UnknownAuthPlugin_Fail)
|
||||
{
|
||||
auth_calculator calc;
|
||||
EXPECT_EQ((calc.calculate("bad_plugin", "password", "challenge", true)),
|
||||
make_error_code(errc::unknown_auth_plugin));
|
||||
EXPECT_EQ((calc.calculate("", "password", "challenge", true)),
|
||||
make_error_code(errc::unknown_auth_plugin));
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -1,27 +0,0 @@
|
||||
|
||||
#include "boost/mysql/detail/auth/caching_sha2_password.hpp"
|
||||
#include <gtest/gtest.h>
|
||||
#include <array>
|
||||
|
||||
using namespace boost::mysql::detail;
|
||||
|
||||
TEST(CachingSha2Password, ComputeAuthString_NonEmptyPassword_ReturnsExpectedHash)
|
||||
{
|
||||
// Values snooped using the MySQL Python connector
|
||||
std::array<std::uint8_t, caching_sha2_password::challenge_length> challenge {
|
||||
0x3e, 0x3b, 0x4, 0x55, 0x4, 0x70, 0x16, 0x3a,
|
||||
0x4c, 0x15, 0x35, 0x3, 0x15, 0x76, 0x73, 0x22,
|
||||
0x46, 0x8, 0x18, 0x1
|
||||
};
|
||||
std::array<std::uint8_t, caching_sha2_password::response_length> expected {
|
||||
0xa1, 0xc1, 0xe1, 0xe9, 0x1b, 0xb6, 0x54, 0x4b,
|
||||
0xa7, 0x37, 0x4b, 0x9c, 0x56, 0x6d, 0x69, 0x3e,
|
||||
0x6, 0xca, 0x7, 0x2, 0x98, 0xac, 0xd1, 0x6,
|
||||
0x18, 0xc6, 0x90, 0x38, 0x9d, 0x88, 0xe1, 0x20
|
||||
};
|
||||
std::array<std::uint8_t, caching_sha2_password::response_length> actual {};
|
||||
const char* password = "hola";
|
||||
caching_sha2_password::compute_auth_string(password, challenge.data(), actual.data());
|
||||
EXPECT_EQ(expected, actual);
|
||||
}
|
||||
|
||||
@@ -1,37 +0,0 @@
|
||||
/*
|
||||
* auth.cpp
|
||||
*
|
||||
* Created on: Oct 21, 2019
|
||||
* Author: ruben
|
||||
*/
|
||||
|
||||
#include "boost/mysql/detail/auth/mysql_native_password.hpp"
|
||||
#include <gtest/gtest.h>
|
||||
#include <array>
|
||||
|
||||
using namespace boost::mysql::detail;
|
||||
using namespace testing;
|
||||
|
||||
namespace
|
||||
{
|
||||
|
||||
TEST(MysqlNativePassword, ComputeAuthString_NonEmptyPassword_ReturnsExpectedHash)
|
||||
{
|
||||
// Values snooped using Wireshark
|
||||
std::array<std::uint8_t, mysql_native_password::challenge_length> challenge {
|
||||
0x79, 0x64, 0x3d, 0x12, 0x1d, 0x71, 0x74, 0x47,
|
||||
0x5f, 0x48, 0x3e, 0x3e, 0x0b, 0x62, 0x0a, 0x03,
|
||||
0x3d, 0x27, 0x3a, 0x4c
|
||||
};
|
||||
std::array<std::uint8_t, mysql_native_password::response_length> expected {
|
||||
0xf1, 0xb2, 0xfb, 0x1c, 0x8d, 0xe7, 0x5d, 0xb8,
|
||||
0xeb, 0xa8, 0x12, 0x6a, 0xd1, 0x0f, 0xe9, 0xb1,
|
||||
0x10, 0x50, 0xd4, 0x28
|
||||
};
|
||||
std::array<std::uint8_t, mysql_native_password::response_length> actual {};
|
||||
const char* password = "root";
|
||||
mysql_native_password::compute_auth_string(password, challenge.data(), actual.data());
|
||||
EXPECT_EQ(expected, actual);
|
||||
}
|
||||
|
||||
} // anon namespace
|
||||
@@ -205,5 +205,13 @@ INSTANTIATE_TEST_SUITE_P(SslRequest, SerializeTest, ::testing::Values(
|
||||
}, "default")
|
||||
), test_name_generator);
|
||||
|
||||
INSTANTIATE_TEST_SUITE_P(AuthMoreData, DeserializeTest, ::testing::Values(
|
||||
serialization_testcase(auth_more_data_packet{
|
||||
string_eof("abc")
|
||||
}, {
|
||||
0x61, 0x62, 0x63
|
||||
}, "default")
|
||||
), test_name_generator);
|
||||
|
||||
|
||||
} // anon namespace
|
||||
|
||||
Reference in New Issue
Block a user