Skip to content

Commit

Permalink
HLRC: add support for retrieval/invalidation of owned API keys
Browse files Browse the repository at this point in the history
This commit updates Rest client(get/invalidate API keys APIs) to support retrieval
or invalidation of API keys owned by the currently authenticated user.

Relates: elastic#40031
  • Loading branch information
Yogesh Gaikwad committed Aug 12, 2019
1 parent 9170c81 commit 6166358
Show file tree
Hide file tree
Showing 8 changed files with 171 additions and 49 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -294,7 +294,7 @@ static Request getApiKey(final GetApiKeyRequest getApiKeyRequest) throws IOExcep
if (Strings.hasText(getApiKeyRequest.getRealmName())) {
request.addParameter("realm_name", getApiKeyRequest.getRealmName());
}

request.addParameter("owner", Boolean.toString(getApiKeyRequest.ownedByAuthenticatedUser()));
return request;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,27 +36,34 @@ public final class GetApiKeyRequest implements Validatable, ToXContentObject {
private final String userName;
private final String id;
private final String name;
private final boolean ownedByAuthenticatedUser;

// pkg scope for testing
GetApiKeyRequest(@Nullable String realmName, @Nullable String userName, @Nullable String apiKeyId,
@Nullable String apiKeyName) {
@Nullable String apiKeyName, boolean ownedByAuthenticatedUser) {
if (Strings.hasText(realmName) == false && Strings.hasText(userName) == false && Strings.hasText(apiKeyId) == false
&& Strings.hasText(apiKeyName) == false) {
throwValidationError("One of [api key id, api key name, username, realm name] must be specified");
&& Strings.hasText(apiKeyName) == false && ownedByAuthenticatedUser == false) {
throwValidationError("One of [api key id, api key name, username, realm name] must be specified if [owner] flag is false");
}
if (Strings.hasText(apiKeyId) || Strings.hasText(apiKeyName)) {
if (Strings.hasText(realmName) || Strings.hasText(userName)) {
throwValidationError(
"username or realm name must not be specified when the api key id or api key name is specified");
}
}
if (ownedByAuthenticatedUser) {
if (Strings.hasText(realmName) || Strings.hasText(userName)) {
throwValidationError("neither username nor realm-name may be specified when retrieving owned API keys");
}
}
if (Strings.hasText(apiKeyId) && Strings.hasText(apiKeyName)) {
throwValidationError("only one of [api key id, api key name] can be specified");
}
this.realmName = realmName;
this.userName = userName;
this.id = apiKeyId;
this.name = apiKeyName;
this.ownedByAuthenticatedUser = ownedByAuthenticatedUser;
}

private void throwValidationError(String message) {
Expand All @@ -79,13 +86,17 @@ public String getName() {
return name;
}

public boolean ownedByAuthenticatedUser() {
return ownedByAuthenticatedUser;
}

/**
* Creates get API key request for given realm name
* @param realmName realm name
* @return {@link GetApiKeyRequest}
*/
public static GetApiKeyRequest usingRealmName(String realmName) {
return new GetApiKeyRequest(realmName, null, null, null);
return new GetApiKeyRequest(realmName, null, null, null, false);
}

/**
Expand All @@ -94,7 +105,7 @@ public static GetApiKeyRequest usingRealmName(String realmName) {
* @return {@link GetApiKeyRequest}
*/
public static GetApiKeyRequest usingUserName(String userName) {
return new GetApiKeyRequest(null, userName, null, null);
return new GetApiKeyRequest(null, userName, null, null, false);
}

/**
Expand All @@ -104,25 +115,36 @@ public static GetApiKeyRequest usingUserName(String userName) {
* @return {@link GetApiKeyRequest}
*/
public static GetApiKeyRequest usingRealmAndUserName(String realmName, String userName) {
return new GetApiKeyRequest(realmName, userName, null, null);
return new GetApiKeyRequest(realmName, userName, null, null, false);
}

/**
* Creates get API key request for given api key id
* @param apiKeyId api key id
* @param ownedByAuthenticatedUser set {@code true} if the request is only for the API keys owned by current
* authenticated user else{@code false}
* @return {@link GetApiKeyRequest}
*/
public static GetApiKeyRequest usingApiKeyId(String apiKeyId) {
return new GetApiKeyRequest(null, null, apiKeyId, null);
public static GetApiKeyRequest usingApiKeyId(String apiKeyId, boolean ownedByAuthenticatedUser) {
return new GetApiKeyRequest(null, null, apiKeyId, null, ownedByAuthenticatedUser);
}

/**
* Creates get API key request for given api key name
* @param apiKeyName api key name
* @param ownedByAuthenticatedUser set {@code true} if the request is only for the API keys owned by current
* authenticated user else{@code false}
* @return {@link GetApiKeyRequest}
*/
public static GetApiKeyRequest usingApiKeyName(String apiKeyName) {
return new GetApiKeyRequest(null, null, null, apiKeyName);
public static GetApiKeyRequest usingApiKeyName(String apiKeyName, boolean ownedByAuthenticatedUser) {
return new GetApiKeyRequest(null, null, null, apiKeyName, ownedByAuthenticatedUser);
}

/**
* Creates get api key request to retrieve api key information for the api keys owned by the current authenticated user.
*/
public static GetApiKeyRequest forOwnedApiKeys() {
return new GetApiKeyRequest(null, null, null, null, true);
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,27 +36,34 @@ public final class InvalidateApiKeyRequest implements Validatable, ToXContentObj
private final String userName;
private final String id;
private final String name;
private final boolean ownedByAuthenticatedUser;

// pkg scope for testing
InvalidateApiKeyRequest(@Nullable String realmName, @Nullable String userName, @Nullable String apiKeyId,
@Nullable String apiKeyName) {
@Nullable String apiKeyName, boolean ownedByAuthenticatedUser) {
if (Strings.hasText(realmName) == false && Strings.hasText(userName) == false && Strings.hasText(apiKeyId) == false
&& Strings.hasText(apiKeyName) == false) {
throwValidationError("One of [api key id, api key name, username, realm name] must be specified");
&& Strings.hasText(apiKeyName) == false && ownedByAuthenticatedUser == false) {
throwValidationError("One of [api key id, api key name, username, realm name] must be specified if [owner] flag is false");
}
if (Strings.hasText(apiKeyId) || Strings.hasText(apiKeyName)) {
if (Strings.hasText(realmName) || Strings.hasText(userName)) {
throwValidationError(
"username or realm name must not be specified when the api key id or api key name is specified");
}
}
if (ownedByAuthenticatedUser) {
if (Strings.hasText(realmName) || Strings.hasText(userName)) {
throwValidationError("neither username nor realm-name may be specified when invalidating owned API keys");
}
}
if (Strings.hasText(apiKeyId) && Strings.hasText(apiKeyName)) {
throwValidationError("only one of [api key id, api key name] can be specified");
}
this.realmName = realmName;
this.userName = userName;
this.id = apiKeyId;
this.name = apiKeyName;
this.ownedByAuthenticatedUser = ownedByAuthenticatedUser;
}

private void throwValidationError(String message) {
Expand All @@ -79,13 +86,17 @@ public String getName() {
return name;
}

public boolean ownedByAuthenticatedUser() {
return ownedByAuthenticatedUser;
}

/**
* Creates invalidate API key request for given realm name
* @param realmName realm name
* @return {@link InvalidateApiKeyRequest}
*/
public static InvalidateApiKeyRequest usingRealmName(String realmName) {
return new InvalidateApiKeyRequest(realmName, null, null, null);
return new InvalidateApiKeyRequest(realmName, null, null, null, false);
}

/**
Expand All @@ -94,7 +105,7 @@ public static InvalidateApiKeyRequest usingRealmName(String realmName) {
* @return {@link InvalidateApiKeyRequest}
*/
public static InvalidateApiKeyRequest usingUserName(String userName) {
return new InvalidateApiKeyRequest(null, userName, null, null);
return new InvalidateApiKeyRequest(null, userName, null, null, false);
}

/**
Expand All @@ -104,25 +115,36 @@ public static InvalidateApiKeyRequest usingUserName(String userName) {
* @return {@link InvalidateApiKeyRequest}
*/
public static InvalidateApiKeyRequest usingRealmAndUserName(String realmName, String userName) {
return new InvalidateApiKeyRequest(realmName, userName, null, null);
return new InvalidateApiKeyRequest(realmName, userName, null, null, false);
}

/**
* Creates invalidate API key request for given api key id
* @param apiKeyId api key id
* @param ownedByAuthenticatedUser set {@code true} if the request is only for the API keys owned by current authenticated user else
* {@code false}
* @return {@link InvalidateApiKeyRequest}
*/
public static InvalidateApiKeyRequest usingApiKeyId(String apiKeyId) {
return new InvalidateApiKeyRequest(null, null, apiKeyId, null);
public static InvalidateApiKeyRequest usingApiKeyId(String apiKeyId, boolean ownedByAuthenticatedUser) {
return new InvalidateApiKeyRequest(null, null, apiKeyId, null, ownedByAuthenticatedUser);
}

/**
* Creates invalidate API key request for given api key name
* @param apiKeyName api key name
* @param ownedByAuthenticatedUser set {@code true} if the request is only for the API keys owned by current authenticated user else
* {@code false}
* @return {@link InvalidateApiKeyRequest}
*/
public static InvalidateApiKeyRequest usingApiKeyName(String apiKeyName) {
return new InvalidateApiKeyRequest(null, null, null, apiKeyName);
public static InvalidateApiKeyRequest usingApiKeyName(String apiKeyName, boolean ownedByAuthenticatedUser) {
return new InvalidateApiKeyRequest(null, null, null, apiKeyName, ownedByAuthenticatedUser);
}

/**
* Creates invalidate api key request to invalidate api keys owned by the current authenticated user.
*/
public static InvalidateApiKeyRequest forOwnedApiKeys() {
return new InvalidateApiKeyRequest(null, null, null, null, true);
}

@Override
Expand All @@ -140,6 +162,7 @@ public XContentBuilder toXContent(XContentBuilder builder, Params params) throws
if (name != null) {
builder.field("name", name);
}
builder.field("owner", ownedByAuthenticatedUser);
return builder.endObject();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -1917,7 +1917,7 @@ public void testGetApiKey() throws Exception {
Instant.now().plusMillis(expiration.getMillis()), false, "test_user", "default_file");
{
// tag::get-api-key-id-request
GetApiKeyRequest getApiKeyRequest = GetApiKeyRequest.usingApiKeyId(createApiKeyResponse1.getId());
GetApiKeyRequest getApiKeyRequest = GetApiKeyRequest.usingApiKeyId(createApiKeyResponse1.getId(), false);
// end::get-api-key-id-request

// tag::get-api-key-execute
Expand All @@ -1931,7 +1931,7 @@ public void testGetApiKey() throws Exception {

{
// tag::get-api-key-name-request
GetApiKeyRequest getApiKeyRequest = GetApiKeyRequest.usingApiKeyName(createApiKeyResponse1.getName());
GetApiKeyRequest getApiKeyRequest = GetApiKeyRequest.usingApiKeyName(createApiKeyResponse1.getName(), false);
// end::get-api-key-name-request

GetApiKeyResponse getApiKeyResponse = client.security().getApiKey(getApiKeyRequest, RequestOptions.DEFAULT);
Expand Down Expand Up @@ -1965,6 +1965,18 @@ public void testGetApiKey() throws Exception {
verifyApiKey(getApiKeyResponse.getApiKeyInfos().get(0), expectedApiKeyInfo);
}

{
// tag::get-api-keys-owned-by-authenticated-user-request
GetApiKeyRequest getApiKeyRequest = GetApiKeyRequest.forOwnedApiKeys();
// end::get-api-keys-owned-by-authenticated-user-request

GetApiKeyResponse getApiKeyResponse = client.security().getApiKey(getApiKeyRequest, RequestOptions.DEFAULT);

assertThat(getApiKeyResponse.getApiKeyInfos(), is(notNullValue()));
assertThat(getApiKeyResponse.getApiKeyInfos().size(), is(1));
verifyApiKey(getApiKeyResponse.getApiKeyInfos().get(0), expectedApiKeyInfo);
}

{
// tag::get-user-realm-api-keys-request
GetApiKeyRequest getApiKeyRequest = GetApiKeyRequest.usingRealmAndUserName("default_file", "test_user");
Expand All @@ -1980,7 +1992,7 @@ public void testGetApiKey() throws Exception {
}

{
GetApiKeyRequest getApiKeyRequest = GetApiKeyRequest.usingApiKeyId(createApiKeyResponse1.getId());
GetApiKeyRequest getApiKeyRequest = GetApiKeyRequest.usingApiKeyId(createApiKeyResponse1.getId(), false);

ActionListener<GetApiKeyResponse> listener;
// tag::get-api-key-execute-listener
Expand Down Expand Up @@ -2041,7 +2053,7 @@ public void testInvalidateApiKey() throws Exception {

{
// tag::invalidate-api-key-id-request
InvalidateApiKeyRequest invalidateApiKeyRequest = InvalidateApiKeyRequest.usingApiKeyId(createApiKeyResponse1.getId());
InvalidateApiKeyRequest invalidateApiKeyRequest = InvalidateApiKeyRequest.usingApiKeyId(createApiKeyResponse1.getId(), false);
// end::invalidate-api-key-id-request

// tag::invalidate-api-key-execute
Expand All @@ -2066,7 +2078,8 @@ public void testInvalidateApiKey() throws Exception {
assertNotNull(createApiKeyResponse2.getKey());

// tag::invalidate-api-key-name-request
InvalidateApiKeyRequest invalidateApiKeyRequest = InvalidateApiKeyRequest.usingApiKeyName(createApiKeyResponse2.getName());
InvalidateApiKeyRequest invalidateApiKeyRequest = InvalidateApiKeyRequest.usingApiKeyName(createApiKeyResponse2.getName(),
false);
// end::invalidate-api-key-name-request

InvalidateApiKeyResponse invalidateApiKeyResponse = client.security().invalidateApiKey(invalidateApiKeyRequest,
Expand Down Expand Up @@ -2159,7 +2172,7 @@ public void testInvalidateApiKey() throws Exception {
assertThat(createApiKeyResponse6.getName(), equalTo("k6"));
assertNotNull(createApiKeyResponse6.getKey());

InvalidateApiKeyRequest invalidateApiKeyRequest = InvalidateApiKeyRequest.usingApiKeyId(createApiKeyResponse6.getId());
InvalidateApiKeyRequest invalidateApiKeyRequest = InvalidateApiKeyRequest.usingApiKeyId(createApiKeyResponse6.getId(), false);

ActionListener<InvalidateApiKeyResponse> listener;
// tag::invalidate-api-key-execute-listener
Expand Down Expand Up @@ -2195,5 +2208,29 @@ public void onFailure(Exception e) {
assertThat(invalidatedApiKeyIds, containsInAnyOrder(expectedInvalidatedApiKeyIds.toArray(Strings.EMPTY_ARRAY)));
assertThat(response.getPreviouslyInvalidatedApiKeys().size(), equalTo(0));
}

{
createApiKeyRequest = new CreateApiKeyRequest("k7", roles, expiration, refreshPolicy);
CreateApiKeyResponse createApiKeyResponse7 = client.security().createApiKey(createApiKeyRequest, RequestOptions.DEFAULT);
assertThat(createApiKeyResponse7.getName(), equalTo("k7"));
assertNotNull(createApiKeyResponse7.getKey());

// tag::invalidate-api-keys-owned-by-authenticated-user-request
InvalidateApiKeyRequest invalidateApiKeyRequest = InvalidateApiKeyRequest.forOwnedApiKeys();
// end::invalidate-api-keys-owned-by-authenticated-user-request

InvalidateApiKeyResponse invalidateApiKeyResponse = client.security().invalidateApiKey(invalidateApiKeyRequest,
RequestOptions.DEFAULT);

final List<ElasticsearchException> errors = invalidateApiKeyResponse.getErrors();
final List<String> invalidatedApiKeyIds = invalidateApiKeyResponse.getInvalidatedApiKeys();
final List<String> previouslyInvalidatedApiKeyIds = invalidateApiKeyResponse.getPreviouslyInvalidatedApiKeys();

assertTrue(errors.isEmpty());
List<String> expectedInvalidatedApiKeyIds = Arrays.asList(createApiKeyResponse7.getId());
assertThat(invalidatedApiKeyIds, containsInAnyOrder(expectedInvalidatedApiKeyIds.toArray(Strings.EMPTY_ARRAY)));
assertThat(previouslyInvalidatedApiKeyIds.size(), equalTo(0));
}

}
}
Loading

0 comments on commit 6166358

Please sign in to comment.