Skip to content

Add support for API keys to access Elasticsearch #38291

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 71 commits into from
Feb 5, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
71 commits
Select commit Hold shift + click to select a range
f087b54
Security: add create api key transport action (#34572)
jaymode Nov 2, 2018
0a35463
Merge branch 'master' into security_api_keys
jaymode Nov 5, 2018
1baa802
Merge branch 'master' into security_api_keys
jaymode Nov 5, 2018
c6dcda7
fix compile after merging master
jaymode Nov 5, 2018
74262c7
Merge branch 'master' into security_api_keys
jaymode Nov 6, 2018
67a4c1f
Merge branch 'master' into security_api_keys
jaymode Nov 8, 2018
d1e838b
fix compile after merge
jaymode Nov 8, 2018
0cb799f
Merge branch 'master' into security_api_keys
jaymode Nov 9, 2018
1ed071f
Merge branch 'master' into security_api_keys
jaymode Nov 13, 2018
39477a2
Implement verification of API keys (#35318)
jaymode Nov 14, 2018
5b6c3a2
Merge branch 'master' into security_api_keys
Nov 16, 2018
03fa3a6
Merge branch 'master' into security_api_keys
jaymode Nov 16, 2018
2a1a59f
Merge branch 'master' into security_api_keys
Nov 21, 2018
9133299
Merge branch 'master' into security_api_keys
jaymode Nov 26, 2018
22624cf
Integrate api keys with the authentication service (#35555)
jaymode Nov 27, 2018
e421428
Merge branch 'master' into security_api_keys
jaymode Nov 27, 2018
187eb91
Merge branch 'master' into security_api_keys
Nov 28, 2018
53d06f6
Merge branch 'master' into security_api_keys
Nov 30, 2018
155ff6f
Merge branch 'master' into security_api_keys
jaymode Nov 30, 2018
98eb1cb
Merge branch 'master' into security_api_keys
Dec 5, 2018
af2f1f6
Merge branch 'master' into security_api_keys
Dec 6, 2018
476879a
Implement lookup of permissions for API keys (#35970)
jaymode Dec 6, 2018
602feeb
Merge branch 'master' into security_api_keys
jaymode Dec 6, 2018
554bf23
Enable caching of roles from the api keys (#36387)
jaymode Dec 10, 2018
b3bbf4e
Merge branch 'master' into security_api_keys
jaymode Dec 10, 2018
7989b95
Add internal and anonymous authentication types (#36331)
jaymode Dec 13, 2018
d3ab4df
Merge branch 'master' into security_api_keys
Dec 17, 2018
825c9bc
Merge branch 'master' into security_api_keys
Dec 18, 2018
ec9df2a
Merge branch 'master' into security_api_keys
Dec 18, 2018
7c2e455
Add seq num and primary term to GetResult constructor
Dec 19, 2018
5d627da
Merge branch 'master' into security_api_keys
Dec 19, 2018
7e418bd
Merge branch 'master' into security_api_keys
Dec 21, 2018
dc8cd01
[APIKey] Add rest action for create API Key (#36029)
bizybot Dec 24, 2018
d53f448
Merge branch 'master' into security_api_keys
Jan 7, 2019
2fba9bf
Fix merge failures from master
Jan 8, 2019
da6b2dc
Merge branch 'master' into security_api_keys
Jan 11, 2019
1a12c59
Fix merge issue
Jan 15, 2019
52401be
Merge branch 'master' into security_api_keys
Jan 15, 2019
5174769
Merge branch 'master' into security_api_keys
Jan 16, 2019
d2a3088
Merge branch 'master' into security_api_keys
Jan 16, 2019
cd43f09
Merge branch 'master' into security_api_keys
Jan 16, 2019
23eff70
Add invalidate API key transport action (#37399)
bizybot Jan 17, 2019
278a4a5
Merge branch 'master' into security_api_keys
Jan 17, 2019
fabcbb8
HLRC - Add support for create API key (#37389)
bizybot Jan 18, 2019
7413dc9
Merge branch 'master' into security_api_keys
Jan 19, 2019
18b4760
Merge branch 'master' into security_api_keys
Jan 21, 2019
b5d1214
Merge branch 'master' into security_api_keys
Jan 22, 2019
890c3a6
Fix test after merge from master for allow_restricted_indices
Jan 22, 2019
75d27a9
Add invalidated API keys remover (#37572)
bizybot Jan 22, 2019
9d9614b
Merge branch 'master' into security_api_keys
Jan 23, 2019
fadbdfb
Invalidate API rest action (#37628)
bizybot Jan 23, 2019
3988a92
Get API keys API transport action (#37632)
bizybot Jan 23, 2019
0039528
API key authorization support (#37335)
bizybot Jan 23, 2019
ce1c6c4
Merge branch 'master' into security_api_keys
Jan 24, 2019
ee2cfb1
Use StreamOutput#writeStringCollection
Jan 24, 2019
d433fc9
check for null or empty role descriptors
Jan 25, 2019
771c1f2
Merge branch 'master' into security_api_keys
Jan 25, 2019
a5d0d67
Merge branch 'master' into security_api_keys
Jan 27, 2019
c7a0b13
Merge branch 'master' into security_api_keys
Jan 29, 2019
0c438cd
Merge branch 'master' into security_api_keys
Jan 30, 2019
4203f36
Fix test case after merge from master
Jan 30, 2019
de15a80
Merge branch 'master' into security_api_keys
Jan 30, 2019
a59150d
Merge branch 'master' into security_api_keys
Jan 30, 2019
f47d21a
Invalidate API keys support to HLRC (#37779)
bizybot Jan 30, 2019
382d6cb
Handle has privileges API response for `LimitedRole` (#37831)
bizybot Jan 30, 2019
8973a60
Merge branch 'master' into security_api_keys
Jan 31, 2019
bfa8dbd
Rest action for Get API keys API (#37955)
bizybot Jan 31, 2019
9cdfffb
Merge branch 'master' into security_api_keys
Feb 1, 2019
e2fbef2
Merge branch 'master' into security_api_keys
Feb 2, 2019
376c625
HLRC - Implement Get API keys API (#38083)
bizybot Feb 2, 2019
e8ef557
Merge branch 'master' into security_api_keys
Feb 3, 2019
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions client/rest-high-level/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,7 @@ integTestCluster {
setting 'xpack.license.self_generated.type', 'trial'
setting 'xpack.security.enabled', 'true'
setting 'xpack.security.authc.token.enabled', 'true'
setting 'xpack.security.authc.api_key.enabled', 'true'
// Truststore settings are not used since TLS is not enabled. Included for testing the get certificates API
setting 'xpack.security.http.ssl.certificate_authorities', 'testnode.crt'
setting 'xpack.security.transport.ssl.truststore.path', 'testnode.jks'
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@
import org.elasticsearch.client.security.ClearRealmCacheResponse;
import org.elasticsearch.client.security.ClearRolesCacheRequest;
import org.elasticsearch.client.security.ClearRolesCacheResponse;
import org.elasticsearch.client.security.CreateApiKeyRequest;
import org.elasticsearch.client.security.CreateApiKeyResponse;
import org.elasticsearch.client.security.CreateTokenRequest;
import org.elasticsearch.client.security.CreateTokenResponse;
import org.elasticsearch.client.security.DeletePrivilegesRequest;
Expand All @@ -40,6 +42,8 @@
import org.elasticsearch.client.security.DisableUserRequest;
import org.elasticsearch.client.security.EmptyResponse;
import org.elasticsearch.client.security.EnableUserRequest;
import org.elasticsearch.client.security.GetApiKeyRequest;
import org.elasticsearch.client.security.GetApiKeyResponse;
import org.elasticsearch.client.security.GetPrivilegesRequest;
import org.elasticsearch.client.security.GetPrivilegesResponse;
import org.elasticsearch.client.security.GetRoleMappingsRequest;
Expand All @@ -54,6 +58,8 @@
import org.elasticsearch.client.security.GetUsersResponse;
import org.elasticsearch.client.security.HasPrivilegesRequest;
import org.elasticsearch.client.security.HasPrivilegesResponse;
import org.elasticsearch.client.security.InvalidateApiKeyRequest;
import org.elasticsearch.client.security.InvalidateApiKeyResponse;
import org.elasticsearch.client.security.InvalidateTokenRequest;
import org.elasticsearch.client.security.InvalidateTokenResponse;
import org.elasticsearch.client.security.PutPrivilegesRequest;
Expand Down Expand Up @@ -850,4 +856,95 @@ public void deletePrivilegesAsync(DeletePrivilegesRequest request, RequestOption
restHighLevelClient.performRequestAsyncAndParseEntity(request, SecurityRequestConverters::deletePrivileges, options,
DeletePrivilegesResponse::fromXContent, listener, singleton(404));
}

/**
* Create an API Key.<br>
* See <a href="https://www.elastic.co/guide/en/elasticsearch/reference/current/security-api-create-api-key.html">
* the docs</a> for more.
*
* @param request the request to create a API key
* @param options the request options (e.g. headers), use {@link RequestOptions#DEFAULT} if nothing needs to be customized
* @return the response from the create API key call
* @throws IOException in case there is a problem sending the request or parsing back the response
*/
public CreateApiKeyResponse createApiKey(final CreateApiKeyRequest request, final RequestOptions options) throws IOException {
return restHighLevelClient.performRequestAndParseEntity(request, SecurityRequestConverters::createApiKey, options,
CreateApiKeyResponse::fromXContent, emptySet());
}

/**
* Asynchronously creates an API key.<br>
* See <a href="https://www.elastic.co/guide/en/elasticsearch/reference/current/security-api-create-api-key.html">
* the docs</a> for more.
*
* @param request the request to create a API key
* @param options the request options (e.g. headers), use {@link RequestOptions#DEFAULT} if nothing needs to be customized
* @param listener the listener to be notified upon request completion
*/
public void createApiKeyAsync(final CreateApiKeyRequest request, final RequestOptions options,
final ActionListener<CreateApiKeyResponse> listener) {
restHighLevelClient.performRequestAsyncAndParseEntity(request, SecurityRequestConverters::createApiKey, options,
CreateApiKeyResponse::fromXContent, listener, emptySet());
}

/**
* Retrieve API Key(s) information.<br>
* See <a href="https://www.elastic.co/guide/en/elasticsearch/reference/current/security-api-get-api-key.html">
* the docs</a> for more.
*
* @param request the request to retrieve API key(s)
* @param options the request options (e.g. headers), use {@link RequestOptions#DEFAULT} if nothing needs to be customized
* @return the response from the create API key call
* @throws IOException in case there is a problem sending the request or parsing back the response
*/
public GetApiKeyResponse getApiKey(final GetApiKeyRequest request, final RequestOptions options) throws IOException {
return restHighLevelClient.performRequestAndParseEntity(request, SecurityRequestConverters::getApiKey, options,
GetApiKeyResponse::fromXContent, emptySet());
}

/**
* Asynchronously retrieve API Key(s) information.<br>
* See <a href="https://www.elastic.co/guide/en/elasticsearch/reference/current/security-api-get-api-key.html">
* the docs</a> for more.
*
* @param request the request to retrieve API key(s)
* @param options the request options (e.g. headers), use {@link RequestOptions#DEFAULT} if nothing needs to be customized
* @param listener the listener to be notified upon request completion
*/
public void getApiKeyAsync(final GetApiKeyRequest request, final RequestOptions options,
final ActionListener<GetApiKeyResponse> listener) {
restHighLevelClient.performRequestAsyncAndParseEntity(request, SecurityRequestConverters::getApiKey, options,
GetApiKeyResponse::fromXContent, listener, emptySet());
}

/**
* Invalidate API Key(s).<br>
* See <a href="https://www.elastic.co/guide/en/elasticsearch/reference/current/security-api-invalidate-api-key.html">
* the docs</a> for more.
*
* @param request the request to invalidate API key(s)
* @param options the request options (e.g. headers), use {@link RequestOptions#DEFAULT} if nothing needs to be customized
* @return the response from the invalidate API key call
* @throws IOException in case there is a problem sending the request or parsing back the response
*/
public InvalidateApiKeyResponse invalidateApiKey(final InvalidateApiKeyRequest request, final RequestOptions options)
throws IOException {
return restHighLevelClient.performRequestAndParseEntity(request, SecurityRequestConverters::invalidateApiKey, options,
InvalidateApiKeyResponse::fromXContent, emptySet());
}

/**
* Asynchronously invalidates API key(s).<br>
* See <a href="https://www.elastic.co/guide/en/elasticsearch/reference/current/security-api-invalidate-api-key.html">
* the docs</a> for more.
*
* @param request the request to invalidate API key(s)
* @param options the request options (e.g. headers), use {@link RequestOptions#DEFAULT} if nothing needs to be customized
* @param listener the listener to be notified upon request completion
*/
public void invalidateApiKeyAsync(final InvalidateApiKeyRequest request, final RequestOptions options,
final ActionListener<InvalidateApiKeyResponse> listener) {
restHighLevelClient.performRequestAsyncAndParseEntity(request, SecurityRequestConverters::invalidateApiKey, options,
InvalidateApiKeyResponse::fromXContent, listener, emptySet());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -26,18 +26,21 @@
import org.elasticsearch.client.security.ChangePasswordRequest;
import org.elasticsearch.client.security.ClearRealmCacheRequest;
import org.elasticsearch.client.security.ClearRolesCacheRequest;
import org.elasticsearch.client.security.CreateApiKeyRequest;
import org.elasticsearch.client.security.CreateTokenRequest;
import org.elasticsearch.client.security.DeletePrivilegesRequest;
import org.elasticsearch.client.security.DeleteRoleMappingRequest;
import org.elasticsearch.client.security.DeleteRoleRequest;
import org.elasticsearch.client.security.DeleteUserRequest;
import org.elasticsearch.client.security.DisableUserRequest;
import org.elasticsearch.client.security.EnableUserRequest;
import org.elasticsearch.client.security.GetApiKeyRequest;
import org.elasticsearch.client.security.GetPrivilegesRequest;
import org.elasticsearch.client.security.GetRoleMappingsRequest;
import org.elasticsearch.client.security.GetRolesRequest;
import org.elasticsearch.client.security.GetUsersRequest;
import org.elasticsearch.client.security.HasPrivilegesRequest;
import org.elasticsearch.client.security.InvalidateApiKeyRequest;
import org.elasticsearch.client.security.InvalidateTokenRequest;
import org.elasticsearch.client.security.PutPrivilegesRequest;
import org.elasticsearch.client.security.PutRoleMappingRequest;
Expand Down Expand Up @@ -256,4 +259,36 @@ static Request putRole(final PutRoleRequest putRoleRequest) throws IOException {
params.withRefreshPolicy(putRoleRequest.getRefreshPolicy());
return request;
}

static Request createApiKey(final CreateApiKeyRequest createApiKeyRequest) throws IOException {
final Request request = new Request(HttpPost.METHOD_NAME, "/_security/api_key");
request.setEntity(createEntity(createApiKeyRequest, REQUEST_BODY_CONTENT_TYPE));
final RequestConverters.Params params = new RequestConverters.Params(request);
params.withRefreshPolicy(createApiKeyRequest.getRefreshPolicy());
return request;
}

static Request getApiKey(final GetApiKeyRequest getApiKeyRequest) throws IOException {
final Request request = new Request(HttpGet.METHOD_NAME, "/_security/api_key");
if (Strings.hasText(getApiKeyRequest.getId())) {
request.addParameter("id", getApiKeyRequest.getId());
}
if (Strings.hasText(getApiKeyRequest.getName())) {
request.addParameter("name", getApiKeyRequest.getName());
}
if (Strings.hasText(getApiKeyRequest.getUserName())) {
request.addParameter("username", getApiKeyRequest.getUserName());
}
if (Strings.hasText(getApiKeyRequest.getRealmName())) {
request.addParameter("realm_name", getApiKeyRequest.getRealmName());
}
return request;
}

static Request invalidateApiKey(final InvalidateApiKeyRequest invalidateApiKeyRequest) throws IOException {
final Request request = new Request(HttpDelete.METHOD_NAME, "/_security/api_key");
request.setEntity(createEntity(invalidateApiKeyRequest, REQUEST_BODY_CONTENT_TYPE));
final RequestConverters.Params params = new RequestConverters.Params(request);
return request;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
/*
* Licensed to Elasticsearch under one or more contributor
* license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright
* ownership. Elasticsearch licenses this file to you under
* the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/

package org.elasticsearch.client.security;

import org.elasticsearch.client.Validatable;
import org.elasticsearch.client.security.user.privileges.Role;
import org.elasticsearch.common.Nullable;
import org.elasticsearch.common.Strings;
import org.elasticsearch.common.unit.TimeValue;
import org.elasticsearch.common.xcontent.ToXContentObject;
import org.elasticsearch.common.xcontent.XContentBuilder;

import java.io.IOException;
import java.util.List;
import java.util.Objects;

/**
* Request to create API key
*/
public final class CreateApiKeyRequest implements Validatable, ToXContentObject {

private final String name;
private final TimeValue expiration;
private final List<Role> roles;
private final RefreshPolicy refreshPolicy;

/**
* Create API Key request constructor
* @param name name for the API key
* @param roles list of {@link Role}s
* @param expiration to specify expiration for the API key
*/
public CreateApiKeyRequest(String name, List<Role> roles, @Nullable TimeValue expiration, @Nullable final RefreshPolicy refreshPolicy) {
if (Strings.hasText(name)) {
this.name = name;
} else {
throw new IllegalArgumentException("name must not be null or empty");
}
this.roles = Objects.requireNonNull(roles, "roles may not be null");
this.expiration = expiration;
this.refreshPolicy = (refreshPolicy == null) ? RefreshPolicy.getDefault() : refreshPolicy;
}

public String getName() {
return name;
}

public TimeValue getExpiration() {
return expiration;
}

public List<Role> getRoles() {
return roles;
}

public RefreshPolicy getRefreshPolicy() {
return refreshPolicy;
}

@Override
public int hashCode() {
return Objects.hash(name, refreshPolicy, roles, expiration);
}

@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
final CreateApiKeyRequest that = (CreateApiKeyRequest) o;
return Objects.equals(name, that.name) && Objects.equals(refreshPolicy, that.refreshPolicy) && Objects.equals(roles, that.roles)
&& Objects.equals(expiration, that.expiration);
}

@Override
public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException {
builder.startObject().field("name", name);
if (expiration != null) {
builder.field("expiration", expiration.getStringRep());
}
builder.startObject("role_descriptors");
for (Role role : roles) {
builder.startObject(role.getName());
if (role.getApplicationPrivileges() != null) {
builder.field(Role.APPLICATIONS.getPreferredName(), role.getApplicationPrivileges());
}
if (role.getClusterPrivileges() != null) {
builder.field(Role.CLUSTER.getPreferredName(), role.getClusterPrivileges());
}
if (role.getGlobalPrivileges() != null) {
builder.field(Role.GLOBAL.getPreferredName(), role.getGlobalPrivileges());
}
if (role.getIndicesPrivileges() != null) {
builder.field(Role.INDICES.getPreferredName(), role.getIndicesPrivileges());
}
if (role.getMetadata() != null) {
builder.field(Role.METADATA.getPreferredName(), role.getMetadata());
}
if (role.getRunAsPrivilege() != null) {
builder.field(Role.RUN_AS.getPreferredName(), role.getRunAsPrivilege());
}
builder.endObject();
}
builder.endObject();
return builder.endObject();
}

}
Loading