Skip to content

Commit b58b30e

Browse files
committed
add user authentication test for ILM
1 parent b218b1c commit b58b30e

File tree

3 files changed

+152
-1
lines changed

3 files changed

+152
-1
lines changed

x-pack/plugin/ilm/qa/with-security/build.gradle

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ task copyILMRestTests(type: Copy) {
1313
include 'rest-api-spec/test/ilm/**'
1414
}
1515

16-
def clusterCredentials = [username: System.getProperty('tests.rest.cluster.username', 'test_user'),
16+
def clusterCredentials = [username: System.getProperty('tests.rest.cluster.username', 'test_admin'),
1717
password: System.getProperty('tests.rest.cluster.password', 'x-pack-test-password')]
1818

1919
integTestRunner {
@@ -29,6 +29,11 @@ integTestCluster {
2929
setting 'xpack.monitoring.enabled', 'false'
3030
setting 'xpack.ml.enabled', 'false'
3131
setting 'xpack.license.self_generated.type', 'trial'
32+
extraConfigFile 'roles.yml', 'roles.yml'
33+
setupCommand 'setupIlmUser',
34+
'bin/elasticsearch-users',
35+
'useradd', "test_ilm",
36+
'-p', 'x-pack-test-password', '-r', "ilm_admin"
3237
setupCommand 'setupDummyUser',
3338
'bin/elasticsearch-users',
3439
'useradd', clusterCredentials.username,
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
ilm_admin:
2+
cluster:
3+
- monitor
4+
- manage
5+
indices:
6+
- names: [ 'ilm-*' ]
7+
privileges:
8+
- monitor
9+
- manage
10+
- read
11+
- write
Lines changed: 135 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,135 @@
1+
/*
2+
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
3+
* or more contributor license agreements. Licensed under the Elastic License;
4+
* you may not use this file except in compliance with the Elastic License.
5+
*/
6+
package org.elasticsearch.xpack.security;
7+
8+
import org.apache.http.entity.ContentType;
9+
import org.apache.http.entity.StringEntity;
10+
import org.elasticsearch.client.Request;
11+
import org.elasticsearch.client.Response;
12+
import org.elasticsearch.client.ResponseException;
13+
import org.elasticsearch.common.Strings;
14+
import org.elasticsearch.common.settings.SecureString;
15+
import org.elasticsearch.common.settings.Settings;
16+
import org.elasticsearch.common.unit.TimeValue;
17+
import org.elasticsearch.common.util.concurrent.ThreadContext;
18+
import org.elasticsearch.common.xcontent.XContentBuilder;
19+
import org.elasticsearch.common.xcontent.XContentHelper;
20+
import org.elasticsearch.common.xcontent.XContentType;
21+
import org.elasticsearch.common.xcontent.json.JsonXContent;
22+
import org.elasticsearch.rest.RestStatus;
23+
import org.elasticsearch.test.rest.ESRestTestCase;
24+
import org.elasticsearch.xpack.core.indexlifecycle.DeleteAction;
25+
import org.elasticsearch.xpack.core.indexlifecycle.LifecycleAction;
26+
import org.elasticsearch.xpack.core.indexlifecycle.LifecyclePolicy;
27+
import org.elasticsearch.xpack.core.indexlifecycle.LifecycleSettings;
28+
import org.elasticsearch.xpack.core.indexlifecycle.Phase;
29+
import org.elasticsearch.xpack.core.indexlifecycle.TimeseriesLifecycleType;
30+
import org.junit.Before;
31+
32+
import java.io.IOException;
33+
import java.io.InputStream;
34+
import java.util.Map;
35+
36+
import static java.util.Collections.singletonMap;
37+
import static org.elasticsearch.common.xcontent.XContentFactory.jsonBuilder;
38+
import static org.elasticsearch.xpack.core.security.authc.support.UsernamePasswordToken.basicAuthHeaderValue;
39+
import static org.hamcrest.Matchers.equalTo;
40+
41+
public class PermissionsIT extends ESRestTestCase {
42+
43+
private String deletePolicy = "deletePolicy";
44+
private Settings indexSettingsWithPolicy;
45+
46+
@Override
47+
protected Settings restClientSettings() {
48+
String token = basicAuthHeaderValue("test_ilm", new SecureString("x-pack-test-password".toCharArray()));
49+
return Settings.builder()
50+
.put(ThreadContext.PREFIX + ".Authorization", token)
51+
.build();
52+
}
53+
54+
@Override
55+
protected Settings restAdminSettings() {
56+
String token = basicAuthHeaderValue("test_admin", new SecureString("x-pack-test-password".toCharArray()));
57+
return Settings.builder()
58+
.put(ThreadContext.PREFIX + ".Authorization", token)
59+
.build();
60+
}
61+
62+
@Before
63+
public void init() throws Exception {
64+
Request request = new Request("PUT", "/_cluster/settings");
65+
XContentBuilder pollIntervalEntity = JsonXContent.contentBuilder();
66+
pollIntervalEntity.startObject();
67+
{
68+
pollIntervalEntity.startObject("transient");
69+
{
70+
pollIntervalEntity.field(LifecycleSettings.LIFECYCLE_POLL_INTERVAL, "1s");
71+
}pollIntervalEntity.endObject();
72+
} pollIntervalEntity.endObject();
73+
request.setJsonEntity(Strings.toString(pollIntervalEntity));
74+
assertOK(adminClient().performRequest(request));
75+
indexSettingsWithPolicy = Settings.builder()
76+
.put(LifecycleSettings.LIFECYCLE_NAME, deletePolicy)
77+
.put("number_of_shards", 1)
78+
.put("number_of_replicas", 0)
79+
.build();
80+
createNewSingletonPolicy(deletePolicy,"delete", new DeleteAction());
81+
}
82+
83+
public void testCanManageIndexAndPolicyDifferentUsers() throws Exception {
84+
String index = "ilm-00001";
85+
createIndexAsAdmin(index, indexSettingsWithPolicy, "");
86+
assertBusy(() -> assertFalse(indexExists(index)));
87+
}
88+
89+
/**
90+
* This tests the awkward behavior where an admin can have permissions to create a policy,
91+
* but then not have permissions to operate on an index that was later associated with that policy by another
92+
* user
93+
*/
94+
@SuppressWarnings("unchecked")
95+
public void testCanManageIndexWithNoPermissions() throws Exception {
96+
createIndexAsAdmin("not-ilm", indexSettingsWithPolicy, "");
97+
Request request = new Request("GET", "/not-ilm/_ilm/explain");
98+
// test_ilm user does not have permissions on this index
99+
ResponseException exception = expectThrows(ResponseException.class, () -> client().performRequest(request));
100+
assertThat(exception.getResponse().getStatusLine().getStatusCode(), equalTo(RestStatus.FORBIDDEN.getStatus()));
101+
102+
assertBusy(() -> {
103+
Response response = adminClient().performRequest(request);
104+
assertOK(response);
105+
try (InputStream is = response.getEntity().getContent()) {
106+
Map<String, Object> mapResponse = XContentHelper.convertToMap(XContentType.JSON.xContent(), is, true);
107+
Map<String, Object> indexExplain = (Map<String, Object>) ((Map<String, Object>) mapResponse.get("indices")).get("not-ilm");
108+
assertThat(indexExplain.get("managed"), equalTo(true));
109+
assertThat(indexExplain.get("step"), equalTo("error"));
110+
assertThat(indexExplain.get("failed_step"), equalTo("readonly"));
111+
assertThat(indexExplain.get("step_info"), equalTo("permissionsss!"));
112+
}
113+
});
114+
}
115+
116+
private void createNewSingletonPolicy(String policy, String phaseName, LifecycleAction action) throws IOException {
117+
Phase phase = new Phase(phaseName, TimeValue.ZERO, singletonMap(action.getWriteableName(), action));
118+
LifecyclePolicy lifecyclePolicy =
119+
new LifecyclePolicy(TimeseriesLifecycleType.INSTANCE, policy, singletonMap(phase.getName(), phase));
120+
XContentBuilder builder = jsonBuilder();
121+
lifecyclePolicy.toXContent(builder, null);
122+
final StringEntity entity = new StringEntity(
123+
"{ \"policy\":" + Strings.toString(builder) + "}", ContentType.APPLICATION_JSON);
124+
Request request = new Request("PUT", "_ilm/" + policy);
125+
request.setEntity(entity);
126+
client().performRequest(request);
127+
}
128+
129+
private void createIndexAsAdmin(String name, Settings settings, String mapping) throws IOException {
130+
Request request = new Request("PUT", "/" + name);
131+
request.setJsonEntity("{\n \"settings\": " + Strings.toString(settings)
132+
+ ", \"mappings\" : {" + mapping + "} }");
133+
adminClient().performRequest(request);
134+
}
135+
}

0 commit comments

Comments
 (0)