-
Notifications
You must be signed in to change notification settings - Fork 67
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Enable cleartext plugin #176
Changes from 1 commit
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -78,6 +78,23 @@ defmodule MyXQL.ClientTest do | |
Client.com_quit(client) | ||
end | ||
|
||
# mysql_clear_password | ||
|
||
test "mysql_clear_password" do | ||
opts = [username: "mysql_clear", password: "secret", enable_cleartext_plugin: true] ++ @opts | ||
%{port: port} = start_cleartext_fake_server() | ||
opts = Keyword.put(opts, :port, port) | ||
assert {:ok, client} = Client.connect(opts) | ||
Client.com_quit(client) | ||
end | ||
|
||
test "mysql_clear_password (bad password)" do | ||
opts = [username: "mysql_clear", password: "bad", enable_cleartext_plugin: true] ++ @opts | ||
%{port: port} = start_cleartext_fake_server() | ||
opts = Keyword.put(opts, :port, port) | ||
{:error, err_packet(message: "Access denied" <> _)} = Client.connect(opts) | ||
end | ||
|
||
# sha256_password | ||
|
||
@tag sha256_password: true, public_key_exchange: true | ||
|
@@ -447,4 +464,57 @@ defmodule MyXQL.ClientTest do | |
|
||
%{pid: pid, port: port} | ||
end | ||
|
||
|
||
defp start_cleartext_fake_server() do | ||
start_fake_server(fn %{accept_socket: sock} -> | ||
initial_handshake = | ||
<<74, 0, 0, 0, 10, 56, 46, 48, 46, 51, 53, 0, 127, 24, 4, 0, 93, 42, 61, 27, 60, | ||
38, 85, 12, 0, 255, 255, 255, 2, 0, 255, 223, 21, 0, 0, 0, 0, 0, 0, 0, 0, 0, | ||
0, 39, 48, 10, 117, 54, 65, 74, 37, 125, 121, 93, 6, 0, 109, 121, 115, 113, | ||
108, 95, 110, 97, 116, 105, 118, 101, 95, 112, 97, 115, 115, 119, 111, 114, | ||
100, 0>> | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. this is tough to understand and maintain. Could you break it down to along the lines of: [
<<74, 0, 0, 0>>,
[
# protocol version, always 0x10
10,
# server version
<<"8.0.35", 0>>,
# ...
]
] I'm really curious to see where exactly the scramble was supposed to be and is empty. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Sure, but just FYI this part doesn't matter. It's just priming the connection with a scramble, that we are going to make (knowingly) an unsuccesful authentication with. When that fails we continue with the cleartext password. This came from painfully figuring out why I couldn't just send the cleartext password with the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I decided to just add comments to each packet rather than expanding the packets. There's not really much to expand on within the packets, but this will definitely help others understand how this works. |
||
|
||
client_auth_response = | ||
<<98, 0, 0, 1, 10, 162, 11, 0, 255, 255, 255, 0, 45, 0, 0, 0, 0, 0, 0, 0, 0, 0, | ||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 109, 121, 115, 113, 108, 95, 99, | ||
108, 101, 97, 114, 0, 20, 254, 122, 75, 71, 45, 200, 185, 238, 55, 229, 170, | ||
5, 207, 204, 65, 246, 243, 144, 91, 183, 109, 121, 120, 113, 108, 95, 116, | ||
101, 115, 116, 0, 109, 121, 115, 113, 108, 95, 110, 97, 116, 105, 118, 101, | ||
95, 112, 97, 115, 115, 119, 111, 114, 100, 0>> | ||
|
||
switch_auth_response = | ||
<<22, 0, 0, 2, 254, 109, 121, 115, 113, 108, 95, 99, 108, 101, 97, 114, 95, 112, | ||
97, 115, 115, 119, 111, 114, 100, 0>> | ||
|
||
client_switch_auth_response = | ||
<<7, 0, 0, 3, 115, 101, 99, 114, 101, 116, 0>> | ||
|
||
ok_response = | ||
<<7, 0, 0, 4, 0, 0, 0, 2, 0, 0, 0>> | ||
|
||
client_quit = <<1, 0, 0, 0, 1>> | ||
|
||
auth_response_invalid = | ||
<<83, 0, 0, 1, 255, 21, 4, 35, 50, 56, 48, 48, 48, 65, 99, 99, 101, 115, 115, | ||
32, 100, 101, 110, 105, 101, 100, 32, 102, 111, 114, 32, 117, 115, 101, 114, | ||
32, 39, 100, 101, 102, 97, 117, 108, 116, 95, 97, 117, 116, 104, 39, 64, 39, | ||
49, 57, 50, 46, 49, 54, 56, 46, 54, 53, 46, 49, 39, 32, 40, 117, 115, 105, | ||
110, 103, 32, 112, 97, 115, 115, 119, 111, 114, 100, 58, 32, 89, 69, 83, 41>> | ||
|
||
:gen_tcp.send(sock, initial_handshake) | ||
|
||
case :gen_tcp.recv(sock, 0) do | ||
{:ok, ^client_auth_response} -> | ||
:ok = :gen_tcp.send(sock, switch_auth_response) | ||
{:ok, ^client_switch_auth_response} = :gen_tcp.recv(sock, 0) | ||
:ok = :gen_tcp.send(sock, ok_response) | ||
{:ok, ^client_quit} = :gen_tcp.recv(sock, 0) | ||
:ok = :gen_tcp.send(sock, ok_response) | ||
|
||
{:ok, _other} -> | ||
:ok = :gen_tcp.send(sock, auth_response_invalid) | ||
end | ||
end) | ||
end | ||
end |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think matching mysql CLI is a great starting point but curious if any other connectors have something like
auth_plugin: mysql_native_password | caching_sha2_password | ...
. I think that'd be preferred as we'd reuse the same option when we support more methods.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The cleartext password is distinct in that it has no server side library: https://dev.mysql.com/doc/refman/8.0/en/cleartext-pluggable-authentication.html
And especially note this:
This has been an issue with other mysql connectors: sidorares/node-mysql2#1617
Ruby mysql2 sets the env flag for the mysql client it communicates with (but uses the same
enable_cleartext_plugin
flag in config): brianmario/mysql2#845The closest thing there is to decide what auth plugin to use is hinting: https://dev.mysql.com/doc/refman/8.3/en/mysql-command-options.html#option_mysql_default-auth
As I understand it, the way the auth works with cleartext password from the mysql client is that it will always go through the auth switch, and it's after the switch that it's possible to succesfully authenticate. In the case of RDS IAM it will first ask for the
mysql_native_password
and expects the client to send a response for this format (I tried just sending the token itself, but the server wanted a sha1 size response). After this step fails it asks formysql_clear_password
which is what we actually wanted to send.So IMO it doesn't really make sense to treat
mysql_clear_password
the same way as other auth plugin. It's a special case. We could force it on our side by setting something like:auth_plugin
, which arguably is more explicit, but this is not how the mysql client works, and I haven't seen other libraries do this.