From 42bfb5f30ecd29942fe68a2b7ea07d8a54a8f1d3 Mon Sep 17 00:00:00 2001 From: Andrey Sidorov Date: Mon, 20 Jun 2016 23:18:46 +1000 Subject: [PATCH 01/40] allow to pass connection handler as createServer parameter --- index.js | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/index.js b/index.js index 211da864b2..d83cfbe65e 100644 --- a/index.js +++ b/index.js @@ -21,9 +21,13 @@ exports.createPoolCluster = function (config) { return new PoolCluster(config); }; -module.exports.createServer = function () { +module.exports.createServer = function (handler) { var Server = require('./lib/server.js'); - return new Server(); + var s = new Server(); + if (handler) { + s.on('connection', handler); + } + return s; }; exports.escape = SqlString.escape; @@ -43,4 +47,3 @@ exports.__defineGetter__('createPoolClusterPromise', function () { }); module.exports.Types = require('./lib/constants/types.js'); - From 0c4bad6a26949fd3d2143a1371f10795e47820dc Mon Sep 17 00:00:00 2001 From: Andrey Sidorov Date: Tue, 21 Jun 2016 16:29:34 +1000 Subject: [PATCH 02/40] start using portfinder in tests --- package.json | 1 + 1 file changed, 1 insertion(+) diff --git a/package.json b/package.json index ccfb57e640..20e8f2b94f 100644 --- a/package.json +++ b/package.json @@ -39,6 +39,7 @@ "devDependencies": { "assert-diff": "^1.0.1", "eslint": "^2.10.0", + "portfinder": "^1.0.3", "progress": "1.1.8", "urun": "0.0.8", "utest": "0.0.8" From 491e32d8ac24802446a3c5b556303327876c8894 Mon Sep 17 00:00:00 2001 From: Andrey Sidorov Date: Tue, 21 Jun 2016 16:31:03 +1000 Subject: [PATCH 03/40] connection.end() for server said of connections pair --- lib/connection.js | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/lib/connection.js b/lib/connection.js index 268a765f23..97fcd07bc0 100644 --- a/lib/connection.js +++ b/lib/connection.js @@ -119,7 +119,7 @@ function Connection (opts) handshakeCommand.on('end', function () { connection._handshakePacket = handshakeCommand.handshake; connection.threadId = handshakeCommand.handshake.connectionId; - connection.emit('connect', handshakeCommand.handshake) + connection.emit('connect', handshakeCommand.handshake); }); this.addCommand(handshakeCommand); } @@ -649,6 +649,17 @@ Connection.prototype.serverHandshake = function serverHandshake (args) { // TODO: domainify Connection.prototype.end = function (callback) { var connection = this; + + if (this.config.isServer) { + connection._closing = true; + var quitCmd = new EventEmitter(); + setImmediate(function () { + connection.stream.end(); + quitCmd.emit('end'); + }); + return quitCmd; + } + // trigger error if more commands enqueued after end command var quitCmd = this.addCommand(new Commands.Quit(callback)); connection.addCommand = function () { From 1d4de1cd00309c235f864119c626340759694d9d Mon Sep 17 00:00:00 2001 From: Andrey Sidorov Date: Tue, 21 Jun 2016 16:31:38 +1000 Subject: [PATCH 04/40] add connectAttributes config parameter --- lib/connection_config.js | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/lib/connection_config.js b/lib/connection_config.js index 1346791859..ca6f9e7a75 100644 --- a/lib/connection_config.js +++ b/lib/connection_config.js @@ -32,7 +32,6 @@ function ConnectionConfig (options) { this.trace = options.trace !== false; this.stringifyObjects = options.stringifyObjects || false; this.timezone = options.timezone || 'local'; - this.flags = options.flags || ''; this.queryFormat = options.queryFormat; this.pool = options.pool || undefined; this.ssl = (typeof options.ssl === 'string') @@ -64,8 +63,12 @@ function ConnectionConfig (options) { this.compress = options.compress || false; + this.authSwitchHandler = options.authSwitchHandler; + this.clientFlags = ConnectionConfig.mergeFlags(ConnectionConfig.getDefaultFlags(options), options.flags || ''); + + this.connectAttributes = options.connectAttributes; } ConnectionConfig.mergeFlags = function (default_flags, user_flags) { @@ -102,11 +105,15 @@ ConnectionConfig.getDefaultFlags = function (options) { 'CONNECT_WITH_DB', 'ODBC', 'LOCAL_FILES', 'IGNORE_SPACE', 'PROTOCOL_41', 'IGNORE_SIGPIPE', 'TRANSACTIONS', 'RESERVED', 'SECURE_CONNECTION', - 'MULTI_RESULTS']; + 'MULTI_RESULTS', 'PLUGIN_AUTH', 'PLUGIN_AUTH_LENENC_CLIENT_DATA']; if (options && options.multipleStatements) { defaultFlags.push('MULTI_STATEMENTS'); } + if (options && options.connectAttributes) { + defaultFlags.push('CONNECT_ATTRS'); + } + return defaultFlags; }; From 478de354721299d5ef70c70f80a46b914d0a2018 Mon Sep 17 00:00:00 2001 From: Andrey Sidorov Date: Tue, 21 Jun 2016 16:32:19 +1000 Subject: [PATCH 05/40] initial implementation of AuthSwitchRequest/Response/MoreData in handshake --- lib/commands/client_handshake.js | 38 +++++- lib/packets/auth_switch_request.js | 37 ++++++ lib/packets/auth_switch_request_more_data.js | 32 +++++ lib/packets/auth_switch_response.js | 28 +++++ lib/packets/handshake.js | 7 ++ lib/packets/handshake_response.js | 104 +++++++++++++---- lib/packets/index.js | 5 +- lib/packets/packet.js | 21 +++- test/integration/test-auth-switch.js | 117 +++++++++++++++++++ 9 files changed, 361 insertions(+), 28 deletions(-) create mode 100644 lib/packets/auth_switch_request.js create mode 100644 lib/packets/auth_switch_request_more_data.js create mode 100644 lib/packets/auth_switch_response.js create mode 100644 test/integration/test-auth-switch.js diff --git a/lib/commands/client_handshake.js b/lib/commands/client_handshake.js index c26635ab37..d2e55c4091 100644 --- a/lib/commands/client_handshake.js +++ b/lib/commands/client_handshake.js @@ -45,7 +45,8 @@ ClientHandshake.prototype.sendCredentials = function (connection) { charsetNumber : connection.config.charsetNumber, authPluginData1: this.handshake.authPluginData1, authPluginData2: this.handshake.authPluginData2, - compress: connection.config.compress + compress: connection.config.compress, + connectAttributes: connection.config.connectAttributes }); connection.writePacket(handshakeResponse.toPacket()); }; @@ -100,7 +101,39 @@ ClientHandshake.prototype.handshakeInit = function (helloPacket, connection) { return ClientHandshake.prototype.handshakeResult; }; -ClientHandshake.prototype.handshakeResult = function (okPacket, connection) { +ClientHandshake.prototype.handshakeResult = function (packet, connection) { + var marker = packet.peekByte(); + if (marker === 0xfe || marker === 1) { + if (connection.config.authSwitchHandler) { + var asr, asrmd; + var authSwitchHandlerParams = {}; + if (marker === 1) { + asrmd = Packets.AuthSwitchRequestMoreData.fromPacket(packet); + authSwitchHandlerParams.pluginData = asrmd.data; + } else { + asr = Packets.AuthSwitchRequest.fromPacket(packet); + authSwitchHandlerParams.pluginName = asr.pluginName; + authSwitchHandlerParams.pluginData = asr.pluginData; + } + connection.config.authSwitchHandler(authSwitchHandlerParams, function (err, data) { + if (err) { + connection.emit('error', err); + return; + } + connection.writePacket(new Packets.AuthSwitchResponse(data).toPacket()); + }); + } else { + connection.emit('error', new Error('Server requires auth switch, but no auth switch handler provided')); + return null; + } + return ClientHandshake.prototype.handshakeResult; + } + + if (marker !== 0) { + connection.emit('error', new Error('Unexpected packet during handshake phase')); + return null; + } + // error is already checked in base class. Done auth. connection.authorized = true; if (connection.config.compress) { @@ -109,4 +142,5 @@ ClientHandshake.prototype.handshakeResult = function (okPacket, connection) { } return null; }; + module.exports = ClientHandshake; diff --git a/lib/packets/auth_switch_request.js b/lib/packets/auth_switch_request.js new file mode 100644 index 0000000000..9774199a88 --- /dev/null +++ b/lib/packets/auth_switch_request.js @@ -0,0 +1,37 @@ +// http://dev.mysql.com/doc/internals/en/connection-phase-packets.html#packet-Protocol::AuthSwitchRequest + +var Packet = require('../packets/packet'); + +function AuthSwitchRequest(opts) +{ + this.pluginName = opts.pluginName; + this.pluginData = opts.pluginData; +} + +AuthSwitchRequest.prototype.toPacket = function () +{ + var length = 6 + this.pluginName.length + this.pluginData.length; + var buffer = new Buffer(length).fill(0); + var packet = new Packet(0, buffer, 0, length); + packet.offset = 4; + packet.writeInt8(0xfe); + packet.writeNullTerminatedString(this.pluginName); + packet.writeBuffer(this.pluginData); + return packet; +}; + +AuthSwitchRequest.fromPacket = function (packet) +{ + var marker = packet.readInt8(); + // assert marker == 0xfe? + + var name = packet.readNullTerminatedString(); + var data = packet.readBuffer(); + + return new AuthSwitchRequest({ + pluginName: name, + pluginData: data + }); +}; + +module.exports = AuthSwitchRequest; diff --git a/lib/packets/auth_switch_request_more_data.js b/lib/packets/auth_switch_request_more_data.js new file mode 100644 index 0000000000..d157f2f82b --- /dev/null +++ b/lib/packets/auth_switch_request_more_data.js @@ -0,0 +1,32 @@ +// http://dev.mysql.com/doc/internals/en/connection-phase-packets.html#packet-Protocol::AuthSwitchRequest + +var Packet = require('../packets/packet'); + +function AuthSwitchRequestMoreData(data) +{ + this.data = data; +} + +AuthSwitchRequestMoreData.prototype.toPacket = function () +{ + var length = 5 + this.data.length; + var buffer = new Buffer(length).fill(0); + var packet = new Packet(0, buffer, 0, length); + packet.offset = 4; + packet.writeInt8(0x01); + packet.writeBuffer(this.data); + return packet; +}; + +AuthSwitchRequestMoreData.fromPacket = function (packet) +{ + var marker = packet.readInt8(); + var data = packet.readBuffer(); + return new AuthSwitchRequestMoreData(data); +}; + +AuthSwitchRequestMoreData.verifyMarker = function(packet) { + return (packet.peekByte() == 0x01); +} + +module.exports = AuthSwitchRequestMoreData; diff --git a/lib/packets/auth_switch_response.js b/lib/packets/auth_switch_response.js new file mode 100644 index 0000000000..5b1a30c634 --- /dev/null +++ b/lib/packets/auth_switch_response.js @@ -0,0 +1,28 @@ +// http://dev.mysql.com/doc/internals/en/connection-phase-packets.html#packet-Protocol::AuthSwitchRequest + +var Packet = require('../packets/packet'); + +function AuthSwitchResponse(data) +{ + if (!Buffer.isBuffer(data)) + data = Buffer(data); + this.data = data; +} + +AuthSwitchResponse.prototype.toPacket = function () +{ + var length = 4 + this.data.length; + var buffer = new Buffer(length); + var packet = new Packet(0, buffer, 0, length); + packet.offset = 4; + packet.writeBuffer(this.data); + return packet; +}; + +AuthSwitchResponse.fromPacket = function (packet) +{ + var data = packet.readBuffer(); + return new AuthSwitchResponse(data); +}; + +module.exports = AuthSwitchResponse; diff --git a/lib/packets/handshake.js b/lib/packets/handshake.js index d18d2c84c0..dcbb6a325c 100644 --- a/lib/packets/handshake.js +++ b/lib/packets/handshake.js @@ -30,6 +30,13 @@ Handshake.fromPacket = function (packet) } // var len = Math.max(12, args.authPluginDataLength - 8); args.authPluginData2 = packet.readBuffer(12); + + // TODO: expose combined authPluginData1 + authPluginData2 as authPluginData + // + // TODO + // if capabilities & CLIENT_PLUGIN_AUTH { + // string[NUL] auth-plugin name + // } return new Handshake(args); }; diff --git a/lib/packets/handshake_response.js b/lib/packets/handshake_response.js index d02266d97e..2e9af24e80 100644 --- a/lib/packets/handshake_response.js +++ b/lib/packets/handshake_response.js @@ -23,50 +23,110 @@ function HandshakeResponse (handshake) } this.authToken = authToken; this.charsetNumber = handshake.charsetNumber; + this.connectAttributes = handshake.connectAttributes; } HandshakeResponse.fromPacket = function (packet) { var args = {}; - // packet.skip(4); args.clientFlags = packet.readInt32(); + + function isSet (flag) { + return args.clientFlags & ClientConstants[flag]; + } + args.maxPacketSize = packet.readInt32(); args.charsetNumber = packet.readInt8(); packet.skip(23); args.user = packet.readNullTerminatedString(); - var authTokenLength = packet.readInt8(); - args.authToken = packet.readBuffer(authTokenLength); - args.database = packet.readNullTerminatedString(); - // return new HandshakeResponse(args); + var authTokenLength; + if (isSet('PLUGIN_AUTH_LENENC_CLIENT_DATA')) { + authTokenLength = packet.readLengthCodedNumber(); + args.authToken = packet.readBuffer(authTokenLength); + } else if (isSet('SECURE_CONNECTION')) { + authTokenLength = packet.readInt8(); + args.authToken = packet.readBuffer(authTokenLength); + } else { + args.authToken = packet.readNullTerminatedString(); + } if (isSet('CONNECT_WITH_DB')) { + args.database = packet.readNullTerminatedString(); + } + if (isSet('PLUGIN_AUTH')) { + args.authPluginName = packet.readNullTerminatedString(); + } + if (isSet('CONNECT_ATTRS')) { + var keysLength = packet.readLengthCodedNumber(); + var keysEnd = packet.offset + keysLength; + var attrs = {}; + while (packet.offset < keysEnd) { + attrs[packet.readLengthCodedString()] = packet.readLengthCodedString(); + } + args.connectAttributes = attrs; + } return args; }; -HandshakeResponse.prototype.toPacket = function () -{ - if (typeof this.user != 'string') { - throw new Error('"user" connection config property must be a string'); - } - - if (typeof this.database != 'string') { - throw new Error('"database" connection config property must be a string'); +HandshakeResponse.prototype.serializeResponse = function (buffer) { + var self = this; + function isSet (flag) { + return self.clientFlags & ClientConstants[flag]; } - var length = 36 + 23 + this.user.length + this.database.length; - - var buffer = new Buffer(length); - var packet = new Packet(0, buffer, 0, length); - buffer.fill(0); + var packet = new Packet(0, buffer, 0, 0); packet.offset = 4; - packet.writeInt32(this.clientFlags); packet.writeInt32(0); // max packet size. todo: move to config packet.writeInt8(this.charsetNumber); packet.skip(23); packet.writeNullTerminatedString(this.user); - packet.writeInt8(this.authToken.length); - packet.writeBuffer(this.authToken); - packet.writeNullTerminatedString(this.database); + + var authTokenLength, k; + if (isSet('PLUGIN_AUTH_LENENC_CLIENT_DATA')) { + packet.writeLengthCodedNumber(this.authToken.length); + packet.writeBuffer(this.authToken); + } else if (isSet('SECURE_CONNECTION')) { + packet.writeInt8(this.authToken.length); + packet.writeBuffer(this.authToken); + } else { + packet.writeNullTerminatedString(Buffer(this.authToken)); + } if (isSet('CONNECT_WITH_DB')) { + packet.writeNullTerminatedString(this.database); + } + if (isSet('PLUGIN_AUTH')) { + // TODO: pass from config + packet.writeNullTerminatedString('mysql_native_auth'); + } + if (isSet('CONNECT_ATTRS')) { + var connectAttributes = this.connectAttributes || {}; + var attrNames = Object.keys(connectAttributes); + var keysLength = 0; + for (k = 0; k < attrNames.length; ++k) { + keysLength += Packet.lengthCodedStringLength(attrNames[k]); + keysLength += Packet.lengthCodedStringLength(connectAttributes[attrNames[k]]); + } + packet.writeLengthCodedNumber(keysLength); + for (k = 0; k < attrNames.length; ++k) { + packet.writeLengthCodedString(attrNames[k]); + packet.writeLengthCodedString(connectAttributes[attrNames[k]]); + } + } return packet; }; +HandshakeResponse.prototype.toPacket = function () +{ + if (typeof this.user != 'string') { + throw new Error('"user" connection config prperty must be a string'); + } + if (typeof this.database != 'string') { + throw new Error('"database" connection config prperty must be a string'); + } + var length = 36 + 23 + this.user.length + this.database.length; + + // dry run: calculate resulting packet length + var p = this.serializeResponse(Packet.MockBuffer()); + + return this.serializeResponse(new Buffer(p.offset)); +}; + module.exports = HandshakeResponse; diff --git a/lib/packets/index.js b/lib/packets/index.js index fc0622a562..0929c0343f 100644 --- a/lib/packets/index.js +++ b/lib/packets/index.js @@ -1,4 +1,4 @@ -'binlog_dump register_slave ssl_request handshake handshake_response query resultset_header column_definition text_row binary_row prepare_statement close_statement prepared_statement_header execute change_user'.split(' ').forEach(function (name) { +'auth_switch_request auth_switch_response auth_switch_request_more_data binlog_dump register_slave ssl_request handshake handshake_response query resultset_header column_definition text_row binary_row prepare_statement close_statement prepared_statement_header execute change_user'.split(' ').forEach(function(name) { var ctor = require('./' + name + '.js'); module.exports[ctor.name] = ctor; // monkey-patch it to include name if debug is on @@ -9,7 +9,7 @@ var p = old.call(this); p._name = ctor.name; return p; - }; + } } } }); @@ -53,7 +53,6 @@ module.exports.EOF.toPacket = function (warnings, statusFlags) { if (typeof warnings == 'undefined') { warnings = 0; } - if (typeof statusFlags == 'undefined') { statusFlags = 0; } diff --git a/lib/packets/packet.js b/lib/packets/packet.js index 0ba842d523..69bdd76608 100644 --- a/lib/packets/packet.js +++ b/lib/packets/packet.js @@ -516,8 +516,18 @@ Packet.prototype.parseLengthCodedFloat = function () { return this.parseFloat(this.readLengthCodedNumber()); }; +Packet.prototype.peekByte = function () { + return this.buffer[this.offset]; +}; + +// OxFE is often used as "Alt" flag - not ok, not error. +// For example, it's first byte of AuthSwitchRequest +Packet.prototype.isAlt = function () { + return this.peekByte() == 0xfe; +}; + Packet.prototype.isError = function () { - return this.buffer[this.offset] == 0xff; + return this.peekByte() == 0xff; }; Packet.prototype.asError = function () { @@ -670,4 +680,13 @@ Packet.prototype.type = function () { return ''; }; +Packet.MockBuffer = function () { + var noop = function () {}; + var res = Buffer(0); + for (var op in Buffer.prototype) { + res[op] = noop; + } + return res; +}; + module.exports = Packet; diff --git a/test/integration/test-auth-switch.js b/test/integration/test-auth-switch.js new file mode 100644 index 0000000000..f61335531f --- /dev/null +++ b/test/integration/test-auth-switch.js @@ -0,0 +1,117 @@ +var util = require('util'); +var mysql = require('../../index.js'); +var Command = require('../../lib/commands/command.js'); +var Packets = require('../../lib/packets/index.js'); + +var assert = require('assert'); + +function TestAuthSwitchHandshake (args) +{ + Command.call(this); + this.args = args; +} +util.inherits(TestAuthSwitchHandshake, Command); + +var connectAttributes = { foo: 'bar', baz: 'foo' }; + +TestAuthSwitchHandshake.prototype.start = function (packet, connection) { + var serverHelloPacket = new Packets.Handshake({ + protocolVersion: 10, + serverVersion: 'node.js rocks', + connectionId: 1234, + statusFlags: 2, + characterSet: 8, + capabilityFlags: 0xffffff + }); + this.serverHello = serverHelloPacket; + serverHelloPacket.setScrambleData(function (err) { + connection.writePacket(serverHelloPacket.toPacket(0)); + }); + return TestAuthSwitchHandshake.prototype.readClientReply; +}; + +TestAuthSwitchHandshake.prototype.readClientReply = function (packet, connection) { + var clientHelloReply = new Packets.HandshakeResponse.fromPacket(packet); + + assert.equal(clientHelloReply.user, 'test_user'); + assert.equal(clientHelloReply.database, 'test_database'); + assert.equal(clientHelloReply.authPluginName, 'mysql_native_auth'); + assert.deepEqual(clientHelloReply.connectAttributes, connectAttributes); + + var asr = new Packets.AuthSwitchRequest(this.args); + connection.writePacket(asr.toPacket()); + return TestAuthSwitchHandshake.prototype.readClientAuthSwitchResponse; +}; + +var count = 0; + +TestAuthSwitchHandshake.prototype.readClientAuthSwitchResponse = function (packet, connection) { + var authSwitchResponse = new Packets.AuthSwitchResponse.fromPacket(packet); + //var pluginData = authSwitchResponse.data.toString(); + + count++; + if (count < 10) { + var asrmd = new Packets.AuthSwitchRequestMoreData(Buffer('hahaha ' + count)); + connection.writePacket(asrmd.toPacket()); + return TestAuthSwitchHandshake.prototype.readClientAuthSwitchResponse; + } else { + connection.writeOk(); + return TestAuthSwitchHandshake.prototype.dispatchCommands; + } +} + +TestAuthSwitchHandshake.prototype.dispatchCommands = function (packet, connection) { + // Quit command here + // TODO: assert it's actually Quit + connection.end(); + return TestAuthSwitchHandshake.prototype.dispatchCommands; +}; + +var server = mysql.createServer(function(conn) { + conn.addCommand(new TestAuthSwitchHandshake({ + pluginName: 'auth_test_plugin', + pluginData: Buffer('f\{tU-{K@BhfHt/-4^Z,') + })); +}); + +var fullAuthExchangeDone = false; + +var portfinder = require('portfinder'); +portfinder.getPort(function (err, port) { + + var makeSwitchHandler = function() { + var count = 0; + return function(data, cb) { + if (count == 0) { + assert.equal(data.pluginName, 'auth_test_plugin'); + } else { + assert.equal(data.pluginData.toString(), 'hahaha ' + count); + } + + if (count == 9) { + fullAuthExchangeDone = true; + } + count++; + cb(null, "some data back" + count); + }; + } + + server.listen(port); + var conn = mysql.createConnection({ + user: 'test_user', + password: 'test', + database: 'test_database', + port: port, + authSwitchHandler: makeSwitchHandler(), + connectAttributes: connectAttributes + }) + + conn.on('connect', function(data) { + assert.equal(data.serverVersion, 'node.js rocks'); + assert.equal(data.connectionId, 1234); + + conn.end(); + server.close(); + }); + +}); From 06ceb9bde5c9057d0395e09fc79de89dd74c9bd1 Mon Sep 17 00:00:00 2001 From: Andrey Sidorov Date: Tue, 21 Jun 2016 16:37:28 +1000 Subject: [PATCH 06/40] fix lint errors --- lib/packets/auth_switch_request.js | 2 +- lib/packets/auth_switch_request_more_data.js | 6 +++--- lib/packets/auth_switch_response.js | 5 +++-- lib/packets/index.js | 4 ++-- test/integration/test-auth-switch.js | 19 +++++++++---------- 5 files changed, 18 insertions(+), 18 deletions(-) diff --git a/lib/packets/auth_switch_request.js b/lib/packets/auth_switch_request.js index 9774199a88..ce2ba03bd6 100644 --- a/lib/packets/auth_switch_request.js +++ b/lib/packets/auth_switch_request.js @@ -2,7 +2,7 @@ var Packet = require('../packets/packet'); -function AuthSwitchRequest(opts) +function AuthSwitchRequest (opts) { this.pluginName = opts.pluginName; this.pluginData = opts.pluginData; diff --git a/lib/packets/auth_switch_request_more_data.js b/lib/packets/auth_switch_request_more_data.js index d157f2f82b..696a6bdc93 100644 --- a/lib/packets/auth_switch_request_more_data.js +++ b/lib/packets/auth_switch_request_more_data.js @@ -2,7 +2,7 @@ var Packet = require('../packets/packet'); -function AuthSwitchRequestMoreData(data) +function AuthSwitchRequestMoreData (data) { this.data = data; } @@ -25,8 +25,8 @@ AuthSwitchRequestMoreData.fromPacket = function (packet) return new AuthSwitchRequestMoreData(data); }; -AuthSwitchRequestMoreData.verifyMarker = function(packet) { +AuthSwitchRequestMoreData.verifyMarker = function (packet) { return (packet.peekByte() == 0x01); -} +}; module.exports = AuthSwitchRequestMoreData; diff --git a/lib/packets/auth_switch_response.js b/lib/packets/auth_switch_response.js index 5b1a30c634..f9fe861fa9 100644 --- a/lib/packets/auth_switch_response.js +++ b/lib/packets/auth_switch_response.js @@ -2,10 +2,11 @@ var Packet = require('../packets/packet'); -function AuthSwitchResponse(data) +function AuthSwitchResponse (data) { - if (!Buffer.isBuffer(data)) + if (!Buffer.isBuffer(data)) { data = Buffer(data); + } this.data = data; } diff --git a/lib/packets/index.js b/lib/packets/index.js index 0929c0343f..9378b99013 100644 --- a/lib/packets/index.js +++ b/lib/packets/index.js @@ -1,4 +1,4 @@ -'auth_switch_request auth_switch_response auth_switch_request_more_data binlog_dump register_slave ssl_request handshake handshake_response query resultset_header column_definition text_row binary_row prepare_statement close_statement prepared_statement_header execute change_user'.split(' ').forEach(function(name) { +'auth_switch_request auth_switch_response auth_switch_request_more_data binlog_dump register_slave ssl_request handshake handshake_response query resultset_header column_definition text_row binary_row prepare_statement close_statement prepared_statement_header execute change_user'.split(' ').forEach(function (name) { var ctor = require('./' + name + '.js'); module.exports[ctor.name] = ctor; // monkey-patch it to include name if debug is on @@ -9,7 +9,7 @@ var p = old.call(this); p._name = ctor.name; return p; - } + }; } } }); diff --git a/test/integration/test-auth-switch.js b/test/integration/test-auth-switch.js index f61335531f..a49bc61325 100644 --- a/test/integration/test-auth-switch.js +++ b/test/integration/test-auth-switch.js @@ -12,7 +12,7 @@ function TestAuthSwitchHandshake (args) } util.inherits(TestAuthSwitchHandshake, Command); -var connectAttributes = { foo: 'bar', baz: 'foo' }; +var connectAttributes = {foo: 'bar', baz: 'foo'}; TestAuthSwitchHandshake.prototype.start = function (packet, connection) { var serverHelloPacket = new Packets.Handshake({ @@ -47,7 +47,6 @@ var count = 0; TestAuthSwitchHandshake.prototype.readClientAuthSwitchResponse = function (packet, connection) { var authSwitchResponse = new Packets.AuthSwitchResponse.fromPacket(packet); - //var pluginData = authSwitchResponse.data.toString(); count++; if (count < 10) { @@ -58,7 +57,7 @@ TestAuthSwitchHandshake.prototype.readClientAuthSwitchResponse = function (packe connection.writeOk(); return TestAuthSwitchHandshake.prototype.dispatchCommands; } -} +}; TestAuthSwitchHandshake.prototype.dispatchCommands = function (packet, connection) { // Quit command here @@ -67,7 +66,7 @@ TestAuthSwitchHandshake.prototype.dispatchCommands = function (packet, connectio return TestAuthSwitchHandshake.prototype.dispatchCommands; }; -var server = mysql.createServer(function(conn) { +var server = mysql.createServer(function (conn) { conn.addCommand(new TestAuthSwitchHandshake({ pluginName: 'auth_test_plugin', pluginData: Buffer('f\{tU-{K@BhfHt/-4^Z,') @@ -79,9 +78,9 @@ var fullAuthExchangeDone = false; var portfinder = require('portfinder'); portfinder.getPort(function (err, port) { - var makeSwitchHandler = function() { + var makeSwitchHandler = function () { var count = 0; - return function(data, cb) { + return function (data, cb) { if (count == 0) { assert.equal(data.pluginName, 'auth_test_plugin'); } else { @@ -92,9 +91,9 @@ portfinder.getPort(function (err, port) { fullAuthExchangeDone = true; } count++; - cb(null, "some data back" + count); + cb(null, 'some data back' + count); }; - } + }; server.listen(port); var conn = mysql.createConnection({ @@ -104,9 +103,9 @@ portfinder.getPort(function (err, port) { port: port, authSwitchHandler: makeSwitchHandler(), connectAttributes: connectAttributes - }) + }); - conn.on('connect', function(data) { + conn.on('connect', function (data) { assert.equal(data.serverVersion, 'node.js rocks'); assert.equal(data.connectionId, 1234); From 039914fc7550a9c2fa87b642a2bce2d9816e6992 Mon Sep 17 00:00:00 2001 From: Andrey Sidorov Date: Tue, 21 Jun 2016 17:05:29 +1000 Subject: [PATCH 07/40] typo in default auth plugin name --- lib/packets/handshake_response.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/packets/handshake_response.js b/lib/packets/handshake_response.js index 2e9af24e80..208b025581 100644 --- a/lib/packets/handshake_response.js +++ b/lib/packets/handshake_response.js @@ -94,7 +94,7 @@ HandshakeResponse.prototype.serializeResponse = function (buffer) { } if (isSet('PLUGIN_AUTH')) { // TODO: pass from config - packet.writeNullTerminatedString('mysql_native_auth'); + packet.writeNullTerminatedString('mysql_native_password'); } if (isSet('CONNECT_ATTRS')) { var connectAttributes = this.connectAttributes || {}; From 97f932f7c564e742226345f8220001c69b466878 Mon Sep 17 00:00:00 2001 From: Andrey Sidorov Date: Tue, 21 Jun 2016 17:10:22 +1000 Subject: [PATCH 08/40] typo in default auth plugin name --- test/integration/test-auth-switch.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/integration/test-auth-switch.js b/test/integration/test-auth-switch.js index a49bc61325..31ad148bed 100644 --- a/test/integration/test-auth-switch.js +++ b/test/integration/test-auth-switch.js @@ -35,7 +35,7 @@ TestAuthSwitchHandshake.prototype.readClientReply = function (packet, connection assert.equal(clientHelloReply.user, 'test_user'); assert.equal(clientHelloReply.database, 'test_database'); - assert.equal(clientHelloReply.authPluginName, 'mysql_native_auth'); + assert.equal(clientHelloReply.authPluginName, 'mysql_native_password'); assert.deepEqual(clientHelloReply.connectAttributes, connectAttributes); var asr = new Packets.AuthSwitchRequest(this.args); From 2e8aa561720169cfd591927d076f7f57c07b64a6 Mon Sep 17 00:00:00 2001 From: Andrey Sidorov Date: Tue, 21 Jun 2016 23:18:16 +1000 Subject: [PATCH 09/40] use PLUGIN_AUTH flag by default only when authSwitchHandler connect parameter is set --- lib/connection_config.js | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/lib/connection_config.js b/lib/connection_config.js index ca6f9e7a75..8503ae2132 100644 --- a/lib/connection_config.js +++ b/lib/connection_config.js @@ -105,11 +105,16 @@ ConnectionConfig.getDefaultFlags = function (options) { 'CONNECT_WITH_DB', 'ODBC', 'LOCAL_FILES', 'IGNORE_SPACE', 'PROTOCOL_41', 'IGNORE_SIGPIPE', 'TRANSACTIONS', 'RESERVED', 'SECURE_CONNECTION', - 'MULTI_RESULTS', 'PLUGIN_AUTH', 'PLUGIN_AUTH_LENENC_CLIENT_DATA']; + 'MULTI_RESULTS', + 'PLUGIN_AUTH_LENENC_CLIENT_DATA']; if (options && options.multipleStatements) { defaultFlags.push('MULTI_STATEMENTS'); } + if (options && options.authSwitchHandler) { + defaultFlags.push('PLUGIN_AUTH'); + } + if (options && options.connectAttributes) { defaultFlags.push('CONNECT_ATTRS'); } From 6afe56f1c090861c9f8c9cd292d30f8a4a25e829 Mon Sep 17 00:00:00 2001 From: Andrey Sidorov Date: Tue, 21 Jun 2016 23:33:13 +1000 Subject: [PATCH 10/40] change_user command flow when plugin auth is enabled --- lib/commands/change_user.js | 43 +++++++------ lib/commands/client_handshake.js | 52 ++++++++++----- lib/packets/change_user.js | 62 ++++++++++++++---- lib/packets/handshake_response.js | 2 - test/common.js | 3 +- .../test-change-user-plugin-auth.js | 63 +++++++++++++++++++ 6 files changed, 171 insertions(+), 54 deletions(-) create mode 100644 test/integration/connection/test-change-user-plugin-auth.js diff --git a/lib/commands/change_user.js b/lib/commands/change_user.js index 503fb2ad4e..7e56bed28a 100644 --- a/lib/commands/change_user.js +++ b/lib/commands/change_user.js @@ -3,44 +3,43 @@ var util = require('util'); var Command = require('./command.js'); var Packets = require('../packets/index.js'); var ClientConstants = require('../constants/client.js'); +var ClientHandshake = require('./client_handshake.js'); function ChangeUser (options, callback) { this.onResult = callback; - this._user = options.user; - this._password = options.password; - this._database = options.database; - this._passwordSha1 = options.passwordSha1; - this._charsetNumber = options.charsetNumber; - this._currentConfig = options.currentConfig; + this.user = options.user; + this.password = options.password; + this.database = options.database; + this.passwordSha1 = options.passwordSha1; + this.charsetNumber = options.charsetNumber; + this.currentConfig = options.currentConfig; Command.call(this); } util.inherits(ChangeUser, Command); +ChangeUser.prototype.handshakeResult = ClientHandshake.prototype.handshakeResult; +ChangeUser.prototype.calculateNativePasswordAuthToken = ClientHandshake.prototype.calculateNativePasswordAuthToken; + ChangeUser.prototype.start = function (packet, connection) { var packet = new Packets.ChangeUser({ - user : this._user, - database : this._database, - charsetNumber : this._charsetNumber, - password : this._password, - passwordSha1 : this._passwordSha1, + flags : connection.config.clientFlags, + user : this.user, + database : this.database, + charsetNumber : this.charsetNumber, + password : this.password, + passwordSha1 : this.passwordSha1, authPluginData1 : connection._handshakePacket.authPluginData1, authPluginData2 : connection._handshakePacket.authPluginData2 }); - this._currentConfig.user = this._user; - this._currentConfig.password = this._password; - this._currentConfig.database = this._database; - this._currentConfig.charsetNumber = this._charsetNumber; + this.currentConfig.user = this.user; + this.currentConfig.password = this.password; + this.currentConfig.database = this.database; + this.currentConfig.charsetNumber = this.charsetNumber; // reset prepared statements cache as all statements become invalid after changeUser connection._statements = {}; connection.writePacket(packet.toPacket()); - return ChangeUser.prototype.changeOk; + return ChangeUser.prototype.handshakeResult; }; -ChangeUser.prototype.changeOk = function (okPacket, connection) { - if (this.onResult) { - this.onResult(null); - } - return null; -}; module.exports = ChangeUser; diff --git a/lib/commands/client_handshake.js b/lib/commands/client_handshake.js index d2e55c4091..3ba21b19ab 100644 --- a/lib/commands/client_handshake.js +++ b/lib/commands/client_handshake.js @@ -51,6 +51,20 @@ ClientHandshake.prototype.sendCredentials = function (connection) { connection.writePacket(handshakeResponse.toPacket()); }; +var auth41 = require('../auth_41.js'); +ClientHandshake.prototype.calculateNativePasswordAuthToken = function (authPluginData) { + // TODO: dont split into authPluginData1 and authPluginData2, instead join when 1 & 2 received + var authPluginData1 = authPluginData.slice(0, 8); + var authPluginData2 = authPluginData.slice(8, 20); + var authToken; + if (this.passwordSha1) { + authToken = auth41.calculateTokenFromPasswordSha(this.passwordSha1, authPluginData1, authPluginData2); + } else { + authToken = auth41.calculateToken(this.password, authPluginData1, authPluginData2); + } + return authToken; +}; + ClientHandshake.prototype.handshakeInit = function (helloPacket, connection) { var command = this; @@ -104,17 +118,20 @@ ClientHandshake.prototype.handshakeInit = function (helloPacket, connection) { ClientHandshake.prototype.handshakeResult = function (packet, connection) { var marker = packet.peekByte(); if (marker === 0xfe || marker === 1) { - if (connection.config.authSwitchHandler) { - var asr, asrmd; - var authSwitchHandlerParams = {}; - if (marker === 1) { - asrmd = Packets.AuthSwitchRequestMoreData.fromPacket(packet); - authSwitchHandlerParams.pluginData = asrmd.data; - } else { - asr = Packets.AuthSwitchRequest.fromPacket(packet); - authSwitchHandlerParams.pluginName = asr.pluginName; - authSwitchHandlerParams.pluginData = asr.pluginData; - } + var asr, asrmd; + var authSwitchHandlerParams = {}; + if (marker === 1) { + asrmd = Packets.AuthSwitchRequestMoreData.fromPacket(packet); + authSwitchHandlerParams.pluginData = asrmd.data; + } else { + asr = Packets.AuthSwitchRequest.fromPacket(packet); + authSwitchHandlerParams.pluginName = asr.pluginName; + authSwitchHandlerParams.pluginData = asr.pluginData; + } + if (authSwitchHandlerParams.pluginName == 'mysql_native_password') { + var authToken = this.calculateNativePasswordAuthToken(authSwitchHandlerParams.pluginData); + connection.writePacket(new Packets.AuthSwitchResponse(authToken).toPacket()); + } else if (connection.config.authSwitchHandler) { connection.config.authSwitchHandler(authSwitchHandlerParams, function (err, data) { if (err) { connection.emit('error', err); @@ -134,11 +151,14 @@ ClientHandshake.prototype.handshakeResult = function (packet, connection) { return null; } - // error is already checked in base class. Done auth. - connection.authorized = true; - if (connection.config.compress) { - var enableCompression = require('../compressed_protocol.js').enableCompression; - enableCompression(connection); + // this should be called from ClientHandshake command only + // and skipped when called from ChangeUser command + if (!connection.authorized) { + connection.authorized = true; + if (connection.config.compress) { + var enableCompression = require('../compressed_protocol.js').enableCompression; + enableCompression(connection); + } } return null; }; diff --git a/lib/packets/change_user.js b/lib/packets/change_user.js index 1ac31275ea..e123c6f123 100644 --- a/lib/packets/change_user.js +++ b/lib/packets/change_user.js @@ -1,16 +1,18 @@ var CommandCode = require('../constants/commands.js'); +var ClientConstants = require('../constants/client.js'); var Packet = require('../packets/packet.js'); - var auth41 = require('../auth_41.js'); function ChangeUser (opts) { + this.flags = opts.flags; this.user = opts.user || ''; this.database = opts.database || ''; this.password = opts.password || ''; this.passwordSha1 = opts.passwordSha1; this.authPluginData1 = opts.authPluginData1; this.authPluginData2 = opts.authPluginData2; + this.connectAttributes = opts.connectAttrinutes || {}; var authToken; if (this.passwordSha1) { authToken = auth41.calculateTokenFromPasswordSha(this.passwordSha1, this.authPluginData1, this.authPluginData2); @@ -25,6 +27,49 @@ function ChangeUser (opts) // ChangeUser.fromPacket = function(packet) // }; +ChangeUser.prototype.serializeToBuffer = function (buffer) +{ + var self = this; + function isSet (flag) { + return self.flags & ClientConstants[flag]; + } + + var packet = new Packet(0, buffer, 0, 0); + packet.offset = 4; + + packet.writeInt8(CommandCode.CHANGE_USER); + packet.writeNullTerminatedString(this.user); + if (isSet('SECURE_CONNECTION')) { + packet.writeInt8(this.authToken.length); + packet.writeBuffer(this.authToken); + } else { + packet.writeBuffer(this.authToken); + packet.writeInt8(0); + } + packet.writeNullTerminatedString(this.database); + packet.writeInt16(this.charsetNumber); + + if (isSet('PLUGIN_AUTH')) { + packet.writeNullTerminatedString('mysql_native_password'); + } + + if (isSet('CONNECT_ATTRS')) { + var connectAttributes = this.connectAttributes; + var attrNames = Object.keys(connectAttributes); + var keysLength = 0; + for (k = 0; k < attrNames.length; ++k) { + keysLength += Packet.lengthCodedStringLength(attrNames[k]); + keysLength += Packet.lengthCodedStringLength(connectAttributes[attrNames[k]]); + } + packet.writeLengthCodedNumber(keysLength); + for (k = 0; k < attrNames.length; ++k) { + packet.writeLengthCodedString(attrNames[k]); + packet.writeLengthCodedString(connectAttributes[attrNames[k]]); + } + } + return packet; +}; + ChangeUser.prototype.toPacket = function () { if (typeof this.user != 'string') { @@ -35,19 +80,10 @@ ChangeUser.prototype.toPacket = function () throw new Error('"database" connection config property must be a string'); } - var length = 4 + 1 + (1 + this.authToken.length) + (2 + this.user.length + this.database.length) + 2; + // dry run: calculate resulting packet length + var p = this.serializeToBuffer(Packet.MockBuffer()); - var buffer = new Buffer(length); - var packet = new Packet(0, buffer, 0, length); - packet.offset = 4; - - packet.writeInt8(CommandCode.CHANGE_USER); - packet.writeNullTerminatedString(this.user); - packet.writeInt8(this.authToken.length); - packet.writeBuffer(this.authToken); - packet.writeNullTerminatedString(this.database); - packet.writeInt16(this.charsetNumber); - return packet; + return this.serializeToBuffer(new Buffer(p.offset)); }; module.exports = ChangeUser; diff --git a/lib/packets/handshake_response.js b/lib/packets/handshake_response.js index 208b025581..81a169977c 100644 --- a/lib/packets/handshake_response.js +++ b/lib/packets/handshake_response.js @@ -121,8 +121,6 @@ HandshakeResponse.prototype.toPacket = function () if (typeof this.database != 'string') { throw new Error('"database" connection config prperty must be a string'); } - var length = 36 + 23 + this.user.length + this.database.length; - // dry run: calculate resulting packet length var p = this.serializeResponse(Packet.MockBuffer()); diff --git a/test/common.js b/test/common.js index 4a9d372212..7590accd4d 100644 --- a/test/common.js +++ b/test/common.js @@ -71,7 +71,8 @@ module.exports.createConnection = function (args, callback) { bigNumberStrings: args && args.bigNumberStrings, compress: (args && args.compress) || config.compress, decimalNumbers: args && args.decimalNumbers, - dateStrings: args && args.dateStrings + dateStrings: args && args.dateStrings, + authSwitchHandler: args && args.authSwitchHandler }); conn.query('create database IF NOT EXISTS test', function (err) { diff --git a/test/integration/connection/test-change-user-plugin-auth.js b/test/integration/connection/test-change-user-plugin-auth.js new file mode 100644 index 0000000000..225fac07cf --- /dev/null +++ b/test/integration/connection/test-change-user-plugin-auth.js @@ -0,0 +1,63 @@ +var assert = require('assert'); +var common = require('../../common'); +var connection = common.createConnection({ + authSwitchHandler: function () { + throw new Error('should not be called - we expect mysql_native_password ' + + 'plugin to be handled by internal handler'); + } +}); + +// create test user first +connection.query('GRANT ALL ON *.* TO \'changeuser1\'@\'localhost\' IDENTIFIED BY \'changeuser1pass\''); +connection.query('GRANT ALL ON *.* TO \'changeuser2\'@\'localhost\' IDENTIFIED BY \'changeuser2pass\''); +connection.query('FLUSH PRIVILEGES'); + +connection.changeUser({ + user: 'changeuser1', + password: 'changeuser1pass' +}); +connection.query('select user()', function (err, rows) { + if (err) { + throw err; + } + assert.deepEqual(rows, [{'user()': 'changeuser1@localhost'}]); +}); + +connection.changeUser({ + user: 'changeuser2', + password: 'changeuser2pass' +}); + +connection.query('select user()', function (err, rows) { + if (err) { + throw err; + } + assert.deepEqual(rows, [{'user()': 'changeuser2@localhost'}]); +}); + +connection.changeUser({ + user: 'changeuser1', + passwordSha1: new Buffer('f961d39c82138dcec42b8d0dcb3e40a14fb7e8cd', 'hex') // sha1(changeuser1pass) +}); +connection.query('select user()', function (err, rows) { + if (err) { + throw err; + } + assert.deepEqual(rows, [{'user()': 'changeuser1@localhost'}]); +}); + +connection.end(); + + +var beforeChange = 1; +connection.changeUser({database: 'does-not-exist'}, function (err) { + assert.ok(err, 'got error'); + assert.equal(err.code, 'ER_BAD_DB_ERROR'); + assert.equal(err.fatal, true); +}); + +connection.on('error', function (err) { + assert.ok(err, 'got disconnect'); + assert.equal(err.code, 'PROTOCOL_CONNECTION_LOST'); + assert.equal(beforeChange, 1); +}); From 63e13254499d9335d15d43eb122011e906079b3e Mon Sep 17 00:00:00 2001 From: Andrey Sidorov Date: Wed, 22 Jun 2016 09:49:05 +1000 Subject: [PATCH 11/40] cleanup debug output --- test/common.js | 9 +++++++-- test/integration/connection/test-datetime.js | 2 -- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/test/common.js b/test/common.js index 7590accd4d..cf4575f735 100644 --- a/test/common.js +++ b/test/common.js @@ -58,7 +58,7 @@ module.exports.createConnection = function (args, callback) { driver = require('mysql'); } - var conn = driver.createConnection({ + var params = { host: config.host, rowsAsArray: args.rowsAsArray, user: (args && args.user) || config.user, @@ -73,8 +73,12 @@ module.exports.createConnection = function (args, callback) { decimalNumbers: args && args.decimalNumbers, dateStrings: args && args.dateStrings, authSwitchHandler: args && args.authSwitchHandler - }); + }; + + //console.log('cc params', params); + var conn = driver.createConnection(params); + /* conn.query('create database IF NOT EXISTS test', function (err) { if (err) { console.log('error during "create database IF NOT EXISTS test"', err); @@ -85,6 +89,7 @@ module.exports.createConnection = function (args, callback) { console.log('error during "use test"', err); } }); + */ return conn; }; diff --git a/test/integration/connection/test-datetime.js b/test/integration/connection/test-datetime.js index fe0dd1c657..08abcc6e66 100644 --- a/test/integration/connection/test-datetime.js +++ b/test/integration/connection/test-datetime.js @@ -53,7 +53,6 @@ connection.execute('select * from t', function (err, _rows, _fields) { }); connection1.query('select * from t', function (err, _rows, _fields) { - console.log(_rows); if (err) { throw err; } @@ -61,7 +60,6 @@ connection1.query('select * from t', function (err, _rows, _fields) { }); connection1.execute('select * from t', function (err, _rows, _fields) { - console.log(_rows); if (err) { throw err; } From fa2661bef2deb326d9fe691b0457814e376ed002 Mon Sep 17 00:00:00 2001 From: Andrey Sidorov Date: Wed, 22 Jun 2016 09:58:01 +1000 Subject: [PATCH 12/40] debug --- test/common.js | 2 +- test/integration/connection/test-change-user-plugin-auth.js | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/test/common.js b/test/common.js index cf4575f735..4871066cf0 100644 --- a/test/common.js +++ b/test/common.js @@ -66,7 +66,7 @@ module.exports.createConnection = function (args, callback) { database: (args && args.database) || config.database, multipleStatements: args ? args.multipleStatements : false, port: (args && args.port) || config.port, - debug: process.env.DEBUG, + debug: process.env.DEBUG || (args && args.debug), supportBigNumbers: args && args.supportBigNumbers, bigNumberStrings: args && args.bigNumberStrings, compress: (args && args.compress) || config.compress, diff --git a/test/integration/connection/test-change-user-plugin-auth.js b/test/integration/connection/test-change-user-plugin-auth.js index 225fac07cf..fc21965d56 100644 --- a/test/integration/connection/test-change-user-plugin-auth.js +++ b/test/integration/connection/test-change-user-plugin-auth.js @@ -1,6 +1,7 @@ var assert = require('assert'); var common = require('../../common'); var connection = common.createConnection({ + debug: true, authSwitchHandler: function () { throw new Error('should not be called - we expect mysql_native_password ' + 'plugin to be handled by internal handler'); From 086042da411fc6d0b86b68762fa26d90058cb9e7 Mon Sep 17 00:00:00 2001 From: Andrey Sidorov Date: Wed, 22 Jun 2016 10:33:28 +1000 Subject: [PATCH 13/40] christmas tree --- .../test-change-user-plugin-auth.js | 59 ++++++++++--------- 1 file changed, 30 insertions(+), 29 deletions(-) diff --git a/test/integration/connection/test-change-user-plugin-auth.js b/test/integration/connection/test-change-user-plugin-auth.js index fc21965d56..41dfca3f68 100644 --- a/test/integration/connection/test-change-user-plugin-auth.js +++ b/test/integration/connection/test-change-user-plugin-auth.js @@ -4,7 +4,7 @@ var connection = common.createConnection({ debug: true, authSwitchHandler: function () { throw new Error('should not be called - we expect mysql_native_password ' - + 'plugin to be handled by internal handler'); + + 'plugin switch request to be handled by internal handler'); } }); @@ -16,40 +16,40 @@ connection.query('FLUSH PRIVILEGES'); connection.changeUser({ user: 'changeuser1', password: 'changeuser1pass' -}); -connection.query('select user()', function (err, rows) { - if (err) { - throw err; - } - assert.deepEqual(rows, [{'user()': 'changeuser1@localhost'}]); -}); +}, function(err, res) { + asert.ifError(err); + connection.query('select user()', function (err, rows) { + asert.ifError(err); + assert.deepEqual(rows, [{'user()': 'changeuser1@localhost'}]); -connection.changeUser({ - user: 'changeuser2', - password: 'changeuser2pass' -}); + connection.changeUser({ + user: 'changeuser2', + password: 'changeuser2pass' + }, function(err, res) { -connection.query('select user()', function (err, rows) { - if (err) { - throw err; - } - assert.deepEqual(rows, [{'user()': 'changeuser2@localhost'}]); -}); + asert.ifError(err); -connection.changeUser({ - user: 'changeuser1', - passwordSha1: new Buffer('f961d39c82138dcec42b8d0dcb3e40a14fb7e8cd', 'hex') // sha1(changeuser1pass) -}); -connection.query('select user()', function (err, rows) { - if (err) { - throw err; - } - assert.deepEqual(rows, [{'user()': 'changeuser1@localhost'}]); -}); + connection.query('select user()', function (err, rows) { + asert.ifError(err); + assert.deepEqual(rows, [{'user()': 'changeuser2@localhost'}]); -connection.end(); + connection.changeUser({ + user: 'changeuser1', + passwordSha1: new Buffer('f961d39c82138dcec42b8d0dcb3e40a14fb7e8cd', 'hex') // sha1(changeuser1pass) + }, function(err, res) { + connection.query('select user()', function (err, rows) { + assert.iferror(err); + assert.deepEqual(rows, [{'user()': 'changeuser1@localhost'}]); + connection.end(); + }); + }); + }); + }); + }); +}); +/* var beforeChange = 1; connection.changeUser({database: 'does-not-exist'}, function (err) { assert.ok(err, 'got error'); @@ -62,3 +62,4 @@ connection.on('error', function (err) { assert.equal(err.code, 'PROTOCOL_CONNECTION_LOST'); assert.equal(beforeChange, 1); }); +*/ From cf9851fe08d6083fd39288192503c3e3a0d3ae1a Mon Sep 17 00:00:00 2001 From: Andrey Sidorov Date: Wed, 22 Jun 2016 11:54:22 +1000 Subject: [PATCH 14/40] fix typos --- .../connection/test-change-user-plugin-auth.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/test/integration/connection/test-change-user-plugin-auth.js b/test/integration/connection/test-change-user-plugin-auth.js index 41dfca3f68..e534ea4cab 100644 --- a/test/integration/connection/test-change-user-plugin-auth.js +++ b/test/integration/connection/test-change-user-plugin-auth.js @@ -17,9 +17,9 @@ connection.changeUser({ user: 'changeuser1', password: 'changeuser1pass' }, function(err, res) { - asert.ifError(err); + assert.ifError(err); connection.query('select user()', function (err, rows) { - asert.ifError(err); + assert.ifError(err); assert.deepEqual(rows, [{'user()': 'changeuser1@localhost'}]); connection.changeUser({ @@ -27,10 +27,10 @@ connection.changeUser({ password: 'changeuser2pass' }, function(err, res) { - asert.ifError(err); + assert.ifError(err); connection.query('select user()', function (err, rows) { - asert.ifError(err); + assert.ifError(err); assert.deepEqual(rows, [{'user()': 'changeuser2@localhost'}]); connection.changeUser({ From a2c8fd9ea6353e61d6e6273f4bfbe9be54774329 Mon Sep 17 00:00:00 2001 From: Andrey Sidorov Date: Wed, 22 Jun 2016 11:59:05 +1000 Subject: [PATCH 15/40] bisect --- test/integration/connection/test-change-user-plugin-auth.js | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/test/integration/connection/test-change-user-plugin-auth.js b/test/integration/connection/test-change-user-plugin-auth.js index e534ea4cab..79ad12a11b 100644 --- a/test/integration/connection/test-change-user-plugin-auth.js +++ b/test/integration/connection/test-change-user-plugin-auth.js @@ -13,6 +13,9 @@ connection.query('GRANT ALL ON *.* TO \'changeuser1\'@\'localhost\' IDENTIFIED B connection.query('GRANT ALL ON *.* TO \'changeuser2\'@\'localhost\' IDENTIFIED BY \'changeuser2pass\''); connection.query('FLUSH PRIVILEGES'); +connection.end(); + +/* connection.changeUser({ user: 'changeuser1', password: 'changeuser1pass' @@ -47,7 +50,7 @@ connection.changeUser({ }); }); }); - +*/ /* var beforeChange = 1; From 0248454a5b20bf15d6aec8029fee8ba297bb54f7 Mon Sep 17 00:00:00 2001 From: Andrey Sidorov Date: Wed, 22 Jun 2016 22:56:58 +1000 Subject: [PATCH 16/40] use portfinder to allocate test server ports --- lib/server.js | 1 + test/common.js | 5 +- .../connection/test-connect-sha1.js | 79 ++++++++++--------- .../connection/test-disconnects.js | 2 +- .../connection/test-protocol-errors.js | 2 +- test/integration/connection/test-quit.js | 2 +- .../connection/test-stream-errors.js | 2 +- 7 files changed, 51 insertions(+), 42 deletions(-) diff --git a/lib/server.js b/lib/server.js index fb2190690b..43b6d41c2f 100644 --- a/lib/server.js +++ b/lib/server.js @@ -21,6 +21,7 @@ Server.prototype._handleConnection = function (socket) { }; Server.prototype.listen = function (port, host, backlog, callback) { + this._port = port; this._server.listen.apply(this._server, arguments); return this; }; diff --git a/test/common.js b/test/common.js index 4871066cf0..24f457b372 100644 --- a/test/common.js +++ b/test/common.js @@ -110,6 +110,7 @@ module.exports.createTemplate = function () { var ClientFlags = require('../lib/constants/client.js'); +var portfinder = require('portfinder'); module.exports.createServer = function (onListening, handler) { var server = require('../index.js').createServer(); server.on('connection', function (conn) { @@ -131,7 +132,9 @@ module.exports.createServer = function (onListening, handler) { handler(conn); } }); - server.listen(3307, onListening); + portfinder.getPort(function (err, port) { + server.listen(port, onListening); + }); return server; }; diff --git a/test/integration/connection/test-connect-sha1.js b/test/integration/connection/test-connect-sha1.js index a423ed40cb..b04888034a 100644 --- a/test/integration/connection/test-connect-sha1.js +++ b/test/integration/connection/test-connect-sha1.js @@ -13,52 +13,57 @@ function authenticate (params, cb) { var queryCalls = 0; +var portfinder = require('portfinder'); +portfinder.getPort(function (err, port) { + var server = mysql.createServer(); -server.listen(3307); -server.on('connection', function (conn) { - conn.serverHandshake({ - protocolVersion: 10, - serverVersion: 'node.js rocks', - connectionId: 1234, - statusFlags: 2, - characterSet: 8, - capabilityFlags: 0xffffff, - authCallback: authenticate + server.listen(port); + server.on('connection', function (conn) { + conn.serverHandshake({ + protocolVersion: 10, + serverVersion: 'node.js rocks', + connectionId: 1234, + statusFlags: 2, + characterSet: 8, + capabilityFlags: 0xffffff, + authCallback: authenticate + }); + conn.on('query', function (sql) { + assert.equal(sql, 'select 1+1'); + queryCalls++; + conn.close(); + }); }); - conn.on('query', function (sql) { - assert.equal(sql, 'select 1+1'); - queryCalls++; - conn.close(); + + var connection = mysql.createConnection({ + port: port, + user: 'testuser', + database: 'testdatabase', + passwordSha1: Buffer('8bb6118f8fd6935ad0876a3be34a717d32708ffd', 'hex') }); -}); -var connection = mysql.createConnection({ - port: 3307, - user: 'testuser', - database: 'testdatabase', - passwordSha1: Buffer('8bb6118f8fd6935ad0876a3be34a717d32708ffd', 'hex') -}); + connection.on('error', function (err) { + assert.equal(err.code, 'PROTOCOL_CONNECTION_LOST'); + }); -connection.on('error', function (err) { - assert.equal(err.code, 'PROTOCOL_CONNECTION_LOST'); -}); + connection.query('select 1+1', function (err) { + assert.equal(err.code, 'PROTOCOL_CONNECTION_LOST'); + server._server.close(); + }); -connection.query('select 1+1', function (err) { - assert.equal(err.code, 'PROTOCOL_CONNECTION_LOST'); - server._server.close(); -}); + var _1_2 = false; + var _1_3 = false; -var _1_2 = false; -var _1_3 = false; + connection.query('select 1+2', function (err) { + assert.equal(err.code, 'PROTOCOL_CONNECTION_LOST'); + _1_2 = true; + }); -connection.query('select 1+2', function (err) { - assert.equal(err.code, 'PROTOCOL_CONNECTION_LOST'); - _1_2 = true; -}); + connection.query('select 1+3', function (err) { + assert.equal(err.code, 'PROTOCOL_CONNECTION_LOST'); + _1_3 = true; + }); -connection.query('select 1+3', function (err) { - assert.equal(err.code, 'PROTOCOL_CONNECTION_LOST'); - _1_3 = true; }); process.on('exit', function () { diff --git a/test/integration/connection/test-disconnects.js b/test/integration/connection/test-disconnects.js index f840fd342c..a55e0a2738 100644 --- a/test/integration/connection/test-disconnects.js +++ b/test/integration/connection/test-disconnects.js @@ -9,7 +9,7 @@ var server; var connections = []; function test () { - var connection = common.createConnection({port: 3307}); + var connection = common.createConnection({port: server._port}); connection.query('SELECT 123', function (err, _rows, _fields) { if (err) { throw err; diff --git a/test/integration/connection/test-protocol-errors.js b/test/integration/connection/test-protocol-errors.js index 8e223d061f..38d5c8a3ee 100644 --- a/test/integration/connection/test-protocol-errors.js +++ b/test/integration/connection/test-protocol-errors.js @@ -21,7 +21,7 @@ var server = common.createServer(serverReady, function (conn) { var fields, error; var query = 'SELECT 1'; function serverReady () { - var connection = common.createConnection({port: 3307}); + var connection = common.createConnection({port: server._port, debug: 1}); connection.query(query, function (err, _rows, _fields) { if (err) { throw err; diff --git a/test/integration/connection/test-quit.js b/test/integration/connection/test-quit.js index b287146af4..07bad9c886 100644 --- a/test/integration/connection/test-quit.js +++ b/test/integration/connection/test-quit.js @@ -27,7 +27,7 @@ var server = common.createServer(serverReady, function (conn) { }); function serverReady () { - var connection = common.createConnection({port: 3307}); + var connection = common.createConnection({port: server._port}); connection.query(queryCli, function (err, _rows, _fields) { if (err) { diff --git a/test/integration/connection/test-stream-errors.js b/test/integration/connection/test-stream-errors.js index 8fc87e90d5..afcbd054d4 100644 --- a/test/integration/connection/test-stream-errors.js +++ b/test/integration/connection/test-stream-errors.js @@ -29,7 +29,7 @@ var server = common.createServer(serverReady, function (conn) { var receivedError1, receivedError2, receivedError3; var query = 'SELECT 1'; function serverReady () { - clientConnection = common.createConnection({port: 3307}); + clientConnection = common.createConnection({port: server._port}); clientConnection.query(query, function (err, _rows, _fields) { receivedError1 = err; }); From 0e350ced59c35e59969364224f5a137a4fa8c125 Mon Sep 17 00:00:00 2001 From: Andrey Sidorov Date: Thu, 23 Jun 2016 07:41:41 +1000 Subject: [PATCH 17/40] fix failing tests --- test/integration/connection/test-binary-notnull-nulls.js | 2 ++ test/integration/connection/test-connect-sha1.js | 6 +++--- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/test/integration/connection/test-binary-notnull-nulls.js b/test/integration/connection/test-binary-notnull-nulls.js index 6ab376acf5..91da620624 100644 --- a/test/integration/connection/test-binary-notnull-nulls.js +++ b/test/integration/connection/test-binary-notnull-nulls.js @@ -7,6 +7,8 @@ var conn = common.createConnection(); // it's possible to receive null values for columns marked with NOT_NULL flag // see https://github.com/sidorares/node-mysql2/issues/178 for info +conn.query('set sql_mode=""'); + conn.query('CREATE TEMPORARY TABLE `tmp_account` ( ' + ' `id` int(11) NOT NULL AUTO_INCREMENT, ' + ' `username` varchar(64) NOT NULL, ' + diff --git a/test/integration/connection/test-connect-sha1.js b/test/integration/connection/test-connect-sha1.js index b04888034a..2eda0e238b 100644 --- a/test/integration/connection/test-connect-sha1.js +++ b/test/integration/connection/test-connect-sha1.js @@ -11,6 +11,9 @@ function authenticate (params, cb) { cb(null); } +var _1_2 = false; +var _1_3 = false; + var queryCalls = 0; var portfinder = require('portfinder'); @@ -51,9 +54,6 @@ var server = mysql.createServer(); server._server.close(); }); - var _1_2 = false; - var _1_3 = false; - connection.query('select 1+2', function (err) { assert.equal(err.code, 'PROTOCOL_CONNECTION_LOST'); _1_2 = true; From 8f2bb33e629fa7f7194fb0ae387e0a74ee776045 Mon Sep 17 00:00:00 2001 From: Andrey Sidorov Date: Thu, 23 Jun 2016 07:50:28 +1000 Subject: [PATCH 18/40] don't crash in debug log if there is unexpected packet --- lib/connection.js | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/connection.js b/lib/connection.js index 97fcd07bc0..e5b6533cae 100644 --- a/lib/connection.js +++ b/lib/connection.js @@ -249,6 +249,7 @@ Connection.prototype.handlePacket = function (packet) { if (packet) { console.log(' raw: ' + packet.buffer.slice(packet.offset, packet.offset + packet.length()).toString('hex')); console.trace(); + var commandName = this._command ? this._command._commandName + '#' : '(no command)#'; console.log(this._internalId + ' ' + this.connectionId + ' ==> ' + this._command._commandName + '#' + this._command.stateName() + '(' + [packet.sequenceId, packet.type(), packet.length()].join(',') + ')'); } } From 1029ce4c9dd82e9145d45b4d2a5e90294602c6c8 Mon Sep 17 00:00:00 2001 From: Andrey Sidorov Date: Thu, 23 Jun 2016 08:00:32 +1000 Subject: [PATCH 19/40] don't crash in debug log if there is unexpected packet --- lib/connection.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/connection.js b/lib/connection.js index e5b6533cae..540cce92bf 100644 --- a/lib/connection.js +++ b/lib/connection.js @@ -249,8 +249,8 @@ Connection.prototype.handlePacket = function (packet) { if (packet) { console.log(' raw: ' + packet.buffer.slice(packet.offset, packet.offset + packet.length()).toString('hex')); console.trace(); - var commandName = this._command ? this._command._commandName + '#' : '(no command)#'; - console.log(this._internalId + ' ' + this.connectionId + ' ==> ' + this._command._commandName + '#' + this._command.stateName() + '(' + [packet.sequenceId, packet.type(), packet.length()].join(',') + ')'); + var commandName = this._command ? this._command._commandName : '(no command)'; + console.log(this._internalId + ' ' + this.connectionId + ' ==> ' + commandName + '#' + this._command.stateName() + '(' + [packet.sequenceId, packet.type(), packet.length()].join(',') + ')'); } } if (!this._command) { From 82c81095f782985f1556944dc58d87409ea658ea Mon Sep 17 00:00:00 2001 From: Andrey Sidorov Date: Thu, 23 Jun 2016 08:17:16 +1000 Subject: [PATCH 20/40] don't crash in debug log if there is unexpected packet --- lib/connection.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/connection.js b/lib/connection.js index 540cce92bf..4ea939a2cc 100644 --- a/lib/connection.js +++ b/lib/connection.js @@ -250,7 +250,8 @@ Connection.prototype.handlePacket = function (packet) { console.log(' raw: ' + packet.buffer.slice(packet.offset, packet.offset + packet.length()).toString('hex')); console.trace(); var commandName = this._command ? this._command._commandName : '(no command)'; - console.log(this._internalId + ' ' + this.connectionId + ' ==> ' + commandName + '#' + this._command.stateName() + '(' + [packet.sequenceId, packet.type(), packet.length()].join(',') + ')'); + var stateName = this._command ? this._command..stateName() : '(no command)'; + console.log(this._internalId + ' ' + this.connectionId + ' ==> ' + commandName + '#' + stateName + '(' + [packet.sequenceId, packet.type(), packet.length()].join(',') + ')'); } } if (!this._command) { From f1dfd67a06d8388605cf0baeaf5ad10400e7380b Mon Sep 17 00:00:00 2001 From: Andrey Sidorov Date: Thu, 23 Jun 2016 08:19:02 +1000 Subject: [PATCH 21/40] don't crash in debug log if there is unexpected packet --- lib/connection.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/connection.js b/lib/connection.js index 4ea939a2cc..5b2f273fbf 100644 --- a/lib/connection.js +++ b/lib/connection.js @@ -250,7 +250,7 @@ Connection.prototype.handlePacket = function (packet) { console.log(' raw: ' + packet.buffer.slice(packet.offset, packet.offset + packet.length()).toString('hex')); console.trace(); var commandName = this._command ? this._command._commandName : '(no command)'; - var stateName = this._command ? this._command..stateName() : '(no command)'; + var stateName = this._command ? this._command.stateName() : '(no command)'; console.log(this._internalId + ' ' + this.connectionId + ' ==> ' + commandName + '#' + stateName + '(' + [packet.sequenceId, packet.type(), packet.length()].join(',') + ')'); } } From 4b73868eb1f074de4bc3987ea3d1848d76cb5e45 Mon Sep 17 00:00:00 2001 From: Andrey Sidorov Date: Thu, 23 Jun 2016 08:32:31 +1000 Subject: [PATCH 22/40] remove debug --- test/integration/connection/test-change-user-plugin-auth.js | 1 - test/integration/connection/test-protocol-errors.js | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/test/integration/connection/test-change-user-plugin-auth.js b/test/integration/connection/test-change-user-plugin-auth.js index 79ad12a11b..79945f6991 100644 --- a/test/integration/connection/test-change-user-plugin-auth.js +++ b/test/integration/connection/test-change-user-plugin-auth.js @@ -1,7 +1,6 @@ var assert = require('assert'); var common = require('../../common'); var connection = common.createConnection({ - debug: true, authSwitchHandler: function () { throw new Error('should not be called - we expect mysql_native_password ' + 'plugin switch request to be handled by internal handler'); diff --git a/test/integration/connection/test-protocol-errors.js b/test/integration/connection/test-protocol-errors.js index 38d5c8a3ee..6507eca6d1 100644 --- a/test/integration/connection/test-protocol-errors.js +++ b/test/integration/connection/test-protocol-errors.js @@ -21,7 +21,7 @@ var server = common.createServer(serverReady, function (conn) { var fields, error; var query = 'SELECT 1'; function serverReady () { - var connection = common.createConnection({port: server._port, debug: 1}); + var connection = common.createConnection({port: server._port}); connection.query(query, function (err, _rows, _fields) { if (err) { throw err; From b164242859d2161b3cdb29143ff05884a20e6cd0 Mon Sep 17 00:00:00 2001 From: Andrey Sidorov Date: Thu, 23 Jun 2016 08:41:31 +1000 Subject: [PATCH 23/40] node 0.10: buffer.fill() does not return ref to buffer --- lib/packets/auth_switch_request.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/packets/auth_switch_request.js b/lib/packets/auth_switch_request.js index ce2ba03bd6..8c18e82864 100644 --- a/lib/packets/auth_switch_request.js +++ b/lib/packets/auth_switch_request.js @@ -11,7 +11,7 @@ function AuthSwitchRequest (opts) AuthSwitchRequest.prototype.toPacket = function () { var length = 6 + this.pluginName.length + this.pluginData.length; - var buffer = new Buffer(length).fill(0); + var buffer = new Buffer(length); var packet = new Packet(0, buffer, 0, length); packet.offset = 4; packet.writeInt8(0xfe); From 4d30a57874b529bd33bbec66028c56640bb1b4df Mon Sep 17 00:00:00 2001 From: Andrey Sidorov Date: Thu, 23 Jun 2016 08:50:48 +1000 Subject: [PATCH 24/40] node 0.10: buffer.fill() does not return ref to buffer --- lib/packets/auth_switch_request_more_data.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/packets/auth_switch_request_more_data.js b/lib/packets/auth_switch_request_more_data.js index 696a6bdc93..b77f2f0888 100644 --- a/lib/packets/auth_switch_request_more_data.js +++ b/lib/packets/auth_switch_request_more_data.js @@ -10,7 +10,7 @@ function AuthSwitchRequestMoreData (data) AuthSwitchRequestMoreData.prototype.toPacket = function () { var length = 5 + this.data.length; - var buffer = new Buffer(length).fill(0); + var buffer = new Buffer(length); var packet = new Packet(0, buffer, 0, length); packet.offset = 4; packet.writeInt8(0x01); From c1b2e889c59efba6fe1bd315a1a99e5e5438ac54 Mon Sep 17 00:00:00 2001 From: Andrey Sidorov Date: Thu, 23 Jun 2016 09:50:05 +1000 Subject: [PATCH 25/40] debug default flags --- lib/connection_config.js | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/lib/connection_config.js b/lib/connection_config.js index 8503ae2132..39f3613027 100644 --- a/lib/connection_config.js +++ b/lib/connection_config.js @@ -105,20 +105,21 @@ ConnectionConfig.getDefaultFlags = function (options) { 'CONNECT_WITH_DB', 'ODBC', 'LOCAL_FILES', 'IGNORE_SPACE', 'PROTOCOL_41', 'IGNORE_SIGPIPE', 'TRANSACTIONS', 'RESERVED', 'SECURE_CONNECTION', - 'MULTI_RESULTS', - 'PLUGIN_AUTH_LENENC_CLIENT_DATA']; + 'MULTI_RESULTS']; if (options && options.multipleStatements) { defaultFlags.push('MULTI_STATEMENTS'); } if (options && options.authSwitchHandler) { defaultFlags.push('PLUGIN_AUTH'); + defaultFlags.push('PLUGIN_AUTH_LENENC_CLIENT_DATA'); } if (options && options.connectAttributes) { defaultFlags.push('CONNECT_ATTRS'); } + console.log('=================DEFFLAGS ', defaultFlags); return defaultFlags; }; From 275e26b162cc96d0d8fbdfed768dcc640078d969 Mon Sep 17 00:00:00 2001 From: Andrey Sidorov Date: Thu, 23 Jun 2016 10:09:16 +1000 Subject: [PATCH 26/40] debugging change-user test --- test/integration/connection/test-change-user.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/test/integration/connection/test-change-user.js b/test/integration/connection/test-change-user.js index e9643c53f1..3c3b55ea49 100644 --- a/test/integration/connection/test-change-user.js +++ b/test/integration/connection/test-change-user.js @@ -43,6 +43,8 @@ connection.query('select user()', function (err, rows) { connection.end(); +/* + // from felixge/node-mysql/test/unit/connection/test-change-database-fatal-error.js: // This test verifies that changeUser errors are treated as fatal errors. The // rationale for that is that a failure to execute a changeUser sequence may @@ -61,3 +63,4 @@ connection.on('error', function (err) { assert.equal(err.code, 'PROTOCOL_CONNECTION_LOST'); assert.equal(beforeChange, 1); }); +*/ From 5b0cb522fa1abd7c3b27ffe7f7142798baac5c2c Mon Sep 17 00:00:00 2001 From: Andrey Sidorov Date: Thu, 23 Jun 2016 10:22:04 +1000 Subject: [PATCH 27/40] debug change-user --- lib/connection_config.js | 1 - test/integration/connection/test-change-user.js | 15 +++++++++++---- 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/lib/connection_config.js b/lib/connection_config.js index 39f3613027..8461e50dbe 100644 --- a/lib/connection_config.js +++ b/lib/connection_config.js @@ -119,7 +119,6 @@ ConnectionConfig.getDefaultFlags = function (options) { defaultFlags.push('CONNECT_ATTRS'); } - console.log('=================DEFFLAGS ', defaultFlags); return defaultFlags; }; diff --git a/test/integration/connection/test-change-user.js b/test/integration/connection/test-change-user.js index 3c3b55ea49..288953b620 100644 --- a/test/integration/connection/test-change-user.js +++ b/test/integration/connection/test-change-user.js @@ -3,10 +3,18 @@ var common = require('../../common'); var connection = common.createConnection(); // create test user first -connection.query('GRANT ALL ON *.* TO \'changeuser1\'@\'localhost\' IDENTIFIED BY \'changeuser1pass\''); -connection.query('GRANT ALL ON *.* TO \'changeuser2\'@\'localhost\' IDENTIFIED BY \'changeuser2pass\''); -connection.query('FLUSH PRIVILEGES'); +connection.query('GRANT ALL ON *.* TO \'changeuser1\'@\'localhost\' IDENTIFIED BY \'changeuser1pass\'', function(err) { + assert.ifError(err); +}); +connection.query('GRANT ALL ON *.* TO \'changeuser2\'@\'localhost\' IDENTIFIED BY \'changeuser2pass\'', function(err) { + assert.ifError(err); +}); +connection.query('FLUSH PRIVILEGES', function(err) { + assert.ifError(err); +}); +connection.end(); +/* connection.changeUser({ user: 'changeuser1', password: 'changeuser1pass' @@ -43,7 +51,6 @@ connection.query('select user()', function (err, rows) { connection.end(); -/* // from felixge/node-mysql/test/unit/connection/test-change-database-fatal-error.js: // This test verifies that changeUser errors are treated as fatal errors. The From 432ea6430ca6d017b02c95ec455ffeee4b860572 Mon Sep 17 00:00:00 2001 From: Andrey Sidorov Date: Thu, 23 Jun 2016 10:30:38 +1000 Subject: [PATCH 28/40] debug change-user --- test/integration/connection/test-change-user.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/integration/connection/test-change-user.js b/test/integration/connection/test-change-user.js index 288953b620..cd525ef765 100644 --- a/test/integration/connection/test-change-user.js +++ b/test/integration/connection/test-change-user.js @@ -1,6 +1,6 @@ var assert = require('assert'); var common = require('../../common'); -var connection = common.createConnection(); +var connection = common.createConnection({debug : 1}); // create test user first connection.query('GRANT ALL ON *.* TO \'changeuser1\'@\'localhost\' IDENTIFIED BY \'changeuser1pass\'', function(err) { From 27e0f0c07fee258b326b7ec6b7629134c1412724 Mon Sep 17 00:00:00 2001 From: Andrey Sidorov Date: Tue, 28 Jun 2016 13:37:09 +1000 Subject: [PATCH 29/40] debug failing test only --- .travis.yml | 8 ++++---- package.json | 2 +- .../connection/test-change-user-plugin-auth.js | 3 --- 3 files changed, 5 insertions(+), 8 deletions(-) diff --git a/.travis.yml b/.travis.yml index 4b421de337..68a1bcf20b 100644 --- a/.travis.yml +++ b/.travis.yml @@ -4,10 +4,10 @@ language: node_js before_script: - mysql -e 'create database /*M!50701 IF NOT EXISTS */ test;' node_js: - - '0.10' - - '0.12' - - '4.4' - - '5.11' +# - '0.10' +# - '0.12' +# - '4.4' +# - '5.11' - '6.2' diff --git a/package.json b/package.json index 20e8f2b94f..c4914e921f 100644 --- a/package.json +++ b/package.json @@ -8,7 +8,7 @@ }, "scripts": { "lint": "eslint lib/**/*.js index.js test/**/*.js", - "test": "node ./test/run.js && MYSQL_USE_COMPRESSION=1 node ./test/run.js", + "test": "node test/integration/connection/test-change-user-plugin-auth.js", "benchmark": "./benchmarks/run-unit.js", "benchmarks": "./benchmarks/run-unit.js", "format-eslintrc": "jsonlint --sort-keys --in-place --indent ' ' ./.eslintrc" diff --git a/test/integration/connection/test-change-user-plugin-auth.js b/test/integration/connection/test-change-user-plugin-auth.js index 79945f6991..f7c2947602 100644 --- a/test/integration/connection/test-change-user-plugin-auth.js +++ b/test/integration/connection/test-change-user-plugin-auth.js @@ -12,9 +12,6 @@ connection.query('GRANT ALL ON *.* TO \'changeuser1\'@\'localhost\' IDENTIFIED B connection.query('GRANT ALL ON *.* TO \'changeuser2\'@\'localhost\' IDENTIFIED BY \'changeuser2pass\''); connection.query('FLUSH PRIVILEGES'); -connection.end(); - -/* connection.changeUser({ user: 'changeuser1', password: 'changeuser1pass' From f74f7b7b73e462b0c8acbda2a902831d2c3ac25a Mon Sep 17 00:00:00 2001 From: Andrey Sidorov Date: Tue, 28 Jun 2016 13:39:46 +1000 Subject: [PATCH 30/40] update example --- examples/promise-co-await/await.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/promise-co-await/await.js b/examples/promise-co-await/await.js index 7262e71714..87c3924764 100644 --- a/examples/promise-co-await/await.js +++ b/examples/promise-co-await/await.js @@ -24,7 +24,7 @@ async function test() { console.log(end - start); await c.end(); - const p = mysql.createPool({ port: 3306, user: 'mycause_dev', namedPlaceholders: true, password: 'mycause' }); + const p = mysql.createPool({ port: 3306, user: 'testuser', namedPlaceholders: true, password: 'testpassword' }); console.log( await p.execute('select sleep(0.5)') ); console.log('after first pool sleep'); var start = +new Date() From 08b27429b08dc1c7dba1f17620da789b406abae6 Mon Sep 17 00:00:00 2001 From: Andrey Sidorov Date: Tue, 28 Jun 2016 13:40:31 +1000 Subject: [PATCH 31/40] update example --- examples/promise-co-await/await.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/promise-co-await/await.js b/examples/promise-co-await/await.js index 87c3924764..5568b90c4b 100644 --- a/examples/promise-co-await/await.js +++ b/examples/promise-co-await/await.js @@ -1,7 +1,7 @@ var mysql = require('../../promise.js'); async function test() { - const c = await mysql.createConnection({ port: 3306, user: 'mycause_dev', namedPlaceholders: true, password: 'mycause' }); + const c = await mysql.createConnection({ port: 3306, user: 'testuser', namedPlaceholders: true, password: 'testpassword' }); console.log('connected!'); const [rows, fields] = await c.query('show databases'); console.log(rows); From be528539fbf13696de0e29c61f6869d8e469324a Mon Sep 17 00:00:00 2001 From: Andrey Sidorov Date: Tue, 28 Jun 2016 13:41:21 +1000 Subject: [PATCH 32/40] typo --- test/integration/connection/test-change-user-plugin-auth.js | 1 - 1 file changed, 1 deletion(-) diff --git a/test/integration/connection/test-change-user-plugin-auth.js b/test/integration/connection/test-change-user-plugin-auth.js index f7c2947602..12844a7581 100644 --- a/test/integration/connection/test-change-user-plugin-auth.js +++ b/test/integration/connection/test-change-user-plugin-auth.js @@ -46,7 +46,6 @@ connection.changeUser({ }); }); }); -*/ /* var beforeChange = 1; From 95ff96e9981f9996e081bf4c00ff4aae0d833336 Mon Sep 17 00:00:00 2001 From: Andrey Sidorov Date: Tue, 28 Jun 2016 13:49:38 +1000 Subject: [PATCH 33/40] check server version --- package.json | 2 +- test/integration/connection/test-change-user-plugin-auth.js | 4 ++++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/package.json b/package.json index c4914e921f..c90fcb2909 100644 --- a/package.json +++ b/package.json @@ -8,7 +8,7 @@ }, "scripts": { "lint": "eslint lib/**/*.js index.js test/**/*.js", - "test": "node test/integration/connection/test-change-user-plugin-auth.js", + "test": "DEBUG=1 node test/integration/connection/test-change-user-plugin-auth.js", "benchmark": "./benchmarks/run-unit.js", "benchmarks": "./benchmarks/run-unit.js", "format-eslintrc": "jsonlint --sort-keys --in-place --indent ' ' ./.eslintrc" diff --git a/test/integration/connection/test-change-user-plugin-auth.js b/test/integration/connection/test-change-user-plugin-auth.js index 12844a7581..9984914d45 100644 --- a/test/integration/connection/test-change-user-plugin-auth.js +++ b/test/integration/connection/test-change-user-plugin-auth.js @@ -7,6 +7,10 @@ var connection = common.createConnection({ } }); +connection.on('connect', function(hello) { + console.log(JSON.stringify(hello, null, 4)); +}); + // create test user first connection.query('GRANT ALL ON *.* TO \'changeuser1\'@\'localhost\' IDENTIFIED BY \'changeuser1pass\''); connection.query('GRANT ALL ON *.* TO \'changeuser2\'@\'localhost\' IDENTIFIED BY \'changeuser2pass\''); From c97eed50752b3efbbdfe29d09fba28c2a8679cba Mon Sep 17 00:00:00 2001 From: Andrey Sidorov Date: Tue, 28 Jun 2016 17:15:38 +1000 Subject: [PATCH 34/40] handle end of handshake if there is no switch-auth request --- lib/commands/client_handshake.js | 11 +- package.json | 2 +- .../test-change-user-plugin-auth.js | 39 +++--- .../connection/test-change-user.js | 117 ++++++++---------- 4 files changed, 82 insertions(+), 87 deletions(-) diff --git a/lib/commands/client_handshake.js b/lib/commands/client_handshake.js index 3ba21b19ab..b6a4dd26e3 100644 --- a/lib/commands/client_handshake.js +++ b/lib/commands/client_handshake.js @@ -147,7 +147,12 @@ ClientHandshake.prototype.handshakeResult = function (packet, connection) { } if (marker !== 0) { - connection.emit('error', new Error('Unexpected packet during handshake phase')); + var err = new Error('Unexpected packet during handshake phase'); + if (this.onResult) { + this.onResult(err); + } else { + connection.emit('error', err); + } return null; } @@ -160,6 +165,10 @@ ClientHandshake.prototype.handshakeResult = function (packet, connection) { enableCompression(connection); } } + + if (this.onResult) { + this.onResult(null); + } return null; }; diff --git a/package.json b/package.json index c90fcb2909..20e8f2b94f 100644 --- a/package.json +++ b/package.json @@ -8,7 +8,7 @@ }, "scripts": { "lint": "eslint lib/**/*.js index.js test/**/*.js", - "test": "DEBUG=1 node test/integration/connection/test-change-user-plugin-auth.js", + "test": "node ./test/run.js && MYSQL_USE_COMPRESSION=1 node ./test/run.js", "benchmark": "./benchmarks/run-unit.js", "benchmarks": "./benchmarks/run-unit.js", "format-eslintrc": "jsonlint --sort-keys --in-place --indent ' ' ./.eslintrc" diff --git a/test/integration/connection/test-change-user-plugin-auth.js b/test/integration/connection/test-change-user-plugin-auth.js index 9984914d45..2b02d87f38 100644 --- a/test/integration/connection/test-change-user-plugin-auth.js +++ b/test/integration/connection/test-change-user-plugin-auth.js @@ -7,10 +7,6 @@ var connection = common.createConnection({ } }); -connection.on('connect', function(hello) { - console.log(JSON.stringify(hello, null, 4)); -}); - // create test user first connection.query('GRANT ALL ON *.* TO \'changeuser1\'@\'localhost\' IDENTIFIED BY \'changeuser1pass\''); connection.query('GRANT ALL ON *.* TO \'changeuser2\'@\'localhost\' IDENTIFIED BY \'changeuser2pass\''); @@ -41,9 +37,10 @@ connection.changeUser({ passwordSha1: new Buffer('f961d39c82138dcec42b8d0dcb3e40a14fb7e8cd', 'hex') // sha1(changeuser1pass) }, function(err, res) { connection.query('select user()', function (err, rows) { - assert.iferror(err); + assert.ifError(err); assert.deepEqual(rows, [{'user()': 'changeuser1@localhost'}]); - connection.end(); + + testIncorrectDb(); }); }); }); @@ -51,17 +48,19 @@ connection.changeUser({ }); }); -/* -var beforeChange = 1; -connection.changeUser({database: 'does-not-exist'}, function (err) { - assert.ok(err, 'got error'); - assert.equal(err.code, 'ER_BAD_DB_ERROR'); - assert.equal(err.fatal, true); -}); - -connection.on('error', function (err) { - assert.ok(err, 'got disconnect'); - assert.equal(err.code, 'PROTOCOL_CONNECTION_LOST'); - assert.equal(beforeChange, 1); -}); -*/ +function testIncorrectDb() { + connection.end(); + // TODO figure out if stuff below is still relevant + /* + connection.on('error', function (err) { + assert.ok(err, 'got disconnect'); + assert.equal(err.code, 'PROTOCOL_CONNECTION_LOST'); + }); + connection.changeUser({database: 'does-not-exist', }, function (err) { + assert.ok(err, 'got error'); + assert.equal(err.code, 'ER_BAD_DB_ERROR'); + assert.equal(err.fatal, true); + }); + connection.end(); + */ +} diff --git a/test/integration/connection/test-change-user.js b/test/integration/connection/test-change-user.js index cd525ef765..422a6e02a9 100644 --- a/test/integration/connection/test-change-user.js +++ b/test/integration/connection/test-change-user.js @@ -1,73 +1,60 @@ var assert = require('assert'); var common = require('../../common'); -var connection = common.createConnection({debug : 1}); +var connection = common.createConnection(); // create test user first -connection.query('GRANT ALL ON *.* TO \'changeuser1\'@\'localhost\' IDENTIFIED BY \'changeuser1pass\'', function(err) { - assert.ifError(err); -}); -connection.query('GRANT ALL ON *.* TO \'changeuser2\'@\'localhost\' IDENTIFIED BY \'changeuser2pass\'', function(err) { - assert.ifError(err); -}); -connection.query('FLUSH PRIVILEGES', function(err) { - assert.ifError(err); -}); +connection.query('GRANT ALL ON *.* TO \'changeuser1\'@\'localhost\' IDENTIFIED BY \'changeuser1pass\''); +connection.query('GRANT ALL ON *.* TO \'changeuser2\'@\'localhost\' IDENTIFIED BY \'changeuser2pass\''); +connection.query('FLUSH PRIVILEGES'); -connection.end(); -/* connection.changeUser({ user: 'changeuser1', password: 'changeuser1pass' -}); -connection.query('select user()', function (err, rows) { - if (err) { - throw err; - } - assert.deepEqual(rows, [{'user()': 'changeuser1@localhost'}]); -}); - -connection.changeUser({ - user: 'changeuser2', - password: 'changeuser2pass' -}); - -connection.query('select user()', function (err, rows) { - if (err) { - throw err; - } - assert.deepEqual(rows, [{'user()': 'changeuser2@localhost'}]); -}); - -connection.changeUser({ - user: 'changeuser1', - passwordSha1: new Buffer('f961d39c82138dcec42b8d0dcb3e40a14fb7e8cd', 'hex') // sha1(changeuser1pass) -}); -connection.query('select user()', function (err, rows) { - if (err) { - throw err; - } - assert.deepEqual(rows, [{'user()': 'changeuser1@localhost'}]); -}); - -connection.end(); - - -// from felixge/node-mysql/test/unit/connection/test-change-database-fatal-error.js: -// This test verifies that changeUser errors are treated as fatal errors. The -// rationale for that is that a failure to execute a changeUser sequence may -// cause unexpected behavior for queries that were enqueued under the -// assumption of changeUser to succeed. - -var beforeChange = 1; -connection.changeUser({database: 'does-not-exist'}, function (err) { - assert.ok(err, 'got error'); - assert.equal(err.code, 'ER_BAD_DB_ERROR'); - assert.equal(err.fatal, true); -}); - -connection.on('error', function (err) { - assert.ok(err, 'got disconnect'); - assert.equal(err.code, 'PROTOCOL_CONNECTION_LOST'); - assert.equal(beforeChange, 1); -}); -*/ +}, function(err, res) { + assert.ifError(err); + connection.query('select user()', function (err, rows) { + assert.ifError(err); + assert.deepEqual(rows, [{'user()': 'changeuser1@localhost'}]); + + connection.changeUser({ + user: 'changeuser2', + password: 'changeuser2pass' + }, function(err, res) { + + assert.ifError(err); + + connection.query('select user()', function (err, rows) { + assert.ifError(err); + assert.deepEqual(rows, [{'user()': 'changeuser2@localhost'}]); + + connection.changeUser({ + user: 'changeuser1', + passwordSha1: new Buffer('f961d39c82138dcec42b8d0dcb3e40a14fb7e8cd', 'hex') // sha1(changeuser1pass) + }, function(err, res) { + connection.query('select user()', function (err, rows) { + assert.ifError(err); + assert.deepEqual(rows, [{'user()': 'changeuser1@localhost'}]); + testIncorrectDb(); + }); + }); + }); + }); + }); +}); + +function testIncorrectDb() { + connection.end(); + // TODO figure out if stuff below is still relevant + /* + connection.on('error', function (err) { + assert.ok(err, 'got disconnect'); + assert.equal(err.code, 'PROTOCOL_CONNECTION_LOST'); + }); + connection.changeUser({database: 'does-not-exist', }, function (err) { + assert.ok(err, 'got error'); + assert.equal(err.code, 'ER_BAD_DB_ERROR'); + assert.equal(err.fatal, true); + }); + connection.end(); + */ +} From 39012930e82991a6655536f807db4c8d34055436 Mon Sep 17 00:00:00 2001 From: Andrey Sidorov Date: Tue, 28 Jun 2016 17:17:15 +1000 Subject: [PATCH 35/40] re-enable matrix --- .travis.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.travis.yml b/.travis.yml index 68a1bcf20b..b473ef665c 100644 --- a/.travis.yml +++ b/.travis.yml @@ -4,10 +4,10 @@ language: node_js before_script: - mysql -e 'create database /*M!50701 IF NOT EXISTS */ test;' node_js: -# - '0.10' -# - '0.12' -# - '4.4' -# - '5.11' + - '0.10' + - '0.12' + - '4.4' + - '5.12' - '6.2' From 9bba2580dab6c3f04ff9895ec30b82d3d4767e82 Mon Sep 17 00:00:00 2001 From: Andrey Sidorov Date: Tue, 28 Jun 2016 17:31:11 +1000 Subject: [PATCH 36/40] fix lint error --- lib/commands/client_handshake.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/commands/client_handshake.js b/lib/commands/client_handshake.js index b6a4dd26e3..b396f1ccac 100644 --- a/lib/commands/client_handshake.js +++ b/lib/commands/client_handshake.js @@ -149,7 +149,7 @@ ClientHandshake.prototype.handshakeResult = function (packet, connection) { if (marker !== 0) { var err = new Error('Unexpected packet during handshake phase'); if (this.onResult) { - this.onResult(err); + this.onResult(err); } else { connection.emit('error', err); } From 202a5c86c8921e4c62b79aab20cf95e9b39010b8 Mon Sep 17 00:00:00 2001 From: Andrey Sidorov Date: Tue, 28 Jun 2016 18:49:57 +1000 Subject: [PATCH 37/40] debug failing test --- test/integration/connection/test-change-user-plugin-auth.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/test/integration/connection/test-change-user-plugin-auth.js b/test/integration/connection/test-change-user-plugin-auth.js index 2b02d87f38..995f90cbc2 100644 --- a/test/integration/connection/test-change-user-plugin-auth.js +++ b/test/integration/connection/test-change-user-plugin-auth.js @@ -1,12 +1,15 @@ var assert = require('assert'); var common = require('../../common'); var connection = common.createConnection({ + debug: 1, authSwitchHandler: function () { throw new Error('should not be called - we expect mysql_native_password ' + 'plugin switch request to be handled by internal handler'); } }); +console.log(process.env); + // create test user first connection.query('GRANT ALL ON *.* TO \'changeuser1\'@\'localhost\' IDENTIFIED BY \'changeuser1pass\''); connection.query('GRANT ALL ON *.* TO \'changeuser2\'@\'localhost\' IDENTIFIED BY \'changeuser2pass\''); From 7390981d1a8b1e11efbb0e37db3c644f909325d5 Mon Sep 17 00:00:00 2001 From: Andrey Sidorov Date: Tue, 28 Jun 2016 20:28:47 +1000 Subject: [PATCH 38/40] set packet length during real serializing --- lib/packets/change_user.js | 3 +-- lib/packets/handshake_response.js | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/lib/packets/change_user.js b/lib/packets/change_user.js index e123c6f123..f363af7212 100644 --- a/lib/packets/change_user.js +++ b/lib/packets/change_user.js @@ -34,7 +34,7 @@ ChangeUser.prototype.serializeToBuffer = function (buffer) return self.flags & ClientConstants[flag]; } - var packet = new Packet(0, buffer, 0, 0); + var packet = new Packet(0, buffer, 0, buffer.length); packet.offset = 4; packet.writeInt8(CommandCode.CHANGE_USER); @@ -82,7 +82,6 @@ ChangeUser.prototype.toPacket = function () // dry run: calculate resulting packet length var p = this.serializeToBuffer(Packet.MockBuffer()); - return this.serializeToBuffer(new Buffer(p.offset)); }; diff --git a/lib/packets/handshake_response.js b/lib/packets/handshake_response.js index 81a169977c..6a51ce39c4 100644 --- a/lib/packets/handshake_response.js +++ b/lib/packets/handshake_response.js @@ -72,7 +72,7 @@ HandshakeResponse.prototype.serializeResponse = function (buffer) { return self.clientFlags & ClientConstants[flag]; } - var packet = new Packet(0, buffer, 0, 0); + var packet = new Packet(0, buffer, 0, buffer.length); packet.offset = 4; packet.writeInt32(this.clientFlags); packet.writeInt32(0); // max packet size. todo: move to config From 49fe4023c0925b0e322a4cbedf67cc42662faf6a Mon Sep 17 00:00:00 2001 From: Andrey Sidorov Date: Wed, 29 Jun 2016 15:24:55 +1000 Subject: [PATCH 39/40] set mysql server tz offset to 0 in time-related tests --- test/integration/connection/test-change-user-plugin-auth.js | 3 --- test/integration/connection/test-custom-date-parameter.js | 1 + test/integration/connection/test-date-parameter.js | 1 + test/integration/connection/test-datetime.js | 1 + 4 files changed, 3 insertions(+), 3 deletions(-) diff --git a/test/integration/connection/test-change-user-plugin-auth.js b/test/integration/connection/test-change-user-plugin-auth.js index 995f90cbc2..2b02d87f38 100644 --- a/test/integration/connection/test-change-user-plugin-auth.js +++ b/test/integration/connection/test-change-user-plugin-auth.js @@ -1,15 +1,12 @@ var assert = require('assert'); var common = require('../../common'); var connection = common.createConnection({ - debug: 1, authSwitchHandler: function () { throw new Error('should not be called - we expect mysql_native_password ' + 'plugin switch request to be handled by internal handler'); } }); -console.log(process.env); - // create test user first connection.query('GRANT ALL ON *.* TO \'changeuser1\'@\'localhost\' IDENTIFIED BY \'changeuser1pass\''); connection.query('GRANT ALL ON *.* TO \'changeuser2\'@\'localhost\' IDENTIFIED BY \'changeuser2pass\''); diff --git a/test/integration/connection/test-custom-date-parameter.js b/test/integration/connection/test-custom-date-parameter.js index c5e003bd20..5ebde5131c 100644 --- a/test/integration/connection/test-custom-date-parameter.js +++ b/test/integration/connection/test-custom-date-parameter.js @@ -13,6 +13,7 @@ Date = function () { return CustomDate; }(); +connection.query("set time_zone = '+00:00'"); connection.execute('SELECT UNIX_TIMESTAMP(?) t', [new Date('1990-08-08 UTC')], function (err, _rows, _fields) { if (err) { throw err; diff --git a/test/integration/connection/test-date-parameter.js b/test/integration/connection/test-date-parameter.js index c31bb955cb..554e5fa2d6 100644 --- a/test/integration/connection/test-date-parameter.js +++ b/test/integration/connection/test-date-parameter.js @@ -4,6 +4,7 @@ var assert = require('assert'); var rows = undefined; +connection.query("set time_zone = '+00:00'"); connection.execute('SELECT UNIX_TIMESTAMP(?) t', [new Date('1990-01-01 UTC')], function (err, _rows, _fields) { if (err) { throw err; diff --git a/test/integration/connection/test-datetime.js b/test/integration/connection/test-datetime.js index 08abcc6e66..bae3c4fc43 100644 --- a/test/integration/connection/test-datetime.js +++ b/test/integration/connection/test-datetime.js @@ -11,6 +11,7 @@ var date2 = '2010-12-10 14:12:09.019473'; var date3 = null; connection.query('CREATE TEMPORARY TABLE t (d1 DATE)'); +connection.query("set time_zone = '+00:00'"); connection.query('INSERT INTO t set d1=?', [date]); connection1.query('CREATE TEMPORARY TABLE t (d1 DATE, d2 TIMESTAMP, d3 DATETIME, d4 DATETIME)'); From cccff5e9d2961f1a1d2874626693078409caaac5 Mon Sep 17 00:00:00 2001 From: Andrey Sidorov Date: Wed, 29 Jun 2016 16:05:35 +1000 Subject: [PATCH 40/40] add auth-switch api to readme --- Changelog.md | 4 ++++ README.md | 34 ++++++++++++++++++++++++++++++++++ 2 files changed, 38 insertions(+) diff --git a/Changelog.md b/Changelog.md index 34b0bda3de..afb0795d38 100644 --- a/Changelog.md +++ b/Changelog.md @@ -1,3 +1,7 @@ +1.0.0-rc-6 ( 29/06/2016 ) + - AuthSwitch support and partial support for + plugin-based authentication #331 + 1.0.0-rc-5 ( 16/06/2016 ) - Fix incorrect releasing of dead pool connections #326, #325 - Allow pool options to be specified as URL params #327 diff --git a/README.md b/README.md index 592f2c4cb0..087822a57d 100644 --- a/README.md +++ b/README.md @@ -80,6 +80,40 @@ co(function * () { ``` see examples in [/examples/promise-co-await](/examples/promise-co-await) +### Authentication switch request + +During connection phase the server may ask client to switch to a different auth method. +If `authSwitchHandler` connection config option is set it must be a function that receive +switch request data and respond via callback. Note that if `mysql_native_password` method is +requested it will be handled internally according to [Authentication::Native41]( https://dev.mysql.com/doc/internals/en/secure-password-authentication.html#packet-Authentication::Native41) and +`authSwitchHandler` won't be invoked. `authSwitchHandler` MAY be called multiple times if +plugin algorithm requires multiple roundtrips of data exchange between client and server. +First invocation always has `({pluginName, pluginData})` signature, following calls - `({pluginData})`. +The client respond with opaque blob matching requested plugin via `callback(null, data: Buffer)`. + +Example: (imaginary `ssh-key-auth` plugin) pseudo code + +```js +var conn = mysql.createConnection({ + user: 'test_user', + password: 'test', + database: 'test_database', + authSwitchHandler: function(data, cb) { + if (data.pluginName === 'ssh-key-auth') { + getPrivateKey((key) => { + var response = encrypt(key, data.pluginData); + // continue handshake by sending response data + // respond with error to propagate error to connect/changeUser handlers + cb(null, response); + }) + } + } +}); +``` + +Initial handshake always performed using `mysql_native_password` plugin. This will be possible to override in +the future versions. + ### Named placeholders You can use named placeholders for parameters by setting `namedPlaceholders` config value or query/execute time option. Named placeholders are converted to unnamed `?` on the client (mysql protocol does not support named parameters). If you reference parameter multiple times under the same name it is sent to server multiple times.