vertx-sql-client
vertx-sql-client copied to clipboard
RDS IAM auth fails with Vertx mysql driver
Version
io.vertx:vertx-mysql-client:4.3.2
Context
I can't connect to RDS using IAM auth.
Do you have a reproducer?
https://github.com/amkartashov/vertx-mysql-iam-auth-bug
This is a test app just to check IAM auth. It uses both MySQL Java Connector 8.0 and VertX MySQL Client. There are no such issue with MySQL Java Connector.
Steps to reproduce
In README.md of above repo. Basically, you need to have RDS with IAM auth configured, generate RDS auth token with aws cli, and then pass connection settings via env vars (DB_HOST/NAME/USER/PASS) to application (started via gradle run)
Output with failure:
vertx-mysql-iam-auth-bug$ TOKEN=$(aws rds generate-db-auth-token \
--hostname iam-auth-test.cluster-XXXXXXX.eu-west-1.rds.amazonaws.com \
--port 3306 \
--username dbuser)
vertx-mysql-iam-auth-bug$ DB_HOST=iam-auth-test.cluster-XXXXXXX.eu-west-1.rds.amazonaws.com \
DB_USER=dbuser \
DB_NAME=information_schema \
DB_PASS="${TOKEN}" \
gradle -q run
URI: mysql://[email protected]/information_schema
============ Try with MySQL connector ============
1
============ Try with Vertx ============
Access denied for user 'dbuser'@'10.160.3.126' (using password: YES)
Expected:
...
============ Try with Vertx ============
Got 1 rows
Extra
- Anything that can be relevant such as OS version, JVM version
Tested with openjdk 17.0.3+7-Ubuntu-0ubuntu0.20.04.1 and gradle 7.5
Btw, if I set creds for a regular user (via DB_USER/DB_PASS) - reproducer app will work correctly both for MySQL Java Connector and VertX MySQL Client.
Actually, I think I found the problem - password sent in clear text is not null terminated.
My check app starts to work if I recompile vertx-mysql client with this part changed:
from
if ((clientCapabilitiesFlags & CLIENT_PLUGIN_AUTH_LENENC_CLIENT_DATA) != 0) {
BufferUtils.writeLengthEncodedInteger(packet, authResponse.length);
packet.writeBytes(authResponse);
} else if ((clientCapabilitiesFlags & CLIENT_SECURE_CONNECTION) != 0) {
to
if ((clientCapabilitiesFlags & CLIENT_PLUGIN_AUTH_LENENC_CLIENT_DATA) != 0) {
BufferUtils.writeLengthEncodedInteger(packet, authResponse.length + 1);
packet.writeBytes(authResponse);
System.out.println("================================================= NULL TERMINATED");
packet.writeByte(0);
} else if ((clientCapabilitiesFlags & CLIENT_SECURE_CONNECTION) != 0) {
to work around this on app level, I'm adding NULL to a password (converting back and forth between String and byte[]):
byte[] dbPassBytes = dbPass.getBytes("UTF-8");
byte[] dbPassNullTerminatedBytes = new byte[dbPassBytes.length + 1];
System.arraycopy(dbPassBytes, 0, dbPassNullTerminatedBytes, 0, dbPassBytes.length);
String dbPassNullTerminated = new String(dbPassNullTerminatedBytes);
SqlClient client = MySQLPool.client(
new MySQLConnectOptions()
...
.setPassword(dbPassNullTerminated)
Btw, similar bug in PHP client: https://bugs.php.net/bug.php?id=78680
in mysql connector, they write zero byte after the password: https://github.com/mysql/mysql-connector-j/blob/release/8.0/src/main/protocol-impl/java/com/mysql/cj/protocol/a/authentication/MysqlClearPasswordPlugin.java#L92
see also protocol docs :
client-side sends password as string.NUL
Thanks for the investigation! I have submitted a PR in https://github.com/eclipse-vertx/vertx-sql-client/pull/1216, can you have a try with the branch?
Just a note: perhaps it could be interesting to have a feature where authentication can be plugged, and for AWS a plugin could use the following to automate the login process:
https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/UsingWithRDS.IAMDBAuth.Connecting.Java.html
Just a note: perhaps it could be interesting to have a feature where authentication can be plugged, and for AWS a plugin could use the following to automate the login process:
https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/UsingWithRDS.IAMDBAuth.Connecting.Java.html
This is exactly the thing I was working on when discovered this issue. In our project we use hibernate reactive and vertx driver. I extend class io.vertx.mysqlclient.MySQLConnectOptions to override getPassword() method.
Thanks for the investigation! I have submitted a PR in #1216, can you have a try with the branch?
Will be able to do this next week.
Hey @BillyYccc sorry for the delay. I've tested your PR and it works fine.