Skip to content

Commit 493b267

Browse files
authored
feat: use mysql_clear_password for AWS IAM auth (#180)
1 parent 8dcb705 commit 493b267

File tree

3 files changed

+90
-0
lines changed

3 files changed

+90
-0
lines changed
Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
import { describe, it, expect } from 'vitest';
2+
import { MySQLConnector } from '../mysql/index.js';
3+
import { MariaDBConnector } from '../mariadb/index.js';
4+
5+
describe('DSN Parser - AWS IAM Authentication', () => {
6+
describe('MySQL', () => {
7+
const connector = new MySQLConnector();
8+
const parser = connector.dsnParser;
9+
10+
it('should detect AWS IAM token and configure cleartext plugin with SSL', async () => {
11+
const awsToken = 'mydb.abc123.us-east-1.rds.amazonaws.com:3306/?Action=connect&DBUser=myuser&X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=AKIAIOSFODNN7EXAMPLE/20240101/us-east-1/rds-db/aws4_request&X-Amz-Date=20240101T000000Z&X-Amz-SignedHeaders=host&X-Amz-Signature=abc123def456';
12+
const dsn = `mysql://myuser:${encodeURIComponent(awsToken)}@mydb.abc123.us-east-1.rds.amazonaws.com:3306/mydb`;
13+
14+
const config = await parser.parse(dsn);
15+
16+
// Should have authPlugins configured with cleartext plugin
17+
expect(config.authPlugins).toBeDefined();
18+
expect(config.authPlugins?.mysql_clear_password).toBeDefined();
19+
20+
// Should auto-enable SSL for AWS IAM authentication
21+
expect(config.ssl).toEqual({ rejectUnauthorized: false });
22+
23+
// Plugin should return password with null terminator
24+
if (config.authPlugins?.mysql_clear_password) {
25+
const pluginFunc = config.authPlugins.mysql_clear_password();
26+
const result = pluginFunc();
27+
expect(result).toBeInstanceOf(Buffer);
28+
expect(result.toString()).toBe(awsToken + '\0');
29+
}
30+
});
31+
32+
it('should not configure cleartext plugin for normal passwords', async () => {
33+
const dsn = 'mysql://myuser:regularpassword@localhost:3306/mydb';
34+
35+
const config = await parser.parse(dsn);
36+
37+
expect(config.authPlugins).toBeUndefined();
38+
expect(config.ssl).toBeUndefined();
39+
});
40+
});
41+
42+
describe('MariaDB', () => {
43+
const connector = new MariaDBConnector();
44+
const parser = connector.dsnParser;
45+
46+
it('should detect AWS IAM token and auto-enable SSL', async () => {
47+
const awsToken = 'mydb.abc123.us-east-1.rds.amazonaws.com:3306/?Action=connect&DBUser=myuser&X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=AKIAIOSFODNN7EXAMPLE/20240101/us-east-1/rds-db/aws4_request&X-Amz-Date=20240101T000000Z&X-Amz-SignedHeaders=host&X-Amz-Signature=abc123def456';
48+
const dsn = `mariadb://myuser:${encodeURIComponent(awsToken)}@mydb.abc123.us-east-1.rds.amazonaws.com:3306/mydb`;
49+
50+
const config = await parser.parse(dsn);
51+
52+
// SSL should be auto-enabled for AWS IAM auth
53+
// MariaDB connector includes mysql_clear_password in default permitted plugins
54+
expect(config.ssl).toEqual({ rejectUnauthorized: false });
55+
});
56+
57+
it('should not auto-enable SSL for normal passwords', async () => {
58+
const dsn = 'mariadb://myuser:regularpassword@localhost:3306/mydb';
59+
60+
const config = await parser.parse(dsn);
61+
62+
expect(config.ssl).toBeUndefined();
63+
});
64+
});
65+
});

src/connectors/mariadb/index.ts

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,17 @@ class MariadbDSNParser implements DSNParser {
6767
// Add other parameters as needed
6868
});
6969

70+
// Auto-detect AWS IAM authentication tokens and ensure SSL is enabled
71+
// AWS RDS IAM tokens are ~800+ character strings containing "X-Amz-Credential"
72+
// MariaDB connector includes mysql_clear_password in default permitted plugins,
73+
// but AWS IAM authentication requires SSL
74+
if (url.password && url.password.includes("X-Amz-Credential")) {
75+
// AWS IAM authentication requires SSL, enable if not already configured
76+
if (config.ssl === undefined) {
77+
config.ssl = { rejectUnauthorized: false };
78+
}
79+
}
80+
7081
return config;
7182
} catch (error) {
7283
throw new Error(

src/connectors/mysql/index.ts

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,20 @@ class MySQLDSNParser implements DSNParser {
7070
config.connectTimeout = connectionTimeoutSeconds * 1000;
7171
}
7272

73+
// Auto-detect AWS IAM authentication tokens and configure cleartext plugin
74+
// AWS RDS IAM tokens are ~800+ character strings containing "X-Amz-Credential"
75+
if (url.password && url.password.includes("X-Amz-Credential")) {
76+
config.authPlugins = {
77+
mysql_clear_password: () => () => {
78+
return Buffer.from(url.password + "\0");
79+
}
80+
};
81+
// AWS IAM authentication requires SSL, enable if not already configured
82+
if (config.ssl === undefined) {
83+
config.ssl = { rejectUnauthorized: false };
84+
}
85+
}
86+
7387
return config;
7488
} catch (error) {
7589
throw new Error(

0 commit comments

Comments
 (0)