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:
Ioannis Kakavas 2019-04-15 11:08:44 +03:00 committed by Jason Tedor
parent 3589ca8493
commit 8426130553
No known key found for this signature in database
GPG Key ID: FA89F05560F16BC5
2 changed files with 159 additions and 0 deletions

View File

@ -19,6 +19,8 @@ integTestCluster {
setting 'xpack.security.enabled', 'true' setting 'xpack.security.enabled', 'true'
setting 'xpack.security.http.ssl.enabled', 'false' setting 'xpack.security.http.ssl.enabled', 'false'
setting 'xpack.security.transport.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') 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' setupCommand 'setupUser#admin_user', 'bin/elasticsearch-users', 'useradd', 'admin_user', '-p', 'admin-password', '-r', 'superuser'

View File

@ -5,9 +5,12 @@
*/ */
package org.elasticsearch.xpack.security; package org.elasticsearch.xpack.security;
import org.apache.http.HttpHeaders;
import org.elasticsearch.client.Request; import org.elasticsearch.client.Request;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.Response; import org.elasticsearch.client.Response;
import org.elasticsearch.client.ResponseException; import org.elasticsearch.client.ResponseException;
import org.elasticsearch.common.collect.Tuple;
import org.elasticsearch.common.settings.SecureString; import org.elasticsearch.common.settings.SecureString;
import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.util.concurrent.ThreadContext; 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 org.elasticsearch.xpack.security.authc.InternalRealms;
import java.io.IOException; import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.Arrays; import java.util.Arrays;
import java.util.Base64;
import java.util.Map; import java.util.Map;
import static org.elasticsearch.xpack.core.security.authc.support.UsernamePasswordToken.basicAuthHeaderValue; import static org.elasticsearch.xpack.core.security.authc.support.UsernamePasswordToken.basicAuthHeaderValue;
@ -49,18 +54,36 @@ public class SecurityWithBasicLicenseIT extends ESRestTestCase {
checkAuthentication(); checkAuthentication();
checkHasPrivileges(); checkHasPrivileges();
checkIndexWrite(); checkIndexWrite();
assertFailToGetToken();
assertFailToGetApiKey();
assertAddRoleWithDLS(false);
assertAddRoleWithFLS(false);
} }
public void testWithTrialLicense() throws Exception { public void testWithTrialLicense() throws Exception {
startTrial(); startTrial();
String accessToken = null;
Tuple<String, String> keyAndId = null;
try { try {
checkLicenseType("trial"); checkLicenseType("trial");
checkSecurityEnabled(true); checkSecurityEnabled(true);
checkAuthentication(); checkAuthentication();
checkHasPrivileges(); checkHasPrivileges();
checkIndexWrite(); checkIndexWrite();
accessToken = getAccessToken();
keyAndId = getApiKeyAndId();
assertAuthenticateWithToken(accessToken, true);
assertAuthenticateWithApiKey(keyAndId, true);
assertAddRoleWithDLS(true);
assertAddRoleWithFLS(true);
} finally { } finally {
revertTrial(); 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]")); 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]"));
}
}
} }