Add negative tests for security features in basic
Assert that API Keys, Tokens, DLS/FLS do not work in basic
This commit is contained in:
parent
3589ca8493
commit
8426130553
|
@ -19,6 +19,8 @@ integTestCluster {
|
|||
setting 'xpack.security.enabled', 'true'
|
||||
setting 'xpack.security.http.ssl.enabled', 'false'
|
||||
setting 'xpack.security.transport.ssl.enabled', 'false'
|
||||
setting 'xpack.security.authc.token.enabled', 'true'
|
||||
setting 'xpack.security.authc.api_key.enabled', 'true'
|
||||
|
||||
extraConfigFile 'roles.yml', project.projectDir.toPath().resolve('src/test/resources/roles.yml')
|
||||
setupCommand 'setupUser#admin_user', 'bin/elasticsearch-users', 'useradd', 'admin_user', '-p', 'admin-password', '-r', 'superuser'
|
||||
|
|
|
@ -5,9 +5,12 @@
|
|||
*/
|
||||
package org.elasticsearch.xpack.security;
|
||||
|
||||
import org.apache.http.HttpHeaders;
|
||||
import org.elasticsearch.client.Request;
|
||||
import org.elasticsearch.client.RequestOptions;
|
||||
import org.elasticsearch.client.Response;
|
||||
import org.elasticsearch.client.ResponseException;
|
||||
import org.elasticsearch.common.collect.Tuple;
|
||||
import org.elasticsearch.common.settings.SecureString;
|
||||
import org.elasticsearch.common.settings.Settings;
|
||||
import org.elasticsearch.common.util.concurrent.ThreadContext;
|
||||
|
@ -16,7 +19,9 @@ import org.elasticsearch.test.rest.yaml.ObjectPath;
|
|||
import org.elasticsearch.xpack.security.authc.InternalRealms;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.Arrays;
|
||||
import java.util.Base64;
|
||||
import java.util.Map;
|
||||
|
||||
import static org.elasticsearch.xpack.core.security.authc.support.UsernamePasswordToken.basicAuthHeaderValue;
|
||||
|
@ -49,18 +54,36 @@ public class SecurityWithBasicLicenseIT extends ESRestTestCase {
|
|||
checkAuthentication();
|
||||
checkHasPrivileges();
|
||||
checkIndexWrite();
|
||||
assertFailToGetToken();
|
||||
assertFailToGetApiKey();
|
||||
assertAddRoleWithDLS(false);
|
||||
assertAddRoleWithFLS(false);
|
||||
}
|
||||
|
||||
public void testWithTrialLicense() throws Exception {
|
||||
startTrial();
|
||||
String accessToken = null;
|
||||
Tuple<String, String> keyAndId = null;
|
||||
try {
|
||||
checkLicenseType("trial");
|
||||
checkSecurityEnabled(true);
|
||||
checkAuthentication();
|
||||
checkHasPrivileges();
|
||||
checkIndexWrite();
|
||||
accessToken = getAccessToken();
|
||||
keyAndId = getApiKeyAndId();
|
||||
assertAuthenticateWithToken(accessToken, true);
|
||||
assertAuthenticateWithApiKey(keyAndId, true);
|
||||
assertAddRoleWithDLS(true);
|
||||
assertAddRoleWithFLS(true);
|
||||
} finally {
|
||||
revertTrial();
|
||||
assertAuthenticateWithToken(accessToken, false);
|
||||
assertAuthenticateWithApiKey(keyAndId, false);
|
||||
assertFailToGetToken();
|
||||
assertFailToGetApiKey();
|
||||
assertAddRoleWithDLS(false);
|
||||
assertAddRoleWithFLS(false);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -136,4 +159,138 @@ public class SecurityWithBasicLicenseIT extends ESRestTestCase {
|
|||
assertThat(e.getMessage(), containsString("unauthorized for user [security_test_user]"));
|
||||
}
|
||||
|
||||
private Request buildGetTokenRequest() {
|
||||
final Request getToken = new Request("POST", "/_security/oauth2/token");
|
||||
getToken.setJsonEntity("{\"grant_type\" : \"password\",\n" +
|
||||
" \"username\" : \"security_test_user\",\n" +
|
||||
" \"password\" : \"security-test-password\"\n" +
|
||||
"}");
|
||||
return getToken;
|
||||
}
|
||||
|
||||
private Request buildGetApiKeyRequest() {
|
||||
final Request getApiKey = new Request("POST", "/_security/api_key");
|
||||
getApiKey.setJsonEntity("{\"name\" : \"my-api-key\",\n" +
|
||||
" \"expiration\" : \"2d\",\n" +
|
||||
" \"role_descriptors\" : {} \n" +
|
||||
"}");
|
||||
return getApiKey;
|
||||
}
|
||||
|
||||
private String getAccessToken() throws IOException {
|
||||
Response getTokenResponse = adminClient().performRequest(buildGetTokenRequest());
|
||||
assertThat(getTokenResponse.getStatusLine().getStatusCode(), equalTo(200));
|
||||
final Map<String, Object> tokens = entityAsMap(getTokenResponse);
|
||||
return ObjectPath.evaluate(tokens, "access_token").toString();
|
||||
}
|
||||
|
||||
private Tuple<String, String> getApiKeyAndId() throws IOException {
|
||||
Response getApiKeyResponse = adminClient().performRequest(buildGetApiKeyRequest());
|
||||
assertThat(getApiKeyResponse.getStatusLine().getStatusCode(), equalTo(200));
|
||||
final Map<String, Object> apiKeyResponseMap = entityAsMap(getApiKeyResponse);
|
||||
assertOK(getApiKeyResponse);
|
||||
return new Tuple<>(ObjectPath.evaluate(apiKeyResponseMap, "api_key").toString(),
|
||||
ObjectPath.evaluate(apiKeyResponseMap, "id").toString());
|
||||
}
|
||||
|
||||
private void assertFailToGetToken() {
|
||||
ResponseException e = expectThrows(ResponseException.class, () -> adminClient().performRequest(buildGetTokenRequest()));
|
||||
assertThat(e.getResponse().getStatusLine().getStatusCode(), equalTo(403));
|
||||
assertThat(e.getMessage(), containsString("current license is non-compliant for [security tokens]"));
|
||||
}
|
||||
|
||||
private void assertFailToGetApiKey() {
|
||||
ResponseException e = expectThrows(ResponseException.class, () -> adminClient().performRequest(buildGetApiKeyRequest()));
|
||||
assertThat(e.getResponse().getStatusLine().getStatusCode(), equalTo(403));
|
||||
assertThat(e.getMessage(), containsString("current license is non-compliant for [api keys]"));
|
||||
}
|
||||
|
||||
private void assertAuthenticateWithToken(String accessToken, boolean shouldSucceed) throws IOException {
|
||||
assertNotNull("access token cannot be null", accessToken);
|
||||
Request request = new Request("GET", "/_security/_authenticate");
|
||||
RequestOptions.Builder options = request.getOptions().toBuilder();
|
||||
options.addHeader(HttpHeaders.AUTHORIZATION, "Bearer " + accessToken);
|
||||
request.setOptions(options);
|
||||
if (shouldSucceed) {
|
||||
Response authenticateResponse = client().performRequest(request);
|
||||
assertOK(authenticateResponse);
|
||||
assertEquals("security_test_user", entityAsMap(authenticateResponse).get("username"));
|
||||
} else {
|
||||
ResponseException e = expectThrows(ResponseException.class, () -> client().performRequest(request));
|
||||
assertThat(e.getResponse().getStatusLine().getStatusCode(), equalTo(401));
|
||||
assertThat(e.getMessage(), containsString("missing authentication credentials for REST request"));
|
||||
}
|
||||
}
|
||||
|
||||
private void assertAuthenticateWithApiKey(Tuple<String, String> keyAndId, boolean shouldSucceed) throws IOException {
|
||||
assertNotNull("API Key and Id cannot be null", keyAndId);
|
||||
Request request = new Request("GET", "/_security/_authenticate");
|
||||
RequestOptions.Builder options = request.getOptions().toBuilder();
|
||||
String headerValue = Base64.getEncoder().encodeToString((keyAndId.v2() + ":" + keyAndId.v1()).getBytes(StandardCharsets.UTF_8));
|
||||
options.addHeader(HttpHeaders.AUTHORIZATION, "ApiKey " + headerValue);
|
||||
request.setOptions(options);
|
||||
if (shouldSucceed) {
|
||||
Response authenticateResponse = client().performRequest(request);
|
||||
assertOK(authenticateResponse);
|
||||
assertEquals("admin_user", entityAsMap(authenticateResponse).get("username"));
|
||||
} else {
|
||||
ResponseException e = expectThrows(ResponseException.class, () -> client().performRequest(request));
|
||||
assertThat(e.getResponse().getStatusLine().getStatusCode(), equalTo(401));
|
||||
assertThat(e.getMessage(), containsString("missing authentication credentials for REST request"));
|
||||
}
|
||||
}
|
||||
|
||||
private void assertAddRoleWithDLS(boolean shouldSucceed) throws IOException {
|
||||
final Request addRole = new Request("POST", "/_security/role/dlsrole");
|
||||
addRole.setJsonEntity("{\n" +
|
||||
" \"cluster\": [\"all\"],\n" +
|
||||
" \"indices\": [\n" +
|
||||
" {\n" +
|
||||
" \"names\": [ \"index1\", \"index2\" ],\n" +
|
||||
" \"privileges\": [\"all\"],\n" +
|
||||
" \"query\": \"{\\\"match\\\": {\\\"title\\\": \\\"foo\\\"}}\" \n" +
|
||||
" }\n" +
|
||||
" ],\n" +
|
||||
" \"run_as\": [ \"other_user\" ],\n" +
|
||||
" \"metadata\" : { // optional\n" +
|
||||
" \"version\" : 1\n" +
|
||||
" }\n" +
|
||||
"}");
|
||||
if (shouldSucceed) {
|
||||
Response addRoleResponse = adminClient().performRequest(addRole);
|
||||
assertThat(addRoleResponse.getStatusLine().getStatusCode(), equalTo(200));
|
||||
} else {
|
||||
ResponseException e = expectThrows(ResponseException.class, () -> adminClient().performRequest(addRole));
|
||||
assertThat(e.getResponse().getStatusLine().getStatusCode(), equalTo(403));
|
||||
assertThat(e.getMessage(), containsString("current license is non-compliant for [field and document level security]"));
|
||||
}
|
||||
}
|
||||
|
||||
private void assertAddRoleWithFLS(boolean shouldSucceed) throws IOException {
|
||||
final Request addRole = new Request("POST", "/_security/role/dlsrole");
|
||||
addRole.setJsonEntity("{\n" +
|
||||
" \"cluster\": [\"all\"],\n" +
|
||||
" \"indices\": [\n" +
|
||||
" {\n" +
|
||||
" \"names\": [ \"index1\", \"index2\" ],\n" +
|
||||
" \"privileges\": [\"all\"],\n" +
|
||||
" \"field_security\" : { // optional\n" +
|
||||
" \"grant\" : [ \"title\", \"body\" ]\n" +
|
||||
" }\n" +
|
||||
" }\n" +
|
||||
" ],\n" +
|
||||
" \"run_as\": [ \"other_user\" ],\n" +
|
||||
" \"metadata\" : { // optional\n" +
|
||||
" \"version\" : 1\n" +
|
||||
" }\n" +
|
||||
"}");
|
||||
if (shouldSucceed) {
|
||||
Response addRoleResponse = adminClient().performRequest(addRole);
|
||||
assertThat(addRoleResponse.getStatusLine().getStatusCode(), equalTo(200));
|
||||
} else {
|
||||
ResponseException e = expectThrows(ResponseException.class, () -> adminClient().performRequest(addRole));
|
||||
assertThat(e.getResponse().getStatusLine().getStatusCode(), equalTo(403));
|
||||
assertThat(e.getMessage(), containsString("current license is non-compliant for [field and document level security]"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue