Browse Source

Polish "Add support for Elasticsearch API-key-based authentication"

See gh-46167
pull/47047/head
Andy Wilkinson 7 months ago
parent
commit
86deef6abf
  1. 4
      module/spring-boot-elasticsearch/src/main/java/org/springframework/boot/elasticsearch/autoconfigure/ElasticsearchConnectionDetails.java
  2. 13
      module/spring-boot-elasticsearch/src/main/java/org/springframework/boot/elasticsearch/autoconfigure/ElasticsearchProperties.java
  3. 11
      module/spring-boot-elasticsearch/src/main/java/org/springframework/boot/elasticsearch/autoconfigure/ElasticsearchRestClientConfigurations.java
  4. 56
      module/spring-boot-elasticsearch/src/test/java/org/springframework/boot/elasticsearch/autoconfigure/ElasticsearchRestClientAutoConfigurationTests.java

4
module/spring-boot-elasticsearch/src/main/java/org/springframework/boot/elasticsearch/autoconfigure/ElasticsearchConnectionDetails.java

@ -59,9 +59,9 @@ public interface ElasticsearchConnectionDetails extends ConnectionDetails { @@ -59,9 +59,9 @@ public interface ElasticsearchConnectionDetails extends ConnectionDetails {
/**
* APIKey for authentication with Elasticsearch.
* @return APIKey for authentication with Elasticsearch or {@code null}
* @return the API key for authentication with Elasticsearch or {@code null}
*/
default @Nullable String getAPIKey() {
default @Nullable String getApiKey() {
return null;
}

13
module/spring-boot-elasticsearch/src/main/java/org/springframework/boot/elasticsearch/autoconfigure/ElasticsearchProperties.java

@ -48,10 +48,11 @@ public class ElasticsearchProperties { @@ -48,10 +48,11 @@ public class ElasticsearchProperties {
* Password for authentication with Elasticsearch.
*/
private @Nullable String password;
/**
* APIKey for authentication with Elasticsearch.
* API key for authentication with Elasticsearch.
*/
private @Nullable String APIKey;
private @Nullable String apiKey;
/**
* Connection timeout used when communicating with Elasticsearch.
@ -99,12 +100,12 @@ public class ElasticsearchProperties { @@ -99,12 +100,12 @@ public class ElasticsearchProperties {
this.password = password;
}
public @Nullable String getAPIKey() {
return this.APIKey;
public @Nullable String getApiKey() {
return this.apiKey;
}
public void setAPIKey(@Nullable String APIKey) {
this.APIKey = APIKey;
public void setApiKey(@Nullable String apiKey) {
this.apiKey = apiKey;
}
public Duration getConnectionTimeout() {

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

@ -102,10 +102,9 @@ class ElasticsearchRestClientConfigurations { @@ -102,10 +102,9 @@ class ElasticsearchRestClientConfigurations {
.stream()
.map((node) -> new HttpHost(node.protocol().getScheme(), node.hostname(), node.port()))
.toArray(HttpHost[]::new));
if (connectionDetails.getAPIKey() != null) {
builder.setDefaultHeaders(new Header[]{
new BasicHeader("Authorization", "ApiKey " + connectionDetails.getAPIKey()),
});
if (connectionDetails.getApiKey() != null) {
builder.setDefaultHeaders(
new Header[] { new BasicHeader("Authorization", "ApiKey " + connectionDetails.getApiKey()), });
}
builder.setHttpClientConfigCallback((httpClientBuilder) -> builderCustomizers.orderedStream()
.forEach((customizer) -> customizer.customize(httpClientBuilder)));
@ -284,8 +283,8 @@ class ElasticsearchRestClientConfigurations { @@ -284,8 +283,8 @@ class ElasticsearchRestClientConfigurations {
}
@Override
public @Nullable String getAPIKey() {
return this.properties.getAPIKey();
public @Nullable String getApiKey() {
return this.properties.getApiKey();
}
@Override

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

@ -19,7 +19,6 @@ package org.springframework.boot.elasticsearch.autoconfigure; @@ -19,7 +19,6 @@ package org.springframework.boot.elasticsearch.autoconfigure;
import java.time.Duration;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import co.elastic.clients.transport.rest5_client.low_level.Node;
import co.elastic.clients.transport.rest5_client.low_level.Rest5Client;
@ -49,7 +48,6 @@ import org.springframework.boot.test.context.runner.ApplicationContextRunner; @@ -49,7 +48,6 @@ import org.springframework.boot.test.context.runner.ApplicationContextRunner;
import org.springframework.boot.testsupport.classpath.resources.WithPackageResources;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.client.RestClient;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.BDDMockito.then;
@ -138,25 +136,6 @@ class ElasticsearchRestClientAutoConfigurationTests { @@ -138,25 +136,6 @@ class ElasticsearchRestClientAutoConfigurationTests {
});
}
@Test
void configureUriWithAPiKey() {
this.contextRunner.withPropertyValues("spring.elasticsearch.uris=http://user@localhost:9200","spring.elasticsearch.apikey=some-apiKey").run((context) -> {
Rest5Client client = context.getBean(Rest5Client.class);
assertThat(client.getNodes().stream().map(Node::getHost).map(HttpHost::toString))
.containsExactly("http://localhost:9200");
assertThat(client)
.extracting("defaultHeaders", InstanceOfAssertFactories.list(Header.class))
.satisfies(( defaultHeaders) -> {
Optional<? extends Header> authHeader = defaultHeaders.stream()
.filter(x -> x.getName().equals("Authorization"))
.findFirst();
assertThat(authHeader).isPresent();
assertThat(authHeader.get().getValue()).isEqualTo("ApiKey some-apiKey");
});
});
}
@Test
void configureUriWithUsernameOnly() {
this.contextRunner.withPropertyValues("spring.elasticsearch.uris=http://user@localhost:9200").run((context) -> {
@ -216,6 +195,41 @@ class ElasticsearchRestClientAutoConfigurationTests { @@ -216,6 +195,41 @@ class ElasticsearchRestClientAutoConfigurationTests {
});
}
@Test
void whenApiKeyIsConfiguredThenAuthorizationHeaderIsPresent() {
this.contextRunner.withPropertyValues("spring.elasticsearch.api-key=some-api-key").run((context) -> {
Rest5Client client = context.getBean(Rest5Client.class);
assertThat(client).extracting("defaultHeaders", InstanceOfAssertFactories.list(Header.class))
.satisfiesOnlyOnce((header) -> {
assertThat(header.getName().equals("Authorization"));
assertThat(header.getValue().equals("ApiKey some-api-key"));
});
});
}
@Test
void whenApiKeyAndUsernameAndPasswordAreConfiguredThenBothFormsOfCredentialsArePresent() {
this.contextRunner
.withPropertyValues("spring.elasticsearch.api-key=some-api-key", "spring.elasticsearch.username=alice",
"spring.elasticsearch.password=secret")
.run((context) -> {
Rest5Client client = context.getBean(Rest5Client.class);
assertThat(client).extracting("defaultHeaders", InstanceOfAssertFactories.list(Header.class))
.satisfiesOnlyOnce((header) -> {
assertThat(header.getName().equals("Authorization"));
assertThat(header.getValue().equals("ApiKey some-api-key"));
});
assertThat(client)
.extracting("client.credentialsProvider", InstanceOfAssertFactories.type(CredentialsProvider.class))
.satisfies((credentialsProvider) -> {
UsernamePasswordCredentials defaultCredentials = (UsernamePasswordCredentials) credentialsProvider
.getCredentials(new AuthScope(null, -1), null);
assertThat(defaultCredentials.getUserPrincipal().getName()).isEqualTo("alice");
assertThat(defaultCredentials.getUserPassword()).containsExactly("secret".toCharArray());
});
});
}
@Test
void configureWithCustomPathPrefix() {
this.contextRunner.withPropertyValues("spring.elasticsearch.path-prefix=/some/prefix").run((context) -> {

Loading…
Cancel
Save