Skip to content

Commit 6932053

Browse files
authored
Add seperate interface for UIAM authentication (#138635)
This PR separate allowCrossProject from IndicesRequest.Replaceable into its own interface so that it can be implemented by requests that are not replaceable, such as ES|QL query request. Relates: ES-13662 Co-authored-by: Slobodan Adamović <[email protected]>
1 parent 933354b commit 6932053

File tree

4 files changed

+117
-14
lines changed

4 files changed

+117
-14
lines changed

server/src/main/java/org/elasticsearch/action/IndicesRequest.java

Lines changed: 22 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,27 @@ default boolean includeDataStreams() {
4343
return false;
4444
}
4545

46-
interface Replaceable extends IndicesRequest {
46+
/**
47+
* Interface for indicating potential work related to cross-project authentication and authorization.
48+
*/
49+
interface CrossProjectCandidate {
50+
51+
/**
52+
* Determines whether the request type can support cross-project processing. Cross-project processing entails
53+
* 1. UIAM authentication and authorization projects resolution.
54+
* 2. If applicable, cross-project flat-world index resolution and error handling
55+
* Note: this method only determines in the request _supports_ cross-project. Whether cross-project processing
56+
* is actually performed depends on other factors such as:
57+
* - Whether CPS is enabled which impacts both 1 and 2.
58+
* - Whether {@link IndicesOptions} supports it when the request is an {@link IndicesRequest}. This only impacts 2.
59+
* See also {@link org.elasticsearch.search.crossproject.CrossProjectModeDecider}.
60+
*/
61+
default boolean allowsCrossProject() {
62+
return false;
63+
}
64+
}
65+
66+
interface Replaceable extends IndicesRequest, CrossProjectCandidate {
4767
/**
4868
* Sets the indices that the action relates to.
4969
*/
@@ -81,15 +101,6 @@ default boolean allowsRemoteIndices() {
81101
return false;
82102
}
83103

84-
/**
85-
* Determines whether the request type allows cross-project processing. Cross-project processing entails cross-project search
86-
* index resolution and error handling. Note: this method only determines in the request _supports_ cross-project.
87-
* Whether cross-project processing is actually performed is determined by {@link IndicesOptions}.
88-
*/
89-
default boolean allowsCrossProject() {
90-
return false;
91-
}
92-
93104
@Nullable // if no routing is specified
94105
default String getProjectRouting() {
95106
return null;
@@ -103,7 +114,7 @@ default String getProjectRouting() {
103114
*
104115
* This may change with https://github.com/elastic/elasticsearch/issues/105598
105116
*/
106-
interface SingleIndexNoWildcards extends IndicesRequest {
117+
interface SingleIndexNoWildcards extends IndicesRequest, CrossProjectCandidate {
107118
default boolean allowsRemoteIndices() {
108119
return true;
109120
}

server/src/main/java/org/elasticsearch/search/crossproject/CrossProjectModeDecider.java

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -44,11 +44,18 @@ public boolean crossProjectEnabled() {
4444
return crossProjectEnabled;
4545
}
4646

47-
public boolean resolvesCrossProject(IndicesRequest.Replaceable request) {
47+
public boolean resolvesCrossProject(IndicesRequest.CrossProjectCandidate request) {
4848
if (crossProjectEnabled == false) {
4949
return false;
5050
}
51+
5152
// TODO: The following check can be an method on the request itself
52-
return request.allowsCrossProject() && request.indicesOptions().resolveCrossProjectIndexExpression();
53+
if (request.allowsCrossProject() == false) {
54+
return false;
55+
}
56+
if (request instanceof IndicesRequest indicesRequest) {
57+
return indicesRequest.indicesOptions().resolveCrossProjectIndexExpression();
58+
}
59+
return true;
5360
}
5461
}
Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
/*
2+
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
3+
* or more contributor license agreements. Licensed under the "Elastic License
4+
* 2.0", the "GNU Affero General Public License v3.0 only", and the "Server Side
5+
* Public License v 1"; you may not use this file except in compliance with, at
6+
* your election, the "Elastic License 2.0", the "GNU Affero General Public
7+
* License v3.0 only", or the "Server Side Public License, v 1".
8+
*/
9+
10+
package org.elasticsearch.search.crossproject;
11+
12+
import org.elasticsearch.action.IndicesRequest;
13+
import org.elasticsearch.action.support.IndicesOptions;
14+
import org.elasticsearch.common.settings.Settings;
15+
import org.elasticsearch.test.ESTestCase;
16+
17+
import static org.hamcrest.Matchers.is;
18+
19+
public class CrossProjectModeDeciderTests extends ESTestCase {
20+
21+
public void testResolvesCrossProject() {
22+
doTestResolvesCrossProject(new CrossProjectModeDecider(Settings.builder().build()), false);
23+
doTestResolvesCrossProject(
24+
new CrossProjectModeDecider(Settings.builder().put("serverless.cross_project.enabled", true).build()),
25+
true
26+
);
27+
}
28+
29+
private void doTestResolvesCrossProject(CrossProjectModeDecider crossProjectModeDecider, boolean expected) {
30+
final var cpsIndicesOptions = IndicesOptions.builder(org.elasticsearch.action.support.IndicesOptions.DEFAULT)
31+
.crossProjectModeOptions(new IndicesOptions.CrossProjectModeOptions(true))
32+
.build();
33+
34+
final var candidateButNotAllowed = randomFrom(
35+
new CrossProjectCandidateImpl(false),
36+
new IndicesRequestImpl(false, randomFrom(IndicesOptions.DEFAULT, cpsIndicesOptions))
37+
);
38+
final var candidateAndAllowed = new CrossProjectCandidateImpl(true);
39+
40+
final var indicesRequestNoCpsOption = new IndicesRequestImpl(true, IndicesOptions.DEFAULT);
41+
final var indicesRequestWithCpsOption = new IndicesRequestImpl(true, cpsIndicesOptions);
42+
43+
assertFalse(crossProjectModeDecider.resolvesCrossProject(candidateButNotAllowed));
44+
assertFalse(crossProjectModeDecider.resolvesCrossProject(indicesRequestNoCpsOption));
45+
46+
assertThat(crossProjectModeDecider.resolvesCrossProject(candidateAndAllowed), is(expected));
47+
assertThat(crossProjectModeDecider.resolvesCrossProject(indicesRequestWithCpsOption), is(expected));
48+
}
49+
50+
private static class CrossProjectCandidateImpl implements IndicesRequest.CrossProjectCandidate {
51+
52+
private boolean allowsCrossProject;
53+
54+
CrossProjectCandidateImpl(boolean allowsCrossProject) {
55+
this.allowsCrossProject = allowsCrossProject;
56+
}
57+
58+
@Override
59+
public boolean allowsCrossProject() {
60+
return allowsCrossProject;
61+
}
62+
}
63+
64+
private static class IndicesRequestImpl extends CrossProjectCandidateImpl implements IndicesRequest {
65+
66+
private IndicesOptions indicesOptions;
67+
68+
IndicesRequestImpl(boolean allowsCrossProject, IndicesOptions indicesOptions) {
69+
super(allowsCrossProject);
70+
this.indicesOptions = indicesOptions;
71+
}
72+
73+
@Override
74+
public String[] indices() {
75+
return new String[0];
76+
}
77+
78+
@Override
79+
public IndicesOptions indicesOptions() {
80+
return indicesOptions;
81+
}
82+
}
83+
}

x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/authz/IndicesAndAliasesResolver.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -167,7 +167,8 @@ ResolvedIndices tryResolveWithoutWildcards(String action, TransportRequest trans
167167
}
168168

169169
boolean resolvesCrossProject(TransportRequest request) {
170-
return request instanceof IndicesRequest.Replaceable replaceable && crossProjectModeDecider.resolvesCrossProject(replaceable);
170+
return request instanceof IndicesRequest.CrossProjectCandidate crossProjectCandidate
171+
&& crossProjectModeDecider.resolvesCrossProject(crossProjectCandidate);
171172
}
172173

173174
private static boolean requiresWildcardExpansion(IndicesRequest indicesRequest) {
@@ -560,6 +561,7 @@ private static void setResolvedIndexExpressionsIfUnset(IndicesRequest.Replaceabl
560561
+ "]";
561562
logger.debug(message);
562563
// we are excepting `*,-*` below since we've observed this already -- keeping this assertion to catch other cases
564+
// If more exceptions are found, we can add a comment to above linked issue and relax this check further
563565
assert replaceable.indices() == null || isNoneExpression(replaceable.indices()) : message;
564566
}
565567
}

0 commit comments

Comments
 (0)