Skip to content

Commit 8aaf278

Browse files
committed
Remove special handling for do_not_fail_on_forbidden on cluster actions
This special handling does not provide any benefits - rather it just causes some inconsistent behavior. Fixes opensearch-project#4485 Signed-off-by: Nils Bandener <nils.bandener@eliatra.com>
1 parent 37afcaa commit 8aaf278

File tree

4 files changed

+109
-108
lines changed

4 files changed

+109
-108
lines changed

src/integrationTest/java/org/opensearch/security/DoNotFailOnForbiddenTests.java

+30-5
Original file line numberDiff line numberDiff line change
@@ -278,7 +278,7 @@ public void shouldSearchForDocumentsViaAll_negative() throws IOException {
278278
@Test
279279
public void shouldMGetDocument_positive() throws IOException {
280280
try (RestHighLevelClient restHighLevelClient = cluster.getRestHighLevelClient(LIMITED_USER)) {
281-
MultiGetRequest request = new MultiGetRequest().add(BOTH_INDEX_PATTERN, ID_1).add(BOTH_INDEX_PATTERN, ID_4);
281+
MultiGetRequest request = new MultiGetRequest().add(MARVELOUS_SONGS, ID_1).add(MARVELOUS_SONGS, ID_4);
282282

283283
MultiGetResponse response = restHighLevelClient.mget(request, DEFAULT);
284284

@@ -296,12 +296,35 @@ public void shouldMGetDocument_positive() throws IOException {
296296
}
297297
}
298298

299+
@Test
300+
public void shouldMGetDocument_partial() throws Exception {
301+
try (RestHighLevelClient restHighLevelClient = cluster.getRestHighLevelClient(LIMITED_USER)) {
302+
MultiGetRequest request = new MultiGetRequest().add(MARVELOUS_SONGS, ID_1).add(HORRIBLE_SONGS, ID_4);
303+
304+
MultiGetResponse response = restHighLevelClient.mget(request, DEFAULT);
305+
306+
MultiGetItemResponse[] responses = response.getResponses();
307+
assertThat(responses, arrayWithSize(2));
308+
MultiGetItemResponse firstResult = responses[0];
309+
MultiGetItemResponse secondResult = responses[1];
310+
assertThat(firstResult.getFailure(), nullValue());
311+
assertThat(
312+
firstResult.getResponse(),
313+
allOf(containDocument(MARVELOUS_SONGS, ID_1), documentContainField(FIELD_TITLE, TITLE_MAGNUM_OPUS))
314+
);
315+
assertThat(secondResult.getFailure().getMessage(), containsString("no permissions for [indices:data/read/mget[shard]]"));
316+
}
317+
}
318+
299319
@Test
300320
public void shouldMGetDocument_negative() throws IOException {
301321
try (RestHighLevelClient restHighLevelClient = cluster.getRestHighLevelClient(LIMITED_USER)) {
302322
MultiGetRequest request = new MultiGetRequest().add(HORRIBLE_SONGS, ID_4);
303-
304-
assertThatThrownBy(() -> restHighLevelClient.mget(request, DEFAULT), statusException(FORBIDDEN));
323+
MultiGetResponse response = restHighLevelClient.mget(request, DEFAULT);
324+
MultiGetItemResponse[] responses = response.getResponses();
325+
assertThat(responses, arrayWithSize(1));
326+
MultiGetItemResponse firstResult = responses[0];
327+
assertThat(firstResult.getFailure().getMessage(), containsString("no permissions for [indices:data/read/mget[shard]]"));
305328
}
306329
}
307330

@@ -331,8 +354,10 @@ public void shouldMSearchDocument_negative() throws IOException {
331354
try (RestHighLevelClient restHighLevelClient = cluster.getRestHighLevelClient(LIMITED_USER)) {
332355
MultiSearchRequest request = new MultiSearchRequest();
333356
request.add(queryStringQueryRequest(FORBIDDEN_INDEX_ALIAS, QUERY_TITLE_POISON));
334-
335-
assertThatThrownBy(() -> restHighLevelClient.msearch(request, DEFAULT), statusException(FORBIDDEN));
357+
MultiSearchResponse response = restHighLevelClient.msearch(request, DEFAULT);
358+
MultiSearchResponse.Item[] responses = response.getResponses();
359+
assertThat(responses, Matchers.arrayWithSize(1));
360+
assertThat(responses[0].getFailure().getMessage(), containsString("no permissions for [indices:data/read/search]"));
336361
}
337362
}
338363

src/main/java/org/opensearch/security/privileges/PrivilegesEvaluator.java

-28
Original file line numberDiff line numberDiff line change
@@ -411,34 +411,6 @@ public PrivilegesEvaluatorResponse evaluate(
411411
}
412412
}
413413

414-
if (dnfofEnabled && (action0.startsWith("indices:data/read/")) && !requestedResolved.getAllIndices().isEmpty()) {
415-
416-
if (requestedResolved.getAllIndices().isEmpty()) {
417-
presponse.missingPrivileges.clear();
418-
presponse.allowed = true;
419-
return presponse;
420-
}
421-
422-
Set<String> reduced = securityRoles.reduce(
423-
requestedResolved,
424-
user,
425-
new String[] { action0 },
426-
resolver,
427-
clusterService
428-
);
429-
430-
if (reduced.isEmpty()) {
431-
presponse.allowed = false;
432-
return presponse;
433-
}
434-
435-
if (irr.replace(request, true, reduced.toArray(new String[0]))) {
436-
presponse.missingPrivileges.clear();
437-
presponse.allowed = true;
438-
return presponse;
439-
}
440-
}
441-
442414
if (isDebugEnabled) {
443415
log.debug("Allowed because we have cluster permissions for {}", action0);
444416
}

src/main/java/org/opensearch/security/resolver/IndexResolverReplacer.java

+73-73
Original file line numberDiff line numberDiff line change
@@ -176,9 +176,9 @@ private AlreadyResolvedKey(final IndicesOptions indicesOptions, final boolean en
176176
}
177177

178178
private AlreadyResolvedKey(
179-
final IndicesOptions indicesOptions,
180-
final boolean enableCrossClusterResolution,
181-
final String[] original
179+
final IndicesOptions indicesOptions,
180+
final boolean enableCrossClusterResolution,
181+
final String[] original
182182
) {
183183
this.indicesOptions = indicesOptions;
184184
this.enableCrossClusterResolution = enableCrossClusterResolution;
@@ -191,8 +191,8 @@ public boolean equals(Object o) {
191191
if (o == null || getClass() != o.getClass()) return false;
192192
AlreadyResolvedKey that = (AlreadyResolvedKey) o;
193193
return enableCrossClusterResolution == that.enableCrossClusterResolution
194-
&& Objects.equals(indicesOptions, that.indicesOptions)
195-
&& Arrays.equals(original, that.original);
194+
&& Objects.equals(indicesOptions, that.indicesOptions)
195+
&& Arrays.equals(original, that.original);
196196
}
197197

198198
@Override
@@ -213,10 +213,10 @@ public int hashCode() {
213213
}
214214

215215
private void resolveIndexPatterns(
216-
final String name,
217-
final IndicesOptions indicesOptions,
218-
final boolean enableCrossClusterResolution,
219-
final String[] original
216+
final String name,
217+
final IndicesOptions indicesOptions,
218+
final boolean enableCrossClusterResolution,
219+
final String[] original
220220
) {
221221
final boolean isTraceEnabled = log.isTraceEnabled();
222222
if (isTraceEnabled) {
@@ -239,11 +239,11 @@ private void resolveIndexPatterns(
239239
if (remoteClusterService.isCrossClusterSearchEnabled() && enableCrossClusterResolution) {
240240
remoteIndices = new HashSet<>();
241241
final Map<String, OriginalIndices> remoteClusterIndices = OpenSearchSecurityPlugin.GuiceHolder.getRemoteClusterService()
242-
.groupIndices(indicesOptions, original, idx -> resolver.hasIndexAbstraction(idx, clusterService.state()));
242+
.groupIndices(indicesOptions, original, idx -> resolver.hasIndexAbstraction(idx, clusterService.state()));
243243
final Set<String> remoteClusters = remoteClusterIndices.keySet()
244-
.stream()
245-
.filter(k -> !RemoteClusterService.LOCAL_CLUSTER_GROUP_KEY.equals(k))
246-
.collect(Collectors.toSet());
244+
.stream()
245+
.filter(k -> !RemoteClusterService.LOCAL_CLUSTER_GROUP_KEY.equals(k))
246+
.collect(Collectors.toSet());
247247
for (String remoteCluster : remoteClusters) {
248248
for (String remoteIndex : remoteClusterIndices.get(remoteCluster).indices()) {
249249
remoteIndices.add(RemoteClusterService.buildRemoteIndexName(remoteCluster, remoteIndex));
@@ -261,10 +261,10 @@ private void resolveIndexPatterns(
261261

262262
if (isTraceEnabled) {
263263
log.trace(
264-
"CCS is enabled, we found this local patterns "
265-
+ localRequestedPatterns
266-
+ " and this remote patterns: "
267-
+ remoteIndices
264+
"CCS is enabled, we found this local patterns "
265+
+ localRequestedPatterns
266+
+ " and this remote patterns: "
267+
+ remoteIndices
268268
);
269269
}
270270

@@ -294,31 +294,31 @@ private void resolveIndexPatterns(
294294
else {
295295
final ClusterState state = clusterService.state();
296296
final Set<String> dateResolvedLocalRequestedPatterns = localRequestedPatterns.stream()
297-
.map(resolver::resolveDateMathExpression)
298-
.collect(Collectors.toSet());
297+
.map(resolver::resolveDateMathExpression)
298+
.collect(Collectors.toSet());
299299
final WildcardMatcher dateResolvedMatcher = WildcardMatcher.from(dateResolvedLocalRequestedPatterns);
300300
// fill matchingAliases
301301
final Map<String, IndexAbstraction> lookup = state.metadata().getIndicesLookup();
302302
matchingAliases = lookup.entrySet()
303-
.stream()
304-
.filter(e -> e.getValue().getType() == ALIAS)
305-
.map(Map.Entry::getKey)
306-
.filter(dateResolvedMatcher)
307-
.collect(Collectors.toSet());
303+
.stream()
304+
.filter(e -> e.getValue().getType() == ALIAS)
305+
.map(Map.Entry::getKey)
306+
.filter(dateResolvedMatcher)
307+
.collect(Collectors.toSet());
308308

309309
final boolean isDebugEnabled = log.isDebugEnabled();
310310
try {
311311
matchingAllIndices = Arrays.asList(
312-
resolver.concreteIndexNames(state, indicesOptions, localRequestedPatterns.toArray(new String[0]))
312+
resolver.concreteIndexNames(state, indicesOptions, localRequestedPatterns.toArray(new String[0]))
313313
);
314314
matchingDataStreams = resolver.dataStreamNames(state, indicesOptions, localRequestedPatterns.toArray(new String[0]));
315315

316316
if (isDebugEnabled) {
317317
log.debug(
318-
"Resolved pattern {} to indices: {} and data-streams: {}",
319-
localRequestedPatterns,
320-
matchingAllIndices,
321-
matchingDataStreams
318+
"Resolved pattern {} to indices: {} and data-streams: {}",
319+
localRequestedPatterns,
320+
matchingAllIndices,
321+
matchingDataStreams
322322
);
323323
}
324324
} catch (IndexNotFoundException e1) {
@@ -336,15 +336,15 @@ private void resolveIndexPatterns(
336336

337337
if (isTraceEnabled) {
338338
log.trace(
339-
"Resolved patterns {} for {} ({}) to [aliases {}, allIndices {}, dataStreams {}, originalRequested{}, remote indices {}]",
340-
original,
341-
name,
342-
this.name,
343-
matchingAliases,
344-
matchingAllIndices,
345-
matchingDataStreams,
346-
Arrays.toString(original),
347-
remoteIndices
339+
"Resolved patterns {} for {} ({}) to [aliases {}, allIndices {}, dataStreams {}, originalRequested{}, remote indices {}]",
340+
original,
341+
name,
342+
this.name,
343+
matchingAliases,
344+
matchingAllIndices,
345+
matchingDataStreams,
346+
Arrays.toString(original),
347+
remoteIndices
348348
);
349349
}
350350

@@ -358,11 +358,11 @@ private void resolveToLocalAll() {
358358
}
359359

360360
private void resolveTo(
361-
Iterable<String> matchingAliases,
362-
Iterable<String> matchingAllIndices,
363-
Iterable<String> matchingDataStreams,
364-
String[] original,
365-
Iterable<String> remoteIndices
361+
Iterable<String> matchingAliases,
362+
Iterable<String> matchingAllIndices,
363+
Iterable<String> matchingDataStreams,
364+
String[] original,
365+
Iterable<String> remoteIndices
366366
) {
367367
aliases.addAll(matchingAliases);
368368
allIndices.addAll(matchingAllIndices);
@@ -375,8 +375,8 @@ private void resolveTo(
375375
public String[] provide(String[] original, Object localRequest, boolean supportsReplace) {
376376
final IndicesOptions indicesOptions = indicesOptionsFrom(localRequest);
377377
final boolean enableCrossClusterResolution = localRequest instanceof FieldCapabilitiesRequest
378-
|| localRequest instanceof SearchRequest
379-
|| localRequest instanceof ResolveIndexAction.Request;
378+
|| localRequest instanceof SearchRequest
379+
|| localRequest instanceof ResolveIndexAction.Request;
380380
// skip the whole thing if we have seen this exact resolveIndexPatterns request
381381
final AlreadyResolvedKey alreadyResolvedKey;
382382
if (original != null) {
@@ -392,8 +392,8 @@ public String[] provide(String[] original, Object localRequest, boolean supports
392392

393393
Resolved resolved(IndicesOptions indicesOptions) {
394394
final Resolved resolved = alreadyResolved.isEmpty()
395-
? Resolved._LOCAL_ALL
396-
: new Resolved(aliases.build(), allIndices.build(), originalRequested.build(), remoteIndices.build(), indicesOptions);
395+
? Resolved._LOCAL_ALL
396+
: new Resolved(aliases.build(), allIndices.build(), originalRequested.build(), remoteIndices.build(), indicesOptions);
397397

398398
if (log.isTraceEnabled()) {
399399
log.trace("Finally resolved for {}: {}", name, resolved);
@@ -413,7 +413,7 @@ public String[] provide(String[] original, Object request, boolean supportsRepla
413413
if (retainMode && !isAllWithNoRemote(original)) {
414414
final Resolved resolved = resolveRequest(request);
415415
final List<String> retained = WildcardMatcher.from(resolved.getAllIndices())
416-
.getMatchAny(replacements, Collectors.toList());
416+
.getMatchAny(replacements, Collectors.toList());
417417
retained.addAll(resolved.getRemoteIndices());
418418
return retained.toArray(new String[0]);
419419
}
@@ -442,11 +442,11 @@ public final static class Resolved {
442442
private static final ImmutableSet<String> All_SET = ImmutableSet.of(ANY);
443443
private static final Set<String> types = All_SET;
444444
public static final Resolved _LOCAL_ALL = new Resolved(
445-
All_SET,
446-
All_SET,
447-
All_SET,
448-
ImmutableSet.of(),
449-
SearchRequest.DEFAULT_INDICES_OPTIONS
445+
All_SET,
446+
All_SET,
447+
All_SET,
448+
ImmutableSet.of(),
449+
SearchRequest.DEFAULT_INDICES_OPTIONS
450450
);
451451

452452
private final Set<String> aliases;
@@ -457,18 +457,18 @@ public final static class Resolved {
457457
private final IndicesOptions indicesOptions;
458458

459459
public Resolved(
460-
final ImmutableSet<String> aliases,
461-
final ImmutableSet<String> allIndices,
462-
final ImmutableSet<String> originalRequested,
463-
final ImmutableSet<String> remoteIndices,
464-
IndicesOptions indicesOptions
460+
final ImmutableSet<String> aliases,
461+
final ImmutableSet<String> allIndices,
462+
final ImmutableSet<String> originalRequested,
463+
final ImmutableSet<String> remoteIndices,
464+
IndicesOptions indicesOptions
465465
) {
466466
this.aliases = aliases;
467467
this.allIndices = allIndices;
468468
this.originalRequested = originalRequested;
469469
this.remoteIndices = remoteIndices;
470470
this.isLocalAll = IndexResolverReplacer.isLocalAll(originalRequested.toArray(new String[0]))
471-
|| (aliases.contains("*") && allIndices.contains("*"));
471+
|| (aliases.contains("*") && allIndices.contains("*"));
472472
this.indicesOptions = indicesOptions;
473473
}
474474

@@ -507,16 +507,16 @@ public Set<String> getRemoteIndices() {
507507
@Override
508508
public String toString() {
509509
return "Resolved [aliases="
510-
+ aliases
511-
+ ", allIndices="
512-
+ allIndices
513-
+ ", types="
514-
+ types
515-
+ ", originalRequested="
516-
+ originalRequested
517-
+ ", remoteIndices="
518-
+ remoteIndices
519-
+ "]";
510+
+ aliases
511+
+ ", allIndices="
512+
+ allIndices
513+
+ ", types="
514+
+ types
515+
+ ", originalRequested="
516+
+ originalRequested
517+
+ ", remoteIndices="
518+
+ remoteIndices
519+
+ "]";
520520
}
521521

522522
@Override
@@ -690,14 +690,14 @@ private boolean getOrReplaceAllIndices(final Object request, final IndicesProvid
690690

691691
if (snapshotInfo == null) {
692692
log.warn(
693-
"snapshot repository '" + restoreRequest.repository() + "', snapshot '" + restoreRequest.snapshot() + "' not found"
693+
"snapshot repository '" + restoreRequest.repository() + "', snapshot '" + restoreRequest.snapshot() + "' not found"
694694
);
695695
provider.provide(new String[] { "*" }, request, false);
696696
} else {
697697
final List<String> requestedResolvedIndices = IndexUtils.filterIndices(
698-
snapshotInfo.indices(),
699-
restoreRequest.indices(),
700-
restoreRequest.indicesOptions()
698+
snapshotInfo.indices(),
699+
restoreRequest.indices(),
700+
restoreRequest.indicesOptions()
701701
);
702702
final List<String> renamedTargetIndices = renamedIndices(restoreRequest, requestedResolvedIndices);
703703
// final Set<String> indices = new HashSet<>(requestedResolvedIndices);

src/test/java/org/opensearch/security/IntegrationTests.java

+6-2
Original file line numberDiff line numberDiff line change
@@ -659,7 +659,9 @@ public void testDnfof() throws Exception {
659659
+ System.lineSeparator();
660660

661661
resc = rh.executePostRequest("_msearch?pretty", msearchBody, encodeBasicHeader("user_b", "user_b"));
662-
Assert.assertEquals(403, resc.getStatusCode());
662+
Assert.assertEquals(resc.getBody(), 200, resc.getStatusCode());
663+
Assert.assertEquals(resc.getBody(), "security_exception", resc.findValueInJson("responses[0].error.type"));
664+
Assert.assertEquals(resc.getBody(), "security_exception", resc.findValueInJson("responses[1].error.type"));
663665

664666
String mgetBody = "{"
665667
+ "\"docs\" : ["
@@ -696,7 +698,9 @@ public void testDnfof() throws Exception {
696698
+ "}";
697699

698700
resc = rh.executePostRequest("_mget?pretty", mgetBody, encodeBasicHeader("user_b", "user_b"));
699-
Assert.assertEquals(403, resc.getStatusCode());
701+
Assert.assertEquals(resc.getBody(), 200, resc.getStatusCode());
702+
Assert.assertEquals(resc.getBody(), "index_not_found_exception", resc.findValueInJson("docs[0].error.type"));
703+
Assert.assertEquals(resc.getBody(), "index_not_found_exception", resc.findValueInJson("docs[1].error.type"));
700704

701705
Assert.assertEquals(
702706
HttpStatus.SC_OK,

0 commit comments

Comments
 (0)