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
Support user info in Elasticsearch URIs #21381
Conversation
Thanks very much for the PR, @evgeniycheban Could you please take a look at adding some tests for the new functionality? I think they could be implemented as additions to |
Thanks for the review, @wilkinsona Sure, I will add tests. |
6da09b1
to
03c7ca3
Compare
@wilkinsona I added tests. When you have a moment, please take a look. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for the updates. I've left a few more comments. Could you please take a look when you have a moment?
@@ -114,25 +123,48 @@ RestClient elasticsearchRestClient(RestClientBuilder builder) { | |||
|
|||
private final ElasticsearchRestClientProperties properties; | |||
|
|||
private CredentialsProvider credentialsProvider = new BasicCredentialsProvider(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Creating a field for the CredentialsProvider
and allowing it to be injected doesn't seem to be related to supporting user info in the URI. Can you please revert this part of the changes?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I added this to make testing easer, because we can not access credentialsProvider
field from InternalHttpAsyncClient
. It can also be useful in some cases when the user needs to use a custom CredentialsProvider
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think it's safe to expose a CredentialProvider
as a bean. In this case the credentials that it provides are specific to Elasticsearch, but there's nothing about the bean that indicates that's the case. It could be accidentally consumed and used anywhere that's working with an Apache HTTP client, potentially leaking credentials to another service.
For this sort of situation, we prefer to use AssertJ's support for extracting fields. In this case it would look something like this:
assertThat(client).extracting("client")
.extracting("credentialsProvider", InstanceOfAssertFactories.type(CredentialsProvider.class))
.satisfies((credentialsProvider) -> {
Credentials uriCredentials = credentialsProvider.getCredentials(new AuthScope("localhost", 9200));
assertThat(uriCredentials.getUserPrincipal().getName()).isEqualTo("user");
assertThat(uriCredentials.getPassword()).isEqualTo("password");
Credentials defaultCredentials = credentialsProvider.getCredentials(new AuthScope("localhost", 9201));
assertThat(defaultCredentials.getUserPrincipal().getName()).isEqualTo("admin");
assertThat(defaultCredentials.getPassword()).isEqualTo("admin");
});
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thank you for the AssertJ example, @wilkinsona
I will update tests.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed.
|
||
Credentials defaultCredentials = credentialsProvider | ||
.getCredentials(new AuthScope("localhost", 9201)); | ||
assertThat(defaultCredentials.getUserPrincipal().getName()).isEqualTo("admin"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think the username in the URI should win so the name of the principal should be user
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, that is right, in this assert we are checking that if the URI does not contain credentials then spring.elasticsearch.rest.username
and spring.elasticsearch.rest.password
will be used.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sorry, I'd missed that there are two URIs being configured, one with credentials and one without.
Credentials defaultCredentials = credentialsProvider | ||
.getCredentials(new AuthScope("localhost", 9201)); | ||
assertThat(defaultCredentials.getUserPrincipal().getName()).isEqualTo("admin"); | ||
assertThat(defaultCredentials.getPassword()).isEqualTo("admin"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Similarly, I think the password in the URI should win so it should be password
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sorry, ignore this. I'd missed that there are two URIs being configured, one with credentials and one without.
@@ -114,25 +123,48 @@ RestClient elasticsearchRestClient(RestClientBuilder builder) { | |||
|
|||
private final ElasticsearchRestClientProperties properties; | |||
|
|||
private CredentialsProvider credentialsProvider = new BasicCredentialsProvider(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think it's safe to expose a CredentialProvider
as a bean. In this case the credentials that it provides are specific to Elasticsearch, but there's nothing about the bean that indicates that's the case. It could be accidentally consumed and used anywhere that's working with an Apache HTTP client, potentially leaking credentials to another service.
For this sort of situation, we prefer to use AssertJ's support for extracting fields. In this case it would look something like this:
assertThat(client).extracting("client")
.extracting("credentialsProvider", InstanceOfAssertFactories.type(CredentialsProvider.class))
.satisfies((credentialsProvider) -> {
Credentials uriCredentials = credentialsProvider.getCredentials(new AuthScope("localhost", 9200));
assertThat(uriCredentials.getUserPrincipal().getName()).isEqualTo("user");
assertThat(uriCredentials.getPassword()).isEqualTo("password");
Credentials defaultCredentials = credentialsProvider.getCredentials(new AuthScope("localhost", 9201));
assertThat(defaultCredentials.getUserPrincipal().getName()).isEqualTo("admin");
assertThat(defaultCredentials.getPassword()).isEqualTo("admin");
});
@wilkinsona Could you please take a look at the latest changes when you have a moment? |
@wilkinsona : is there any chance to get this in 2.3.x ? |
Yes. Given the situation with Jest, it seems reasonable to include this in 2.3.x. |
Thanks very much for the PR @evgeniycheban, this is now in 2.3.x and master. I made some minor tweaks in f8982bd (mainly to protect against URL parse exceptions). |
Fixes gh-21291