-
Notifications
You must be signed in to change notification settings - Fork 26k
Add Views Security Model #141050
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
elasticsearchmachine
merged 34 commits into
elastic:main
from
jfreden:views/add_security
Mar 6, 2026
Merged
Add Views Security Model #141050
Changes from 28 commits
Commits
Show all changes
34 commits
Select commit
Hold shift + click to select a range
05f3528
Add Views Security Model
jfreden db93092
Merge branch 'main' into views/add_security
jfreden a0a95e4
Update docs/changelog/141050.yaml
jfreden 2aa7cae
Add CCS view tests
jfreden 8c712e1
Merge remote-tracking branch 'upstream/main' into views/add_security
jfreden 75fdad2
fixup! Changelog
jfreden d246aec
Merge branch 'main' into views/add_security
jfreden c65ace2
Merge remote-tracking branch 'origin/main' into views/add_security
craigtaverner 42cb008
Merge branch 'main' into views/add_security
jfreden 60f2013
Some code-review updates
craigtaverner e600412
Merge branch 'views/add_security' of github.com:jfreden/elasticsearch…
craigtaverner 9ed84ed
Merge remote-tracking branch 'origin/main' into views/add_security
craigtaverner 09194af
fixup! Remove comment
jfreden b4603e7
fixup! Remove todo
jfreden 6fb3e59
Merge branch 'main' into views/add_security
jfreden 65698ea
fixup! Code review
jfreden 4a08b72
Merge remote-tracking branch 'upstream/main' into views/add_security
jfreden f198a4b
fixup! Bug + code review
jfreden 754a956
Merge remote-tracking branch 'upstream/main' into views/add_security
jfreden 23ec0d3
Add exclusion tests
jfreden 807279f
fixup! generate error message conditionally
jfreden 1005c0d
fixup! CI
jfreden 727caff
fixup! javadoc
jfreden 7378d83
Fix exclusions and add tests
jfreden 2cd6d1b
Merge branch 'main' into views/add_security
jfreden 1672fe5
fixup! Spotless
jfreden 212b61f
Merge branch 'main' into views/add_security
jfreden d34fc96
Merge branch 'main' into views/add_security
jfreden 2a4c788
Merge branch 'main' into views/add_security
jfreden 16d53ba
fixup! Code review comments
jfreden 1e06a10
Merge branch 'main' into views/add_security
jfreden e4f5cdd
fixup! Exclusions
jfreden da6ebda
Merge branch 'main' into views/add_security
jfreden f93b715
fixup! Added simplification too fast
jfreden File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or 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,5 @@ | ||
| area: "ES|QL" | ||
| issues: [] | ||
| pr: 141050 | ||
| summary: Add Views Security Model | ||
| type: enhancement |
This file contains hidden or 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 hidden or 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 hidden or 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
155 changes: 155 additions & 0 deletions
155
.../plugin/esql/src/main/java/org/elasticsearch/xpack/esql/action/EsqlResolveViewAction.java
This file contains hidden or 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,155 @@ | ||
| /* | ||
| * 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.esql.action; | ||
|
|
||
| import org.elasticsearch.action.ActionListener; | ||
| import org.elasticsearch.action.ActionRequestValidationException; | ||
| import org.elasticsearch.action.ActionResponse; | ||
| import org.elasticsearch.action.ActionType; | ||
| import org.elasticsearch.action.IndicesRequest; | ||
| import org.elasticsearch.action.ResolvedIndexExpressions; | ||
| import org.elasticsearch.action.support.ActionFilters; | ||
| import org.elasticsearch.action.support.IndicesOptions; | ||
| import org.elasticsearch.action.support.TransportAction; | ||
| import org.elasticsearch.action.support.local.LocalClusterStateRequest; | ||
| import org.elasticsearch.action.support.local.TransportLocalProjectMetadataAction; | ||
| import org.elasticsearch.cluster.ProjectState; | ||
| import org.elasticsearch.cluster.block.ClusterBlockException; | ||
| import org.elasticsearch.cluster.block.ClusterBlockLevel; | ||
| import org.elasticsearch.cluster.metadata.IndexNameExpressionResolver; | ||
| import org.elasticsearch.cluster.metadata.View; | ||
| import org.elasticsearch.cluster.project.ProjectResolver; | ||
| import org.elasticsearch.cluster.service.ClusterService; | ||
| import org.elasticsearch.common.io.stream.StreamOutput; | ||
| import org.elasticsearch.common.util.concurrent.EsExecutors; | ||
| import org.elasticsearch.core.TimeValue; | ||
| import org.elasticsearch.injection.guice.Inject; | ||
| import org.elasticsearch.tasks.CancellableTask; | ||
| import org.elasticsearch.tasks.Task; | ||
| import org.elasticsearch.tasks.TaskId; | ||
| import org.elasticsearch.transport.TransportService; | ||
| import org.elasticsearch.xpack.esql.view.ViewResolutionService; | ||
|
|
||
| import java.io.IOException; | ||
| import java.util.Arrays; | ||
| import java.util.Map; | ||
|
|
||
| public class EsqlResolveViewAction extends TransportLocalProjectMetadataAction< | ||
| EsqlResolveViewAction.Request, | ||
| EsqlResolveViewAction.Response> { | ||
| public static final String NAME = "indices:data/read/esql/resolve_views"; | ||
| public static final ActionType<EsqlResolveViewAction.Response> TYPE = new ActionType<>(NAME); | ||
|
|
||
| private final ViewResolutionService viewResolutionService; | ||
|
|
||
| @Inject | ||
| public EsqlResolveViewAction( | ||
| TransportService transportService, | ||
| ActionFilters actionFilters, | ||
| IndexNameExpressionResolver indexNameExpressionResolver, | ||
| ClusterService clusterService, | ||
| ProjectResolver projectResolver | ||
| ) { | ||
| // TODO replace DIRECT_EXECUTOR_SERVICE when removing workaround for https://github.com/elastic/elasticsearch/issues/97916 | ||
| super(NAME, actionFilters, transportService.getTaskManager(), clusterService, EsExecutors.DIRECT_EXECUTOR_SERVICE, projectResolver); | ||
| this.viewResolutionService = new ViewResolutionService(indexNameExpressionResolver); | ||
| } | ||
|
|
||
| @Override | ||
| protected ClusterBlockException checkBlock(Request request, ProjectState state) { | ||
| return state.blocks().globalBlockedException(ClusterBlockLevel.METADATA_READ); | ||
| } | ||
|
|
||
| @Override | ||
| protected void localClusterStateOperation(Task task, Request request, ProjectState project, ActionListener<Response> listener) { | ||
| var result = viewResolutionService.resolveViews( | ||
| project, | ||
| request.indices(), | ||
| request.indicesOptions(), | ||
| request.getResolvedIndexExpressions() | ||
| ); | ||
| listener.onResponse(new EsqlResolveViewAction.Response(result.views(), result.resolvedIndexExpressions())); | ||
| } | ||
|
|
||
| public static class Request extends LocalClusterStateRequest implements IndicesRequest.Replaceable { | ||
|
|
||
| private String[] indices = new String[0]; | ||
| private ResolvedIndexExpressions resolvedIndexExpressions; | ||
| private static final IndicesOptions VIEW_INDICES_OPTIONS = IndicesOptions.builder() | ||
| .wildcardOptions(IndicesOptions.WildcardOptions.builder().resolveViews(true).allowEmptyExpressions(true)) | ||
| .concreteTargetOptions(IndicesOptions.ConcreteTargetOptions.ALLOW_UNAVAILABLE_TARGETS) | ||
| .build(); | ||
|
|
||
| public Request(TimeValue masterTimeout) { | ||
| super(masterTimeout); | ||
| } | ||
|
|
||
| @Override | ||
| public IndicesRequest indices(String... indices) { | ||
| this.indices = indices; | ||
| return this; | ||
| } | ||
|
|
||
| @Override | ||
| public Task createTask(long id, String type, String action, TaskId parentTaskId, Map<String, String> headers) { | ||
| return new CancellableTask(id, type, action, getDescription(), parentTaskId, headers); | ||
| } | ||
|
|
||
| @Override | ||
| public String[] indices() { | ||
| return indices; | ||
| } | ||
|
|
||
| @Override | ||
| public IndicesOptions indicesOptions() { | ||
| return VIEW_INDICES_OPTIONS; | ||
| } | ||
|
|
||
| @Override | ||
| public ActionRequestValidationException validate() { | ||
| return null; | ||
| } | ||
|
|
||
| @Override | ||
| public String toString() { | ||
| return "EsqlResolveViewAction.Request={indices:" + Arrays.toString(indices) + "}"; | ||
| } | ||
|
|
||
| @Override | ||
| public void setResolvedIndexExpressions(ResolvedIndexExpressions expressions) { | ||
| this.resolvedIndexExpressions = expressions; | ||
| } | ||
|
|
||
| @Override | ||
| public ResolvedIndexExpressions getResolvedIndexExpressions() { | ||
| return this.resolvedIndexExpressions; | ||
| } | ||
| } | ||
|
|
||
| public static class Response extends ActionResponse { | ||
| private final View[] views; | ||
| private final ResolvedIndexExpressions resolvedIndexExpressions; | ||
|
|
||
| public Response(View[] views, ResolvedIndexExpressions resolvedIndexExpressions) { | ||
| this.views = views; | ||
| this.resolvedIndexExpressions = resolvedIndexExpressions; | ||
| } | ||
|
|
||
| @Override | ||
| public void writeTo(StreamOutput out) throws IOException { | ||
| TransportAction.localOnly(); | ||
| } | ||
|
|
||
| public View[] views() { | ||
| return views; | ||
| } | ||
|
|
||
| public ResolvedIndexExpressions getResolvedIndexExpressions() { | ||
| return resolvedIndexExpressions; | ||
| } | ||
| } | ||
| } |
This file contains hidden or 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 |
|---|---|---|
|
|
@@ -6,6 +6,8 @@ | |
| */ | ||
| package org.elasticsearch.xpack.esql.core.tree; | ||
|
|
||
| import org.elasticsearch.action.ActionListener; | ||
| import org.elasticsearch.action.support.SubscribableListener; | ||
| import org.elasticsearch.common.io.stream.NamedWriteable; | ||
| import org.elasticsearch.xpack.esql.core.QlIllegalArgumentException; | ||
| import org.elasticsearch.xpack.esql.core.expression.NameId; | ||
|
|
@@ -273,6 +275,50 @@ public <E extends T> T transformDown(Predicate<Node<?>> nodePredicate, Function< | |
| return transformDown((t) -> (nodePredicate.test(t) ? rule.apply((E) t) : t)); | ||
| } | ||
|
|
||
| /** | ||
| * Asynchronous variant of {@link #transformDown(Function)} that allows the transformation rule to perform | ||
| * async I/O operations (e.g., transport actions) without blocking the caller thread. | ||
| * <p> | ||
| * Children are transformed sequentially, not concurrently, one after another in order. | ||
| * This method is intended for cases where async I/O is needed during transformation, not for parallel | ||
| * processing. | ||
| */ | ||
| @SuppressWarnings("unchecked") | ||
| public void transformDown(BiConsumer<? super T, ActionListener<T>> rule, ActionListener<T> listener) { | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Note: I'm deferring to the other reviewers here since it's ES|QL code. It looks complicated but I'm assuming there's not way around it. |
||
| rule.accept((T) this, listener.delegateFailureAndWrap((originalListener, root) -> { | ||
| Node<T> node = this.equals(root) ? this : root; | ||
| node.transformChildren((child, childListener) -> child.transformDown(rule, childListener), originalListener); | ||
| })); | ||
| } | ||
|
|
||
| @SuppressWarnings("unchecked") | ||
| protected void transformChildren(BiConsumer<T, ActionListener<T>> traversalOperation, ActionListener<T> listener) { | ||
| if (children.isEmpty()) { | ||
| listener.onResponse((T) this); | ||
| return; | ||
| } | ||
|
|
||
| final Holder<List<T>> updatedChildren = new Holder<>(); | ||
| SubscribableListener<Void> chain = SubscribableListener.newForked(l -> l.onResponse(null)); | ||
| for (int i = 0; i < children.size(); i++) { | ||
| var index = i; | ||
| var child = children.get(index); | ||
| chain = chain.andThen(originalListener -> { | ||
| traversalOperation.accept(child, originalListener.delegateFailureAndWrap((o, maybeTransformed) -> { | ||
| if (maybeTransformed.equals(child) == false) { | ||
| if (updatedChildren.get() == null) { | ||
| updatedChildren.set(new ArrayList<>(children)); | ||
| } | ||
| updatedChildren.get().set(index, maybeTransformed); | ||
| } | ||
| o.onResponse(null); | ||
| })); | ||
| }); | ||
| } | ||
| chain.andThenApply(ignored -> updatedChildren.get() == null ? (T) this : replaceChildrenSameSize(updatedChildren.get())) | ||
| .addListener(listener); | ||
| } | ||
|
|
||
| @SuppressWarnings("unchecked") | ||
| public T transformUp(Function<? super T, ? extends T> rule) { | ||
| T transformed = transformChildren(child -> child.transformUp(rule)); | ||
|
|
||
This file contains hidden or 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.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.