Bulk invalidate API keys using a list of IDs (#63224) (#63320)

Add a new ids field to the API of invalidating API keys so that it supports bulk
invalidation with a list of IDs.
Note the existing id field is kept as is and it is an error if both id and ids are specified.
This commit is contained in:
Yang Wang 2020-10-07 00:49:21 +11:00 committed by GitHub
parent bbfa2f1303
commit abf9b885b4
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 233 additions and 48 deletions

View File

@ -15,7 +15,9 @@ import org.elasticsearch.common.io.stream.StreamInput;
import org.elasticsearch.common.io.stream.StreamOutput;
import java.io.IOException;
import java.util.Arrays;
import java.util.Objects;
import java.util.stream.IntStream;
import static org.elasticsearch.action.ValidateActions.addValidationError;
@ -26,19 +28,24 @@ public final class InvalidateApiKeyRequest extends ActionRequest {
private final String realmName;
private final String userName;
private final String id;
private final String[] ids;
private final String name;
private final boolean ownedByAuthenticatedUser;
public InvalidateApiKeyRequest() {
this(null, null, null, null, false);
this(null, null, null, null, false, null);
}
public InvalidateApiKeyRequest(StreamInput in) throws IOException {
super(in);
realmName = in.readOptionalString();
userName = in.readOptionalString();
id = in.readOptionalString();
if (in.getVersion().onOrAfter(Version.V_7_10_0)) {
ids = in.readOptionalStringArray();
} else {
final String id = in.readOptionalString();
ids = Strings.hasText(id) == false ? null : new String[] { id };
}
name = in.readOptionalString();
if (in.getVersion().onOrAfter(Version.V_7_4_0)) {
ownedByAuthenticatedUser = in.readOptionalBoolean();
@ -49,9 +56,22 @@ public final class InvalidateApiKeyRequest extends ActionRequest {
public InvalidateApiKeyRequest(@Nullable String realmName, @Nullable String userName, @Nullable String id,
@Nullable String name, boolean ownedByAuthenticatedUser) {
this(realmName, userName, id, name, ownedByAuthenticatedUser, null);
}
public InvalidateApiKeyRequest(@Nullable String realmName, @Nullable String userName, @Nullable String id,
@Nullable String name, boolean ownedByAuthenticatedUser, @Nullable String[] ids) {
if (id != null && ids != null) {
throw new IllegalArgumentException("Must use either [id] or [ids], not both at the same time");
}
this.realmName = realmName;
this.userName = userName;
this.id = id;
if (id != null) {
this.ids = new String[] {id};
} else {
this.ids = ids;
}
this.name = name;
this.ownedByAuthenticatedUser = ownedByAuthenticatedUser;
}
@ -64,8 +84,8 @@ public final class InvalidateApiKeyRequest extends ActionRequest {
return userName;
}
public String getId() {
return id;
public String[] getIds() {
return ids;
}
public String getName() {
@ -141,15 +161,28 @@ public final class InvalidateApiKeyRequest extends ActionRequest {
@Override
public ActionRequestValidationException validate() {
ActionRequestValidationException validationException = null;
if (Strings.hasText(realmName) == false && Strings.hasText(userName) == false && Strings.hasText(id) == false
if (ids != null) {
if (ids.length == 0) {
validationException = addValidationError("Field [ids] cannot be an empty array", validationException);
} else {
final int[] idxOfBlankIds = IntStream.range(0, ids.length).filter(i -> Strings.hasText(ids[i]) == false).toArray();
if (idxOfBlankIds.length > 0) {
validationException = addValidationError("Field [ids] must not contain blank id, but got blank "
+ (idxOfBlankIds.length == 1 ? "id" : "ids") + " at index "
+ (idxOfBlankIds.length == 1 ? "position" : "positions") + ": "
+ Arrays.toString(idxOfBlankIds), validationException);
}
}
}
if (Strings.hasText(realmName) == false && Strings.hasText(userName) == false && ids == null
&& Strings.hasText(name) == false && ownedByAuthenticatedUser == false) {
validationException = addValidationError("One of [api key id, api key name, username, realm name] must be specified if " +
validationException = addValidationError("One of [api key id(s), api key name, username, realm name] must be specified if " +
"[owner] flag is false", validationException);
}
if (Strings.hasText(id) || Strings.hasText(name)) {
if (ids != null || Strings.hasText(name)) {
if (Strings.hasText(realmName) || Strings.hasText(userName)) {
validationException = addValidationError(
"username or realm name must not be specified when the api key id or api key name is specified",
"username or realm name must not be specified when the api key id(s) or api key name are specified",
validationException);
}
}
@ -160,8 +193,8 @@ public final class InvalidateApiKeyRequest extends ActionRequest {
validationException);
}
}
if (Strings.hasText(id) && Strings.hasText(name)) {
validationException = addValidationError("only one of [api key id, api key name] can be specified", validationException);
if (ids != null && Strings.hasText(name)) {
validationException = addValidationError("only one of [api key id(s), api key name] can be specified", validationException);
}
return validationException;
}
@ -171,7 +204,19 @@ public final class InvalidateApiKeyRequest extends ActionRequest {
super.writeTo(out);
out.writeOptionalString(realmName);
out.writeOptionalString(userName);
out.writeOptionalString(id);
if (out.getVersion().onOrAfter(Version.V_7_10_0)) {
out.writeOptionalStringArray(ids);
} else {
if (ids != null) {
if (ids.length == 1) {
out.writeOptionalString(ids[0]);
} else {
throw new IllegalArgumentException("a request with multi-valued field [ids] cannot be sent to an older version");
}
} else {
out.writeOptionalString(null);
}
}
out.writeOptionalString(name);
if (out.getVersion().onOrAfter(Version.V_7_4_0)) {
out.writeOptionalBoolean(ownedByAuthenticatedUser);
@ -190,12 +235,12 @@ public final class InvalidateApiKeyRequest extends ActionRequest {
return ownedByAuthenticatedUser == that.ownedByAuthenticatedUser &&
Objects.equals(realmName, that.realmName) &&
Objects.equals(userName, that.userName) &&
Objects.equals(id, that.id) &&
Arrays.equals(ids, that.ids) &&
Objects.equals(name, that.name);
}
@Override
public int hashCode() {
return Objects.hash(realmName, userName, id, name, ownedByAuthenticatedUser);
return Objects.hash(realmName, userName, ids, name, ownedByAuthenticatedUser);
}
}

View File

@ -18,6 +18,8 @@ import org.elasticsearch.xpack.core.security.authc.Authentication.Authentication
import org.elasticsearch.xpack.core.security.authz.permission.ClusterPermission;
import org.elasticsearch.xpack.core.security.support.Automatons;
import java.util.Arrays;
/**
* Named cluster privilege for managing API keys owned by the current authenticated user.
*/
@ -56,9 +58,16 @@ public class ManageOwnApiKeyClusterPrivilege implements NamedClusterPrivilege {
getApiKeyRequest.getRealmName(), getApiKeyRequest.ownedByAuthenticatedUser());
} else if (request instanceof InvalidateApiKeyRequest) {
final InvalidateApiKeyRequest invalidateApiKeyRequest = (InvalidateApiKeyRequest) request;
return checkIfUserIsOwnerOfApiKeys(authentication, invalidateApiKeyRequest.getId(),
invalidateApiKeyRequest.getUserName(), invalidateApiKeyRequest.getRealmName(),
invalidateApiKeyRequest.ownedByAuthenticatedUser());
final String[] apiKeyIds = invalidateApiKeyRequest.getIds();
if (apiKeyIds == null) {
return checkIfUserIsOwnerOfApiKeys(authentication, null,
invalidateApiKeyRequest.getUserName(), invalidateApiKeyRequest.getRealmName(),
invalidateApiKeyRequest.ownedByAuthenticatedUser());
} else {
return Arrays.stream(apiKeyIds).allMatch(id -> checkIfUserIsOwnerOfApiKeys(authentication, id,
invalidateApiKeyRequest.getUserName(), invalidateApiKeyRequest.getRealmName(),
invalidateApiKeyRequest.ownedByAuthenticatedUser()));
}
}
throw new IllegalArgumentException(
"manage own api key privilege only supports API key requests (not " + request.getClass().getName() + ")");

View File

@ -9,6 +9,7 @@ package org.elasticsearch.xpack.core.security.action;
import org.elasticsearch.Version;
import org.elasticsearch.action.ActionRequest;
import org.elasticsearch.action.ActionRequestValidationException;
import org.elasticsearch.common.Strings;
import org.elasticsearch.common.io.stream.InputStreamStreamInput;
import org.elasticsearch.common.io.stream.OutputStreamStreamOutput;
import org.elasticsearch.common.io.stream.StreamOutput;
@ -18,13 +19,53 @@ import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import static org.elasticsearch.test.VersionUtils.getPreviousVersion;
import static org.elasticsearch.test.VersionUtils.randomVersionBetween;
import static org.hamcrest.Matchers.containsInAnyOrder;
import static org.hamcrest.Matchers.containsString;
import static org.hamcrest.Matchers.equalTo;
import static org.hamcrest.Matchers.is;
public class InvalidateApiKeyRequestTests extends ESTestCase {
public void testCannotSpecifyBothIdAndIds() {
final IllegalArgumentException e =
expectThrows(IllegalArgumentException.class, () -> new InvalidateApiKeyRequest(
randomFrom(randomNullOrEmptyString(), randomAlphaOfLength(8)),
randomFrom(randomNullOrEmptyString(), randomAlphaOfLength(8)),
randomAlphaOfLength(12),
randomFrom(randomNullOrEmptyString(), randomAlphaOfLength(8)),
false,
new String[] { randomAlphaOfLength(12) }));
assertThat(e.getMessage(), containsString("Must use either [id] or [ids], not both at the same time"));
}
public void testNonNullIdsCannotBeEmptyNorContainBlankId() {
InvalidateApiKeyRequest invalidateApiKeyRequest = new InvalidateApiKeyRequest(
randomFrom(randomNullOrEmptyString(), randomAlphaOfLength(8)),
randomFrom(randomNullOrEmptyString(), randomAlphaOfLength(8)),
null,
randomFrom(randomNullOrEmptyString(), randomAlphaOfLength(8)),
false,
new String[] {});
ActionRequestValidationException validationException = invalidateApiKeyRequest.validate();
assertNotNull(validationException);
assertThat(validationException.getMessage(), containsString("Field [ids] cannot be an empty array"));
invalidateApiKeyRequest = new InvalidateApiKeyRequest(
randomFrom(randomNullOrEmptyString(), randomAlphaOfLength(8)),
randomFrom(randomNullOrEmptyString(), randomAlphaOfLength(8)),
null,
randomFrom(randomNullOrEmptyString(), randomAlphaOfLength(8)),
false,
new String[] {randomAlphaOfLength(12), null});
validationException = invalidateApiKeyRequest.validate();
assertNotNull(validationException);
assertThat(validationException.getMessage(), containsString("Field [ids] must not contain blank id, "
+ "but got blank id at index position: [1]"));
}
public void testRequestValidation() {
InvalidateApiKeyRequest request = InvalidateApiKeyRequest.usingApiKeyId(randomAlphaOfLength(5), randomBoolean());
ActionRequestValidationException ve = request.validate();
@ -69,7 +110,15 @@ public class InvalidateApiKeyRequestTests extends ESTestCase {
super.writeTo(out);
out.writeOptionalString(realm);
out.writeOptionalString(user);
out.writeOptionalString(apiKeyId);
if (out.getVersion().onOrAfter(Version.V_7_10_0)) {
if (Strings.hasText(apiKeyId)) {
out.writeOptionalStringArray(new String[] { apiKeyId });
} else {
out.writeOptionalStringArray(null);
}
} else {
out.writeOptionalString(apiKeyId);
}
out.writeOptionalString(apiKeyName);
out.writeOptionalBoolean(ownedByAuthenticatedUser);
}
@ -86,13 +135,13 @@ public class InvalidateApiKeyRequestTests extends ESTestCase {
{randomNullOrEmptyString(), "user", randomNullOrEmptyString(), randomNullOrEmptyString(), "true"},
};
String[][] expectedErrorMessages = new String[][]{
{"One of [api key id, api key name, username, realm name] must be specified if [owner] flag is false"},
{"username or realm name must not be specified when the api key id or api key name is specified",
"only one of [api key id, api key name] can be specified"},
{"username or realm name must not be specified when the api key id or api key name is specified",
"only one of [api key id, api key name] can be specified"},
{"username or realm name must not be specified when the api key id or api key name is specified"},
{"only one of [api key id, api key name] can be specified"},
{"One of [api key id(s), api key name, username, realm name] must be specified if [owner] flag is false"},
{"username or realm name must not be specified when the api key id(s) or api key name are specified",
"only one of [api key id(s), api key name] can be specified"},
{"username or realm name must not be specified when the api key id(s) or api key name are specified",
"only one of [api key id(s), api key name] can be specified"},
{"username or realm name must not be specified when the api key id(s) or api key name are specified"},
{"only one of [api key id(s), api key name] can be specified"},
{"neither username nor realm-name may be specified when invalidating owned API keys"},
{"neither username nor realm-name may be specified when invalidating owned API keys"}
};
@ -100,15 +149,18 @@ public class InvalidateApiKeyRequestTests extends ESTestCase {
for (int caseNo = 0; caseNo < inputs.length; caseNo++) {
try (ByteArrayOutputStream bos = new ByteArrayOutputStream();
OutputStreamStreamOutput osso = new OutputStreamStreamOutput(bos)) {
final Version streamVersion = randomVersionBetween(random(), Version.V_7_4_0, getPreviousVersion(Version.V_7_10_0));
Dummy d = new Dummy(inputs[caseNo]);
osso.setVersion(streamVersion);
d.writeTo(osso);
ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray());
InputStreamStreamInput issi = new InputStreamStreamInput(bis);
issi.setVersion(streamVersion);
InvalidateApiKeyRequest request = new InvalidateApiKeyRequest(issi);
ActionRequestValidationException ve = request.validate();
assertNotNull(ve);
assertNotNull(ve.getMessage(), ve);
assertEquals(expectedErrorMessages[caseNo].length, ve.validationErrors().size());
assertThat(ve.validationErrors(), containsInAnyOrder(expectedErrorMessages[caseNo]));
}
@ -129,22 +181,49 @@ public class InvalidateApiKeyRequestTests extends ESTestCase {
inputStreamStreamInput.setVersion(randomVersionBetween(random(), Version.V_7_0_0, Version.V_7_3_0));
InvalidateApiKeyRequest requestFromInputStream = new InvalidateApiKeyRequest(inputStreamStreamInput);
assertThat(requestFromInputStream.getId(), equalTo(invalidateApiKeyRequest.getId()));
assertThat(requestFromInputStream.getIds(), equalTo(invalidateApiKeyRequest.getIds()));
// old version so the default for `ownedByAuthenticatedUser` is false
assertThat(requestFromInputStream.ownedByAuthenticatedUser(), is(false));
}
{
ByteArrayOutputStream outBuffer = new ByteArrayOutputStream();
OutputStreamStreamOutput out = new OutputStreamStreamOutput(outBuffer);
out.setVersion(randomVersionBetween(random(), Version.V_7_4_0, Version.CURRENT));
out.setVersion(randomVersionBetween(random(), Version.V_7_4_0, Version.V_7_9_0));
invalidateApiKeyRequest.writeTo(out);
InputStreamStreamInput inputStreamStreamInput = new InputStreamStreamInput(new ByteArrayInputStream(outBuffer.toByteArray()));
inputStreamStreamInput.setVersion(randomVersionBetween(random(), Version.V_7_4_0, Version.CURRENT));
inputStreamStreamInput.setVersion(randomVersionBetween(random(), Version.V_7_4_0, Version.V_7_9_0));
InvalidateApiKeyRequest requestFromInputStream = new InvalidateApiKeyRequest(inputStreamStreamInput);
assertThat(requestFromInputStream, equalTo(invalidateApiKeyRequest));
}
{
ByteArrayOutputStream outBuffer = new ByteArrayOutputStream();
OutputStreamStreamOutput out = new OutputStreamStreamOutput(outBuffer);
out.setVersion(randomVersionBetween(random(), Version.V_7_10_0, Version.CURRENT));
invalidateApiKeyRequest.writeTo(out);
InputStreamStreamInput inputStreamStreamInput = new InputStreamStreamInput(new ByteArrayInputStream(outBuffer.toByteArray()));
inputStreamStreamInput.setVersion(randomVersionBetween(random(), Version.V_7_10_0, Version.CURRENT));
InvalidateApiKeyRequest requestFromInputStream = new InvalidateApiKeyRequest(inputStreamStreamInput);
assertThat(requestFromInputStream, equalTo(invalidateApiKeyRequest));
}
}
public void testSerializationWillThrowWhenMultipleIdsAndOldVersionStream() {
final InvalidateApiKeyRequest invalidateApiKeyRequest = new InvalidateApiKeyRequest(
randomFrom(randomNullOrEmptyString(), randomAlphaOfLength(8)),
randomFrom(randomNullOrEmptyString(), randomAlphaOfLength(8)),
null,
randomFrom(randomNullOrEmptyString(), randomAlphaOfLength(8)),
false,
new String[] { randomAlphaOfLength(12), randomAlphaOfLength(12) });
ByteArrayOutputStream outBuffer = new ByteArrayOutputStream();
OutputStreamStreamOutput out = new OutputStreamStreamOutput(outBuffer);
out.setVersion(randomVersionBetween(random(), Version.V_7_4_0, getPreviousVersion(Version.V_7_10_0)));
final IllegalArgumentException e = expectThrows(IllegalArgumentException.class, () -> invalidateApiKeyRequest.writeTo(out));
assertThat(e.getMessage(), containsString("a request with multi-valued field [ids] cannot be sent to an older version"));
}
private static String randomNullOrEmptyString() {

View File

@ -36,7 +36,7 @@ public final class TransportInvalidateApiKeyAction extends HandledTransportActio
@Override
protected void doExecute(Task task, InvalidateApiKeyRequest request, ActionListener<InvalidateApiKeyResponse> listener) {
String apiKeyId = request.getId();
String[] apiKeyIds = request.getIds();
String apiKeyName = request.getName();
String username = request.getUserName();
String realm = request.getRealmName();
@ -53,7 +53,7 @@ public final class TransportInvalidateApiKeyAction extends HandledTransportActio
realm = ApiKeyService.getCreatorRealmName(authentication);
}
apiKeyService.invalidateApiKeys(realm, username, apiKeyName, apiKeyId, listener);
apiKeyService.invalidateApiKeys(realm, username, apiKeyName, apiKeyIds, listener);
}
}

View File

@ -808,24 +808,24 @@ public class ApiKeyService {
* @param realmName realm name
* @param username user name
* @param apiKeyName API key name
* @param apiKeyId API key id
* @param apiKeyIds API key id
* @param invalidateListener listener for {@link InvalidateApiKeyResponse}
*/
public void invalidateApiKeys(String realmName, String username, String apiKeyName, String apiKeyId,
public void invalidateApiKeys(String realmName, String username, String apiKeyName, String[] apiKeyIds,
ActionListener<InvalidateApiKeyResponse> invalidateListener) {
ensureEnabled();
if (Strings.hasText(realmName) == false && Strings.hasText(username) == false && Strings.hasText(apiKeyName) == false
&& Strings.hasText(apiKeyId) == false) {
&& (apiKeyIds == null || apiKeyIds.length == 0)) {
logger.trace("none of the parameters [api key id, api key name, username, realm name] were specified for invalidation");
invalidateListener
.onFailure(new IllegalArgumentException("One of [api key id, api key name, username, realm name] must be specified"));
} else {
findApiKeysForUserRealmApiKeyIdAndNameCombination(realmName, username, apiKeyName, apiKeyId, true, false,
findApiKeysForUserRealmApiKeyIdAndNameCombination(realmName, username, apiKeyName, apiKeyIds, true, false,
ActionListener.wrap(apiKeys -> {
if (apiKeys.isEmpty()) {
logger.debug(
"No active api keys to invalidate for realm [{}], username [{}], api key name [{}] and api key id [{}]",
realmName, username, apiKeyName, apiKeyId);
realmName, username, apiKeyName, Arrays.toString(apiKeyIds));
invalidateListener.onResponse(InvalidateApiKeyResponse.emptyResponse());
} else {
invalidateAllApiKeys(apiKeys.stream().map(apiKey -> apiKey.getId()).collect(Collectors.toSet()),
@ -876,7 +876,7 @@ public class ApiKeyService {
}
}
private void findApiKeysForUserRealmApiKeyIdAndNameCombination(String realmName, String userName, String apiKeyName, String apiKeyId,
private void findApiKeysForUserRealmApiKeyIdAndNameCombination(String realmName, String userName, String apiKeyName, String[] apiKeyIds,
boolean filterOutInvalidatedKeys, boolean filterOutExpiredKeys,
ActionListener<Collection<ApiKey>> listener) {
final SecurityIndexManager frozenSecurityIndex = securityIndex.freeze();
@ -899,8 +899,8 @@ public class ApiKeyService {
boolQuery.filter(QueryBuilders.termQuery("name", apiKeyName));
}
}
if (Strings.hasText(apiKeyId)) {
boolQuery.filter(QueryBuilders.termQuery("_id", apiKeyId));
if (apiKeyIds != null && apiKeyIds.length > 0) {
boolQuery.filter(QueryBuilders.idsQuery().addIds(apiKeyIds));
}
findApiKeys(boolQuery, filterOutInvalidatedKeys, filterOutExpiredKeys, listener);
@ -1059,7 +1059,8 @@ public class ApiKeyService {
public void getApiKeys(String realmName, String username, String apiKeyName, String apiKeyId,
ActionListener<GetApiKeyResponse> listener) {
ensureEnabled();
findApiKeysForUserRealmApiKeyIdAndNameCombination(realmName, username, apiKeyName, apiKeyId, false, false,
final String[] apiKeyIds = Strings.hasText(apiKeyId) == false ? null : new String[] { apiKeyId };
findApiKeysForUserRealmApiKeyIdAndNameCombination(realmName, username, apiKeyName, apiKeyIds, false, false,
ActionListener.wrap(apiKeyInfos -> {
if (apiKeyInfos.isEmpty()) {
logger.debug("No active api keys found for realm [{}], user [{}], api key name [{}] and api key id [{}]",

View File

@ -34,8 +34,9 @@ import static org.elasticsearch.rest.RestRequest.Method.DELETE;
public final class RestInvalidateApiKeyAction extends ApiKeyBaseRestHandler {
static final ConstructingObjectParser<InvalidateApiKeyRequest, Void> PARSER = new ConstructingObjectParser<>("invalidate_api_key",
a -> {
return new InvalidateApiKeyRequest((String) a[0], (String) a[1], (String) a[2], (String) a[3], (a[4] == null) ? false :
(Boolean) a[4]);
return new InvalidateApiKeyRequest((String) a[0], (String) a[1], (String) a[2], (String) a[3],
(a[4] == null) ? false : (Boolean) a[4],
(a[5] == null) ? null : ((List<String>) a[5]).toArray(new String[0]));
});
static {
@ -44,6 +45,7 @@ public final class RestInvalidateApiKeyAction extends ApiKeyBaseRestHandler {
PARSER.declareString(ConstructingObjectParser.optionalConstructorArg(), new ParseField("id"));
PARSER.declareString(ConstructingObjectParser.optionalConstructorArg(), new ParseField("name"));
PARSER.declareBoolean(ConstructingObjectParser.optionalConstructorArg(), new ParseField("owner"));
PARSER.declareStringArray(ConstructingObjectParser.optionalConstructorArg(), new ParseField("ids"));
}
public RestInvalidateApiKeyAction(Settings settings, XPackLicenseState licenseState) {

View File

@ -97,7 +97,8 @@ public class RestInvalidateApiKeyActionTests extends ESTestCase {
return;
}
if (invalidateApiKeyRequest.getName() != null && invalidateApiKeyRequest.getName().equals("api-key-name-1")
|| invalidateApiKeyRequest.getId() != null && invalidateApiKeyRequest.getId().equals("api-key-id-1")
|| invalidateApiKeyRequest.getIds() != null && Arrays.equals(
invalidateApiKeyRequest.getIds(), new String[] {"api-key-id-1"})
|| invalidateApiKeyRequest.getRealmName() != null && invalidateApiKeyRequest.getRealmName().equals("realm-1")
|| invalidateApiKeyRequest.getUserName() != null && invalidateApiKeyRequest.getUserName().equals("user-x")) {
listener.onResponse((Response) invalidateApiKeyResponseExpected);

View File

@ -201,7 +201,7 @@ teardown:
---
"Test invalidate api key":
"Test invalidate api keys":
- skip:
features: transform_and_set
@ -220,7 +220,7 @@ teardown:
- is_true: id
- is_true: api_key
- is_true: expiration
- set: { id: api_key_id }
- set: { id: api_key_id_1 }
- transform_and_set: { login_creds: "#base64EncodeCredentials(id,api_key)" }
- do:
@ -229,10 +229,58 @@ teardown:
security.invalidate_api_key:
body: >
{
"id": "${api_key_id}"
"id": "${api_key_id_1}"
}
- length: { "invalidated_api_keys" : 1 }
- match: { "invalidated_api_keys.0" : "${api_key_id}" }
- match: { "invalidated_api_keys.0" : "${api_key_id_1}" }
- length: { "previously_invalidated_api_keys" : 0 }
- match: { "error_count" : 0 }
- do:
headers:
Authorization: "Basic YXBpX2tleV91c2VyOngtcGFjay10ZXN0LXBhc3N3b3Jk" # api_key_user
security.create_api_key:
body: >
{
"name": "my-api-key-2",
"expiration": "1d",
"role_descriptors": {
}
}
- match: { name: "my-api-key-2" }
- is_true: id
- is_true: api_key
- is_true: expiration
- set: { id: api_key_id_2 }
- do:
headers:
Authorization: "Basic YXBpX2tleV91c2VyOngtcGFjay10ZXN0LXBhc3N3b3Jk" # api_key_user
security.create_api_key:
body: >
{
"name": "my-api-key-3",
"expiration": "1d",
"role_descriptors": {
}
}
- match: { name: "my-api-key-3" }
- is_true: id
- is_true: api_key
- is_true: expiration
- set: { id: api_key_id_3 }
- do:
headers:
Authorization: "Basic YXBpX2tleV91c2VyOngtcGFjay10ZXN0LXBhc3N3b3Jk" # api_key_user
security.invalidate_api_key:
body: >
{
"ids": [ "${api_key_id_1}", "${api_key_id_2}", "${api_key_id_3}" ]
}
- length: { "invalidated_api_keys" : 2 }
- match: { "invalidated_api_keys.0" : "/^(${api_key_id_2}|${api_key_id_3})$/" }
- match: { "invalidated_api_keys.1" : "/^(${api_key_id_2}|${api_key_id_3})$/" }
- length: { "previously_invalidated_api_keys" : 0 }
- match: { "error_count" : 0 }