Skip to content
Permalink
Browse files
[CONJS-166] Restrict authentication plugin list by option
new option `restrictedAuth` permit to restrict authentication plugin used to indicated list.
  • Loading branch information
rusher committed Jun 4, 2021
1 parent ca895c6 commit d176b01
Show file tree
Hide file tree
Showing 8 changed files with 71 additions and 65 deletions.
@@ -28,6 +28,7 @@
| **insertIdAsNumber** | Whether the query should return last insert id from INSERT/UPDATE command as BigInt or Number. default return BigInt |*boolean* | false |
| **decimalAsNumber** | Whether the query should return decimal as Number. If enable, this might return approximate values. |*boolean* | false |
| **bigIntAsNumber** | Whether the query should return BigInt data type as Number. If enable, this might return approximate values. |*boolean* | false |
| **restrictedAuth** | if set, restrict authentication plugin to secure list. Default provided plugins are mysql_native_password, mysql_clear_password, client_ed25519, dialog, sha256_password and caching_sha2_password |*Array|String* | |


### JSON or String configuration
@@ -169,7 +169,16 @@ class Handshake extends Command {
pluginName = packet.readStringNullEnded('cesu8');
pluginData = packet.readBufferRemaining();
}

if (opts.restrictedAuth && !opts.restrictedAuth.includes(pluginName)) {
this.throwNewError(
`Unsupported authentication plugin ${pluginName}. Authorized plugin: ${opts.restrictedAuth.toString()}`,
true,
info,
'42000',
Errors.ER_NOT_SUPPORTED_AUTH_PLUGIN
);
return;
}
try {
this.plugin = Handshake.pluginHandler(
pluginName,
@@ -122,7 +122,12 @@ class ConnectionOptions {
this.decimalAsNumber = opts.decimalAsNumber || false;
this.bigIntAsNumber = opts.bigIntAsNumber || false;
this.prepareCacheLength = opts.prepareCacheLength === undefined ? 256 : opts.prepareCacheLength;

this.restrictedAuth = opts.restrictedAuth;
if (this.restrictedAuth !== undefined && this.restrictedAuth !== null) {
if (!Array.isArray(this.restrictedAuth)) {
this.restrictedAuth = this.restrictedAuth.split(',');
}
}
if (this.maxAllowedPacket && !Number.isInteger(this.maxAllowedPacket)) {
throw new RangeError(
"maxAllowedPacket must be an integer. was '" + this.maxAllowedPacket + "'"
@@ -187,7 +192,6 @@ class ConnectionOptions {
if (opts.insertIdAsNumber) opts.insertIdAsNumber = opts.insertIdAsNumber == 'true';
if (opts.decimalAsNumber) opts.decimalAsNumber = opts.decimalAsNumber == 'true';
if (opts.bigIntAsNumber) opts.bigIntAsNumber = opts.bigIntAsNumber == 'true';

if (opts.charsetNumber && !isNaN(Number.parseInt(opts.charsetNumber))) {
opts.charsetNumber = Number.parseInt(opts.charsetNumber);
}
@@ -110,6 +110,7 @@ module.exports.ER_BAD_PARAMETER_VALUE = 45043;
module.exports.ER_CANNOT_RETRIEVE_RSA_KEY = 45044;
module.exports.ER_MINIMUM_NODE_VERSION_REQUIRED = 45045;
module.exports.ER_MAX_ALLOWED_PACKET = 45046;
module.exports.ER_NOT_SUPPORTED_AUTH_PLUGIN = 45047;

const keys = Object.keys(module.exports);
const errByNo = {};
@@ -63,69 +63,61 @@ describe('authentication plugin', () => {
}
});

it('ed25519 authentication plugin', function (done) {
it('ed25519 authentication plugin', async function () {
if (process.env.srv === 'maxscale' || process.env.srv === 'skysql-ha') this.skip();
const self = this;
if (!shareConn.info.isMariaDB() || !shareConn.info.hasMinVersion(10, 1, 22)) this.skip();

shareConn
.query('SELECT @@strict_password_validation as a')
.then((res) => {
if (res[0].a === 1 && !shareConn.info.hasMinVersion(10, 4, 0)) self.skip();
shareConn
.query("INSTALL SONAME 'auth_ed25519'")
.then(
() => {
shareConn
.query("drop user IF EXISTS verificationEd25519AuthPlugin@'%'")
.then(() => {
if (shareConn.info.hasMinVersion(10, 4, 0)) {
return shareConn.query(
"CREATE USER verificationEd25519AuthPlugin@'%' IDENTIFIED " +
"VIA ed25519 USING PASSWORD('MySup8%rPassw@ord')"
);
}
return shareConn.query(
"CREATE USER verificationEd25519AuthPlugin@'%' IDENTIFIED " +
"VIA ed25519 USING '6aW9C7ENlasUfymtfMvMZZtnkCVlcb1ssxOLJ0kj/AA'"
);
})
.then(() => {
return shareConn.query(
'GRANT SELECT on `' +
Conf.baseConfig.database +
"`.* to verificationEd25519AuthPlugin@'%'"
);
})
.then(() => {
base
.createConnection({
user: 'verificationEd25519AuthPlugin',
password: 'MySup8%rPassw@ord'
})
.then((conn) => {
conn.end();
done();
})
.catch(done);
})
.catch((err) => {
const expectedMsg = err.message.includes(
"Client does not support authentication protocol 'client_ed25519' requested by server."
);
if (!expectedMsg) console.log(err);
assert(expectedMsg);
done();
});
},
(err) => {
//server wasn't build with this plugin, cancelling test
self.skip();
}
)
.catch(done);
})
.catch(done);
const res = await shareConn.query('SELECT @@strict_password_validation as a');
if (res[0].a === 1 && !shareConn.info.hasMinVersion(10, 4, 0)) self.skip();
await shareConn.query("INSTALL SONAME 'auth_ed25519'");
await shareConn.query("drop user IF EXISTS verificationEd25519AuthPlugin@'%'");
if (shareConn.info.hasMinVersion(10, 4, 0)) {
await shareConn.query(
"CREATE USER verificationEd25519AuthPlugin@'%' IDENTIFIED " +
"VIA ed25519 USING PASSWORD('MySup8%rPassw@ord')"
);
} else {
await shareConn.query(
"CREATE USER verificationEd25519AuthPlugin@'%' IDENTIFIED " +
"VIA ed25519 USING '6aW9C7ENlasUfymtfMvMZZtnkCVlcb1ssxOLJ0kj/AA'"
);
}

await shareConn.query(
'GRANT SELECT on `' + Conf.baseConfig.database + "`.* to verificationEd25519AuthPlugin@'%'"
);
try {
let conn = await base.createConnection({
user: 'verificationEd25519AuthPlugin',
password: 'MySup8%rPassw@ord'
});
conn.end();
try {
conn = await base.createConnection({
user: 'verificationEd25519AuthPlugin',
password: 'MySup8%rPassw@ord',
restrictedAuth: ''
});
conn.end();
throw new Error('must have thrown error');
} catch (err) {
assert.equal(
err.text,
'Unsupported authentication plugin client_ed25519. Authorized plugin: '
);
assert.equal(err.errno, 45047);
assert.equal(err.sqlState, '42000');
assert.equal(err.code, 'ER_NOT_SUPPORTED_AUTH_PLUGIN');
assert.isTrue(err.fatal);
}
} catch (err) {
const expectedMsg = err.message.includes(
"Client does not support authentication protocol 'client_ed25519' requested by server."
);
if (!expectedMsg) console.log(err);
assert(expectedMsg);
}
});

it('name pipe authentication plugin', function (done) {
@@ -15,7 +15,6 @@ describe('Compression', function () {
conn = con;
conn.query('SELECT @@max_allowed_packet as t').then((row) => {
maxAllowedSize = Number(row[0].t);
console.log('max_allowed_size:' + maxAllowedSize);
if (testSize < maxAllowedSize) {
buf = Buffer.alloc(testSize);
randomBuf = Buffer.alloc(testSize);
@@ -48,7 +47,7 @@ describe('Compression', function () {
};

it('test compression multiple packet', function (done) {
this.timeout(30000);
this.timeout(60000);
if (maxAllowedSize < 35000000) this.skip();

conn.query(
@@ -621,7 +621,6 @@ describe('Error', () => {
done(new Error('must have thrown error !'));
})
.catch((err) => {
console.log(err);
assert.equal(err.errno, 45016);
assert.equal(err.sqlState, 'HY000');
assert.equal(err.code, 'ER_MISSING_PARAMETER');
@@ -23,6 +23,7 @@ describe('test options', () => {
compress: false,
rsaPublicKey: undefined,
cachingRsaPublicKey: undefined,
restrictedAuth: undefined,
allowPublicKeyRetrieval: false,
forceVersionCheck: false,
maxAllowedPacket: undefined,

0 comments on commit d176b01

Please sign in to comment.