All internal searches (triggered by APIs) across the .security index must be performed while "under the security origin". Otherwise, the search is performed in the context of the caller which most likely does not have privileges to search .security (hopefully). This commit fixes this in the case of two methods in the TokenService and corrects an overly done such context switch in the ApiKeyService. In addition, this makes all tests from the client/rest-high-level module execute as an all mighty administrator, but not a literal superuser. Closes #47151
This commit is contained in:
parent
fe265f0308
commit
69fc715bc3
|
@ -126,8 +126,11 @@ testClusters.integTest {
|
||||||
|
|
||||||
setting 'indices.lifecycle.poll_interval', '1000ms'
|
setting 'indices.lifecycle.poll_interval', '1000ms'
|
||||||
keystore 'xpack.security.transport.ssl.truststore.secure_password', 'testnode'
|
keystore 'xpack.security.transport.ssl.truststore.secure_password', 'testnode'
|
||||||
|
extraConfigFile 'roles.yml', file('roles.yml')
|
||||||
user username: System.getProperty('tests.rest.cluster.username', 'test_user'),
|
user username: System.getProperty('tests.rest.cluster.username', 'test_user'),
|
||||||
password: System.getProperty('tests.rest.cluster.password', 'test-password')
|
password: System.getProperty('tests.rest.cluster.password', 'test-password'),
|
||||||
|
role: System.getProperty('tests.rest.cluster.role', 'admin')
|
||||||
|
user username: 'admin_user', password: 'admin-password'
|
||||||
|
|
||||||
extraConfigFile nodeCert.name, nodeCert
|
extraConfigFile nodeCert.name, nodeCert
|
||||||
extraConfigFile nodeTrustStore.name, nodeTrustStore
|
extraConfigFile nodeTrustStore.name, nodeTrustStore
|
||||||
|
|
|
@ -0,0 +1,12 @@
|
||||||
|
admin:
|
||||||
|
cluster:
|
||||||
|
- all
|
||||||
|
indices:
|
||||||
|
- names: '*'
|
||||||
|
privileges:
|
||||||
|
- all
|
||||||
|
run_as: [ '*' ]
|
||||||
|
applications:
|
||||||
|
- application: '*'
|
||||||
|
privileges: [ '*' ]
|
||||||
|
resources: [ '*' ]
|
|
@ -95,7 +95,9 @@ import org.elasticsearch.client.security.user.privileges.Role.IndexPrivilegeName
|
||||||
import org.elasticsearch.client.security.user.privileges.UserIndicesPrivileges;
|
import org.elasticsearch.client.security.user.privileges.UserIndicesPrivileges;
|
||||||
import org.elasticsearch.common.Strings;
|
import org.elasticsearch.common.Strings;
|
||||||
import org.elasticsearch.common.settings.SecureString;
|
import org.elasticsearch.common.settings.SecureString;
|
||||||
|
import org.elasticsearch.common.settings.Settings;
|
||||||
import org.elasticsearch.common.unit.TimeValue;
|
import org.elasticsearch.common.unit.TimeValue;
|
||||||
|
import org.elasticsearch.common.util.concurrent.ThreadContext;
|
||||||
import org.elasticsearch.common.util.set.Sets;
|
import org.elasticsearch.common.util.set.Sets;
|
||||||
import org.hamcrest.Matchers;
|
import org.hamcrest.Matchers;
|
||||||
|
|
||||||
|
@ -121,6 +123,8 @@ import java.util.concurrent.TimeUnit;
|
||||||
import javax.crypto.SecretKeyFactory;
|
import javax.crypto.SecretKeyFactory;
|
||||||
import javax.crypto.spec.PBEKeySpec;
|
import javax.crypto.spec.PBEKeySpec;
|
||||||
|
|
||||||
|
import static org.elasticsearch.xpack.core.security.authc.support.UsernamePasswordToken.basicAuthHeaderValue;
|
||||||
|
|
||||||
import static org.hamcrest.Matchers.contains;
|
import static org.hamcrest.Matchers.contains;
|
||||||
import static org.hamcrest.Matchers.containsInAnyOrder;
|
import static org.hamcrest.Matchers.containsInAnyOrder;
|
||||||
import static org.hamcrest.Matchers.containsString;
|
import static org.hamcrest.Matchers.containsString;
|
||||||
|
@ -138,6 +142,14 @@ import static org.hamcrest.Matchers.nullValue;
|
||||||
|
|
||||||
public class SecurityDocumentationIT extends ESRestHighLevelClientTestCase {
|
public class SecurityDocumentationIT extends ESRestHighLevelClientTestCase {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected Settings restAdminSettings() {
|
||||||
|
String token = basicAuthHeaderValue("admin_user", new SecureString("admin-password".toCharArray()));
|
||||||
|
return Settings.builder()
|
||||||
|
.put(ThreadContext.PREFIX + ".Authorization", token)
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
|
||||||
public void testGetUsers() throws Exception {
|
public void testGetUsers() throws Exception {
|
||||||
final RestHighLevelClient client = highLevelClient();
|
final RestHighLevelClient client = highLevelClient();
|
||||||
String[] usernames = new String[] {"user1", "user2", "user3"};
|
String[] usernames = new String[] {"user1", "user2", "user3"};
|
||||||
|
@ -737,7 +749,7 @@ public class SecurityDocumentationIT extends ESRestHighLevelClientTestCase {
|
||||||
//end::authenticate-response
|
//end::authenticate-response
|
||||||
|
|
||||||
assertThat(user.getUsername(), is("test_user"));
|
assertThat(user.getUsername(), is("test_user"));
|
||||||
assertThat(user.getRoles(), contains(new String[]{"superuser"}));
|
assertThat(user.getRoles(), contains(new String[]{"admin"}));
|
||||||
assertThat(user.getFullName(), nullValue());
|
assertThat(user.getFullName(), nullValue());
|
||||||
assertThat(user.getEmail(), nullValue());
|
assertThat(user.getEmail(), nullValue());
|
||||||
assertThat(user.getMetadata().isEmpty(), is(true));
|
assertThat(user.getMetadata().isEmpty(), is(true));
|
||||||
|
|
|
@ -23,6 +23,7 @@ import org.elasticsearch.action.get.GetResponse;
|
||||||
import org.elasticsearch.action.index.IndexAction;
|
import org.elasticsearch.action.index.IndexAction;
|
||||||
import org.elasticsearch.action.index.IndexRequest;
|
import org.elasticsearch.action.index.IndexRequest;
|
||||||
import org.elasticsearch.action.search.SearchRequest;
|
import org.elasticsearch.action.search.SearchRequest;
|
||||||
|
import org.elasticsearch.action.support.ContextPreservingActionListener;
|
||||||
import org.elasticsearch.action.support.WriteRequest.RefreshPolicy;
|
import org.elasticsearch.action.support.WriteRequest.RefreshPolicy;
|
||||||
import org.elasticsearch.action.update.UpdateRequest;
|
import org.elasticsearch.action.update.UpdateRequest;
|
||||||
import org.elasticsearch.action.update.UpdateResponse;
|
import org.elasticsearch.action.update.UpdateResponse;
|
||||||
|
@ -91,6 +92,7 @@ import java.util.concurrent.ExecutionException;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
import java.util.concurrent.atomic.AtomicBoolean;
|
import java.util.concurrent.atomic.AtomicBoolean;
|
||||||
import java.util.function.Function;
|
import java.util.function.Function;
|
||||||
|
import java.util.function.Supplier;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
import javax.crypto.SecretKeyFactory;
|
import javax.crypto.SecretKeyFactory;
|
||||||
|
@ -666,6 +668,7 @@ public class ApiKeyService {
|
||||||
expiredQuery.should(QueryBuilders.boolQuery().mustNot(QueryBuilders.existsQuery("expiration_time")));
|
expiredQuery.should(QueryBuilders.boolQuery().mustNot(QueryBuilders.existsQuery("expiration_time")));
|
||||||
boolQuery.filter(expiredQuery);
|
boolQuery.filter(expiredQuery);
|
||||||
}
|
}
|
||||||
|
final Supplier<ThreadContext.StoredContext> supplier = client.threadPool().getThreadContext().newRestorableContext(false);
|
||||||
try (ThreadContext.StoredContext ignore = client.threadPool().getThreadContext().stashWithOrigin(SECURITY_ORIGIN)) {
|
try (ThreadContext.StoredContext ignore = client.threadPool().getThreadContext().stashWithOrigin(SECURITY_ORIGIN)) {
|
||||||
final SearchRequest request = client.prepareSearch(SECURITY_MAIN_ALIAS)
|
final SearchRequest request = client.prepareSearch(SECURITY_MAIN_ALIAS)
|
||||||
.setScroll(DEFAULT_KEEPALIVE_SETTING.get(settings))
|
.setScroll(DEFAULT_KEEPALIVE_SETTING.get(settings))
|
||||||
|
@ -675,7 +678,7 @@ public class ApiKeyService {
|
||||||
.setFetchSource(true)
|
.setFetchSource(true)
|
||||||
.request();
|
.request();
|
||||||
securityIndex.checkIndexVersionThenExecute(listener::onFailure,
|
securityIndex.checkIndexVersionThenExecute(listener::onFailure,
|
||||||
() -> ScrollHelper.fetchAllByEntity(client, request, listener,
|
() -> ScrollHelper.fetchAllByEntity(client, request, new ContextPreservingActionListener<>(supplier, listener),
|
||||||
(SearchHit hit) -> {
|
(SearchHit hit) -> {
|
||||||
Map<String, Object> source = hit.getSourceAsMap();
|
Map<String, Object> source = hit.getSourceAsMap();
|
||||||
String name = (String) source.get("name");
|
String name = (String) source.get("name");
|
||||||
|
|
|
@ -30,6 +30,7 @@ import org.elasticsearch.action.index.IndexAction;
|
||||||
import org.elasticsearch.action.index.IndexRequest;
|
import org.elasticsearch.action.index.IndexRequest;
|
||||||
import org.elasticsearch.action.search.SearchRequest;
|
import org.elasticsearch.action.search.SearchRequest;
|
||||||
import org.elasticsearch.action.search.SearchResponse;
|
import org.elasticsearch.action.search.SearchResponse;
|
||||||
|
import org.elasticsearch.action.support.ContextPreservingActionListener;
|
||||||
import org.elasticsearch.action.support.TransportActions;
|
import org.elasticsearch.action.support.TransportActions;
|
||||||
import org.elasticsearch.action.support.WriteRequest.RefreshPolicy;
|
import org.elasticsearch.action.support.WriteRequest.RefreshPolicy;
|
||||||
import org.elasticsearch.action.support.master.AcknowledgedRequest;
|
import org.elasticsearch.action.support.master.AcknowledgedRequest;
|
||||||
|
@ -135,6 +136,7 @@ import java.util.concurrent.atomic.AtomicBoolean;
|
||||||
import java.util.concurrent.atomic.AtomicLong;
|
import java.util.concurrent.atomic.AtomicLong;
|
||||||
import java.util.function.Consumer;
|
import java.util.function.Consumer;
|
||||||
import java.util.function.Predicate;
|
import java.util.function.Predicate;
|
||||||
|
import java.util.function.Supplier;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
import static org.elasticsearch.action.support.TransportActions.isShardNotAvailableException;
|
import static org.elasticsearch.action.support.TransportActions.isShardNotAvailableException;
|
||||||
|
@ -1240,6 +1242,8 @@ public final class TokenService {
|
||||||
- TimeValue.timeValueHours(ExpiredTokenRemover.MAXIMUM_TOKEN_LIFETIME_HOURS).millis()))
|
- TimeValue.timeValueHours(ExpiredTokenRemover.MAXIMUM_TOKEN_LIFETIME_HOURS).millis()))
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
final Supplier<ThreadContext.StoredContext> supplier = client.threadPool().getThreadContext().newRestorableContext(false);
|
||||||
|
try (ThreadContext.StoredContext ignore = client.threadPool().getThreadContext().stashWithOrigin(SECURITY_ORIGIN)) {
|
||||||
final SearchRequest request = client.prepareSearch(indicesWithTokens.toArray(new String[0]))
|
final SearchRequest request = client.prepareSearch(indicesWithTokens.toArray(new String[0]))
|
||||||
.setScroll(DEFAULT_KEEPALIVE_SETTING.get(settings))
|
.setScroll(DEFAULT_KEEPALIVE_SETTING.get(settings))
|
||||||
.setQuery(boolQuery)
|
.setQuery(boolQuery)
|
||||||
|
@ -1247,10 +1251,11 @@ public final class TokenService {
|
||||||
.setSize(1000)
|
.setSize(1000)
|
||||||
.setFetchSource(true)
|
.setFetchSource(true)
|
||||||
.request();
|
.request();
|
||||||
ScrollHelper.fetchAllByEntity(client, request, listener, (SearchHit hit) -> filterAndParseHit(hit, filter));
|
ScrollHelper.fetchAllByEntity(client, request, new ContextPreservingActionListener<>(supplier, listener),
|
||||||
|
(SearchHit hit) -> filterAndParseHit(hit, filter));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}, listener::onFailure));
|
}, listener::onFailure));
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -1284,6 +1289,8 @@ public final class TokenService {
|
||||||
- TimeValue.timeValueHours(ExpiredTokenRemover.MAXIMUM_TOKEN_LIFETIME_HOURS).millis()))
|
- TimeValue.timeValueHours(ExpiredTokenRemover.MAXIMUM_TOKEN_LIFETIME_HOURS).millis()))
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
final Supplier<ThreadContext.StoredContext> supplier = client.threadPool().getThreadContext().newRestorableContext(false);
|
||||||
|
try (ThreadContext.StoredContext ignore = client.threadPool().getThreadContext().stashWithOrigin(SECURITY_ORIGIN)) {
|
||||||
final SearchRequest request = client.prepareSearch(indicesWithTokens.toArray(new String[0]))
|
final SearchRequest request = client.prepareSearch(indicesWithTokens.toArray(new String[0]))
|
||||||
.setScroll(DEFAULT_KEEPALIVE_SETTING.get(settings))
|
.setScroll(DEFAULT_KEEPALIVE_SETTING.get(settings))
|
||||||
.setQuery(boolQuery)
|
.setQuery(boolQuery)
|
||||||
|
@ -1291,7 +1298,9 @@ public final class TokenService {
|
||||||
.setSize(1000)
|
.setSize(1000)
|
||||||
.setFetchSource(true)
|
.setFetchSource(true)
|
||||||
.request();
|
.request();
|
||||||
ScrollHelper.fetchAllByEntity(client, request, listener, (SearchHit hit) -> filterAndParseHit(hit, isOfUser(username)));
|
ScrollHelper.fetchAllByEntity(client, request, new ContextPreservingActionListener<>(supplier, listener),
|
||||||
|
(SearchHit hit) -> filterAndParseHit(hit, isOfUser(username)));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}, listener::onFailure));
|
}, listener::onFailure));
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,204 @@
|
||||||
|
---
|
||||||
|
setup:
|
||||||
|
- skip:
|
||||||
|
features: headers
|
||||||
|
|
||||||
|
- do:
|
||||||
|
cluster.health:
|
||||||
|
wait_for_status: yellow
|
||||||
|
|
||||||
|
- do:
|
||||||
|
security.put_role:
|
||||||
|
name: "admin_role"
|
||||||
|
body: >
|
||||||
|
{
|
||||||
|
"cluster": ["manage_api_key"]
|
||||||
|
}
|
||||||
|
|
||||||
|
- do:
|
||||||
|
security.put_role:
|
||||||
|
name: "user_role"
|
||||||
|
body: >
|
||||||
|
{
|
||||||
|
"cluster": ["manage_own_api_key"]
|
||||||
|
}
|
||||||
|
|
||||||
|
- do:
|
||||||
|
security.put_user:
|
||||||
|
username: "api_key_manager"
|
||||||
|
body: >
|
||||||
|
{
|
||||||
|
"password" : "x-pack-test-password",
|
||||||
|
"roles" : [ "admin_role" ],
|
||||||
|
"full_name" : "API key manager"
|
||||||
|
}
|
||||||
|
|
||||||
|
- do:
|
||||||
|
security.put_user:
|
||||||
|
username: "api_key_user_1"
|
||||||
|
body: >
|
||||||
|
{
|
||||||
|
"password" : "x-pack-test-password",
|
||||||
|
"roles" : [ "user_role" ],
|
||||||
|
"full_name" : "API key user"
|
||||||
|
}
|
||||||
|
|
||||||
|
---
|
||||||
|
teardown:
|
||||||
|
- do:
|
||||||
|
security.delete_role:
|
||||||
|
name: "admin_role"
|
||||||
|
ignore: 404
|
||||||
|
|
||||||
|
- do:
|
||||||
|
security.delete_role:
|
||||||
|
name: "use_role"
|
||||||
|
ignore: 404
|
||||||
|
|
||||||
|
- do:
|
||||||
|
security.delete_user:
|
||||||
|
username: "api_key_user_1"
|
||||||
|
ignore: 404
|
||||||
|
|
||||||
|
- do:
|
||||||
|
security.delete_user:
|
||||||
|
username: "api_key_manager"
|
||||||
|
ignore: 404
|
||||||
|
|
||||||
|
---
|
||||||
|
"Test invalidate api key by username":
|
||||||
|
|
||||||
|
# every user first gets its own API key
|
||||||
|
- do:
|
||||||
|
headers:
|
||||||
|
Authorization: "Basic YXBpX2tleV9tYW5hZ2VyOngtcGFjay10ZXN0LXBhc3N3b3Jk" # api_key_manager
|
||||||
|
security.create_api_key:
|
||||||
|
body: >
|
||||||
|
{
|
||||||
|
"name": "manager-api-key",
|
||||||
|
"expiration": "1d",
|
||||||
|
"role_descriptors": {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
- match: { name: "manager-api-key" }
|
||||||
|
- is_true: id
|
||||||
|
- is_true: api_key
|
||||||
|
- is_true: expiration
|
||||||
|
- set: { id: manager_key_id }
|
||||||
|
|
||||||
|
- do:
|
||||||
|
headers:
|
||||||
|
Authorization: "Basic YXBpX2tleV91c2VyXzE6eC1wYWNrLXRlc3QtcGFzc3dvcmQ=" # api_key_user_1
|
||||||
|
security.create_api_key:
|
||||||
|
body: >
|
||||||
|
{
|
||||||
|
"name": "user1-api-key",
|
||||||
|
"expiration": "1d",
|
||||||
|
"role_descriptors": {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
- match: { name: "user1-api-key" }
|
||||||
|
- is_true: id
|
||||||
|
- is_true: api_key
|
||||||
|
- is_true: expiration
|
||||||
|
- set: { id: user1_key_id }
|
||||||
|
|
||||||
|
- do:
|
||||||
|
headers:
|
||||||
|
Authorization: "Basic YXBpX2tleV9tYW5hZ2VyOngtcGFjay10ZXN0LXBhc3N3b3Jk" # api_key_manager
|
||||||
|
security.invalidate_api_key:
|
||||||
|
body: >
|
||||||
|
{
|
||||||
|
"username": "api_key_user_1"
|
||||||
|
}
|
||||||
|
- length: { "invalidated_api_keys" : 1 }
|
||||||
|
- match: { "invalidated_api_keys.0" : "${user1_key_id}" }
|
||||||
|
- length: { "previously_invalidated_api_keys" : 0 }
|
||||||
|
- match: { "error_count" : 0 }
|
||||||
|
|
||||||
|
- do:
|
||||||
|
catch: forbidden
|
||||||
|
headers:
|
||||||
|
Authorization: "Basic YXBpX2tleV91c2VyXzE6eC1wYWNrLXRlc3QtcGFzc3dvcmQ=" # api_key_user_1
|
||||||
|
security.invalidate_api_key:
|
||||||
|
body: >
|
||||||
|
{
|
||||||
|
"username": "api_key_manager"
|
||||||
|
}
|
||||||
|
- match: { "error.type": "security_exception" }
|
||||||
|
- match: { "error.reason": "action [cluster:admin/xpack/security/api_key/invalidate] is unauthorized for user [api_key_user_1]" }
|
||||||
|
|
||||||
|
- do:
|
||||||
|
headers:
|
||||||
|
Authorization: "Basic YXBpX2tleV9tYW5hZ2VyOngtcGFjay10ZXN0LXBhc3N3b3Jk" # api_key_manager
|
||||||
|
security.invalidate_api_key:
|
||||||
|
body: >
|
||||||
|
{
|
||||||
|
"username": "api_key_manager"
|
||||||
|
}
|
||||||
|
- length: { "invalidated_api_keys" : 1 }
|
||||||
|
- match: { "invalidated_api_keys.0" : "${manager_key_id}" }
|
||||||
|
- length: { "previously_invalidated_api_keys" : 0 }
|
||||||
|
- match: { "error_count" : 0 }
|
||||||
|
|
||||||
|
---
|
||||||
|
"Test invalidate api key by realm name":
|
||||||
|
|
||||||
|
# every user first gets its own API key
|
||||||
|
- do:
|
||||||
|
headers:
|
||||||
|
Authorization: "Basic YXBpX2tleV9tYW5hZ2VyOngtcGFjay10ZXN0LXBhc3N3b3Jk" # api_key_manager
|
||||||
|
security.create_api_key:
|
||||||
|
body: >
|
||||||
|
{
|
||||||
|
"name": "manager-api-key",
|
||||||
|
"expiration": "1d",
|
||||||
|
"role_descriptors": {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
- match: { name: "manager-api-key" }
|
||||||
|
- is_true: id
|
||||||
|
- is_true: api_key
|
||||||
|
- is_true: expiration
|
||||||
|
- set: { id: manager_key_id }
|
||||||
|
|
||||||
|
- do:
|
||||||
|
headers:
|
||||||
|
Authorization: "Basic YXBpX2tleV91c2VyXzE6eC1wYWNrLXRlc3QtcGFzc3dvcmQ=" # api_key_user_1
|
||||||
|
security.create_api_key:
|
||||||
|
body: >
|
||||||
|
{
|
||||||
|
"name": "user1-api-key",
|
||||||
|
"expiration": "1d",
|
||||||
|
"role_descriptors": {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
- match: { name: "user1-api-key" }
|
||||||
|
- is_true: id
|
||||||
|
- is_true: api_key
|
||||||
|
- is_true: expiration
|
||||||
|
- set: { id: user1_key_id }
|
||||||
|
|
||||||
|
- do:
|
||||||
|
catch: forbidden
|
||||||
|
headers:
|
||||||
|
Authorization: "Basic YXBpX2tleV91c2VyXzE6eC1wYWNrLXRlc3QtcGFzc3dvcmQ=" # api_key_user_1
|
||||||
|
security.invalidate_api_key:
|
||||||
|
body: >
|
||||||
|
{
|
||||||
|
"realm_name": "default_native"
|
||||||
|
}
|
||||||
|
- match: { "error.type": "security_exception" }
|
||||||
|
- match: { "error.reason": "action [cluster:admin/xpack/security/api_key/invalidate] is unauthorized for user [api_key_user_1]" }
|
||||||
|
|
||||||
|
- do:
|
||||||
|
headers:
|
||||||
|
Authorization: "Basic YXBpX2tleV9tYW5hZ2VyOngtcGFjay10ZXN0LXBhc3N3b3Jk" # api_key_manager
|
||||||
|
security.invalidate_api_key:
|
||||||
|
body: >
|
||||||
|
{
|
||||||
|
"realm_name": "default_native"
|
||||||
|
}
|
||||||
|
- length: { "invalidated_api_keys" : 2 }
|
||||||
|
- length: { "previously_invalidated_api_keys" : 0 }
|
||||||
|
- match: { "error_count" : 0 }
|
|
@ -7,18 +7,32 @@ setup:
|
||||||
cluster.health:
|
cluster.health:
|
||||||
wait_for_status: yellow
|
wait_for_status: yellow
|
||||||
|
|
||||||
|
- do:
|
||||||
|
security.put_role:
|
||||||
|
name: "admin_role"
|
||||||
|
body: >
|
||||||
|
{
|
||||||
|
"cluster": ["manage_security"]
|
||||||
|
}
|
||||||
|
|
||||||
- do:
|
- do:
|
||||||
security.put_user:
|
security.put_user:
|
||||||
username: "token_user"
|
username: "token_user"
|
||||||
body: >
|
body: >
|
||||||
{
|
{
|
||||||
"password" : "x-pack-test-password",
|
"password" : "x-pack-test-password",
|
||||||
"roles" : [ "superuser" ],
|
"roles" : [ "admin_role" ],
|
||||||
"full_name" : "Token User"
|
"full_name" : "Token User"
|
||||||
}
|
}
|
||||||
|
|
||||||
---
|
---
|
||||||
teardown:
|
teardown:
|
||||||
|
|
||||||
|
- do:
|
||||||
|
security.delete_role:
|
||||||
|
name: "admin_role"
|
||||||
|
ignore: 404
|
||||||
|
|
||||||
- do:
|
- do:
|
||||||
security.delete_user:
|
security.delete_user:
|
||||||
username: "token_user"
|
username: "token_user"
|
||||||
|
@ -46,7 +60,7 @@ teardown:
|
||||||
security.authenticate: {}
|
security.authenticate: {}
|
||||||
|
|
||||||
- match: { username: "token_user" }
|
- match: { username: "token_user" }
|
||||||
- match: { roles.0: "superuser" }
|
- match: { roles.0: "admin_role" }
|
||||||
- match: { full_name: "Token User" }
|
- match: { full_name: "Token User" }
|
||||||
|
|
||||||
---
|
---
|
||||||
|
@ -71,7 +85,7 @@ teardown:
|
||||||
security.authenticate: {}
|
security.authenticate: {}
|
||||||
|
|
||||||
- match: { username: "token_user" }
|
- match: { username: "token_user" }
|
||||||
- match: { roles.0: "superuser" }
|
- match: { roles.0: "admin_role" }
|
||||||
- match: { full_name: "Token User" }
|
- match: { full_name: "Token User" }
|
||||||
|
|
||||||
- do:
|
- do:
|
||||||
|
@ -111,7 +125,7 @@ teardown:
|
||||||
security.authenticate: {}
|
security.authenticate: {}
|
||||||
|
|
||||||
- match: { username: "token_user" }
|
- match: { username: "token_user" }
|
||||||
- match: { roles.0: "superuser" }
|
- match: { roles.0: "admin_role" }
|
||||||
- match: { full_name: "Token User" }
|
- match: { full_name: "Token User" }
|
||||||
|
|
||||||
- do:
|
- do:
|
||||||
|
@ -152,7 +166,7 @@ teardown:
|
||||||
security.authenticate: {}
|
security.authenticate: {}
|
||||||
|
|
||||||
- match: { username: "token_user" }
|
- match: { username: "token_user" }
|
||||||
- match: { roles.0: "superuser" }
|
- match: { roles.0: "admin_role" }
|
||||||
- match: { full_name: "Token User" }
|
- match: { full_name: "Token User" }
|
||||||
|
|
||||||
- do:
|
- do:
|
||||||
|
|
Loading…
Reference in New Issue