Skip to content

Commit 05b4517

Browse files
committed
Merge remote-tracking branch 'elastic/master' into ccr
* elastic/master: Enable setting client path prefix to / (#30119) [DOCS] Secure settings specified per node (#31621) has_parent builder: exception message/param fix (#31182)
2 parents e46d23d + 2971dd5 commit 05b4517

File tree

9 files changed

+57
-21
lines changed

9 files changed

+57
-21
lines changed

client/rest/src/main/java/org/elasticsearch/client/RestClient.java

+4-2
Original file line numberDiff line numberDiff line change
@@ -794,8 +794,10 @@ static URI buildUri(String pathPrefix, String path, Map<String, String> params)
794794
Objects.requireNonNull(path, "path must not be null");
795795
try {
796796
String fullPath;
797-
if (pathPrefix != null) {
798-
if (path.startsWith("/")) {
797+
if (pathPrefix != null && pathPrefix.isEmpty() == false) {
798+
if (pathPrefix.endsWith("/") && path.startsWith("/")) {
799+
fullPath = pathPrefix.substring(0, pathPrefix.length() - 1) + path;
800+
} else if (pathPrefix.endsWith("/") || path.startsWith("/")) {
799801
fullPath = pathPrefix + path;
800802
} else {
801803
fullPath = pathPrefix + "/" + path;

client/rest/src/main/java/org/elasticsearch/client/RestClientBuilder.java

+9-8
Original file line numberDiff line numberDiff line change
@@ -143,32 +143,33 @@ public RestClientBuilder setRequestConfigCallback(RequestConfigCallback requestC
143143
* For example, if this is set to "/my/path", then any client request will become <code>"/my/path/" + endpoint</code>.
144144
* <p>
145145
* In essence, every request's {@code endpoint} is prefixed by this {@code pathPrefix}. The path prefix is useful for when
146-
* Elasticsearch is behind a proxy that provides a base path; it is not intended for other purposes and it should not be supplied in
147-
* other scenarios.
146+
* Elasticsearch is behind a proxy that provides a base path or a proxy that requires all paths to start with '/';
147+
* it is not intended for other purposes and it should not be supplied in other scenarios.
148148
*
149149
* @throws NullPointerException if {@code pathPrefix} is {@code null}.
150-
* @throws IllegalArgumentException if {@code pathPrefix} is empty, only '/', or ends with more than one '/'.
150+
* @throws IllegalArgumentException if {@code pathPrefix} is empty, or ends with more than one '/'.
151151
*/
152152
public RestClientBuilder setPathPrefix(String pathPrefix) {
153153
Objects.requireNonNull(pathPrefix, "pathPrefix must not be null");
154-
String cleanPathPrefix = pathPrefix;
155154

155+
if (pathPrefix.isEmpty()) {
156+
throw new IllegalArgumentException("pathPrefix must not be empty");
157+
}
158+
159+
String cleanPathPrefix = pathPrefix;
156160
if (cleanPathPrefix.startsWith("/") == false) {
157161
cleanPathPrefix = "/" + cleanPathPrefix;
158162
}
159163

160164
// best effort to ensure that it looks like "/base/path" rather than "/base/path/"
161-
if (cleanPathPrefix.endsWith("/")) {
165+
if (cleanPathPrefix.endsWith("/") && cleanPathPrefix.length() > 1) {
162166
cleanPathPrefix = cleanPathPrefix.substring(0, cleanPathPrefix.length() - 1);
163167

164168
if (cleanPathPrefix.endsWith("/")) {
165169
throw new IllegalArgumentException("pathPrefix is malformed. too many trailing slashes: [" + pathPrefix + "]");
166170
}
167171
}
168172

169-
if (cleanPathPrefix.isEmpty() || "/".equals(cleanPathPrefix)) {
170-
throw new IllegalArgumentException("pathPrefix must not be empty or '/': [" + pathPrefix + "]");
171-
}
172173

173174
this.pathPrefix = cleanPathPrefix;
174175
return this;

client/rest/src/test/java/org/elasticsearch/client/RestClientBuilderTests.java

-1
Original file line numberDiff line numberDiff line change
@@ -180,7 +180,6 @@ public void testSetPathPrefixNull() {
180180
}
181181

182182
public void testSetPathPrefixEmpty() {
183-
assertSetPathPrefixThrows("/");
184183
assertSetPathPrefixThrows("");
185184
}
186185

client/rest/src/test/java/org/elasticsearch/client/RestClientTests.java

+23-2
Original file line numberDiff line numberDiff line change
@@ -223,12 +223,33 @@ public void onFailure(Exception exception) {
223223
}
224224

225225
public void testBuildUriLeavesPathUntouched() {
226+
final Map<String, String> emptyMap = Collections.emptyMap();
226227
{
227-
URI uri = RestClient.buildUri("/foo$bar", "/index/type/id", Collections.<String, String>emptyMap());
228+
URI uri = RestClient.buildUri("/foo$bar", "/index/type/id", emptyMap);
228229
assertEquals("/foo$bar/index/type/id", uri.getPath());
229230
}
230231
{
231-
URI uri = RestClient.buildUri(null, "/foo$bar/ty/pe/i/d", Collections.<String, String>emptyMap());
232+
URI uri = RestClient.buildUri("/", "/*", emptyMap);
233+
assertEquals("/*", uri.getPath());
234+
}
235+
{
236+
URI uri = RestClient.buildUri("/", "*", emptyMap);
237+
assertEquals("/*", uri.getPath());
238+
}
239+
{
240+
URI uri = RestClient.buildUri(null, "*", emptyMap);
241+
assertEquals("*", uri.getPath());
242+
}
243+
{
244+
URI uri = RestClient.buildUri("", "*", emptyMap);
245+
assertEquals("*", uri.getPath());
246+
}
247+
{
248+
URI uri = RestClient.buildUri(null, "/*", emptyMap);
249+
assertEquals("/*", uri.getPath());
250+
}
251+
{
252+
URI uri = RestClient.buildUri(null, "/foo$bar/ty/pe/i/d", emptyMap);
232253
assertEquals("/foo$bar/ty/pe/i/d", uri.getPath());
233254
}
234255
{

docs/reference/setup/secure-settings.asciidoc

+5-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
[[secure-settings]]
2-
=== Secure Settings
2+
=== Secure settings
33

44
Some settings are sensitive, and relying on filesystem permissions to protect
55
their values is not sufficient. For this use case, Elasticsearch provides a
@@ -16,6 +16,10 @@ Elasticsearch.
1616
NOTE: The elasticsearch keystore currently only provides obfuscation. In the future,
1717
password protection will be added.
1818

19+
These settings, just like the regular ones in the `elasticsearch.yml` config file,
20+
need to be specified on each node in the cluster. Currently, all secure settings
21+
are node-specific settings that must have the same value on every node.
22+
1923
[float]
2024
[[creating-keystore]]
2125
=== Creating the keystore

modules/parent-join/src/main/java/org/elasticsearch/join/query/HasParentQueryBuilder.java

+5-5
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ public class HasParentQueryBuilder extends AbstractQueryBuilder<HasParentQueryBu
5858
public static final boolean DEFAULT_IGNORE_UNMAPPED = false;
5959

6060
private static final ParseField QUERY_FIELD = new ParseField("query");
61-
private static final ParseField TYPE_FIELD = new ParseField("parent_type");
61+
private static final ParseField PARENT_TYPE_FIELD = new ParseField("parent_type");
6262
private static final ParseField SCORE_FIELD = new ParseField("score");
6363
private static final ParseField INNER_HITS_FIELD = new ParseField("inner_hits");
6464
private static final ParseField IGNORE_UNMAPPED_FIELD = new ParseField("ignore_unmapped");
@@ -74,8 +74,8 @@ public HasParentQueryBuilder(String type, QueryBuilder query, boolean score) {
7474
}
7575

7676
private HasParentQueryBuilder(String type, QueryBuilder query, boolean score, InnerHitBuilder innerHitBuilder) {
77-
this.type = requireValue(type, "[" + NAME + "] requires 'type' field");
78-
this.query = requireValue(query, "[" + NAME + "] requires 'query' field");
77+
this.type = requireValue(type, "[" + NAME + "] requires '" + PARENT_TYPE_FIELD.getPreferredName() + "' field");
78+
this.query = requireValue(query, "[" + NAME + "] requires '" + QUERY_FIELD.getPreferredName() + "' field");
7979
this.score = score;
8080
this.innerHitBuilder = innerHitBuilder;
8181
}
@@ -201,7 +201,7 @@ protected void doXContent(XContentBuilder builder, Params params) throws IOExcep
201201
builder.startObject(NAME);
202202
builder.field(QUERY_FIELD.getPreferredName());
203203
query.toXContent(builder, params);
204-
builder.field(TYPE_FIELD.getPreferredName(), type);
204+
builder.field(PARENT_TYPE_FIELD.getPreferredName(), type);
205205
builder.field(SCORE_FIELD.getPreferredName(), score);
206206
builder.field(IGNORE_UNMAPPED_FIELD.getPreferredName(), ignoreUnmapped);
207207
printBoostAndQueryName(builder);
@@ -235,7 +235,7 @@ public static HasParentQueryBuilder fromXContent(XContentParser parser) throws I
235235
"[has_parent] query does not support [" + currentFieldName + "]");
236236
}
237237
} else if (token.isValue()) {
238-
if (TYPE_FIELD.match(currentFieldName, parser.getDeprecationHandler())) {
238+
if (PARENT_TYPE_FIELD.match(currentFieldName, parser.getDeprecationHandler())) {
239239
parentType = parser.text();
240240
} else if (SCORE_FIELD.match(currentFieldName, parser.getDeprecationHandler())) {
241241
score = parser.booleanValue();

modules/parent-join/src/test/java/org/elasticsearch/join/query/HasParentQueryBuilderTests.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -183,7 +183,7 @@ public void testIllegalValues() throws IOException {
183183
QueryBuilder query = new MatchAllQueryBuilder();
184184
IllegalArgumentException e = expectThrows(IllegalArgumentException.class,
185185
() -> hasParentQuery(null, query, false));
186-
assertThat(e.getMessage(), equalTo("[has_parent] requires 'type' field"));
186+
assertThat(e.getMessage(), equalTo("[has_parent] requires 'parent_type' field"));
187187

188188
e = expectThrows(IllegalArgumentException.class,
189189
() -> hasParentQuery("foo", null, false));

test/framework/src/main/java/org/elasticsearch/test/rest/ESRestTestCase.java

+9-1
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,7 @@ public abstract class ESRestTestCase extends ESTestCase {
9090
public static final String TRUSTSTORE_PASSWORD = "truststore.password";
9191
public static final String CLIENT_RETRY_TIMEOUT = "client.retry.timeout";
9292
public static final String CLIENT_SOCKET_TIMEOUT = "client.socket.timeout";
93+
public static final String CLIENT_PATH_PREFIX = "client.path.prefix";
9394

9495
/**
9596
* Convert the entity from a {@link Response} into a map of maps.
@@ -383,7 +384,11 @@ private void waitForClusterStateUpdatesToFinish() throws Exception {
383384
* Used to obtain settings for the REST client that is used to send REST requests.
384385
*/
385386
protected Settings restClientSettings() {
386-
return Settings.EMPTY;
387+
Settings.Builder builder = Settings.builder();
388+
if (System.getProperty("tests.rest.client_path_prefix") != null) {
389+
builder.put(CLIENT_PATH_PREFIX, System.getProperty("tests.rest.client_path_prefix"));
390+
}
391+
return builder.build();
387392
}
388393

389394
/**
@@ -454,6 +459,9 @@ protected static void configureClient(RestClientBuilder builder, Settings settin
454459
final TimeValue socketTimeout = TimeValue.parseTimeValue(socketTimeoutString, CLIENT_SOCKET_TIMEOUT);
455460
builder.setRequestConfigCallback(conf -> conf.setSocketTimeout(Math.toIntExact(socketTimeout.getMillis())));
456461
}
462+
if (settings.hasValue(CLIENT_PATH_PREFIX)) {
463+
builder.setPathPrefix(settings.get(CLIENT_PATH_PREFIX));
464+
}
457465
}
458466

459467
@SuppressWarnings("unchecked")

x-pack/qa/core-rest-tests-with-security/src/test/java/org/elasticsearch/xpack/security/CoreWithSecurityClientYamlTestSuiteIT.java

+1
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ public static Iterable<Object[]> parameters() throws Exception {
3939
protected Settings restClientSettings() {
4040
String token = basicAuthHeaderValue(USER, new SecureString(PASS.toCharArray()));
4141
return Settings.builder()
42+
.put(super.restClientSettings())
4243
.put(ThreadContext.PREFIX + ".Authorization", token)
4344
.build();
4445
}

0 commit comments

Comments
 (0)