Skip to content

Conversation

nibix
Copy link
Collaborator

@nibix nibix commented Sep 16, 2025

Description

This introduces new integration tests for authorization against index APIs.

In order to be as thorough as possible, the test suites use parameters to define several test dimensions:

  • Users with different privileges
  • Cluster configurations (at the moment system index privilege disabled vs enabled)
  • The final dimension are different operations with different options; this is manifested by the test methods

This is mostly a preparation for #5399; it will give us a good overview over the changed behaviors and allows us to judge whether we want to change a behavior or not.

Check List

  • New functionality includes testing
  • New functionality has been documented
  • Commits are signed per the DCO using --signoff

By submitting this pull request, I confirm that my contribution is made under the terms of the Apache 2.0 license.
For more information on following Developer Certificate of Origin and signing off your commits, please check here.

Copy link

codecov bot commented Sep 16, 2025

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 72.88%. Comparing base (ebed295) to head (66f19f0).
⚠️ Report is 18 commits behind head on main.

Additional details and impacted files

Impacted file tree graph

@@            Coverage Diff             @@
##             main    #5632      +/-   ##
==========================================
- Coverage   72.96%   72.88%   -0.08%     
==========================================
  Files         414      420       +6     
  Lines       25873    26269     +396     
  Branches     3934     3974      +40     
==========================================
+ Hits        18879    19147     +268     
- Misses       5083     5214     +131     
+ Partials     1911     1908       -3     

see 46 files with indirect coverage changes

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@nibix nibix marked this pull request as ready for review September 16, 2025 08:34
@nibix nibix force-pushed the authz-tests-rb branch 2 times, most recently from bdecbde to f5c21bf Compare September 17, 2025 10:50
* The test suites run on different cluster configurations; the possible cluster configurations are defined here.
*/
public enum ClusterConfig {
LEGACY_PRIVILEGES_EVALUATION(
Copy link
Member

Choose a reason for hiding this comment

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

To make sure I understand correctly, legacy here is related to how DNFOF relates to system index authorization?

Copy link
Collaborator Author

@nibix nibix Sep 19, 2025

Choose a reason for hiding this comment

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

Good point.

The naming is already in anticipation of the enhanced privilege evaluation PR which introduces one further element to the enum; thus, the enum looks like this:

public enum ClusterConfig {
LEGACY_PRIVILEGES_EVALUATION(
"legacy",
c -> c.doNotFailOnForbidden(true).nodeSettings(Map.of("plugins.security.system_indices.enabled", true)),
true,
false,
false
),
LEGACY_PRIVILEGES_EVALUATION_SYSTEM_INDEX_PERMISSION(
"legacy_system_index_perm",
c -> c.doNotFailOnForbidden(true)
.nodeSettings(
Map.of("plugins.security.system_indices.enabled", true, "plugins.security.system_indices.permission.enabled", true)
),
true,
true,
false
),
NEXT_GEN_PRIVILEGES_EVALUATION("next_gen", c -> c.privilegesEvaluationType("next_gen"), false, true, true);

Thus, currently, this is not really legacy. But maybe we can keep it this way, as it is only temporary and avoids lots of renaming?

But, generally, I am also not sure about a good way to name these things. Also I am not too happy about this "next_gen" name.

@cwperks
Copy link
Member

cwperks commented Sep 18, 2025

Thank you @nibix ! This is quite a large PR (even if only test files). It may make sense to break this up into smaller PRs for sake of review similar to what was done to the integrationTest framework. Would there be any good opportunities for splitting this PR up into smaller ones?

@nibix
Copy link
Collaborator Author

nibix commented Sep 19, 2025

@cwperks

Would there be any good opportunities for splitting this PR up into smaller ones?

Well, we have 5 main test classes:

  • IndexAuthorizationReadOnlyIntTests
  • IndexAuthorizationReadWriteIntTests
  • DataStreamAuthorizationReadOnlyIntTests
  • DataStreamAuthorizationReadWriteIntTests
  • SnapshotAuthorizationIntTests

Thus, one could break it down into 5 PRs:

  • IndexAuthorizationReadOnlyIntTests and all the framework stuff
  • One PR for the remaining classes

Still, I am not sure if this will be really helpful, as this does not really change the grouping of the changes. Already now, you could review class by class.

Also, the test cases themselves are then quite repetetive; if you reviewed the first few test cases, you will likely just skim over the remaining ones. In a few cases, these document some oddities; but in most cases, these will be addressed in the enhanced index resolution PR. In the end, this PR is only a preparation for the next one.

nibix added 9 commits October 2, 2025 13:38
Signed-off-by: Nils Bandener <[email protected]>
Signed-off-by: Nils Bandener <[email protected]>
Signed-off-by: Nils Bandener <[email protected]>
Signed-off-by: Nils Bandener <[email protected]>
Signed-off-by: Nils Bandener <[email protected]>
Signed-off-by: Nils Bandener <[email protected]>
Signed-off-by: Nils Bandener <[email protected]>
nibix added 2 commits October 3, 2025 06:44
Signed-off-by: Nils Bandener <[email protected]>
Signed-off-by: Nils Bandener <[email protected]>
nibix added 5 commits October 3, 2025 06:44
Signed-off-by: Nils Bandener <[email protected]>
Signed-off-by: Nils Bandener <[email protected]>
Signed-off-by: Nils Bandener <[email protected]>
Signed-off-by: Nils Bandener <[email protected]>
Signed-off-by: Nils Bandener <[email protected]>
nibix added 2 commits October 7, 2025 13:42
Signed-off-by: Nils Bandener <[email protected]>
Signed-off-by: Nils Bandener <[email protected]>
Copy link
Member

@DarshitChanpura DarshitChanpura left a comment

Choose a reason for hiding this comment

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

Hi @nibix Given that this is a huge PR i did my best to thoroughly review the PR and have left some comments and clarification questions.

Could this be broken down into smaller PRs? i.e. data-stream, index and snapshot tests individually?

integrationTestImplementation 'org.slf4j:slf4j-api:2.0.12'
integrationTestImplementation 'com.selectivem.collections:special-collections-complete:1.4.0'

integrationTestImplementation ('com.jayway.jsonpath:json-path:2.9.0') {
Copy link
Member

Choose a reason for hiding this comment

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

why do we need this? would defaultObjectMapper not work?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

JSON path allows you to use expressions like "$.data_streams[*].name" to extract information from JSON documents in a very versatile manner. This is not supported by Jackson (ObjectMapper).

}

public User adminCertUser() {
this.adminCertUser = true;
Copy link
Member

Choose a reason for hiding this comment

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

i'm confused, how does this validate that "this" user is an adminCert user? or is the point not to validate?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

This is evaluated here and has the effect that a admin client certificate is used to create the connection:

default TestRestClient getRestClient(UserCredentialsHolder user, Header... headers) {
if (user.isAdminCertUser()) {
return getRestClient(getTestCertificates().getAdminCertificateData());
}
return getRestClient(user.getName(), user.getPassword(), null, headers);
}

}

if (response.getStatusCode() != 200) {
return true;
Copy link
Member

Choose a reason for hiding this comment

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

why return true on non 200 code? is it because of empty list of indices and non-existent status code entry ?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

This is the case that an empty set of indices is expected.

If we have a 200 response, we have a valid response and can check this in the response body. But if we do not have 200 response, we must/can just assume that we did not get any indices and stop without further checks.

// Additionally, the dnfof implementation has the effect that hidden indices might be included even though not requested
assertThat(
httpResponse,
containsExactly(clusterConfig.systemIndexPrivilegeEnabled ? ALL_INDICES : ALL_INDICES_EXCEPT_SYSTEM_INDICES).at(
Copy link
Member

Choose a reason for hiding this comment

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

will unlimited user see less results than limited users?

Copy link
Collaborator Author

@nibix nibix Oct 10, 2025

Choose a reason for hiding this comment

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

yes (still, both will only see authorized indices), the limited users will just see more than they requested (the request shall request no indices).

// This causes a few more 403 errors where the granted index patterns do not use wildcards

if (user == LIMITED_USER_B1 || user == LIMITED_USER_ALIAS_AB1) {
assertThat(httpResponse, isForbidden());
Copy link
Member

Choose a reason for hiding this comment

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

should it be forbidden for B1 user with dnfof enabled?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

That's also a bug, to be fixed in the follow up PR

// out indices without authorization from eligible requests. However, the SystemIndexAccessEvaluator
// is not aware of this and just denies all these requests
// See also https://github.com/opensearch-project/security/issues/5546
assertThat(httpResponse, isForbidden());
Copy link
Member

Choose a reason for hiding this comment

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

both blocks are checking same 403 response. Can be clubbed together?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

For the first branch, this is a bug, for the else branch, this is expected behavior. That's why i kept it separate with the comments explaining the behavior.

// _analyze without index is different from most other operations:
// Usually, the absence of an index means "all indices". For analyze, however, it means: "no index".
// However, the IndexResolverReplacer does not get this right; it assumes that all indices are requested.
// Thus, we get only through to this operation with full privileges for all indices
Copy link
Member

Choose a reason for hiding this comment

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

should we fix this?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

This will be fixed by #5399

Signed-off-by: Nils Bandener <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants