vertx-sql-client icon indicating copy to clipboard operation
vertx-sql-client copied to clipboard

RDS IAM auth fails with Vertx mysql driver

Open amkartashov opened this issue 3 years ago • 6 comments

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.

amkartashov avatar Jul 21 '22 14:07 amkartashov

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

amkartashov avatar Jul 21 '22 18:07 amkartashov

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

amk-papaya avatar Jul 21 '22 19:07 amk-papaya

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?

BillyYccc avatar Jul 22 '22 15:07 BillyYccc

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

pmlopes avatar Jul 22 '22 17:07 pmlopes

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.

amkartashov avatar Jul 23 '22 04:07 amkartashov

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.

amkartashov avatar Jul 23 '22 04:07 amkartashov

Hey @BillyYccc sorry for the delay. I've tested your PR and it works fine.

amkartashov avatar Aug 21 '22 12:08 amkartashov