From 9f9425d2c1957b972bb48c2192813b3fe4ef44ed Mon Sep 17 00:00:00 2001 From: Honah J Date: Tue, 7 Oct 2025 12:28:51 -0500 Subject: [PATCH] Add new authorizeOrThrow variation for fine grained authorizableOperations --- .../polaris/core/auth/PolarisAuthorizer.java | 14 ++++ .../core/auth/PolarisAuthorizerImpl.java | 75 +++++++++++++------ .../catalog/common/CatalogHandler.java | 14 ++-- 3 files changed, 73 insertions(+), 30 deletions(-) diff --git a/polaris-core/src/main/java/org/apache/polaris/core/auth/PolarisAuthorizer.java b/polaris-core/src/main/java/org/apache/polaris/core/auth/PolarisAuthorizer.java index 55c3792067..53a349584c 100644 --- a/polaris-core/src/main/java/org/apache/polaris/core/auth/PolarisAuthorizer.java +++ b/polaris-core/src/main/java/org/apache/polaris/core/auth/PolarisAuthorizer.java @@ -41,4 +41,18 @@ void authorizeOrThrow( @Nonnull PolarisAuthorizableOperation authzOp, @Nullable List targets, @Nullable List secondaries); + + void authorizeOrThrow( + @Nonnull PolarisPrincipal polarisPrincipal, + @Nonnull Set activatedEntities, + @Nonnull Set authzOps, + @Nullable PolarisResolvedPathWrapper target, + @Nullable PolarisResolvedPathWrapper secondary); + + void authorizeOrThrow( + @Nonnull PolarisPrincipal polarisPrincipal, + @Nonnull Set activatedEntities, + @Nonnull Set authzOps, + @Nullable List targets, + @Nullable List secondaries); } diff --git a/polaris-core/src/main/java/org/apache/polaris/core/auth/PolarisAuthorizerImpl.java b/polaris-core/src/main/java/org/apache/polaris/core/auth/PolarisAuthorizerImpl.java index 9d943823a7..764ca1fc95 100644 --- a/polaris-core/src/main/java/org/apache/polaris/core/auth/PolarisAuthorizerImpl.java +++ b/polaris-core/src/main/java/org/apache/polaris/core/auth/PolarisAuthorizerImpl.java @@ -128,6 +128,7 @@ import jakarta.annotation.Nonnull; import jakarta.annotation.Nullable; import jakarta.inject.Inject; +import java.util.EnumSet; import java.util.List; import java.util.Set; import java.util.stream.Collectors; @@ -774,33 +775,63 @@ public void authorizeOrThrow( @Nonnull PolarisAuthorizableOperation authzOp, @Nullable List targets, @Nullable List secondaries) { + authorizeOrThrow( + polarisPrincipal, activatedEntities, EnumSet.of(authzOp), targets, secondaries); + } + + @Override + public void authorizeOrThrow( + @Nonnull PolarisPrincipal polarisPrincipal, + @Nonnull Set activatedEntities, + @Nonnull Set authzOps, + @Nullable PolarisResolvedPathWrapper target, + @Nullable PolarisResolvedPathWrapper secondary) { + authorizeOrThrow( + polarisPrincipal, + activatedEntities, + authzOps, + target == null ? null : List.of(target), + secondary == null ? null : List.of(secondary)); + } + + @Override + public void authorizeOrThrow( + @Nonnull PolarisPrincipal polarisPrincipal, + @Nonnull Set activatedEntities, + @Nonnull Set authzOps, + @Nullable List targets, + @Nullable List secondaries) { boolean enforceCredentialRotationRequiredState = realmConfig.getConfig( FeatureConfiguration.ENFORCE_PRINCIPAL_CREDENTIAL_ROTATION_REQUIRED_CHECKING); boolean isRoot = getRootPrincipalName().equals(polarisPrincipal.getName()); - if (enforceCredentialRotationRequiredState - && polarisPrincipal - .getProperties() - .containsKey(PolarisEntityConstants.PRINCIPAL_CREDENTIAL_ROTATION_REQUIRED_STATE) - && authzOp != PolarisAuthorizableOperation.ROTATE_CREDENTIALS) { - throw new ForbiddenException( - "Principal '%s' is not authorized for op %s due to PRINCIPAL_CREDENTIAL_ROTATION_REQUIRED_STATE", - polarisPrincipal.getName(), authzOp); - } else if (authzOp == PolarisAuthorizableOperation.RESET_CREDENTIALS) { - if (!isRoot) { - throw new ForbiddenException("Only Root principal(service-admin) can perform %s", authzOp); + for (PolarisAuthorizableOperation authzOp : authzOps) { + if (enforceCredentialRotationRequiredState + && polarisPrincipal + .getProperties() + .containsKey(PolarisEntityConstants.PRINCIPAL_CREDENTIAL_ROTATION_REQUIRED_STATE) + && authzOp != PolarisAuthorizableOperation.ROTATE_CREDENTIALS) { + throw new ForbiddenException( + "Principal '%s' is not authorized for op %s due to PRINCIPAL_CREDENTIAL_ROTATION_REQUIRED_STATE", + polarisPrincipal.getName(), authzOp); + } else if (authzOp == PolarisAuthorizableOperation.RESET_CREDENTIALS) { + if (!isRoot) { + throw new ForbiddenException( + "Only Root principal(service-admin) can perform %s", authzOp); + } + LOGGER + .atDebug() + .addKeyValue("principalName", polarisPrincipal.getName()) + .log("Root principal allowed to reset credentials"); + } else if (!isAuthorized( + polarisPrincipal, activatedEntities, authzOp, targets, secondaries)) { + throw new ForbiddenException( + "Principal '%s' with activated PrincipalRoles '%s' and activated grants via '%s' is not authorized for op %s", + polarisPrincipal.getName(), + polarisPrincipal.getRoles(), + activatedEntities.stream().map(PolarisEntityCore::getName).collect(Collectors.toSet()), + authzOp); } - LOGGER - .atDebug() - .addKeyValue("principalName", polarisPrincipal.getName()) - .log("Root principal allowed to reset credentials"); - } else if (!isAuthorized(polarisPrincipal, activatedEntities, authzOp, targets, secondaries)) { - throw new ForbiddenException( - "Principal '%s' with activated PrincipalRoles '%s' and activated grants via '%s' is not authorized for op %s", - polarisPrincipal.getName(), - polarisPrincipal.getRoles(), - activatedEntities.stream().map(PolarisEntityCore::getName).collect(Collectors.toSet()), - authzOp); } } diff --git a/runtime/service/src/main/java/org/apache/polaris/service/catalog/common/CatalogHandler.java b/runtime/service/src/main/java/org/apache/polaris/service/catalog/common/CatalogHandler.java index 8919aeb2ac..bb809925f0 100644 --- a/runtime/service/src/main/java/org/apache/polaris/service/catalog/common/CatalogHandler.java +++ b/runtime/service/src/main/java/org/apache/polaris/service/catalog/common/CatalogHandler.java @@ -275,14 +275,12 @@ protected void authorizeBasicTableLikeOperationsOrThrow( throwNotFoundExceptionForTableLikeEntity(identifier, List.of(subType)); } - for (PolarisAuthorizableOperation op : ops) { - authorizer.authorizeOrThrow( - polarisPrincipal, - resolutionManifest.getAllActivatedCatalogRoleAndPrincipalRoles(), - op, - target, - null /* secondary */); - } + authorizer.authorizeOrThrow( + polarisPrincipal, + resolutionManifest.getAllActivatedCatalogRoleAndPrincipalRoles(), + ops, + target, + null /* secondary */); initializeCatalog(); }