forked from elastic/elasticsearch
-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Refactor Async Search security into a common class
This commit moves code from AsyncTaskIndexService and DeleteAsyncResultsService into a new AsyncSearchSecurity so that all security code is centralised.,
- Loading branch information
Showing
5 changed files
with
289 additions
and
209 deletions.
There are no files selected for viewing
109 changes: 109 additions & 0 deletions
109
x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/async/AsyncSearchSecurity.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,109 @@ | ||
/* | ||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one | ||
* or more contributor license agreements. Licensed under the Elastic License | ||
* 2.0; you may not use this file except in compliance with the Elastic License | ||
* 2.0. | ||
*/ | ||
|
||
package org.elasticsearch.xpack.core.async; | ||
|
||
import org.elasticsearch.ResourceNotFoundException; | ||
import org.elasticsearch.action.ActionListener; | ||
import org.elasticsearch.action.get.GetRequest; | ||
import org.elasticsearch.client.internal.Client; | ||
import org.elasticsearch.client.internal.OriginSettingClient; | ||
import org.elasticsearch.common.Strings; | ||
import org.elasticsearch.search.fetch.subphase.FetchSourceContext; | ||
import org.elasticsearch.xpack.core.security.SecurityContext; | ||
import org.elasticsearch.xpack.core.security.action.user.HasPrivilegesAction; | ||
import org.elasticsearch.xpack.core.security.action.user.HasPrivilegesRequest; | ||
import org.elasticsearch.xpack.core.security.authc.Authentication; | ||
import org.elasticsearch.xpack.core.security.authz.RoleDescriptor; | ||
import org.elasticsearch.xpack.core.security.authz.privilege.ClusterPrivilegeResolver; | ||
|
||
import java.io.IOException; | ||
import java.util.Map; | ||
import java.util.Objects; | ||
import java.util.function.Consumer; | ||
|
||
public class AsyncSearchSecurity { | ||
|
||
private static final FetchSourceContext FETCH_HEADERS_FIELD_CONTEXT = FetchSourceContext.of( | ||
true, | ||
new String[] { AsyncTaskIndexService.HEADERS_FIELD }, | ||
Strings.EMPTY_ARRAY | ||
); | ||
|
||
private final String indexName; | ||
private final SecurityContext securityContext; | ||
private final Client client; | ||
private final OriginSettingClient clientWithOrigin; | ||
|
||
public AsyncSearchSecurity(String indexName, SecurityContext securityContext, Client client, String origin) { | ||
this.securityContext = securityContext; | ||
this.client = client; | ||
this.clientWithOrigin = new OriginSettingClient(client, origin); | ||
this.indexName = indexName; | ||
} | ||
|
||
public void currentUserHasCancelTaskPrivilege(Consumer<Boolean> consumer) { | ||
final Authentication current = securityContext.getAuthentication(); | ||
if (current != null) { | ||
HasPrivilegesRequest req = new HasPrivilegesRequest(); | ||
req.username(current.getEffectiveSubject().getUser().principal()); | ||
req.clusterPrivileges(ClusterPrivilegeResolver.CANCEL_TASK.name()); | ||
req.indexPrivileges(new RoleDescriptor.IndicesPrivileges[] {}); | ||
req.applicationPrivileges(new RoleDescriptor.ApplicationResourcePrivileges[] {}); | ||
try { | ||
client.execute( | ||
HasPrivilegesAction.INSTANCE, | ||
req, | ||
ActionListener.wrap(resp -> consumer.accept(resp.isCompleteMatch()), exc -> consumer.accept(false)) | ||
); | ||
} catch (Exception exc) { | ||
consumer.accept(false); | ||
} | ||
} else { | ||
consumer.accept(false); | ||
} | ||
} | ||
|
||
public boolean currentUserHasAccessToTask(AsyncTask asyncTask) throws IOException { | ||
Objects.requireNonNull(asyncTask, "Task cannot be null"); | ||
return currentUserHasAccessToTaskWithHeaders(asyncTask.getOriginHeaders()); | ||
} | ||
|
||
public boolean currentUserHasAccessToTaskWithHeaders(Map<String, String> headers) throws IOException { | ||
return securityContext.canIAccessResourcesCreatedWithHeaders(headers); | ||
} | ||
|
||
/** | ||
* Checks if the current user can access the async search result of the original user. | ||
*/ | ||
void ensureAuthenticatedUserCanDeleteFromIndex(AsyncExecutionId executionId, ActionListener<Void> listener) { | ||
getTaskHeadersFromIndex(executionId, listener.map(headers -> { | ||
if (currentUserHasAccessToTaskWithHeaders(headers)) { | ||
return null; | ||
} else { | ||
throw new ResourceNotFoundException(executionId.getEncoded()); | ||
} | ||
})); | ||
} | ||
|
||
private void getTaskHeadersFromIndex(AsyncExecutionId executionId, ActionListener<Map<String, String>> listener) { | ||
GetRequest internalGet = new GetRequest(indexName).preference(executionId.getEncoded()) | ||
.id(executionId.getDocId()) | ||
.fetchSourceContext(FETCH_HEADERS_FIELD_CONTEXT); | ||
|
||
clientWithOrigin.get(internalGet, ActionListener.wrap(get -> { | ||
if (get.isExists() == false) { | ||
listener.onFailure(new ResourceNotFoundException(executionId.getEncoded())); | ||
return; | ||
} | ||
// Check authentication for the user | ||
@SuppressWarnings("unchecked") | ||
Map<String, String> headers = (Map<String, String>) get.getSource().get(AsyncTaskIndexService.HEADERS_FIELD); | ||
listener.onResponse(headers); | ||
}, exc -> listener.onFailure(new ResourceNotFoundException(executionId.getEncoded())))); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.