-
Notifications
You must be signed in to change notification settings - Fork 2.5k
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
Fix MySQL 8.0.x incompatibilities #1962
base: master
Are you sure you want to change the base?
Fix MySQL 8.0.x incompatibilities #1962
Conversation
This is awesome, thank you soo much! The only real issues I'm seeing with the PR to continue to work on is the following:
|
lib/ConnectionConfig.js
Outdated
'+PROTOCOL_41', // Uses the 4.1 protocol | ||
'+PS_MULTI_RESULTS', // Can handle multiple resultsets for COM_STMT_EXECUTE | ||
'+RESERVED', // Unused | ||
'+SECURE_CONNECTION', // Supports Authentication::Native41 | ||
'+TRANSACTIONS' // Expects status flags | ||
]; | ||
|
||
if (options && options.database) { |
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.
Is this change related specifically to the MySQL 8 support, or just a general fix. Just curious.
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.
For the new authentication magic to happen in the server, we need to explicitly provide the authentication plugin name in the ClientAuthenticationPacket
, and, doing that, we need to be careful of which flags to enable, otherwise the server will, for instance, interpret caching_sha2_password
or mysql_native_password
as the schema/database name, if none is provided.
I didn't want to mess around with the PacketWriter
and this seemed the easiest way to overcome that hurdle. However, we can try to think of something else if it feels weird.
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.
Sure, but I was more curious on if this is a general fix or specific to MySQL 8. But even then, users can pass in their own flags
list, and this module will enable / disable them unless it's listed here with a flag to force one way or the other. If having it set when it shouldn't is an issue, then it should probably be flagged here so the users cannot pass in the flag and get it set when no db is specified.
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.
Actually, maybe this specific change is not required after all. The schema name is a null terminated string, so it should not cause that issue I mentioned. This is sort of a leftover from my earlier experiments. I'll try to work around this and update the patch.
Good catch!
To address your points. Regarding the first one, I've missed those tests (sorry), but as far as I can tell there is no sane way to use RSA public key encryption on Missed the coverage as well, I'll try to fix that ASAP. Again, missed the CI config. Should be fine, at least on Travis. However, besides that, I suggest we also create a test account to run the tests (besides |
Ah, very sad :( Did you do a through search on this (it sounds like it)? Because I can always help if you want to focus on the other parts, but just asking before I duplicate the search for no reason. If we really have to drop supported versions, we can, and it wouldn't particularly delay this, just wanted to make sure it was actually required to do so before saying we should :)
Yea, so in Travis CI it just uses a Docker image. You can make multiple non-root accounts too; the current setup was just what was needed for testing, so if MySQL 8 requires more elaborate setup, that sounds fine to me. I would ignore AppVeyor. |
I'm using There's this node-rsa thingy which apparently is pure JS, but I couldn't make it work and it's pretty slow. I've also seen other approaches like delegating work to openssl via a child process, but that's probably not a good idea either, since it introduces a huge moving part. There's also this forge kit which brings the entire browser kitchen sink with it and I also haven't managed to figure out how it worked. In any case, most of these things, when they work, it's usually on node My suggestion here is to fail with a client error (the However, if you still feel you are better off bumping the major version, that's fine. |
@dougwilson what's your preference about the issue I mentioned? Do you want me to add the workaround for older node.js versions or do you think it's better to have a major version bump (in that case I guess all we need is to remove the CI setup for older versions)? |
Sorry I didn't reply. Your comment on a new issue reminded me of this. Yea that works: if the server requires an auth that the client can't do we can error out. We should feature detect that, though, not sniff the version string. |
Ok. Just to be sure, are you talking about sniffing the Node.js version string, MySQL version string, or both? Because we have two different issues right now. Supporting MySQL 8.0.4 (previous DMR release) which expects the password to be encrypted with the server public key using Regarding the Node.js encryption APIs, I guess we can always resort to duck typing to check if they are available (or not) instead of sniffing the version. So, no problem here. Let me know if there is something else that bothers you about these or other issues. I'll try to push this forward ASAP. Maybe during the weekend. |
Why do you have to sniff the server version? Shouldn't the server say which one it expects directly? I'm just asking because I think version numbers break down when we start talking about compatible things like MariaDB, right? They may share some version numbers. I have done Node.js version sniffing before and when it broke the Node.js collaborators just said I should never have been version sniffing their versions and told me feature detect only. So if that is the official direction from there I would go with that. |
The case where we might need to sniff the server version is to distinguish MySQL 8.0.10 (pre GA, first one introduced chaching_sha1_passwors) from MySQL 8.0.11 (GA). since 8.0.11 was released yesterday one also could not support 8.0.10, as nobody should be using that RC anyways.
jojannes
…On April 20, 2018 1:38:35 PM GMT+02:00, Douglas Wilson ***@***.***> wrote:
Sorry I didn't reply. Your comment on a new issue reminded me of this.
Yea that works: if the server requires an auth that the client can't do
we can error out. We should feature detect that, though, not sniff the
version string.
|
Right. However, in this case we would be sort of "whitelisting" MySQL 8.0.4 specifically. I don't think MariaDB has this new authentication plugin (enabled by default or not), but I'm not entirely sure. In any case, I believe the padding mode was probably a mistake, which was "fixed" for GA. So we can just default to This is currently my only open question. Other than that, not doing Node.js version sniffing makes perfect sense, so that is settled. |
By the way, just to be clear, there was a straight jump from 8.0.4 (last RC) to 8.0.11 (GA). |
I like the idea to either (a) just ignore the pre GA padding or (b) retry with the old padding because that would not involve the version sniffing 👍 |
@dougwilson I've kept the option for providing a custom key padding, to allow users to exceptionally connect to a MySQL I couldn't find a sane way to add an additional Travis CI test matrix for users with non-empty passwords though. I was constantly bumping into an authentication error (I believe it might be related to the Let me know if there is something else you would like to see in this PR. Otherwise, feel free to merge it! 😉 |
This is awesome, thank you. I've been reviewing it, and sorry I didn't reply that I was in progress. I did find at least one regression just in existing behavior so far, and pushed a test to cover this to I'll look at what the fix is and push it up to your PR branch here 👍 |
This comment has been minimized.
This comment has been minimized.
@fan123199 everything should still work if you use the ALTER USER 'root'@'localhost' IDENTIFIED WITH mysql_native_password BY 'YourRootPassword';
-- or
CREATE USER 'foo'@'%' IDENTIFIED WITH mysql_native_password BY 'bar'; |
In addition to what @ruiquelhas said, I also had to:
And then restart the server. |
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
For more information see: mysqljs/mysql#1962 (comment)
@dougwilson Is this still planned to be merged? It obviously keeps accumulating conflicts while it is not :( |
This PR regresses behavior and cannot be merged until fixed as I noted above. I volunteered to fix the PR but have not gotten to it. Anyone is welcome to fix the regression in the PR, though, and will merge. |
@dougwilson Thanks for the update! Not sure I'll get to it in the nearby future personally, though (but it's a possibility). |
It's np. I did get it mostly rebased and fixed locally but didn't quite finish. I'll bring this close to the top of my current todo list. |
@dougwilson I was under the impression you would take over from there, and just assumed something else was blocking this. In any case, I'll gladly help to push this forward. Please, let me know what I can do. |
You are correct. I volunteered to fix the PR. I did get it mostly rebased and fixed locally but didn't quite finish. I'll bring this close to the top of my current todo list. |
Alright, perfect. Let me know if there is something I can help with. |
This comment has been minimized.
This comment has been minimized.
946727b
to
37fbbdd
Compare
This patch accommodates some breaking changes introduced with MySQL 8.
Closes #1959
In a nutshell, the
caching_sha2_password
plugin (which is used by default since MySQL 8.0.4) hashes the password using SHA-256 and, after a first successful authentication attempt, saves it in a cache. That first attempt needs to be done under one of two conditions. The client either uses SSL and sends the password as clear text or it encrypts the password using the RSA public key generated by the server. On any subsequent attempt, until the password is somehow removed from the cache or the server shuts down, these rules no longer apply.The handshake process remains unchanged when connecting to any server with version lower or equal to
8.0.3
. Whereas for8.0.4
or above, the process is now the following:ClientAuthenticationPacket
with a scramble computed using a SHA-256 hashPerformFullAuthenticationPacket
ClearTextPasswordPacket
to which the server replies with aOkPacket
AuthSwitchResponsePacket
to which the server replies with aOkPacket
AuthMoreDataPacket
ClientAuthenticationPacket
with aFastAuthSuccessPacket
(which basically just signals that anOkPacket
will follow)If the account is created using the
mysql_native_password
authentication plugin, the client will just fall back to the "traditional" process during the handshake, keeping compatibility, by default for any previously supported server version.MySQL 8.0.2 disables the
local_infile
server variable by default, which breaks a couple of integration tests. The tests were updated to enable the feature by themselves (something that does not have any effect on older server versions and allows the tests to pass with newer versions).Additionally, one of the integration tests was updated to avoid failing after the first run (using any server version) since it tried to create a table that already existed from the previous runs.