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
49 changes: 49 additions & 0 deletions src/minimysql/connection_context.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -178,6 +178,43 @@ void connection_context::parse_client_greeting(
client_attributes_ = client_greeting.attributes();
}

[[nodiscard]] network_buffer_type
connection_context::generate_encoded_auth_method_switch() {
std::string result_buffer{};

classic_protocol::message::server::AuthMethodSwitch auth_method_switch{
get_server_auth_method(), generate_server_auth_method_switch_data()};
using auth_method_switch_frame = classic_protocol::frame::Frame<
classic_protocol::message::server::AuthMethodSwitch>;
auto encode_result{classic_protocol::encode<auth_method_switch_frame>(
{generate_sequence_number(), auth_method_switch},
get_shared_capabilities(), boost::asio::dynamic_buffer(result_buffer))};

if (!encode_result) {
throw boost::system::system_error{encode_result.error()};
}
return result_buffer;
}

void connection_context::parse_client_auth_method_data(
const network_buffer_type &payload) {
auto buffer{boost::asio::buffer(payload)};
using auth_method_data_frame = classic_protocol::frame::Frame<
classic_protocol::message::client::AuthMethodData>;
auto decode_result{classic_protocol::decode<auth_method_data_frame>(
buffer, get_shared_capabilities())};
if (!decode_result) {
throw boost::system::system_error{decode_result.error()};
}

validate_and_update_sequence_number(decode_result.value().second.seq_id());

// after the auth method switch the client uses the server's auth method
client_auth_method_ = server_auth_method_;
client_auth_method_data_ =
decode_result.value().second.payload().auth_method_data();
}

[[nodiscard]] network_buffer_type
connection_context::generate_encoded_fast_auth() {
std::string result_buffer{};
Expand Down Expand Up @@ -429,6 +466,18 @@ connection_context::generate_server_auth_method_data() {
return server_auth_method_data_;
}

[[nodiscard]] std::string
connection_context::generate_server_auth_method_switch_data() const {
if (get_server_auth_method() ==
caching_sha2_password_authenticator::plugin_name) {
// caching_sha2_password follows the historical handshake seed shape:
// 20 bytes of challenge data plus a trailing NUL filler.
return get_server_auth_method_data() + '\0';
}

return get_server_auth_method_data();
}

[[nodiscard]] std::uint8_t connection_context::generate_sequence_number() {
return sequence_number_++;
}
Expand Down
4 changes: 4 additions & 0 deletions src/minimysql/connection_context.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,9 @@ class connection_context {
[[nodiscard]] network_buffer_type generate_encoded_server_greeting();
void parse_client_greeting(const network_buffer_type &payload);

[[nodiscard]] network_buffer_type generate_encoded_auth_method_switch();
void parse_client_auth_method_data(const network_buffer_type &payload);

[[nodiscard]] network_buffer_type generate_encoded_fast_auth();
[[nodiscard]] network_buffer_type generate_encoded_ok();
[[nodiscard]] network_buffer_type generate_encoded_eof();
Expand Down Expand Up @@ -228,6 +231,7 @@ class connection_context {
[[nodiscard]] static capability_bitset
get_default_server_capabilities() noexcept;
[[nodiscard]] const std::string &generate_server_auth_method_data();
[[nodiscard]] std::string generate_server_auth_method_switch_data() const;
[[nodiscard]] std::uint8_t generate_sequence_number();
void validate_and_update_sequence_number(std::uint8_t sequence_number);

Expand Down
24 changes: 22 additions & 2 deletions src/minimysql/network_service.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -291,8 +291,28 @@ void handle_exception(std::string_view context) {
<< " authentication that does not match the one associated "
"with the user account ("
<< context.get_server_auth_method() << ")\n";
// TODO: send SwitchAuthentication packet
co_return;

const auto auth_method_switch{
context.generate_encoded_auth_method_switch()};
print_generic(remote_endpoint, context, "auth method switch");
co_await minimysql::async_write_mysql_frame(
socket, auth_method_switch,
network_service::session_authentication_timeout);
std::cout << "sent server auth method switch ("
<< std::size(auth_method_switch) << " bytes to "
<< remote_endpoint << ")\n";

co_await minimysql::async_read_mysql_frame(
socket, data, network_service::session_authentication_timeout);
std::cout << "received client auth method switch response ("
<< std::size(data) << " bytes from " << remote_endpoint
<< ")\n";
context.parse_client_auth_method_data(data);
std::cout << "client auth method after switch: "
<< context.get_client_auth_method() << '\n'
<< " auth_method_data: "
<< std::size(context.get_client_auth_method_data())
<< " byte(s)\n";
}
if (!context.check_client_authentication()) {
std::cout << "client authentication failed for "
Expand Down
Loading