Skip to content

Commit 43aff62

Browse files
committed
HLRC: Add InvalidateToken security API (#35114)
This change adds the Invalidate Token API (DELETE /_xpack/security/oauth2/token) to the Elasticsearch High Level Rest Client. Relates: #29827
1 parent e57fea5 commit 43aff62

File tree

9 files changed

+466
-17
lines changed

9 files changed

+466
-17
lines changed

client/rest-high-level/src/main/java/org/elasticsearch/client/SecurityClient.java

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,8 @@
4040
import org.elasticsearch.client.security.GetRoleMappingsResponse;
4141
import org.elasticsearch.client.security.GetSslCertificatesRequest;
4242
import org.elasticsearch.client.security.GetSslCertificatesResponse;
43+
import org.elasticsearch.client.security.InvalidateTokenRequest;
44+
import org.elasticsearch.client.security.InvalidateTokenResponse;
4345
import org.elasticsearch.client.security.PutRoleMappingRequest;
4446
import org.elasticsearch.client.security.PutRoleMappingResponse;
4547
import org.elasticsearch.client.security.PutUserRequest;
@@ -440,4 +442,35 @@ public void createTokenAsync(CreateTokenRequest request, RequestOptions options,
440442
restHighLevelClient.performRequestAsyncAndParseEntity(request, SecurityRequestConverters::createToken, options,
441443
CreateTokenResponse::fromXContent, listener, emptySet());
442444
}
445+
446+
/**
447+
* Invalidates an OAuth2 token.
448+
* See <a href="https://www.elastic.co/guide/en/elasticsearch/reference/current/security-api-invalidate-token.html">
449+
* the docs</a> for more.
450+
*
451+
* @param request the request to invalidate the token
452+
* @param options the request options (e.g. headers), use {@link RequestOptions#DEFAULT} if nothing needs to be customized
453+
* @return the response from the create token call
454+
* @throws IOException in case there is a problem sending the request or parsing back the response
455+
*/
456+
public InvalidateTokenResponse invalidateToken(InvalidateTokenRequest request, RequestOptions options) throws IOException {
457+
return restHighLevelClient.performRequestAndParseEntity(request, SecurityRequestConverters::invalidateToken, options,
458+
InvalidateTokenResponse::fromXContent, emptySet());
459+
}
460+
461+
/**
462+
* Asynchronously invalidates an OAuth2 token.
463+
* See <a href="https://www.elastic.co/guide/en/elasticsearch/reference/current/security-api-invalidate-token.html">
464+
* the docs</a> for more.
465+
*
466+
* @param request the request to invalidate the token
467+
* @param options the request options (e.g. headers), use {@link RequestOptions#DEFAULT} if nothing needs to be customized
468+
* @param listener the listener to be notified upon request completion
469+
*/
470+
public void invalidateTokenAsync(InvalidateTokenRequest request, RequestOptions options,
471+
ActionListener<InvalidateTokenResponse> listener) {
472+
restHighLevelClient.performRequestAsyncAndParseEntity(request, SecurityRequestConverters::invalidateToken, options,
473+
InvalidateTokenResponse::fromXContent, listener, emptySet());
474+
}
475+
443476
}

client/rest-high-level/src/main/java/org/elasticsearch/client/SecurityRequestConverters.java

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
import org.elasticsearch.client.security.CreateTokenRequest;
2929
import org.elasticsearch.client.security.DeleteRoleMappingRequest;
3030
import org.elasticsearch.client.security.DeleteRoleRequest;
31+
import org.elasticsearch.client.security.InvalidateTokenRequest;
3132
import org.elasticsearch.client.security.PutRoleMappingRequest;
3233
import org.elasticsearch.client.security.DisableUserRequest;
3334
import org.elasticsearch.client.security.EnableUserRequest;
@@ -165,4 +166,10 @@ static Request createToken(CreateTokenRequest createTokenRequest) throws IOExcep
165166
request.setEntity(createEntity(createTokenRequest, REQUEST_BODY_CONTENT_TYPE));
166167
return request;
167168
}
169+
170+
static Request invalidateToken(InvalidateTokenRequest invalidateTokenRequest) throws IOException {
171+
Request request = new Request(HttpDelete.METHOD_NAME, "/_xpack/security/oauth2/token");
172+
request.setEntity(createEntity(invalidateTokenRequest, REQUEST_BODY_CONTENT_TYPE));
173+
return request;
174+
}
168175
}
Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
/*
2+
* Licensed to Elasticsearch under one or more contributor
3+
* license agreements. See the NOTICE file distributed with
4+
* this work for additional information regarding copyright
5+
* ownership. Elasticsearch licenses this file to you under
6+
* the Apache License, Version 2.0 (the "License"); you may
7+
* not use this file except in compliance with the License.
8+
* You may obtain a copy of the License at
9+
*
10+
* http://www.apache.org/licenses/LICENSE-2.0
11+
*
12+
* Unless required by applicable law or agreed to in writing,
13+
* software distributed under the License is distributed on an
14+
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15+
* KIND, either express or implied. See the License for the
16+
* specific language governing permissions and limitations
17+
* under the License.
18+
*/
19+
20+
package org.elasticsearch.client.security;
21+
22+
import org.elasticsearch.client.Validatable;
23+
import org.elasticsearch.common.Nullable;
24+
import org.elasticsearch.common.Strings;
25+
import org.elasticsearch.common.xcontent.ToXContentObject;
26+
import org.elasticsearch.common.xcontent.XContentBuilder;
27+
28+
import java.io.IOException;
29+
import java.util.Objects;
30+
31+
/**
32+
* Request to invalidate a OAuth2 token within the Elasticsearch cluster.
33+
*/
34+
public final class InvalidateTokenRequest implements Validatable, ToXContentObject {
35+
36+
private final String accessToken;
37+
private final String refreshToken;
38+
39+
InvalidateTokenRequest(@Nullable String accessToken, @Nullable String refreshToken) {
40+
if (Strings.isNullOrEmpty(accessToken)) {
41+
if (Strings.isNullOrEmpty(refreshToken)) {
42+
throw new IllegalArgumentException("Either access-token or refresh-token is required");
43+
}
44+
} else if (Strings.isNullOrEmpty(refreshToken) == false) {
45+
throw new IllegalArgumentException("Cannot supply both access-token and refresh-token");
46+
}
47+
this.accessToken = accessToken;
48+
this.refreshToken = refreshToken;
49+
}
50+
51+
public static InvalidateTokenRequest accessToken(String accessToken) {
52+
if (Strings.isNullOrEmpty(accessToken)) {
53+
throw new IllegalArgumentException("token is required");
54+
}
55+
return new InvalidateTokenRequest(accessToken, null);
56+
}
57+
58+
public static InvalidateTokenRequest refreshToken(String refreshToken) {
59+
if (Strings.isNullOrEmpty(refreshToken)) {
60+
throw new IllegalArgumentException("refresh_token is required");
61+
}
62+
return new InvalidateTokenRequest(null, refreshToken);
63+
}
64+
65+
public String getAccessToken() {
66+
return accessToken;
67+
}
68+
69+
public String getRefreshToken() {
70+
return refreshToken;
71+
}
72+
73+
@Override
74+
public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException {
75+
builder.startObject();
76+
if (accessToken != null) {
77+
builder.field("token", accessToken);
78+
}
79+
if (refreshToken != null) {
80+
builder.field("refresh_token", refreshToken);
81+
}
82+
return builder.endObject();
83+
}
84+
85+
@Override
86+
public boolean equals(Object o) {
87+
if (this == o) {
88+
return true;
89+
}
90+
if (o == null || getClass() != o.getClass()) {
91+
return false;
92+
}
93+
final InvalidateTokenRequest that = (InvalidateTokenRequest) o;
94+
return Objects.equals(this.accessToken, that.accessToken) &&
95+
Objects.equals(this.refreshToken, that.refreshToken);
96+
}
97+
98+
@Override
99+
public int hashCode() {
100+
return Objects.hash(accessToken, refreshToken);
101+
}
102+
}
Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
/*
2+
* Licensed to Elasticsearch under one or more contributor
3+
* license agreements. See the NOTICE file distributed with
4+
* this work for additional information regarding copyright
5+
* ownership. Elasticsearch licenses this file to you under
6+
* the Apache License, Version 2.0 (the "License"); you may
7+
* not use this file except in compliance with the License.
8+
* You may obtain a copy of the License at
9+
*
10+
* http://www.apache.org/licenses/LICENSE-2.0
11+
*
12+
* Unless required by applicable law or agreed to in writing,
13+
* software distributed under the License is distributed on an
14+
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15+
* KIND, either express or implied. See the License for the
16+
* specific language governing permissions and limitations
17+
* under the License.
18+
*/
19+
20+
package org.elasticsearch.client.security;
21+
22+
import org.elasticsearch.common.ParseField;
23+
import org.elasticsearch.common.xcontent.ConstructingObjectParser;
24+
import org.elasticsearch.common.xcontent.XContentParser;
25+
26+
import java.io.IOException;
27+
import java.util.Objects;
28+
29+
import static org.elasticsearch.common.xcontent.ConstructingObjectParser.constructorArg;
30+
31+
/**
32+
* Response when invalidating an OAuth2 token. Returns a
33+
* single boolean field for whether the invalidation record was created or updated.
34+
*/
35+
public final class InvalidateTokenResponse {
36+
37+
private final boolean created;
38+
39+
public InvalidateTokenResponse(boolean created) {
40+
this.created = created;
41+
}
42+
43+
public boolean isCreated() {
44+
return created;
45+
}
46+
47+
@Override
48+
public boolean equals(Object o) {
49+
if (this == o) {
50+
return true;
51+
}
52+
if (o == null || getClass() != o.getClass()) {
53+
return false;
54+
}
55+
InvalidateTokenResponse that = (InvalidateTokenResponse) o;
56+
return created == that.created;
57+
}
58+
59+
@Override
60+
public int hashCode() {
61+
return Objects.hash(created);
62+
}
63+
64+
private static final ConstructingObjectParser<InvalidateTokenResponse, Void> PARSER = new ConstructingObjectParser<>(
65+
"invalidate_token_response", true, args -> new InvalidateTokenResponse((boolean) args[0]));
66+
67+
static {
68+
PARSER.declareBoolean(constructorArg(), new ParseField("created"));
69+
}
70+
71+
public static InvalidateTokenResponse fromXContent(XContentParser parser) throws IOException {
72+
return PARSER.parse(parser, null);
73+
}
74+
}

0 commit comments

Comments
 (0)