asyncer-io / r2dbc-mysql

Reactive Relational Database Connectivity for MySQL. The official successor to mirromutth/r2dbc-mysql(dev.miku:r2dbc-mysql).
https://r2dbc.io
Apache License 2.0
195 stars 21 forks source link

Added Support for providing configuration option for supplying password function #157

Closed bhosale closed 11 months ago

bhosale commented 11 months ago

Motivation: Currently r2dbc-mysql does not support IAM based Authentication for authenticating with AWS Aurora RDS database. The way IAM based authentication works is requesting token from AWS RDS for that hostname and username (which is same as AWS IAM Role name). These tokens are valid for 15 minutes, cannot reuse same token after 15 minutes. By adding configuration option for supplying password function, whenever a new connection is made then password is retrieved using supplier function each time.

Modification: Modified MySqlConnectionFactoryProvider - Added new configurable option. Option<Supplier<Mono<String>>> PASSWORD_SUPPLIER = Option.valueOf("passwordSupplier"); Modified MySqlConnectionConfiguration - Added the new configuration for Password Supplier function. Supplier<Mono<String>> passwordSupplier; Modified MySqlConnectionFactory - Retrieves Password Supplier function from configuration, and then retrieves password each time connection factory is created.

Result: Users can provide a supplier function using PASSWORD_SUPPLIER option. This function will be used for retrieving password/token each time.

public ConnectionFactory writeConnectionFactory(final RdsTokenGenerator rdsTokenGenerator) {
        return ConnectionFactories.get(ConnectionFactoryOptions.builder()
            .option(ConnectionFactoryOptions.DRIVER, "mysql")
            .option(ConnectionFactoryOptions.HOST, "Hostname of AWS Aurora DB instance")
            .option(ConnectionFactoryOptions.PORT, 3306)
            .option(ConnectionFactoryOptions.USER, "IAM ROLE Having access to RDS")
            .option(MySqlConnectionFactoryProvider.PASSWORD_SUPPLIER, rdsTokenGenerator::generateAuthenticationToken)
            .build());
    }

Example of RdsTokenGenerator

public class RdsTokenGenerator {
    public Mono<String> generateAuthenticationToken() {
        return Mono.fromCallable(() -> RdsUtilities.builder()
            .credentialsProvider(DefaultCredentialsProvider.create())
            .region(Region.US_EAST_1)
            .build();
            .generateAuthenticationToken((builder) ->
                builder
                    .hostname(hostname)
                    .port(port)
                    .username(user)
            ))
            .flatMap(token -> LOGGER.info("Retrieved token from RdsUtilities")
                .then(Mono.just(token)))
            .subscribeOn(Schedulers.boundedElastic());
    }

}
jchrys commented 11 months ago

Hello, @bhosale thank you so much for your efforts in supporting this.

I believe we could utilize Supplier<String> instead of Supplier<Mono<String>> to avoid imposing the adoption of Reactor and simplify the interface. WDYT?

Additionally, could you please write a test case for this change?

jchrys commented 11 months ago

PTAL @JohnNiang @mobidick1969

bhosale commented 11 months ago

Thanks @jchrys for reviewing and providing feedback on the pull request. I have added couple of unit test cases.

As I understand the connection is established each time an SQL statement is executed, if we use just Supplier<String> instead of Supplier<Mono<String>>, there's a potential risk that the supplier function might involve blocking operations, which could have adverse consequences.

jchrys commented 11 months ago

Establishing a connection involves multiple round-trip operations, which is why many of our users choose to pool connections using r2dbc-pool or similar solutions (and we highly recommend it).

I understand your point. I believe it would be more suitable to expose org.reactivestreams.Publisher<String> instead of Supplier<Mono<String>>. This way, we provide a more general interface that accommodates users who may use RxJava, Reactor, or other reactive libraries

bhosale commented 11 months ago

Agree, I am also using pool.

Publisher<String> makes sense instead of Subscriber<Mono<String>>. Updated the code with that change.