Skip to content
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

Add cache for application privileges #55836

Merged
merged 57 commits into from
Jun 29, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
57 commits
Select commit Hold shift + click to select a range
b72d0d3
WIP
ywangd Apr 27, 2020
a02aba3
Add tests
ywangd Apr 27, 2020
6d9fa0a
Add invalidation
ywangd Apr 27, 2020
ee33fff
Add some corrurrency liveness protection
ywangd Apr 27, 2020
4bbd16d
Add API for both rest and transport
ywangd Apr 27, 2020
df28676
Simplify NativePrivilegeStore
ywangd Apr 27, 2020
4a63a16
Minor
ywangd Apr 27, 2020
a1d177c
More tweak
ywangd Apr 27, 2020
05061f9
Add single node tests
ywangd Apr 28, 2020
daafb80
checkstyle
ywangd Apr 28, 2020
545e27c
More checkstyle
ywangd Apr 28, 2020
5987b3b
checkstyle again
ywangd Apr 28, 2020
6094178
Fix json API file
ywangd Apr 28, 2020
1c58309
Update API json file
ywangd Apr 28, 2020
9100c24
WIP
ywangd Apr 30, 2020
3f9c5b7
Update x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/s…
ywangd Apr 30, 2020
08865dd
Merge branch 'es-54317-app-privilege-cache' of github.com:ywangd/elas…
ywangd Apr 30, 2020
b9538a8
Update x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/s…
ywangd Apr 30, 2020
9c5e947
Merge branch 'es-54317-app-privilege-cache' of github.com:ywangd/elas…
ywangd Apr 30, 2020
f5b166c
WIP
ywangd Apr 30, 2020
1e7ce7c
Merge remote-tracking branch 'origin/master' into es-54317-app-privil…
ywangd Apr 30, 2020
f1f3e72
Address feedback
ywangd Apr 30, 2020
a7b5b40
Checkstyle
ywangd Apr 30, 2020
5306bc1
Address feedback
ywangd May 4, 2020
03680bc
Skip yaml tests for 7.x
ywangd May 4, 2020
cdfe886
Merge remote-tracking branch 'origin/master' into es-54317-app-privil…
ywangd May 4, 2020
435993d
Fix yaml tests
ywangd May 4, 2020
20be80d
Add HLRC relevant files
ywangd May 4, 2020
d2f2f3e
check style
ywangd May 4, 2020
f1f7035
Fix broken docs
ywangd May 4, 2020
db6020e
Add bwc for the new transport action
ywangd May 4, 2020
73dda1f
Add working rolling upgrade mixed-cluster tests for privilege cache c…
ywangd May 5, 2020
ea9172f
Merge remote-tracking branch 'origin/master' into es-54317-app-privil…
ywangd May 5, 2020
65f9524
Remove bwc handling code and simply report no handler
ywangd May 5, 2020
04bb476
Checkstyle
ywangd May 5, 2020
07b7837
Clear privilege cache on security index changes
ywangd May 15, 2020
34464d7
Merge remote-tracking branch 'origin/master' into es-54317-app-privil…
ywangd May 15, 2020
e87d897
Update x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/s…
ywangd May 29, 2020
5acc7ec
Update x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/s…
ywangd May 29, 2020
5e3174a
Update x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/s…
ywangd May 29, 2020
385fb12
Update x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/s…
ywangd May 29, 2020
e411dc9
Update x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/s…
ywangd May 29, 2020
58b3942
Address feedback
ywangd May 29, 2020
a8f8e81
Merge remote-tracking branch 'origin/master' into es-54317-app-privil…
ywangd May 29, 2020
9a763c3
Address feedback
ywangd May 29, 2020
a43b3ef
Fix docs
ywangd May 29, 2020
ac6c39f
Address feedback
ywangd Jun 2, 2020
8e1dc13
Merge remote-tracking branch 'origin/master' into es-54317-app-privil…
ywangd Jun 2, 2020
21c89fb
Remove todo as it is pointless
ywangd Jun 2, 2020
1499a26
Address feedback for readwritelock and cache invalidation
ywangd Jun 3, 2020
3b7e773
Merge remote-tracking branch 'origin/master' into es-54317-app-privil…
ywangd Jun 3, 2020
83a0e19
add tests for caching behaviour
ywangd Jun 4, 2020
3deef1e
Merge remote-tracking branch 'origin/master' into es-54317-app-privil…
ywangd Jun 4, 2020
9364e36
Add TTL as a safety net. Also consolidate cache size to a single setting
ywangd Jun 15, 2020
0280c3e
Merge remote-tracking branch 'origin/master' into es-54317-app-privil…
ywangd Jun 15, 2020
ae3c784
Address feedback about lock duration
ywangd Jun 29, 2020
68a4dc1
Merge remote-tracking branch 'origin/master' into es-54317-app-privil…
ywangd Jun 29, 2020
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
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@
import org.elasticsearch.client.security.AuthenticateRequest;
import org.elasticsearch.client.security.AuthenticateResponse;
import org.elasticsearch.client.security.ChangePasswordRequest;
import org.elasticsearch.client.security.ClearPrivilegesCacheRequest;
import org.elasticsearch.client.security.ClearPrivilegesCacheResponse;
import org.elasticsearch.client.security.ClearRealmCacheRequest;
import org.elasticsearch.client.security.ClearRealmCacheResponse;
import org.elasticsearch.client.security.ClearRolesCacheRequest;
Expand Down Expand Up @@ -510,6 +512,38 @@ public Cancellable clearRolesCacheAsync(ClearRolesCacheRequest request, RequestO
ClearRolesCacheResponse::fromXContent, listener, emptySet());
}

/**
* Clears the privileges cache for a set of privileges.
* See <a href="https://www.elastic.co/guide/en/elasticsearch/reference/current/security-api-clear-privilege-cache.html">
* the docs</a> for more.
*
* @param request the request with the privileges for which the cache should be cleared.
* @param options the request options (e.g. headers), use {@link RequestOptions#DEFAULT} if nothing needs to be customized
* @return the response from the clear privileges cache call
* @throws IOException in case there is a problem sending the request or parsing back the response
*/
public ClearPrivilegesCacheResponse clearPrivilegesCache(ClearPrivilegesCacheRequest request,
RequestOptions options) throws IOException {
return restHighLevelClient.performRequestAndParseEntity(request, SecurityRequestConverters::clearPrivilegesCache, options,
ClearPrivilegesCacheResponse::fromXContent, emptySet());
}

/**
* Clears the privileges cache for a set of privileges asynchronously.
* See <a href="https://www.elastic.co/guide/en/elasticsearch/reference/current/security-api-clear-privilege-cache.html">
* the docs</a> for more.
*
* @param request the request with the privileges for which the cache should be cleared.
* @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
* @return cancellable that may be used to cancel the request
*/
public Cancellable clearPrivilegesCacheAsync(ClearPrivilegesCacheRequest request, RequestOptions options,
ActionListener<ClearPrivilegesCacheResponse> listener) {
return restHighLevelClient.performRequestAsyncAndParseEntity(request, SecurityRequestConverters::clearPrivilegesCache, options,
ClearPrivilegesCacheResponse::fromXContent, listener, emptySet());
}

/**
* Synchronously retrieve the X.509 certificates that are used to encrypt communications in an Elasticsearch cluster.
* See <a href="https://www.elastic.co/guide/en/elasticsearch/reference/current/security-api-ssl.html">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.methods.HttpPut;
import org.elasticsearch.client.security.ChangePasswordRequest;
import org.elasticsearch.client.security.ClearPrivilegesCacheRequest;
import org.elasticsearch.client.security.ClearRealmCacheRequest;
import org.elasticsearch.client.security.ClearRolesCacheRequest;
import org.elasticsearch.client.security.CreateApiKeyRequest;
Expand Down Expand Up @@ -183,6 +184,15 @@ static Request clearRolesCache(ClearRolesCacheRequest disableCacheRequest) {
return new Request(HttpPost.METHOD_NAME, endpoint);
}

static Request clearPrivilegesCache(ClearPrivilegesCacheRequest disableCacheRequest) {
String endpoint = new RequestConverters.EndpointBuilder()
.addPathPartAsIs("_security/privilege")
.addCommaSeparatedPathParts(disableCacheRequest.applications())
.addPathPart("_clear_cache")
.build();
return new Request(HttpPost.METHOD_NAME, endpoint);
}

static Request deleteRoleMapping(DeleteRoleMappingRequest deleteRoleMappingRequest) {
final String endpoint = new RequestConverters.EndpointBuilder()
.addPathPartAsIs("_security/role_mapping")
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
/*
* 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 java.util.Arrays;

/**
* The request used to clear the cache for native application privileges stored in an index.
*/
public final class ClearPrivilegesCacheRequest implements Validatable {

private final String[] applications;

/**
* Sets the applications for which caches will be evicted. When not set all privileges will be evicted from the cache.
*
* @param applications The application names
*/
public ClearPrivilegesCacheRequest(String... applications) {
this.applications = applications;
}

/**
* @return an array of application names that will have the cache evicted or <code>null</code> if all
*/
public String[] applications() {
return applications;
}

@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
ClearPrivilegesCacheRequest that = (ClearPrivilegesCacheRequest) o;
return Arrays.equals(applications, that.applications);
}

@Override
public int hashCode() {
return Arrays.hashCode(applications);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
/*
* 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.NodesResponseHeader;
import org.elasticsearch.common.xcontent.ConstructingObjectParser;
import org.elasticsearch.common.xcontent.XContentParser;

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

/**
* The response object that will be returned when clearing the privileges cache
*/
public final class ClearPrivilegesCacheResponse extends SecurityNodesResponse {

@SuppressWarnings("unchecked")
private static final ConstructingObjectParser<ClearPrivilegesCacheResponse, Void> PARSER =
new ConstructingObjectParser<>("clear_privileges_cache_response", false,
args -> new ClearPrivilegesCacheResponse((List<Node>)args[0], (NodesResponseHeader) args[1], (String) args[2]));

static {
SecurityNodesResponse.declareCommonNodesResponseParsing(PARSER);
}

public ClearPrivilegesCacheResponse(List<Node> nodes, NodesResponseHeader header, String clusterName) {
super(nodes, header, clusterName);
}

public static ClearPrivilegesCacheResponse fromXContent(XContentParser parser) throws IOException {
return PARSER.parse(parser, null);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,8 @@
import org.elasticsearch.client.security.AuthenticateResponse;
import org.elasticsearch.client.security.AuthenticateResponse.RealmInfo;
import org.elasticsearch.client.security.ChangePasswordRequest;
import org.elasticsearch.client.security.ClearPrivilegesCacheRequest;
import org.elasticsearch.client.security.ClearPrivilegesCacheResponse;
import org.elasticsearch.client.security.ClearRealmCacheRequest;
import org.elasticsearch.client.security.ClearRealmCacheResponse;
import org.elasticsearch.client.security.ClearRolesCacheRequest;
Expand Down Expand Up @@ -1003,6 +1005,52 @@ public void onFailure(Exception e) {
}
}

public void testClearPrivilegesCache() throws Exception {
RestHighLevelClient client = highLevelClient();
{
//tag::clear-privileges-cache-request
ClearPrivilegesCacheRequest request = new ClearPrivilegesCacheRequest("my_app"); // <1>
//end::clear-privileges-cache-request
//tag::clear-privileges-cache-execute
ClearPrivilegesCacheResponse response = client.security().clearPrivilegesCache(request, RequestOptions.DEFAULT);
//end::clear-privileges-cache-execute

assertNotNull(response);
assertThat(response.getNodes(), not(empty()));

//tag::clear-privileges-cache-response
List<ClearPrivilegesCacheResponse.Node> nodes = response.getNodes(); // <1>
//end::clear-privileges-cache-response
}

{
//tag::clear-privileges-cache-execute-listener
ClearPrivilegesCacheRequest request = new ClearPrivilegesCacheRequest("my_app");
ActionListener<ClearPrivilegesCacheResponse> listener = new ActionListener<>() {
@Override
public void onResponse(ClearPrivilegesCacheResponse clearPrivilegesCacheResponse) {
// <1>
}

@Override
public void onFailure(Exception e) {
// <2>
}
};
//end::clear-privileges-cache-execute-listener

// Replace the empty listener by a blocking listener in test
final CountDownLatch latch = new CountDownLatch(1);
listener = new LatchedActionListener<>(listener, latch);

// tag::clear-privileges-cache-execute-async
client.security().clearPrivilegesCacheAsync(request, RequestOptions.DEFAULT, listener); // <1>
// end::clear-privileges-cache-execute-async

assertTrue(latch.await(30L, TimeUnit.SECONDS));
}
}

public void testGetSslCertificates() throws Exception {
RestHighLevelClient client = highLevelClient();
{
Expand Down
33 changes: 33 additions & 0 deletions docs/java-rest/high-level/security/clear-privileges-cache.asciidoc
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@

--
:api: clear-privileges-cache
:request: ClearPrivilegesCacheRequest
:response: ClearPrivilegesCacheResponse
--
[role="xpack"]
[id="{upid}-{api}"]
=== Clear Privileges Cache API

[id="{upid}-{api}-request"]
==== Clear Privileges Cache Request

A +{request}+ supports defining the name of applications that the cache should be cleared for.

["source","java",subs="attributes,callouts,macros"]
--------------------------------------------------
include-tagged::{doc-tests-file}[{api}-request]
--------------------------------------------------
<1> the name of the application(s) for which the cache should be cleared

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Per my comment above, maybe

<1> The name of the application(s) for which the cache should be cleared 

include::../execution.asciidoc[]

[id="{upid}-{api}-response"]
==== Clear Privileges Cache Response

The returned +{response}+ allows to retrieve information about where the cache was cleared.

["source","java",subs="attributes,callouts,macros"]
--------------------------------------------------
include-tagged::{doc-tests-file}[{api}-response]
--------------------------------------------------
<1> the list of nodes that the cache was cleared on
2 changes: 2 additions & 0 deletions docs/java-rest/high-level/supported-apis.asciidoc
Original file line number Diff line number Diff line change
Expand Up @@ -455,6 +455,7 @@ The Java High Level REST Client supports the following Security APIs:
* <<{upid}-get-roles>>
* <<java-rest-high-security-delete-role>>
* <<{upid}-clear-roles-cache>>
* <<{upid}-clear-privileges-cache>>
* <<{upid}-clear-realm-cache>>
* <<{upid}-authenticate>>
* <<{upid}-has-privileges>>
Expand Down Expand Up @@ -486,6 +487,7 @@ include::security/delete-privileges.asciidoc[]
include::security/get-builtin-privileges.asciidoc[]
include::security/get-privileges.asciidoc[]
include::security/clear-roles-cache.asciidoc[]
include::security/clear-privileges-cache.asciidoc[]
include::security/clear-realm-cache.asciidoc[]
include::security/authenticate.asciidoc[]
include::security/has-privileges.asciidoc[]
Expand Down
8 changes: 5 additions & 3 deletions x-pack/docs/en/rest-api/security.asciidoc
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,11 @@ You can use the following APIs to perform security activities.
[[security-api-app-privileges]]
=== Application privileges

You can use the following APIs to add, update, retrieve, and remove application
You can use the following APIs to add, update, retrieve, and remove application
privileges:

* <<security-api-put-privileges,Create or update privileges>>
* <<security-api-put-privileges,Create or update privileges>>
* <<security-api-clear-privilege-cache,Clear privileges cache>>
* <<security-api-delete-privilege,Delete privileges>>
* <<security-api-get-privileges,Get privileges>>

Expand All @@ -28,7 +29,7 @@ privileges:

You can use the following APIs to add, remove, update, and retrieve role mappings:

* <<security-api-put-role-mapping,Create or update role mappings>>
* <<security-api-put-role-mapping,Create or update role mappings>>
* <<security-api-delete-role-mapping,Delete role mappings>>
* <<security-api-get-role-mapping,Get role mappings>>

Expand Down Expand Up @@ -106,6 +107,7 @@ include::security/authenticate.asciidoc[]
include::security/change-password.asciidoc[]
include::security/clear-cache.asciidoc[]
include::security/clear-roles-cache.asciidoc[]
include::security/clear-privileges-cache.asciidoc[]
include::security/create-api-keys.asciidoc[]
include::security/put-app-privileges.asciidoc[]
include::security/create-role-mappings.asciidoc[]
Expand Down
4 changes: 3 additions & 1 deletion x-pack/docs/en/rest-api/security/clear-cache.asciidoc
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,10 @@ There are realm settings that you can use to configure the user cache. For more
information, see
<<controlling-user-cache>>.

To evict roles from the role cache, see the
To evict roles from the role cache, see the
<<security-api-clear-role-cache,Clear roles cache API>>.
To evict privileges from the privilege cache, see the
<<security-api-clear-privilege-cache,Clear privileges cache API>>.

[[security-api-clear-path-params]]
==== {api-path-parms-title}
Expand Down
43 changes: 43 additions & 0 deletions x-pack/docs/en/rest-api/security/clear-privileges-cache.asciidoc
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
[role="xpack"]
[[security-api-clear-privilege-cache]]
=== Clear privileges cache API
++++
<titleabbrev>Clear privileges cache</titleabbrev>
++++

Evicts privileges from the native application privilege cache.
The cache is also automatically cleared for applications that have their privileges updated.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I know we don't do this in the other clear cache docs (but we should strive to improve) however I think it's worth stating that the cache is automatically cleared when a privilege is modified.

I mention it because kibana_system has permission to update privileges, but not clear the cache. This could seem like a problem, but it is actually fine, because we'll do it automatically.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes makes sense. I'll add "The cache is also automatically cleared for applications that have their privileges updated."

[[security-api-clear-privilege-cache-request]]
==== {api-request-title}

`POST /_security/privilege/<application>/_clear_cache`

[[security-api-clear-privilege-cache-prereqs]]
==== {api-prereq-title}

* To use this API, you must have at least the `manage_security` cluster
privilege.

[[security-api-clear-privilege-cache-desc]]
==== {api-description-title}

For more information about the native realm, see
<<realms>> and <<native-realm>>.

[[security-api-clear-privilege-cache-path-params]]
==== {api-path-parms-title}

`application`::
(string) The name of the application. If omitted, all entries are evicted from the cache.

[[security-api-clear-privilege-cache-example]]
==== {api-examples-title}

The clear privileges cache API evicts privileges from the native application privilege cache.
For example, to clear the cache for `myapp`:

[source,console]
--------------------------------------------------
POST /_security/privilege/myapp/_clear_cache
--------------------------------------------------
Loading