Skip to content

Conversation

@poojanilangekar
Copy link
Contributor

@poojanilangekar poojanilangekar commented Jul 24, 2025

I encountered the bug while implementing RBAC for federation.
For grant/revoke operations on tables, polaris checks the subtype of the leaf entity and make sure it matches. However, for namespace the only check is that the resolved path is not null.

Ideally we should check that the entire path matches the one sent in the request. Further, all entities except the root should be of the type NAMESPACE.

Testing:
Added unit tests.

@poojanilangekar
Copy link
Contributor Author

CC: @eric-maynard @dennishuo

Copy link
Contributor

@dimas-b dimas-b left a comment

Choose a reason for hiding this comment

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

Hi @poojanilangekar , this fix makes sense to me, but I've got some comments/suggestions :)

isNamespaceFullyResolvedMethod.invoke(
adminService, null, "test-catalog", Namespace.of("ns1"));

assertThat(result).isFalse();
Copy link
Contributor

Choose a reason for hiding this comment

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

nit: Why not inline result? The expression is already multi-line 🤔

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done.

Comment on lines 119 to 121
(boolean)
isNamespaceFullyResolvedMethod.invoke(
adminService, resolvedPathWrapper, catalogName, namespace);
Copy link
Contributor

Choose a reason for hiding this comment

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

This pattern is repeated... Maybe add a help method in this test class?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I've moved the test, so that fixed it.


List<PolarisEntity> fullPath = resolvedPathWrapper.getRawFullPath();
int expectedPathLength = 1 + namespace.levels().length;
if (fullPath.size() < expectedPathLength) {
Copy link
Contributor

Choose a reason for hiding this comment

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

why not ==?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done, changed it to !=

* @param namespace the namespace we're trying to resolve
* @return true if the namespace is considered fully resolved for the given catalog type
*/
private boolean isNamespaceFullyResolved(
Copy link
Contributor

Choose a reason for hiding this comment

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

Why keep it as a private instance method? It does not use any state from this... It could be a package-private static method in a utility class.

Copy link
Contributor

Choose a reason for hiding this comment

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

... or perhaps a public method in PolarisResolvedPathWrapper? 🤔

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done.

Copy link
Contributor Author

@poojanilangekar poojanilangekar left a comment

Choose a reason for hiding this comment

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

Done, I have addressed your comments.


List<PolarisEntity> fullPath = resolvedPathWrapper.getRawFullPath();
int expectedPathLength = 1 + namespace.levels().length;
if (fullPath.size() < expectedPathLength) {
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done, changed it to !=

* @param namespace the namespace we're trying to resolve
* @return true if the namespace is considered fully resolved for the given catalog type
*/
private boolean isNamespaceFullyResolved(
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done.

isNamespaceFullyResolvedMethod.invoke(
adminService, null, "test-catalog", Namespace.of("ns1"));

assertThat(result).isFalse();
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done.

Comment on lines 119 to 121
(boolean)
isNamespaceFullyResolvedMethod.invoke(
adminService, resolvedPathWrapper, catalogName, namespace);
Copy link
Contributor Author

Choose a reason for hiding this comment

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

I've moved the test, so that fixed it.

}

for (int i = 0; i < namespace.levels().length; i++) {
if (!fullPath.get(i + 1).getName().equals(namespace.levels()[i])
Copy link
Contributor

Choose a reason for hiding this comment

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

This may not be a big deal, but since we're always scanning this list from head to tail, using iterators might be more portable and easier to understand. Probably as efficient as .get(N) for array-based lists, but potentially more efficient for linked lists.

It might be preferable to move namespace.levels() to a local variable. Iterate it in for, but do simple iterator.next() for fullPath.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done.


boolean result = wrapper.isFullyResolvedNamespace("test-catalog", Namespace.of("ns1"));

assertThat(result).isFalse();
Copy link
Contributor

Choose a reason for hiding this comment

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

nit: inline?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done.

throws Exception {
String catalogName = "test-catalog";
String catalogRoleName = "test-role";
Namespace namespace = Namespace.of("incomplete-ns");
Copy link
Contributor

Choose a reason for hiding this comment

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

This is a single-level namespace... How is "incomplete" different from "non existent"?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done.

Namespace namespace = Namespace.of("ns1");

PolarisEntity catalogEntity = createEntity(catalogName, PolarisEntityType.CATALOG);
PolarisEntity wrongTypeEntity = createEntity("ns1", PolarisEntityType.TABLE_LIKE);
Copy link
Contributor

Choose a reason for hiding this comment

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

For completeness this test should probably also have some NS level with the right type and some with another type.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done.

Copy link
Contributor

@dimas-b dimas-b left a comment

Choose a reason for hiding this comment

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

Thanks, @poojanilangekar ! I'll be merging late Friday if there are no more review (or Mon if I forget :) )

@github-project-automation github-project-automation bot moved this from PRs In Progress to Ready to merge in Basic Kanban Board Jul 24, 2025
@poojanilangekar
Copy link
Contributor Author

Hi @dimas-b, could you please merge this PR?

@dimas-b dimas-b merged commit 364b53c into apache:main Jul 28, 2025
12 checks passed
@github-project-automation github-project-automation bot moved this from Ready to merge to Done in Basic Kanban Board Jul 28, 2025
@poojanilangekar poojanilangekar deleted the check-namespace-resolution branch August 6, 2025 20:07
snazy added a commit to snazy/polaris that referenced this pull request Nov 20, 2025
* fix(deps): update dependency com.google.errorprone:error_prone_core to v2.41.0 (apache#2181)

* Simplify bootstrapServiceAndCreatePolarisPrincipalForRealm (apache#2172)

this is a small follow-up to 5faa371
because the same pattern existed for this method.

note that we do some minor additional "formatting" changes to minimize
the diff between the two files (as they were originally copy pasted).
this could lead to having a common base class in the future.

* fix(deps): update dependency boto3 to v1.39.13 (apache#2182)

* Add podman support (apache#2143)

* Add Polaris Community Meeting 2025-07-24 (apache#2184)

* fix(deps): update dependency com.adobe.testing:s3mock-testcontainers to v4.7.0 (apache#2185)

* Push AccessConfig creation to PolarisStorageIntegration (apache#2171)

This refactoring does not change Polaris behaviour.

* Move storage-specific access properties processing logic from
  core code to storage integration implementations.

* Add `isExpirationTimestamp` flag to `StorageAccessProperty` to
  allow them to be processed uniformly.

* Prepare for supporting access config properties that may have
  different values in Polaris Servers and Clients. This enables
  future enhancements to support different S3 endpoint DNS names
  in servers and clients for apache#1530

* Fix doc to remove privileges may take up to one hour to take effect and add Policy to securable object (apache#2009)

* fix(deps): update dependency boto3 to v1.39.14 (apache#2186)

* chore(deps): update plugin jetbrains-changelog to v2.3.0 (apache#2187)

* fix(deps): update dependency software.amazon.awssdk:bom to v2.32.9 (apache#2191)

* Add Principal lookup helpers to PolarisMetaStoreManager (apache#2174)

`PolarisMetaStoreManager.readEntityByName` is quite a low-level api, so we can simplify a lot of callers with additional helpers:

- add `PolarisMetaStoreManager.findRootPrincipal`
- add `PolarisMetaStoreManager.findPrincipalByName`
- add `PolarisMetaStoreManager.findPrincipalRoleByName`

also we now prefer `PolarisEntityConstants` where applicable

* Remove PolarisDiagnostics from json utils (apache#2176)

With transitive cleanups of, PolarisStorageConfigurationInfo, ConnectionConfigInfoDpo, BaseMetaStoreManager, PolarisObjectMapperUtil, CurrentContext

* Fix Namespace resolution on grant/revoke privilege operations (apache#2170)

* Fix Namespace resolution on grant/revoke privilege operations

* Move isFullyResolvedNamespace to PolarisResolvedPathWrapper

* fix(deps): update dependency boto3 to v1.39.15 (apache#2199)

* fix(deps): update dependency com.google.cloud:google-cloud-storage-bom to v2.54.0 (apache#2200)

* fix(deps): update dependency boto3 to v1.39.16 (apache#2209)

* chore(deps): update actions/stale digest to a92fd57 (apache#2208)

* fix(deps): update quarkus platform and group to v3.25.0 (apache#2167)

* NoSQL updates

* Last merged commit 914be46

---------

Co-authored-by: Mend Renovate <bot@renovateapp.com>
Co-authored-by: Christopher Lambert <xn137@gmx.de>
Co-authored-by: Yong Zheng <yongzheng0809@gmail.com>
Co-authored-by: JB Onofré <jbonofre@apache.org>
Co-authored-by: Dmitri Bourlatchkov <dmitri.bourlatchkov@gmail.com>
Co-authored-by: CG <cgpoh@users.noreply.github.com>
Co-authored-by: Pooja Nilangekar <poojan@umd.edu>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants