Skip to content

Commit 03c7ca3

Browse files
committed
Support userInfo in elasticsearch uri
Fixes gh-21291
1 parent 7afd25f commit 03c7ca3

File tree

2 files changed

+106
-4
lines changed

2 files changed

+106
-4
lines changed

spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/elasticsearch/ElasticsearchRestClientConfigurations.java

Lines changed: 36 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616

1717
package org.springframework.boot.autoconfigure.elasticsearch;
1818

19+
import java.net.URI;
1920
import java.time.Duration;
2021

2122
import org.apache.http.HttpHost;
@@ -31,6 +32,7 @@
3132
import org.elasticsearch.client.RestHighLevelClient;
3233

3334
import org.springframework.beans.factory.ObjectProvider;
35+
import org.springframework.beans.factory.annotation.Autowired;
3436
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
3537
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
3638
import org.springframework.boot.context.properties.PropertyMapper;
@@ -43,6 +45,7 @@
4345
* @author Brian Clozel
4446
* @author Stephane Nicoll
4547
* @author Vedran Pavic
48+
* @author Evgeniy Cheban
4649
*/
4750
class ElasticsearchRestClientConfigurations {
4851

@@ -58,7 +61,7 @@ RestClientBuilderCustomizer defaultRestClientBuilderCustomizer(ElasticsearchRest
5861
@Bean
5962
RestClientBuilder elasticsearchRestClientBuilder(ElasticsearchRestClientProperties properties,
6063
ObjectProvider<RestClientBuilderCustomizer> builderCustomizers) {
61-
HttpHost[] hosts = properties.getUris().stream().map(HttpHost::create).toArray(HttpHost[]::new);
64+
HttpHost[] hosts = properties.getUris().stream().map(this::createHttpHost).toArray(HttpHost[]::new);
6265
RestClientBuilder builder = RestClient.builder(hosts);
6366
builder.setHttpClientConfigCallback((httpClientBuilder) -> {
6467
builderCustomizers.orderedStream().forEach((customizer) -> customizer.customize(httpClientBuilder));
@@ -72,6 +75,12 @@ RestClientBuilder elasticsearchRestClientBuilder(ElasticsearchRestClientProperti
7275
return builder;
7376
}
7477

78+
private HttpHost createHttpHost(String uri) {
79+
URI parsedUri = URI.create(uri);
80+
String userInfo = parsedUri.getUserInfo();
81+
return HttpHost.create((userInfo != null) ? uri.replace(userInfo + "@", "") : uri);
82+
}
83+
7584
}
7685

7786
@Configuration(proxyBeanMethods = false)
@@ -114,25 +123,48 @@ static class DefaultRestClientBuilderCustomizer implements RestClientBuilderCust
114123

115124
private final ElasticsearchRestClientProperties properties;
116125

126+
private CredentialsProvider credentialsProvider = new BasicCredentialsProvider();
127+
117128
DefaultRestClientBuilderCustomizer(ElasticsearchRestClientProperties properties) {
118129
this.properties = properties;
119130
}
120131

132+
@Autowired(required = false)
133+
void setCredentialsProvider(CredentialsProvider credentialsProvider) {
134+
this.credentialsProvider = credentialsProvider;
135+
}
136+
121137
@Override
122138
public void customize(RestClientBuilder builder) {
123139
}
124140

125141
@Override
126142
public void customize(HttpAsyncClientBuilder builder) {
143+
builder.setDefaultCredentialsProvider(this.credentialsProvider);
144+
this.properties.getUris().stream().map(URI::create).filter((uri) -> uri.getUserInfo() != null)
145+
.forEach((uri) -> {
146+
AuthScope authScope = new AuthScope(uri.getHost(), uri.getPort());
147+
Credentials credentials = createCredentials(uri.getUserInfo());
148+
this.credentialsProvider.setCredentials(authScope, credentials);
149+
});
127150
map.from(this.properties::getUsername).whenHasText().to((username) -> {
128-
CredentialsProvider credentialsProvider = new BasicCredentialsProvider();
129151
Credentials credentials = new UsernamePasswordCredentials(this.properties.getUsername(),
130152
this.properties.getPassword());
131-
credentialsProvider.setCredentials(AuthScope.ANY, credentials);
132-
builder.setDefaultCredentialsProvider(credentialsProvider);
153+
this.credentialsProvider.setCredentials(AuthScope.ANY, credentials);
133154
});
134155
}
135156

157+
private Credentials createCredentials(String usernameAndPassword) {
158+
int delimiter = usernameAndPassword.indexOf(":");
159+
if (delimiter == -1) {
160+
return new UsernamePasswordCredentials(usernameAndPassword, null);
161+
}
162+
163+
String username = usernameAndPassword.substring(0, delimiter);
164+
String password = usernameAndPassword.substring(delimiter + 1);
165+
return new UsernamePasswordCredentials(username, password);
166+
}
167+
136168
@Override
137169
public void customize(RequestConfig.Builder builder) {
138170
map.from(this.properties::getConnectionTimeout).whenNonNull().asInt(Duration::toMillis)

spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/elasticsearch/ElasticsearchRestClientAutoConfigurationTests.java

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,10 +20,16 @@
2020
import java.util.HashMap;
2121
import java.util.Map;
2222

23+
import org.apache.http.HttpHost;
24+
import org.apache.http.auth.AuthScope;
25+
import org.apache.http.auth.Credentials;
26+
import org.apache.http.client.CredentialsProvider;
2327
import org.apache.http.client.config.RequestConfig;
28+
import org.apache.http.impl.client.BasicCredentialsProvider;
2429
import org.apache.http.impl.nio.client.HttpAsyncClientBuilder;
2530
import org.elasticsearch.action.get.GetRequest;
2631
import org.elasticsearch.action.index.IndexRequest;
32+
import org.elasticsearch.client.Node;
2733
import org.elasticsearch.client.RequestOptions;
2834
import org.elasticsearch.client.RestClient;
2935
import org.elasticsearch.client.RestClientBuilder;
@@ -47,6 +53,7 @@
4753
*
4854
* @author Brian Clozel
4955
* @author Vedran Pavic
56+
* @author Evgeniy Cheban
5057
*/
5158
@Testcontainers(disabledWithoutDocker = true)
5259
class ElasticsearchRestClientAutoConfigurationTests {
@@ -156,6 +163,69 @@ void restClientCanQueryElasticsearchNode() {
156163
});
157164
}
158165

166+
@Test
167+
void configureUriWithUsernameOnly() {
168+
this.contextRunner.withUserConfiguration(CredentialsProviderConfiguration.class)
169+
.withPropertyValues("spring.elasticsearch.rest.uris=http://user@localhost:9200").run((context) -> {
170+
RestClient client = context.getBean(RestClient.class);
171+
assertThat(client.getNodes().stream().map(Node::getHost).map(HttpHost::toString))
172+
.containsExactly("http://localhost:9200");
173+
174+
CredentialsProvider credentialsProvider = context.getBean(CredentialsProvider.class);
175+
Credentials credentials = credentialsProvider.getCredentials(new AuthScope("localhost", 9200));
176+
assertThat(credentials.getUserPrincipal().getName()).isEqualTo("user");
177+
assertThat(credentials.getPassword()).isNull();
178+
});
179+
}
180+
181+
@Test
182+
void configureUriWithUsernameAndEmptyPassword() {
183+
this.contextRunner.withUserConfiguration(CredentialsProviderConfiguration.class)
184+
.withPropertyValues("spring.elasticsearch.rest.uris=http://user:@localhost:9200").run((context) -> {
185+
RestClient client = context.getBean(RestClient.class);
186+
assertThat(client.getNodes().stream().map(Node::getHost).map(HttpHost::toString))
187+
.containsExactly("http://localhost:9200");
188+
189+
CredentialsProvider credentialsProvider = context.getBean(CredentialsProvider.class);
190+
Credentials credentials = credentialsProvider.getCredentials(new AuthScope("localhost", 9200));
191+
assertThat(credentials.getUserPrincipal().getName()).isEqualTo("user");
192+
assertThat(credentials.getPassword()).isEmpty();
193+
});
194+
}
195+
196+
@Test
197+
void configureUriWithUsernameAndPasswordWhenUsernameAndPasswordPropertiesSet() {
198+
this.contextRunner.withUserConfiguration(CredentialsProviderConfiguration.class)
199+
.withPropertyValues("spring.elasticsearch.rest.uris=http://user:password@localhost:9200,localhost:9201",
200+
"spring.elasticsearch.rest.username=admin", "spring.elasticsearch.rest.password=admin")
201+
.run((context) -> {
202+
RestClient client = context.getBean(RestClient.class);
203+
assertThat(client.getNodes().stream().map(Node::getHost).map(HttpHost::toString))
204+
.containsExactly("http://localhost:9200", "http://localhost:9201");
205+
206+
CredentialsProvider credentialsProvider = context.getBean(CredentialsProvider.class);
207+
208+
Credentials uriCredentials = credentialsProvider.getCredentials(new AuthScope("localhost", 9200));
209+
assertThat(uriCredentials.getUserPrincipal().getName()).isEqualTo("user");
210+
assertThat(uriCredentials.getPassword()).isEqualTo("password");
211+
212+
Credentials defaultCredentials = credentialsProvider
213+
.getCredentials(new AuthScope("localhost", 9201));
214+
assertThat(defaultCredentials.getUserPrincipal().getName()).isEqualTo("admin");
215+
assertThat(defaultCredentials.getPassword()).isEqualTo("admin");
216+
});
217+
}
218+
219+
@Configuration(proxyBeanMethods = false)
220+
static class CredentialsProviderConfiguration {
221+
222+
@Bean
223+
CredentialsProvider credentialsProvider() {
224+
return new BasicCredentialsProvider();
225+
}
226+
227+
}
228+
159229
@Configuration(proxyBeanMethods = false)
160230
static class CustomRestClientConfiguration {
161231

0 commit comments

Comments
 (0)