mirror of
https://github.com/honeymoose/OpenSearch.git
synced 2025-02-17 02:14:54 +00:00
Invalidate Token API enhancements - HLRC (#36362)
* Adds Invalidate Token API enhancements to HLRC Relates: #35388
This commit is contained in:
parent
f884b2b1cd
commit
78f9af19c6
@ -35,17 +35,36 @@ public final class InvalidateTokenRequest implements Validatable, ToXContentObje
|
||||
|
||||
private final String accessToken;
|
||||
private final String refreshToken;
|
||||
private final String realmName;
|
||||
private final String username;
|
||||
|
||||
InvalidateTokenRequest(@Nullable String accessToken, @Nullable String refreshToken) {
|
||||
if (Strings.isNullOrEmpty(accessToken)) {
|
||||
if (Strings.isNullOrEmpty(refreshToken)) {
|
||||
throw new IllegalArgumentException("Either access-token or refresh-token is required");
|
||||
this(accessToken, refreshToken, null, null);
|
||||
}
|
||||
|
||||
public InvalidateTokenRequest(@Nullable String accessToken, @Nullable String refreshToken,
|
||||
@Nullable String realmName, @Nullable String username) {
|
||||
if (Strings.hasText(realmName) || Strings.hasText(username)) {
|
||||
if (Strings.hasText(accessToken)) {
|
||||
throw new IllegalArgumentException("access token is not allowed when realm name or username are specified");
|
||||
}
|
||||
if (refreshToken != null) {
|
||||
throw new IllegalArgumentException("refresh token is not allowed when realm name or username are specified");
|
||||
}
|
||||
} else {
|
||||
if (Strings.isNullOrEmpty(accessToken)) {
|
||||
if (Strings.isNullOrEmpty(refreshToken)) {
|
||||
throw new IllegalArgumentException("Either access token or refresh token is required when neither realm name or " +
|
||||
"username are specified");
|
||||
}
|
||||
} else if (Strings.isNullOrEmpty(refreshToken) == false) {
|
||||
throw new IllegalArgumentException("Cannot supply both access token and refresh token");
|
||||
}
|
||||
} else if (Strings.isNullOrEmpty(refreshToken) == false) {
|
||||
throw new IllegalArgumentException("Cannot supply both access-token and refresh-token");
|
||||
}
|
||||
this.accessToken = accessToken;
|
||||
this.refreshToken = refreshToken;
|
||||
this.realmName = realmName;
|
||||
this.username = username;
|
||||
}
|
||||
|
||||
public static InvalidateTokenRequest accessToken(String accessToken) {
|
||||
@ -62,6 +81,20 @@ public final class InvalidateTokenRequest implements Validatable, ToXContentObje
|
||||
return new InvalidateTokenRequest(null, refreshToken);
|
||||
}
|
||||
|
||||
public static InvalidateTokenRequest realmTokens(String realmName) {
|
||||
if (Strings.isNullOrEmpty(realmName)) {
|
||||
throw new IllegalArgumentException("realm name is required");
|
||||
}
|
||||
return new InvalidateTokenRequest(null, null, realmName, null);
|
||||
}
|
||||
|
||||
public static InvalidateTokenRequest userTokens(String username) {
|
||||
if (Strings.isNullOrEmpty(username)) {
|
||||
throw new IllegalArgumentException("username is required");
|
||||
}
|
||||
return new InvalidateTokenRequest(null, null, null, username);
|
||||
}
|
||||
|
||||
public String getAccessToken() {
|
||||
return accessToken;
|
||||
}
|
||||
@ -70,6 +103,14 @@ public final class InvalidateTokenRequest implements Validatable, ToXContentObje
|
||||
return refreshToken;
|
||||
}
|
||||
|
||||
public String getRealmName() {
|
||||
return realmName;
|
||||
}
|
||||
|
||||
public String getUsername() {
|
||||
return username;
|
||||
}
|
||||
|
||||
@Override
|
||||
public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException {
|
||||
builder.startObject();
|
||||
@ -79,24 +120,28 @@ public final class InvalidateTokenRequest implements Validatable, ToXContentObje
|
||||
if (refreshToken != null) {
|
||||
builder.field("refresh_token", refreshToken);
|
||||
}
|
||||
if (realmName != null) {
|
||||
builder.field("realm_name", realmName);
|
||||
}
|
||||
if (username != null) {
|
||||
builder.field("username", username);
|
||||
}
|
||||
return builder.endObject();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) {
|
||||
return true;
|
||||
}
|
||||
if (o == null || getClass() != o.getClass()) {
|
||||
return false;
|
||||
}
|
||||
final InvalidateTokenRequest that = (InvalidateTokenRequest) o;
|
||||
return Objects.equals(this.accessToken, that.accessToken) &&
|
||||
Objects.equals(this.refreshToken, that.refreshToken);
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
InvalidateTokenRequest that = (InvalidateTokenRequest) o;
|
||||
return Objects.equals(accessToken, that.accessToken) &&
|
||||
Objects.equals(refreshToken, that.refreshToken) &&
|
||||
Objects.equals(realmName, that.realmName) &&
|
||||
Objects.equals(username, that.username);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(accessToken, refreshToken);
|
||||
return Objects.hash(accessToken, refreshToken, realmName, username);
|
||||
}
|
||||
}
|
||||
|
@ -19,56 +19,107 @@
|
||||
|
||||
package org.elasticsearch.client.security;
|
||||
|
||||
import org.elasticsearch.ElasticsearchException;
|
||||
import org.elasticsearch.common.Nullable;
|
||||
import org.elasticsearch.common.ParseField;
|
||||
import org.elasticsearch.common.xcontent.ConstructingObjectParser;
|
||||
import org.elasticsearch.common.xcontent.XContentParser;
|
||||
import org.elasticsearch.common.xcontent.XContentParserUtils;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
|
||||
import static org.elasticsearch.common.xcontent.ConstructingObjectParser.constructorArg;
|
||||
import static org.elasticsearch.common.xcontent.ConstructingObjectParser.optionalConstructorArg;
|
||||
|
||||
/**
|
||||
* Response when invalidating an OAuth2 token. Returns a
|
||||
* single boolean field for whether the invalidation record was created or updated.
|
||||
* Response when invalidating one or multiple OAuth2 access tokens and refresh tokens. Returns
|
||||
* information concerning how many tokens were invalidated, how many of the tokens that
|
||||
* were attempted to be invalidated were already invalid, and if there were any errors
|
||||
* encountered.
|
||||
*/
|
||||
public final class InvalidateTokenResponse {
|
||||
|
||||
private final boolean created;
|
||||
public static final ParseField CREATED = new ParseField("created");
|
||||
public static final ParseField INVALIDATED_TOKENS = new ParseField("invalidated_tokens");
|
||||
public static final ParseField PREVIOUSLY_INVALIDATED_TOKENS = new ParseField("previously_invalidated_tokens");
|
||||
public static final ParseField ERROR_COUNT = new ParseField("error_count");
|
||||
public static final ParseField ERRORS = new ParseField("error_details");
|
||||
|
||||
public InvalidateTokenResponse(boolean created) {
|
||||
private final boolean created;
|
||||
private final int invalidatedTokens;
|
||||
private final int previouslyInvalidatedTokens;
|
||||
private List<ElasticsearchException> errors;
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private static final ConstructingObjectParser<InvalidateTokenResponse, Void> PARSER = new ConstructingObjectParser<>(
|
||||
"tokens_invalidation_result", true,
|
||||
// we parse but do not use the count of errors as we implicitly have this in the size of the Exceptions list
|
||||
args -> new InvalidateTokenResponse((boolean) args[0], (int) args[1], (int) args[2], (List<ElasticsearchException>) args[4]));
|
||||
|
||||
static {
|
||||
PARSER.declareBoolean(constructorArg(), CREATED);
|
||||
PARSER.declareInt(constructorArg(), INVALIDATED_TOKENS);
|
||||
PARSER.declareInt(constructorArg(), PREVIOUSLY_INVALIDATED_TOKENS);
|
||||
PARSER.declareInt(constructorArg(), ERROR_COUNT);
|
||||
PARSER.declareObjectArray(optionalConstructorArg(), (p, c) -> ElasticsearchException.fromXContent(p), ERRORS);
|
||||
}
|
||||
|
||||
public InvalidateTokenResponse(boolean created, int invalidatedTokens, int previouslyInvalidatedTokens,
|
||||
@Nullable List<ElasticsearchException> errors) {
|
||||
this.created = created;
|
||||
this.invalidatedTokens = invalidatedTokens;
|
||||
this.previouslyInvalidatedTokens = previouslyInvalidatedTokens;
|
||||
if (null == errors) {
|
||||
this.errors = Collections.emptyList();
|
||||
} else {
|
||||
this.errors = Collections.unmodifiableList(errors);
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isCreated() {
|
||||
return created;
|
||||
}
|
||||
|
||||
public int getInvalidatedTokens() {
|
||||
return invalidatedTokens;
|
||||
}
|
||||
|
||||
public int getPreviouslyInvalidatedTokens() {
|
||||
return previouslyInvalidatedTokens;
|
||||
}
|
||||
|
||||
public List<ElasticsearchException> getErrors() {
|
||||
return errors;
|
||||
}
|
||||
|
||||
public int getErrorsCount() {
|
||||
return errors == null ? 0 : errors.size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) {
|
||||
return true;
|
||||
}
|
||||
if (o == null || getClass() != o.getClass()) {
|
||||
return false;
|
||||
}
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
InvalidateTokenResponse that = (InvalidateTokenResponse) o;
|
||||
return created == that.created;
|
||||
return created == that.created &&
|
||||
invalidatedTokens == that.invalidatedTokens &&
|
||||
previouslyInvalidatedTokens == that.previouslyInvalidatedTokens &&
|
||||
Objects.equals(errors, that.errors);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(created);
|
||||
}
|
||||
|
||||
private static final ConstructingObjectParser<InvalidateTokenResponse, Void> PARSER = new ConstructingObjectParser<>(
|
||||
"invalidate_token_response", true, args -> new InvalidateTokenResponse((boolean) args[0]));
|
||||
|
||||
static {
|
||||
PARSER.declareBoolean(constructorArg(), new ParseField("created"));
|
||||
return Objects.hash(created, invalidatedTokens, previouslyInvalidatedTokens, errors);
|
||||
}
|
||||
|
||||
public static InvalidateTokenResponse fromXContent(XContentParser parser) throws IOException {
|
||||
if (parser.currentToken() == null) {
|
||||
parser.nextToken();
|
||||
}
|
||||
XContentParserUtils.ensureExpectedToken(XContentParser.Token.START_OBJECT, parser.currentToken(), parser::getTokenLocation);
|
||||
return PARSER.parse(parser, null);
|
||||
}
|
||||
}
|
||||
|
@ -19,6 +19,7 @@
|
||||
|
||||
package org.elasticsearch.client.documentation;
|
||||
|
||||
import org.elasticsearch.ElasticsearchException;
|
||||
import org.elasticsearch.ElasticsearchStatusException;
|
||||
import org.elasticsearch.action.ActionListener;
|
||||
import org.elasticsearch.action.LatchedActionListener;
|
||||
@ -1324,19 +1325,52 @@ public class SecurityDocumentationIT extends ESRestHighLevelClientTestCase {
|
||||
String accessToken;
|
||||
String refreshToken;
|
||||
{
|
||||
// Setup user
|
||||
// Setup users
|
||||
final char[] password = "password".toCharArray();
|
||||
User invalidate_token_user = new User("invalidate_token", Collections.singletonList("kibana_user"));
|
||||
PutUserRequest putUserRequest = new PutUserRequest(invalidate_token_user, password, true, RefreshPolicy.IMMEDIATE);
|
||||
User user = new User("user", Collections.singletonList("kibana_user"));
|
||||
PutUserRequest putUserRequest = new PutUserRequest(user, password, true, RefreshPolicy.IMMEDIATE);
|
||||
PutUserResponse putUserResponse = client.security().putUser(putUserRequest, RequestOptions.DEFAULT);
|
||||
assertTrue(putUserResponse.isCreated());
|
||||
|
||||
User this_user = new User("this_user", Collections.singletonList("kibana_user"));
|
||||
PutUserRequest putThisUserRequest = new PutUserRequest(this_user, password, true, RefreshPolicy.IMMEDIATE);
|
||||
PutUserResponse putThisUserResponse = client.security().putUser(putThisUserRequest, RequestOptions.DEFAULT);
|
||||
assertTrue(putThisUserResponse.isCreated());
|
||||
|
||||
User that_user = new User("that_user", Collections.singletonList("kibana_user"));
|
||||
PutUserRequest putThatUserRequest = new PutUserRequest(that_user, password, true, RefreshPolicy.IMMEDIATE);
|
||||
PutUserResponse putThatUserResponse = client.security().putUser(putThatUserRequest, RequestOptions.DEFAULT);
|
||||
assertTrue(putThatUserResponse.isCreated());
|
||||
|
||||
User other_user = new User("other_user", Collections.singletonList("kibana_user"));
|
||||
PutUserRequest putOtherUserRequest = new PutUserRequest(other_user, password, true, RefreshPolicy.IMMEDIATE);
|
||||
PutUserResponse putOtherUserResponse = client.security().putUser(putOtherUserRequest, RequestOptions.DEFAULT);
|
||||
assertTrue(putOtherUserResponse.isCreated());
|
||||
|
||||
User extra_user = new User("extra_user", Collections.singletonList("kibana_user"));
|
||||
PutUserRequest putExtraUserRequest = new PutUserRequest(extra_user, password, true, RefreshPolicy.IMMEDIATE);
|
||||
PutUserResponse putExtraUserResponse = client.security().putUser(putExtraUserRequest, RequestOptions.DEFAULT);
|
||||
assertTrue(putExtraUserResponse.isCreated());
|
||||
|
||||
// Create tokens
|
||||
final CreateTokenRequest createTokenRequest = CreateTokenRequest.passwordGrant("invalidate_token", password);
|
||||
final CreateTokenRequest createTokenRequest = CreateTokenRequest.passwordGrant("user", password);
|
||||
final CreateTokenResponse tokenResponse = client.security().createToken(createTokenRequest, RequestOptions.DEFAULT);
|
||||
accessToken = tokenResponse.getAccessToken();
|
||||
refreshToken = tokenResponse.getRefreshToken();
|
||||
final CreateTokenRequest createThisTokenRequest = CreateTokenRequest.passwordGrant("this_user", password);
|
||||
final CreateTokenResponse thisTokenResponse = client.security().createToken(createThisTokenRequest, RequestOptions.DEFAULT);
|
||||
assertNotNull(thisTokenResponse);
|
||||
final CreateTokenRequest createThatTokenRequest = CreateTokenRequest.passwordGrant("that_user", password);
|
||||
final CreateTokenResponse thatTokenResponse = client.security().createToken(createThatTokenRequest, RequestOptions.DEFAULT);
|
||||
assertNotNull(thatTokenResponse);
|
||||
final CreateTokenRequest createOtherTokenRequest = CreateTokenRequest.passwordGrant("other_user", password);
|
||||
final CreateTokenResponse otherTokenResponse = client.security().createToken(createOtherTokenRequest, RequestOptions.DEFAULT);
|
||||
assertNotNull(otherTokenResponse);
|
||||
final CreateTokenRequest createExtraTokenRequest = CreateTokenRequest.passwordGrant("extra_user", password);
|
||||
final CreateTokenResponse extraTokenResponse = client.security().createToken(createExtraTokenRequest, RequestOptions.DEFAULT);
|
||||
assertNotNull(extraTokenResponse);
|
||||
}
|
||||
|
||||
{
|
||||
// tag::invalidate-access-token-request
|
||||
InvalidateTokenRequest invalidateTokenRequest = InvalidateTokenRequest.accessToken(accessToken);
|
||||
@ -1348,15 +1382,54 @@ public class SecurityDocumentationIT extends ESRestHighLevelClientTestCase {
|
||||
// end::invalidate-token-execute
|
||||
|
||||
// tag::invalidate-token-response
|
||||
boolean isCreated = invalidateTokenResponse.isCreated();
|
||||
final List<ElasticsearchException> errors = invalidateTokenResponse.getErrors();
|
||||
final int invalidatedTokens = invalidateTokenResponse.getInvalidatedTokens();
|
||||
final int previouslyInvalidatedTokens = invalidateTokenResponse.getPreviouslyInvalidatedTokens();
|
||||
// end::invalidate-token-response
|
||||
assertTrue(isCreated);
|
||||
assertTrue(errors.isEmpty());
|
||||
assertThat(invalidatedTokens, equalTo(1));
|
||||
assertThat(previouslyInvalidatedTokens, equalTo(0));
|
||||
}
|
||||
|
||||
{
|
||||
// tag::invalidate-refresh-token-request
|
||||
InvalidateTokenRequest invalidateTokenRequest = InvalidateTokenRequest.refreshToken(refreshToken);
|
||||
// end::invalidate-refresh-token-request
|
||||
InvalidateTokenResponse invalidateTokenResponse =
|
||||
client.security().invalidateToken(invalidateTokenRequest, RequestOptions.DEFAULT);
|
||||
assertTrue(invalidateTokenResponse.getErrors().isEmpty());
|
||||
assertThat(invalidateTokenResponse.getInvalidatedTokens(), equalTo(1));
|
||||
assertThat(invalidateTokenResponse.getPreviouslyInvalidatedTokens(), equalTo(0));
|
||||
}
|
||||
|
||||
{
|
||||
// tag::invalidate-user-tokens-request
|
||||
InvalidateTokenRequest invalidateTokenRequest = InvalidateTokenRequest.userTokens("other_user");
|
||||
// end::invalidate-user-tokens-request
|
||||
InvalidateTokenResponse invalidateTokenResponse =
|
||||
client.security().invalidateToken(invalidateTokenRequest, RequestOptions.DEFAULT);
|
||||
assertTrue(invalidateTokenResponse.getErrors().isEmpty());
|
||||
// We have one refresh and one access token for that user
|
||||
assertThat(invalidateTokenResponse.getInvalidatedTokens(), equalTo(2));
|
||||
assertThat(invalidateTokenResponse.getPreviouslyInvalidatedTokens(), equalTo(0));
|
||||
}
|
||||
|
||||
{
|
||||
// tag::invalidate-user-realm-tokens-request
|
||||
InvalidateTokenRequest invalidateTokenRequest = new InvalidateTokenRequest(null, null, "default_native", "extra_user");
|
||||
// end::invalidate-user-realm-tokens-request
|
||||
InvalidateTokenResponse invalidateTokenResponse =
|
||||
client.security().invalidateToken(invalidateTokenRequest, RequestOptions.DEFAULT);
|
||||
assertTrue(invalidateTokenResponse.getErrors().isEmpty());
|
||||
// We have one refresh and one access token for that user in this realm
|
||||
assertThat(invalidateTokenResponse.getInvalidatedTokens(), equalTo(2));
|
||||
assertThat(invalidateTokenResponse.getPreviouslyInvalidatedTokens(), equalTo(0));
|
||||
}
|
||||
|
||||
{
|
||||
// tag::invalidate-realm-tokens-request
|
||||
InvalidateTokenRequest invalidateTokenRequest = InvalidateTokenRequest.realmTokens("default_native");
|
||||
// end::invalidate-realm-tokens-request
|
||||
|
||||
ActionListener<InvalidateTokenResponse> listener;
|
||||
//tag::invalidate-token-execute-listener
|
||||
@ -1386,8 +1459,10 @@ public class SecurityDocumentationIT extends ESRestHighLevelClientTestCase {
|
||||
|
||||
final InvalidateTokenResponse response = future.get(30, TimeUnit.SECONDS);
|
||||
assertNotNull(response);
|
||||
assertTrue(response.isCreated());// technically, this should be false, but the API is broken
|
||||
// See https://github.com/elastic/elasticsearch/issues/35115
|
||||
assertTrue(response.getErrors().isEmpty());
|
||||
//We still have 4 tokens ( 2 access_tokens and 2 refresh_tokens ) for the default_native realm
|
||||
assertThat(response.getInvalidatedTokens(), equalTo(4));
|
||||
assertThat(response.getPreviouslyInvalidatedTokens(), equalTo(0));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -49,17 +49,66 @@ public class InvalidateTokenRequestTests extends ESTestCase {
|
||||
));
|
||||
}
|
||||
|
||||
public void testInvalidateRealmTokens() {
|
||||
String realmName = "native";
|
||||
final InvalidateTokenRequest request = InvalidateTokenRequest.realmTokens(realmName);
|
||||
assertThat(request.getAccessToken(), nullValue());
|
||||
assertThat(request.getRefreshToken(), nullValue());
|
||||
assertThat(request.getRealmName(), equalTo(realmName));
|
||||
assertThat(request.getUsername(), nullValue());
|
||||
assertThat(Strings.toString(request), equalTo("{" +
|
||||
"\"realm_name\":\"native\"" +
|
||||
"}"
|
||||
));
|
||||
}
|
||||
|
||||
public void testInvalidateUserTokens() {
|
||||
String username = "user";
|
||||
final InvalidateTokenRequest request = InvalidateTokenRequest.userTokens(username);
|
||||
assertThat(request.getAccessToken(), nullValue());
|
||||
assertThat(request.getRefreshToken(), nullValue());
|
||||
assertThat(request.getRealmName(), nullValue());
|
||||
assertThat(request.getUsername(), equalTo(username));
|
||||
assertThat(Strings.toString(request), equalTo("{" +
|
||||
"\"username\":\"user\"" +
|
||||
"}"
|
||||
));
|
||||
}
|
||||
|
||||
public void testInvalidateUserTokensInRealm() {
|
||||
String username = "user";
|
||||
String realmName = "native";
|
||||
final InvalidateTokenRequest request = new InvalidateTokenRequest(null, null, realmName, username);
|
||||
assertThat(request.getAccessToken(), nullValue());
|
||||
assertThat(request.getRefreshToken(), nullValue());
|
||||
assertThat(request.getRealmName(), equalTo(realmName));
|
||||
assertThat(request.getUsername(), equalTo(username));
|
||||
assertThat(Strings.toString(request), equalTo("{" +
|
||||
"\"realm_name\":\"native\"," +
|
||||
"\"username\":\"user\"" +
|
||||
|
||||
"}"
|
||||
));
|
||||
}
|
||||
|
||||
public void testEqualsAndHashCode() {
|
||||
final String token = randomAlphaOfLength(8);
|
||||
final boolean accessToken = randomBoolean();
|
||||
final InvalidateTokenRequest request = accessToken ? InvalidateTokenRequest.accessToken(token)
|
||||
: InvalidateTokenRequest.refreshToken(token);
|
||||
final EqualsHashCodeTestUtils.MutateFunction<InvalidateTokenRequest> mutate = r -> {
|
||||
if (randomBoolean()) {
|
||||
return accessToken ? InvalidateTokenRequest.refreshToken(token) : InvalidateTokenRequest.accessToken(token);
|
||||
} else {
|
||||
return accessToken ? InvalidateTokenRequest.accessToken(randomAlphaOfLength(10))
|
||||
: InvalidateTokenRequest.refreshToken(randomAlphaOfLength(10));
|
||||
int randomCase = randomIntBetween(1, 4);
|
||||
switch (randomCase) {
|
||||
case 1:
|
||||
return InvalidateTokenRequest.refreshToken(randomAlphaOfLength(5));
|
||||
case 2:
|
||||
return InvalidateTokenRequest.accessToken(randomAlphaOfLength(5));
|
||||
case 3:
|
||||
return InvalidateTokenRequest.realmTokens(randomAlphaOfLength(5));
|
||||
case 4:
|
||||
return InvalidateTokenRequest.userTokens(randomAlphaOfLength(5));
|
||||
default:
|
||||
return new InvalidateTokenRequest(null, null, randomAlphaOfLength(5), randomAlphaOfLength(5));
|
||||
}
|
||||
};
|
||||
EqualsHashCodeTestUtils.checkEqualsAndHashCode(request,
|
||||
|
@ -18,7 +18,9 @@
|
||||
*/
|
||||
package org.elasticsearch.client.security;
|
||||
|
||||
import org.elasticsearch.ElasticsearchException;
|
||||
import org.elasticsearch.common.bytes.BytesReference;
|
||||
import org.elasticsearch.common.xcontent.ToXContent;
|
||||
import org.elasticsearch.common.xcontent.XContentBuilder;
|
||||
import org.elasticsearch.common.xcontent.XContentFactory;
|
||||
import org.elasticsearch.common.xcontent.XContentParser;
|
||||
@ -28,23 +30,66 @@ import org.hamcrest.Matchers;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import static org.hamcrest.Matchers.containsString;
|
||||
|
||||
public class InvalidateTokenResponseTests extends ESTestCase {
|
||||
|
||||
public void testFromXContent() throws IOException {
|
||||
final boolean created = randomBoolean();
|
||||
|
||||
final XContentType xContentType = randomFrom(XContentType.values());
|
||||
final XContentBuilder builder = XContentFactory.contentBuilder(xContentType);
|
||||
final int invalidatedTokens = randomInt(32);
|
||||
final int previouslyInvalidatedTokens = randomInt(32);
|
||||
builder.startObject()
|
||||
.field("created", created)
|
||||
.field("created", false)
|
||||
.field("invalidated_tokens", invalidatedTokens)
|
||||
.field("previously_invalidated_tokens", previouslyInvalidatedTokens)
|
||||
.field("error_count", 0)
|
||||
.endObject();
|
||||
BytesReference xContent = BytesReference.bytes(builder);
|
||||
|
||||
try (XContentParser parser = createParser(xContentType.xContent(), xContent)) {
|
||||
final InvalidateTokenResponse response = InvalidateTokenResponse.fromXContent(parser);
|
||||
assertThat(response.isCreated(), Matchers.equalTo(created));
|
||||
assertThat(response.isCreated(), Matchers.equalTo(false));
|
||||
assertThat(response.getInvalidatedTokens(), Matchers.equalTo(invalidatedTokens));
|
||||
assertThat(response.getPreviouslyInvalidatedTokens(), Matchers.equalTo(previouslyInvalidatedTokens));
|
||||
assertThat(response.getErrorsCount(), Matchers.equalTo(0));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public void testFromXContentWithErrors() throws IOException {
|
||||
|
||||
final XContentType xContentType = randomFrom(XContentType.values());
|
||||
final XContentBuilder builder = XContentFactory.contentBuilder(xContentType);
|
||||
final int invalidatedTokens = randomInt(32);
|
||||
final int previouslyInvalidatedTokens = randomInt(32);
|
||||
builder.startObject()
|
||||
.field("created", false)
|
||||
.field("invalidated_tokens", invalidatedTokens)
|
||||
.field("previously_invalidated_tokens", previouslyInvalidatedTokens)
|
||||
.field("error_count", 0)
|
||||
.startArray("error_details")
|
||||
.startObject();
|
||||
ElasticsearchException.generateThrowableXContent(builder, ToXContent.EMPTY_PARAMS, new ElasticsearchException("foo",
|
||||
new IllegalArgumentException("bar")));
|
||||
builder.endObject().startObject();
|
||||
ElasticsearchException.generateThrowableXContent(builder, ToXContent.EMPTY_PARAMS, new ElasticsearchException("boo",
|
||||
new IllegalArgumentException("far")));
|
||||
builder.endObject()
|
||||
.endArray()
|
||||
.endObject();
|
||||
BytesReference xContent = BytesReference.bytes(builder);
|
||||
|
||||
try (XContentParser parser = createParser(xContentType.xContent(), xContent)) {
|
||||
final InvalidateTokenResponse response = InvalidateTokenResponse.fromXContent(parser);
|
||||
assertThat(response.isCreated(), Matchers.equalTo(false));
|
||||
assertThat(response.getInvalidatedTokens(), Matchers.equalTo(invalidatedTokens));
|
||||
assertThat(response.getPreviouslyInvalidatedTokens(), Matchers.equalTo(previouslyInvalidatedTokens));
|
||||
assertThat(response.getErrorsCount(), Matchers.equalTo(2));
|
||||
assertThat(response.getErrors().get(0).toString(), containsString("type=exception, reason=foo"));
|
||||
assertThat(response.getErrors().get(0).toString(), containsString("type=illegal_argument_exception, reason=bar"));
|
||||
assertThat(response.getErrors().get(1).toString(), containsString("type=exception, reason=boo"));
|
||||
assertThat(response.getErrors().get(1).toString(), containsString("type=illegal_argument_exception, reason=far"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -9,29 +9,63 @@
|
||||
|
||||
[id="{upid}-{api}-request"]
|
||||
==== Invalidate Token Request
|
||||
The +{request}+ supports invalidating either an _access token_ or a _refresh token_
|
||||
The +{request}+ supports invalidating
|
||||
|
||||
===== Access Token
|
||||
. A specific token, that can be either an _access token_ or a _refresh token_
|
||||
|
||||
. All tokens (both _access tokens_ and _refresh tokens_) for a specific realm
|
||||
|
||||
. All tokens (both _access tokens_ and _refresh tokens_) for a specific user
|
||||
|
||||
. All tokens (both _access tokens_ and _refresh tokens_) for a specific user in a specific realm
|
||||
|
||||
===== Specific access token
|
||||
["source","java",subs="attributes,callouts,macros"]
|
||||
--------------------------------------------------
|
||||
include-tagged::{doc-tests-file}[invalidate-access-token-request]
|
||||
--------------------------------------------------
|
||||
|
||||
===== Refresh Token
|
||||
===== Specific refresh token
|
||||
["source","java",subs="attributes,callouts,macros"]
|
||||
--------------------------------------------------
|
||||
include-tagged::{doc-tests-file}[invalidate-refresh-token-request]
|
||||
--------------------------------------------------
|
||||
|
||||
===== All tokens for realm
|
||||
["source","java",subs="attributes,callouts,macros"]
|
||||
--------------------------------------------------
|
||||
include-tagged::{doc-tests-file}[invalidate-realm-tokens-request]
|
||||
--------------------------------------------------
|
||||
|
||||
===== All tokens for user
|
||||
["source","java",subs="attributes,callouts,macros"]
|
||||
--------------------------------------------------
|
||||
include-tagged::{doc-tests-file}[invalidate-user-tokens-request]
|
||||
--------------------------------------------------
|
||||
|
||||
===== All tokens for user in realm
|
||||
["source","java",subs="attributes,callouts,macros"]
|
||||
--------------------------------------------------
|
||||
include-tagged::{doc-tests-file}[invalidate-user-realm-tokens-request]
|
||||
--------------------------------------------------
|
||||
|
||||
include::../execution.asciidoc[]
|
||||
|
||||
[id="{upid}-{api}-response"]
|
||||
==== Invalidate Token Response
|
||||
|
||||
The returned +{response}+ contains a single property:
|
||||
The returned +{response}+ contains the information regarding the tokens that the request
|
||||
invalidated.
|
||||
|
||||
`created`:: Whether the invalidation record was newly created (`true`),
|
||||
or if the token had already been invalidated (`false`).
|
||||
`invalidatedTokens`:: Available using `getInvalidatedTokens` denotes the number of tokens
|
||||
that this request invalidated.
|
||||
|
||||
`previouslyInvalidatedTokens`:: Available using `getPreviouslyInvalidatedTokens` denotes
|
||||
the number of tokens that this request attempted to invalidate
|
||||
but were already invalid.
|
||||
|
||||
`errors`:: Available using `getErrors` contains possible errors that were encountered while
|
||||
attempting to invalidate specific tokens.
|
||||
|
||||
["source","java",subs="attributes,callouts,macros"]
|
||||
--------------------------------------------------
|
||||
|
Loading…
x
Reference in New Issue
Block a user