How to configure credentials using Quarkus MongoDB client?

1,836 views
Skip to first unread message

David Hoffer

unread,
Sep 15, 2021, 5:19:47 PM9/15/21
to Quarkus Development mailing list
Our Quarkus app uses the container to manage the JPA/JTA/ORM stack but currently still uses manual connection management of the MongoDB.  I would like to convert to using the container to manage this.

I'm following https://quarkus.io/guides/mongodb but I can't figure out how to configure the DB login.  The current login is creating MongoCredential using SCRAM with a simple username and password.

How do I do something similar when configuring Mongo client in Quarkus?

Ideally I'd like this to be just like the JPA stack where we implement a Quarkus CredentialsProvider and we do the password lookup/decrypting there but it seems Mongo has a different approach.

The MongoDb properties has this:

Configures the authentication mechanism to use if a credential was supplied. The default is unspecified, in which case the client will pick the most secure mechanism available based on the sever version. For the GSSAPI and MONGODB-X509 mechanisms, no password is accepted, only the username. Supported values: MONGO-CR|GSSAPI|PLAIN|MONGODB-X509

I note that SCRAM is not in this list but that is apparently the default approach used by MongoDB client now. I tried MONGO-CR but get a runtime error saying Invalid authMechanism 'MONGO-CR'. So it seems the Mongo runtime that ships with Quarkus has moved on but the configuration in Quarkus still uses the old??

How can I do a regular username/password login to MongoDB using the Quarkus MongoDB client?

I'm using 2.1.4.Final but could move to latest if things are different there.

-Dave

David Hoffer

unread,
Sep 15, 2021, 6:46:02 PM9/15/21
to Quarkus Development mailing list
It looks like the MongoDB client that ships with Quarkus supports SCRAM-SHA-1 & SCRAM-SHA-256 (documentation doesn't mention either) but when Quarkus loads it only loads SCRAM-SHA-1.  My current code uses SCRAM-SHA-256 so probably need that but also how do I configure the client to decrypt the password?

How do I wire in the logic that reads the encrypted password from: quarkus.mongodb.credentials.password ?

Does that use the following somehow?

quarkus.mongodb.credentials.auth-source
quarkus.mongodb.credentials.auth-mechanism-properties

-Dave

Loïc MATHIEU

unread,
Sep 16, 2021, 3:19:23 AM9/16/21
to David Hoffer, Quarkus Development mailing list
Hi,

I didn't have time to dig into your issue but the mongodb-client extension is based on the official MongoDB driver and allows to configure it via application.properties and inject it into your application.

Everything that can be done with the official MongoDB driver should be possible with the extension. As the official MongoDB driver evolves over time, maybe the extension and its configuration capability is not up to date.

If you can provide an example of what you want to do as a piece of code using the MongoDB driver (by creating programmatically the MongoClient) we could be able to help you.

Regards,

Loïc


--
You received this message because you are subscribed to the Google Groups "Quarkus Development mailing list" group.
To unsubscribe from this group and stop receiving emails from it, send an email to quarkus-dev...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/quarkus-dev/ac464497-edf7-4565-9680-0f2b2dbc22d9n%40googlegroups.com.

David Hoffer

unread,
Sep 16, 2021, 10:14:20 AM9/16/21
to Quarkus Development mailing list
Sure, here is what the old code was doing, I'm looking to replace this using the Quarkus injected MongoClient and configuration.  Currently I'm stuck on the  ScramSha256Credential part.

private static MongoClient getMongoClient() {
return new MongoClient(getMongoServerAddresses(),
                    getCredentials(getMongoDb()), 
getOptions().build());
}
private static MongoCredential getCredentials(String mongoDb) {
        return MongoCredential.createScramSha256Credential(mongoUserName, mongoDb,
                AESEncryptDecrypt.decryptStr(mongoPassword).toCharArray());
}

private static MongoClientOptions.Builder getOptions() {
        return MongoClientOptions.builder()
.threadsAllowedToBlockForConnectionMultiplier(500)
            .connectionsPerHost(MONGO_CONNECTIONS_PER_HOST)
            .maxConnectionIdleTime(TIME_LIMIT.intValue())
            .readPreference(ReadPreference.nearest());
}

-Dave

David Hoffer

unread,
Sep 16, 2021, 10:30:56 AM9/16/21
to Quarkus Development mailing list
But here is the Quarkus code from 2.2.3.Final, it's missing SCRAM_SHA_256.  But even bigger question is how to decrypt the password?  The password below has to be decrypted first, how?

// Create the MongoCredential instance.
MongoCredential credential;
if (mechanism == GSSAPI) {
credential = MongoCredential.createGSSAPICredential(username);
} else if (mechanism == PLAIN) {
credential = MongoCredential.createPlainCredential(username, authSource, password);
} else if (mechanism == MONGODB_X509) {
credential = MongoCredential.createMongoX509Credential(username);
} else if (mechanism == SCRAM_SHA_1) {
credential = MongoCredential.createScramSha1Credential(username, authSource, password);
} else if (mechanism == null) {
credential = MongoCredential.createCredential(username, authSource, password);
} else {
throw new IllegalArgumentException("Unsupported authentication mechanism " + mechanism);
}

-Dave

Loïc MATHIEU

unread,
Sep 16, 2021, 10:38:16 AM9/16/21
to David Hoffer, Quarkus Development mailing list
Hi,

I quickly look at the code and SCRAM_SHA_1 is supported but not SCRAM_SHA_256.
The following PR should take care of it (but I cannot really test it as I don't have a MongoDB database with this auth mechanism): https://github.com/quarkusio/quarkus/pull/20203

Loïc MATHIEU

unread,
Sep 16, 2021, 10:42:26 AM9/16/21
to David Hoffer, Quarkus Development mailing list
> The password below has to be decrypted first, how?

I'm not a security expert but I think you configure the decrypted password and it's the responsibility of the MongoDB client to discuss with the server to obtain the key to encrypt the password (via public key), then the server uses its private key to decrypt it.

David Hoffer

unread,
Sep 16, 2021, 10:44:49 AM9/16/21
to Quarkus Development mailing list
Yes I agree that PR should fix the issue so it can support  SCRAM_SHA_256.

But how do we decrypt the password?  We cannot have passwords in plain text in the application.yml file (or any other place).  What is the mechanism to decrypt the password first?

-Dave

David Hoffer

unread,
Sep 16, 2021, 11:09:08 AM9/16/21
to Quarkus Development mailing list
Our posts crossed.

I'm not a security expert either but I don't think that is how SCRAM works.  And we certainly cannot store the password in plain text, that would defeat the entire security system.  I believe SCRAM compares the user's name & password with what is in the Mongo authentication DB.  It does not use public/private keys at all.  It uses 'Salted Challenge Response Authentication Mechanism' which is a standard for authenticating users with passwords. 

It seems what is missing in the Quarkus implementation is a way to decrypt the user's password before the SCRAM process begins.

-Dave 

Loïc MATHIEU

unread,
Sep 16, 2021, 11:36:38 AM9/16/21
to David Hoffer, Quarkus Development mailing list
Well, it's a nonce and a salt but it's the same idea. An exchange between the client and the server.

Reading the Blog post series, it seems that you pass the user/password in clear in your code but encrypted over the wire (this is where it protectes you) and in the database.


In the part 2, you can find this : > db.auth({user: "testUser", pwd: "testPassword"})

Now, if you want to avoid putting the password inside your application.properties, there is multiple things you can do:
- Use an environment variable
- Use a k8s or a Vault secret

I don't think we supported encrypted password in config file yet in Quarkus.


David Hoffer

unread,
Sep 16, 2021, 11:51:30 AM9/16/21
to Loïc MATHIEU, Quarkus Development mailing list
Okay I think I'll have to back off using Quarkus for managing the Mongo client then.  It's a non-starter to put passwords in application.properties.  Ideally I would like Quarkus to use the same approach as it uses for relational database clients, e.g. use the CredentialsProvider approach as that lets users get their usernames/passwords anyway they want.  And why have a different approach for Mongo?

If we did want to continue with this...can you elaborate on how the environment variable approach would work?

-Dave

Stuart Douglas

unread,
Sep 17, 2021, 2:42:10 AM9/17/21
to David Hoffer, Loïc MATHIEU, Quarkus Development mailing list
You could just use a org.eclipse.microprofile.config.spi.ConfigSource to configure the password if you don't want it in application.properties. This will work for any config value.

Stuart

Loïc MATHIEU

unread,
Sep 17, 2021, 5:13:48 AM9/17/21
to Stuart Douglas, David Hoffer, Quarkus Development mailing list
Hi,

Usine env variable or an .env file is q standard to override configuration properties at runtime.
This is explained in the configuration reference guide.

I'd you need more control over the way we deal with Mongo authentication, please open an enhancement request via a github issue and describe why you need this and some idea and pseudo code.

Regards

Loïc 

David Hoffer

unread,
Sep 17, 2021, 1:37:46 PM9/17/21
to Quarkus Development mailing list
Using https://quarkus.io/guides/config-extending-support#config-interceptors is an interesting idea.  If we can use that to read properties we have elsewhere that is a great solution.

I tried using it and have mixed results.  I used the InMemoryConfigSource example/approach, I defer reading the property values until the getValue(String propertyName) method.

The problem is Quarkus is adding my InMemoryConfigSource to its STATIC INIT process and it literally executes my code in the getValue method during the build.  This is problematic because this is normally getting the values from a ZooKeeper cluster which isn't available during build time.  E.g. I need this to get the value at runtime not build time.  The documentation here says that Quarkus won't add it to the STATIC INIT unless I add @io.quarkus.runtime.configuration.StaticInitSafe but that is not true.  It is adding it w/o that annotation too.

So to get around this problem I configured the build to load our properties from a file instead of ZK.  And this did work and I tested that Quarkus does reload the properties at runtime so what it did at build time was extraneous.

Is there a way I can turn off STATIC INIT for my ConfigSources?  It's not going to be convenient to have to add the VM command line options to force loading from files to every build as well as have the external files just to do a build when they are not needed until runtime.

I tried the ConfigSourceFactory approach too but has same issue...it executes code that is not available until runtime.

-Dave

Loïc MATHIEU

unread,
Sep 20, 2021, 5:42:31 AM9/20/21
to David Hoffer, Roberto Cortez, Quarkus Development mailing list
There is a Quarkus consul extension that allows reading configuration items from Consul: https://quarkus.io/guides/consul-config

For the config source issue, maybe @Roberto Cortez can help ?

David Hoffer

unread,
Sep 20, 2021, 10:39:22 AM9/20/21
to Quarkus Development mailing list
Thanks for the tip on the Consul extension.  I'll let others know but I doubt we will be up for a major change like that.  We currently use ZooKeeper for app KV configuration and I doubt up for a major change.  Any chance Quarkus has a ZK extension?

However it seems the ideal solution would be for the MongoDB client to use the same approach as several other Quarkus data stores, e.g. https://quarkus.io/guides/credentials-provider

We use this for all Agroal data sources and works great.  However I see MongoDB client is not on the supported list yet.  

I see this is implemented by the vault extension (whatever that is).  Is that something that can be easily added to MongoDB client?

Also very interested to learn regarding my prior question if the STATIC INIT for my ConfigSources can be disabled.  Documentation implies it is disabled by default but in my usage it was on by default.  If I can get that off then that is good solution as well.

-Dave

Loïc MATHIEU

unread,
Sep 20, 2021, 11:24:28 AM9/20/21
to David Hoffer, Quarkus Development mailing list
Currently, Quarkus Credential Provider only supports Vault as a credential source.
So you need to have Vault (a configuration K/V store from Hashicorp) and use it to store your credentials.

We can provide an integration between the currently supported Credential Provider with MongoDB but in this case you will need to use Vault.

Regarding integration with Zookeeper, I remember some already discussed it and I don't know if there is an existing extension or not. You can open an extension request in the Github repo.

David Hoffer

unread,
Sep 20, 2021, 11:43:18 AM9/20/21
to Loïc MATHIEU, Quarkus Development mailing list
For our purposes it would be terrific if Quarkus supported the Credential Provider solution with MongoDB.  We already use that for all Agroal data sources and would be nice to use the same for MongoDB.

(I don't know the details of how Agroal implemented this but it is simple to configure and it works.)

How easy/quick could that be supported?

-Dave

Loïc MATHIEU

unread,
Sep 20, 2021, 11:56:45 AM9/20/21
to David Hoffer, Quarkus Development mailing list
So you are using a Custom Credential Provider ? https://quarkus.io/guides/credentials-provider#custom-credentials-provider

Please open a enhancement request as a github issue in the Quarkus repo. I cannot say anything about who, how, when for it.
Personally, I will not have the time to have a look in a near future but maybe someone will have.

Regards,

Loïc

David Hoffer

unread,
Sep 20, 2021, 12:21:28 PM9/20/21
to Loïc MATHIEU, Quarkus Development mailing list
Yes we are using a custom credential provider.


-Dave
Reply all
Reply to author
Forward
0 new messages