Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add auth to mongo db container #5595

Open
wants to merge 68 commits into
base: main
Choose a base branch
from

Conversation

silaev
Copy link
Contributor

@silaev silaev commented Jul 13, 2022

Add Authentication to MongoDBContainer
Offical MongoDB doc reference

silaev and others added 30 commits October 7, 2019 16:57
…nfiguration for consistency, Move configure() to be a part of constructors
@github-actions github-actions bot added the github_actions Pull requests that update Github_actions code label Jul 13, 2022
@github-actions github-actions bot removed the github_actions Pull requests that update Github_actions code label Jul 14, 2022
@silaev
Copy link
Contributor Author

silaev commented Aug 8, 2022

Addresses a request to use auth with MongoDBContainer discussed here

@eddumelendez
Copy link
Member

@silaev thanks for the PR! and sorry for the delay. Can you update the branch and resolve the conflicts, please? There have been some changes since it was submitted 😬

# Conflicts:
#	modules/mongodb/src/main/java/org/testcontainers/containers/MongoDBContainer.java
#	modules/mongodb/src/test/java/org/testcontainers/containers/MongoDBContainerTest.java
@silaev
Copy link
Contributor Author

silaev commented Dec 14, 2022

@silaev thanks for the PR! and sorry for the delay. Can you update the branch and resolve the conflicts, please? There have been some changes since it was submitted 😬

Hi @eddumelendez, done

Copy link
Member

@eddumelendez eddumelendez left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the PR! I have left some comments and suggestions. Let's update the getConnectionString and getReplicaSetUrl accordingly.

Comment on lines +252 to +262
@Builder
@Getter
public static class ConnectionString {

@Builder.Default
private final String databaseName = DEFAULT_DATABASE_NAME;

private final String username;

private final String password;
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Mongo already provides a convinient way to create a client.

MongoClients.create(
                        MongoClientSettings.builder()
                            .credential(MongoCredential.createCredential(usernameRestrictedAccess, "admin", passwordRestrictedAccess.toCharArray()))
                            .applyConnectionString(new ConnectionString(String.format("mongodb://%s:%d", mongoDBContainer.getHost(), mongoDBContainer.getFirstMappedPort()) ))
                            .build()
                    )

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure that it's a good idea here because:

  • Exposing MongoClientSettings to the public API seems to be dangerous because a user might set a SRV DNS or other settings that MongoDBContainer does not support. I'd rather not allow a user to construct a URL on their side, it's safer to do delegate it to MongoDBContainer providing a URL string. Otherwise, we might receive some unexpected bug tickets here;

  • ConnectionString is for the public API purpose to expose only databaseName, username and password for now. As apposed to MongoClientSettings, it doesn't require setting auth db source, database etc. which simplifies the public API and takes control of it

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was not proposing to use Mongo API in MongoDBContainer. Just sharing how it can be done from the outside as in this suggestion

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd rather not allow a user to construct a URL on their side, it's safer to do delegate it to MongoDBContainer providing a URL string. Otherwise, we might receive some unexpected bug tickets here;

TBH, I do not expect users to do that but who knows.

I think our docs can be improved in order to make it clear

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We provide a URL string for a user via clear API that we take control of. I reckon it's not a good idea to constantly update docs mentioning "it does not support srv etc."? In my opionin, it's better not to provide a way to set srv.

I was not proposing to use Mongo API in MongoDBContainer. Just sharing how it can be done from the outside as in this suggestion

I see your point, but it's not a part of our public API. This way a user can construct everything, but having an issue with it is on their hands

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd rather not allow a user to construct a URL on their side, it's safer to do delegate it to MongoDBContainer providing a URL string. Otherwise, we might receive some unexpected bug tickets here;

TBH, I do not expect users to do that but who knows.

I think our docs can be improved in order to make it clear

I updated Java doc to make it clear

Copy link
Member

@kiview kiview Dec 16, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry @silaev, but it is still unclear with me what is the issue with the approach suggested by @eddumelendez, since it is very close to how we do it for other modules.

So you think users will struggle doing it this way and construct invalid URLs? Especially since users would normally use getConnectionString(). Or maybe I am missing the point of the discussion?

I thought @eddumelendez's point was about not exposing MongoDBContainer.ConnectionString as a public API.

Copy link
Contributor Author

@silaev silaev Dec 16, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi @kiview The idea of this builder is to provide 3 params for now (might be more in the future): username, pass and db name for MongoDBContainer to generate a URL as simple as this:

MongoClients.create(
    mongoDBContainer.getReplicaSetUrl(
        MongoDBContainer.ConnectionString
            .builder()
            .username(usernameRestrictedAccess)
            .password(passwordRestrictedAccess)
            .build()
    )
)

It’s similar to withUsername(...), withPassword(…) and withDatabaseName(...) etc. builder methods in the PostgreSQLContainer to generate a URL via getJdbcUrl(). As I understand, generating URL inside a container is close to how we do it for other modules. There is already public String getReplicaSetUrl(final String databaseName) {}, so I followed the same approach with a param here public String getReplicaSetUrl(final ConnectionString connectionString).

@eddumelendez proposed a solution when a URL is generated outside of MongoDBContainer via MongoClientSettings which we do not control. Is it close to how we do it for other modules ? This way a user has to construct a URL on their own and know some additional data:

MongoClients.create(
    MongoClientSettings.builder()
        .credential(MongoCredential.createCredential(usernameRestrictedAccess, "admin", passwordRestrictedAccess.toCharArray()))
        .applyConnectionString(new ConnectionString(String.format("mongodb://%s:%d", mongoDBContainer.getHost(), mongoDBContainer.getFirstMappedPort()) ))
        .build()
)

The second variant seems to me as quite complex and error prone, so I'm more comfortable with the first one. Correct me if I'm wrong, but the whole idea of Testcontainers is to simplify testing experience which, as I see it, the first variant follows

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi @kiview , @eddumelendez
I haven’t heard back from you after my last comment. Did I have a change to convince you to go with the simple builder approach?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi, thanks for ping us, I was thinking about it last week. There is a difference with the builders in database modules due to those are used by JdbcDatabaseContainer for the specific wait strategy and, well, JDBC API is in the JDK itself.

With latest changes in the MongoDbContainer, I would suggest the following:

  • Make authentication opt-in, withAuthenticationEnable(), instead of making it the default. Unless, a specific MongoDB version is forcing it, we can check on that version.
  • Provide withUsername and withPassword as initially provided in the PR
  • Do not provide a default key file. So, the user is aware of what's involved to run MongoDB with authentication enabled.
  • Make it work with sharding, if it is possible
  • Improve our javadocs and docs in general to show the correct usage of the module.

Testcontainers responsibility is to provide a ready to use service running in a container. There could be many configuration in the service itself which we do not master and we prefer a generic approach, meanwhile we are learning from uses cases, rather than do something at the beginning that can change later just because we are not aware of it.

I know the answer doesn't answer the last question but I think it is our best effort, meanwhile we also learn about MongoDB and how to use it. So, the builder can be revisited in the future. I'm also aware that this will involve more changes than initially expected but it is due to the evolution of the module itself.

Comment on lines +154 to +159
mongoDBContainer.getReplicaSetUrl(
MongoDBContainer.ConnectionString
.builder()
.username(usernameRestrictedAccess)
.password(passwordRestrictedAccess)
.build()
Copy link
Member

@eddumelendez eddumelendez Dec 14, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
mongoDBContainer.getReplicaSetUrl(
MongoDBContainer.ConnectionString
.builder()
.username(usernameRestrictedAccess)
.password(passwordRestrictedAccess)
.build()
MongoClientSettings.builder()
.credential(MongoCredential.createCredential(usernameRestrictedAccess, "admin", passwordRestrictedAccess.toCharArray()))
.applyConnectionString(new ConnectionString(String.format("mongodb://%s:%d", mongoDBContainer.getHost(), mongoDBContainer.getFirstMappedPort()) ))
.build()

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

pls, see the above mentioned discussion about MongoClientSettings

@silaev
Copy link
Contributor Author

silaev commented Dec 15, 2022

@eddumelendez, thanks for the review. I address all the discussions. Please, let me know if anything else is needed from me

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

4 participants