Skip to content
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

Add support for 'mysql_clear_password - continued #2327

Open
wants to merge 10 commits into
base: master
Choose a base branch
from
6 changes: 6 additions & 0 deletions lib/protocol/Auth.js
Expand Up @@ -8,6 +8,12 @@ function auth(name, data, options) {
switch (name) {
case 'mysql_native_password':
return Auth.token(options.password, data.slice(0, 20));
case 'mysql_clear_password':
if (!options.secureConnection && !options.insecureAuth) {
throw new Error('Authentication method mysql_clear_password not supported on insecure connections');
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I get where this is coming from, but is probably going to be limiting to users in the long run. What about just adding an option the user can use to enable / disable this? I'm thinking along the lines of our insecureAuth option (perhaps clearAuth?) and how the mysql command line program requires a flag to enable it (https://dev.mysql.com/doc/refman/8.0/en/mysql-command-options.html#option_mysql_enable-cleartext-plugin).

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It looks like the --enable-cleartext-plugin is just to enable the plugin itself. Are you thinking the insecureAuth would allow clear_password even if we are not on a tls socket?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm thinking to have it behave inline with the mysql command line program: add an option (like perhaps clearAuth?) that that user must enable to use the clear password auth. That would be the only requirement -- the user can choose to use that over SSL or not as their own choice, just like in the mysql command line program.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I understand. Looking at the python module, if you specify auth_plugin='mysql_clear_password' then cleartext is used whether SSL is on or not. So maybe that would be the expected behavior.

I still think there is a big difference between saying: I want to use cleartext only inside secure channel, vs I want to use cleartext no matter what. For example, some of the GUI Sql clients I tested would bail on cleartext if SSL is not turned on.

Maybe the right way is to use clearAuth = true to enable it for secure channel, and insecureAuth to allow clear to be in an unencrypted socket?

} else {
return Buffer.from(options.password);
}
default:
return undefined;
}
Expand Down
16 changes: 12 additions & 4 deletions lib/protocol/sequences/Handshake.js
Expand Up @@ -35,16 +35,23 @@ Handshake.prototype.determinePacket = function determinePacket(firstByte, parser

Handshake.prototype['AuthSwitchRequestPacket'] = function (packet) {
var name = packet.authMethodName;
var data = Auth.auth(name, packet.authMethodData, {
password: this._config.password
});
var data, error;
try {
data = Auth.auth(name, packet.authMethodData, {
password : this._config.password,
insecureAuth : this._config.insecureAuth,
secureConnection : this._secureConnection
});
} catch (e) {
error = e;
}

if (data !== undefined) {
this.emit('packet', new Packets.AuthSwitchResponsePacket({
data: data
}));
} else {
var err = new Error('MySQL is requesting the ' + name + ' authentication method, which is not supported.');
var err = error || new Error('MySQL is requesting the ' + name + ' authentication method, which is not supported.');
err.code = 'UNSUPPORTED_AUTH_METHOD';
err.fatal = true;
this.end(err);
Expand Down Expand Up @@ -82,6 +89,7 @@ Handshake.prototype['HandshakeInitializationPacket'] = function(packet) {
};

Handshake.prototype._tlsUpgradeCompleteHandler = function() {
this._secureConnection = true;
this._sendCredentials();
};

Expand Down
7 changes: 7 additions & 0 deletions test/integration/connection/test-clear-auth.js
@@ -0,0 +1,7 @@
var assert = require('assert');
var common = require('../../common');

common.getTestConnection({ flags: ['+PLUGIN_AUTH'] }, function (err, connection) {
assert.ifError(err, 'got error');
connection.destroy();
});
39 changes: 39 additions & 0 deletions test/unit/connection/test-auth-switch-clear-insecure.js
@@ -0,0 +1,39 @@
var assert = require('assert');
var Buffer = require('safe-buffer').Buffer;
var common = require('../../common');
var connection = common.createConnection({
port : common.fakeServerPort,
password : 'authswitch'
});

var server = common.createFakeServer();

var error;
server.listen(common.fakeServerPort, function (err) {
assert.ifError(err);

connection.connect(function (err) {
error = err;
connection.destroy();
server.destroy();
});
});

server.on('connection', function(incomingConnection) {
incomingConnection.on('authSwitchResponse', function (packet) {
this._sendAuthResponse(packet.data, Buffer.from('authswitch'));
});

incomingConnection.on('clientAuthentication', function () {
this.authSwitchRequest({
authMethodName : 'mysql_clear_password',
authMethodData : Buffer.alloc(0)
});
});

incomingConnection.handshake();
});

process.on('exit', function() {
assert.equal(error.message, 'Authentication method mysql_clear_password not supported on insecure connections');
});
47 changes: 47 additions & 0 deletions test/unit/connection/test-auth-switch-clear-secure.js
@@ -0,0 +1,47 @@
var assert = require('assert');
var Buffer = require('safe-buffer').Buffer;
var common = require('../../common');
var connection = common.createConnection({
port : common.fakeServerPort,
password : 'authswitch',
ssl : {
rejectUnauthorized: false
}
});

var server = common.createFakeServer();

var connected;
server.listen(common.fakeServerPort, function (err) {
assert.ifError(err);

connection.connect(function (err, result) {
assert.ifError(err);

connected = result;

connection.destroy();
server.destroy();
});
});

server.on('connection', function(incomingConnection) {
incomingConnection.on('authSwitchResponse', function (packet) {
this._sendAuthResponse(packet.data, Buffer.from('authswitch'));
});

incomingConnection.on('clientAuthentication', function () {
this.authSwitchRequest({
authMethodName : 'mysql_clear_password',
authMethodData : Buffer.alloc(0)
});
});

incomingConnection.handshake({
serverCapabilities1: 512 | 1 << 11 // PROTOCOL_41 and SSL
});
});

process.on('exit', function() {
assert.equal(connected.fieldCount, 0);
});
4 changes: 3 additions & 1 deletion test/unit/connection/test-auth-switch-native.js
Expand Up @@ -38,7 +38,9 @@ server.on('connection', function(incomingConnection) {
});
});

incomingConnection.handshake();
incomingConnection.handshake({
serverCapabilities1: 512 | 1 << 11 // PROTOCOL_41 and SSL
});
});
});

Expand Down