diff --git a/polaris-core/src/main/java/org/apache/polaris/core/persistence/AtomicOperationMetaStoreManager.java b/polaris-core/src/main/java/org/apache/polaris/core/persistence/AtomicOperationMetaStoreManager.java index 9796073767..d6cfd84292 100644 --- a/polaris-core/src/main/java/org/apache/polaris/core/persistence/AtomicOperationMetaStoreManager.java +++ b/polaris-core/src/main/java/org/apache/polaris/core/persistence/AtomicOperationMetaStoreManager.java @@ -62,12 +62,10 @@ import org.apache.polaris.core.persistence.dao.entity.PrivilegeResult; import org.apache.polaris.core.persistence.dao.entity.ResolvedEntityResult; import org.apache.polaris.core.persistence.dao.entity.ScopedCredentialsResult; -import org.apache.polaris.core.persistence.dao.entity.ValidateAccessResult; import org.apache.polaris.core.policy.PolarisPolicyMappingRecord; import org.apache.polaris.core.policy.PolicyEntity; import org.apache.polaris.core.policy.PolicyType; import org.apache.polaris.core.storage.PolarisCredentialProperty; -import org.apache.polaris.core.storage.PolarisStorageActions; import org.apache.polaris.core.storage.PolarisStorageConfigurationInfo; import org.apache.polaris.core.storage.PolarisStorageIntegration; import org.slf4j.Logger; @@ -1587,59 +1585,6 @@ private void revokeGrantRecord( } } - /** {@inheritDoc} */ - @Override - public @Nonnull ValidateAccessResult validateAccessToLocations( - @Nonnull PolarisCallContext callCtx, - long catalogId, - long entityId, - PolarisEntityType entityType, - @Nonnull Set actions, - @Nonnull Set locations) { - // get meta store we should be using - BasePersistence ms = callCtx.getMetaStore(); - callCtx - .getDiagServices() - .check( - !actions.isEmpty() && !locations.isEmpty(), - "locations_and_operations_privileges_are_required"); - // reload the entity, error out if not found - EntityResult reloadedEntity = loadEntity(callCtx, catalogId, entityId, entityType); - if (reloadedEntity.getReturnStatus() != BaseResult.ReturnStatus.SUCCESS) { - return new ValidateAccessResult( - reloadedEntity.getReturnStatus(), reloadedEntity.getExtraInformation()); - } - - // get storage integration, expect not null - PolarisStorageIntegration storageIntegration = - ((IntegrationPersistence) ms) - .loadPolarisStorageIntegration(callCtx, reloadedEntity.getEntity()); - callCtx - .getDiagServices() - .checkNotNull( - storageIntegration, - "storage_integration_not_exists", - "catalogId={}, entityId={}", - catalogId, - entityId); - - // validate access - PolarisStorageConfigurationInfo storageConfigurationInfo = - BaseMetaStoreManager.extractStorageConfiguration(callCtx, reloadedEntity.getEntity()); - Map validateLocationAccess = - storageIntegration - .validateAccessToLocations(storageConfigurationInfo, actions, locations) - .entrySet() - .stream() - .collect( - Collectors.toMap( - Map.Entry::getKey, - e -> PolarisObjectMapperUtil.serialize(callCtx, e.getValue()))); - - // done, return result - return new ValidateAccessResult(validateLocationAccess); - } - /** * Get the internal property map for an entity * diff --git a/polaris-core/src/main/java/org/apache/polaris/core/persistence/TransactionWorkspaceMetaStoreManager.java b/polaris-core/src/main/java/org/apache/polaris/core/persistence/TransactionWorkspaceMetaStoreManager.java index 4c3778e980..9b5a6b6dbe 100644 --- a/polaris-core/src/main/java/org/apache/polaris/core/persistence/TransactionWorkspaceMetaStoreManager.java +++ b/polaris-core/src/main/java/org/apache/polaris/core/persistence/TransactionWorkspaceMetaStoreManager.java @@ -50,10 +50,8 @@ import org.apache.polaris.core.persistence.dao.entity.PrivilegeResult; import org.apache.polaris.core.persistence.dao.entity.ResolvedEntityResult; import org.apache.polaris.core.persistence.dao.entity.ScopedCredentialsResult; -import org.apache.polaris.core.persistence.dao.entity.ValidateAccessResult; import org.apache.polaris.core.policy.PolicyEntity; import org.apache.polaris.core.policy.PolicyType; -import org.apache.polaris.core.storage.PolarisStorageActions; /** * Wraps an existing impl of PolarisMetaStoreManager and delegates expected "read" operations @@ -346,20 +344,6 @@ public ScopedCredentialsResult getSubscopedCredsForEntity( allowedWriteLocations); } - @Override - public ValidateAccessResult validateAccessToLocations( - @Nonnull PolarisCallContext callCtx, - long catalogId, - long entityId, - PolarisEntityType entityType, - @Nonnull Set actions, - @Nonnull Set locations) { - callCtx - .getDiagServices() - .fail("illegal_method_in_transaction_workspace", "validateAccessToLocations"); - return null; - } - @Override public ResolvedEntityResult loadResolvedEntityById( @Nonnull PolarisCallContext callCtx, diff --git a/polaris-core/src/main/java/org/apache/polaris/core/persistence/dao/entity/ValidateAccessResult.java b/polaris-core/src/main/java/org/apache/polaris/core/persistence/dao/entity/ValidateAccessResult.java deleted file mode 100644 index 61bc6bd28c..0000000000 --- a/polaris-core/src/main/java/org/apache/polaris/core/persistence/dao/entity/ValidateAccessResult.java +++ /dev/null @@ -1,67 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -package org.apache.polaris.core.persistence.dao.entity; - -import com.fasterxml.jackson.annotation.JsonCreator; -import com.fasterxml.jackson.annotation.JsonProperty; -import jakarta.annotation.Nonnull; -import jakarta.annotation.Nullable; -import java.util.Map; - -/** Result of a validateAccessToLocations() call */ -public class ValidateAccessResult extends BaseResult { - - // null if not success. Else, set of location/validationResult pairs for each location in the - // set - private final Map validateResult; - - /** - * Constructor for an error - * - * @param errorCode error code, cannot be SUCCESS - * @param extraInformation extra information - */ - public ValidateAccessResult(@Nonnull ReturnStatus errorCode, @Nullable String extraInformation) { - super(errorCode, extraInformation); - this.validateResult = null; - } - - /** - * Constructor for success - * - * @param validateResult validate result - */ - public ValidateAccessResult(@Nonnull Map validateResult) { - super(ReturnStatus.SUCCESS); - this.validateResult = validateResult; - } - - @JsonCreator - private ValidateAccessResult( - @JsonProperty("returnStatus") @Nonnull ReturnStatus returnStatus, - @JsonProperty("extraInformation") String extraInformation, - @JsonProperty("validateResult") Map validateResult) { - super(returnStatus, extraInformation); - this.validateResult = validateResult; - } - - public Map getValidateResult() { - return this.validateResult; - } -} diff --git a/polaris-core/src/main/java/org/apache/polaris/core/persistence/transactional/TransactionalMetaStoreManagerImpl.java b/polaris-core/src/main/java/org/apache/polaris/core/persistence/transactional/TransactionalMetaStoreManagerImpl.java index 27b049e917..22120c7a3d 100644 --- a/polaris-core/src/main/java/org/apache/polaris/core/persistence/transactional/TransactionalMetaStoreManagerImpl.java +++ b/polaris-core/src/main/java/org/apache/polaris/core/persistence/transactional/TransactionalMetaStoreManagerImpl.java @@ -63,12 +63,10 @@ import org.apache.polaris.core.persistence.dao.entity.PrivilegeResult; import org.apache.polaris.core.persistence.dao.entity.ResolvedEntityResult; import org.apache.polaris.core.persistence.dao.entity.ScopedCredentialsResult; -import org.apache.polaris.core.persistence.dao.entity.ValidateAccessResult; import org.apache.polaris.core.policy.PolarisPolicyMappingRecord; import org.apache.polaris.core.policy.PolicyEntity; import org.apache.polaris.core.policy.PolicyType; import org.apache.polaris.core.storage.PolarisCredentialProperty; -import org.apache.polaris.core.storage.PolarisStorageActions; import org.apache.polaris.core.storage.PolarisStorageConfigurationInfo; import org.apache.polaris.core.storage.PolarisStorageIntegration; import org.slf4j.Logger; @@ -2016,58 +2014,6 @@ private PolarisEntityResolver resolveSecurableToRoleGrant( } } - /** {@inheritDoc} */ - @Override - public @Nonnull ValidateAccessResult validateAccessToLocations( - @Nonnull PolarisCallContext callCtx, - long catalogId, - long entityId, - PolarisEntityType entityType, - @Nonnull Set actions, - @Nonnull Set locations) { - // get meta store we should be using - TransactionalPersistence ms = ((TransactionalPersistence) callCtx.getMetaStore()); - callCtx - .getDiagServices() - .check( - !actions.isEmpty() && !locations.isEmpty(), - "locations_and_operations_privileges_are_required"); - // reload the entity, error out if not found - EntityResult reloadedEntity = loadEntity(callCtx, catalogId, entityId, entityType); - if (reloadedEntity.getReturnStatus() != BaseResult.ReturnStatus.SUCCESS) { - return new ValidateAccessResult( - reloadedEntity.getReturnStatus(), reloadedEntity.getExtraInformation()); - } - - // get storage integration, expect not null - PolarisStorageIntegration storageIntegration = - ms.loadPolarisStorageIntegrationInCurrentTxn(callCtx, reloadedEntity.getEntity()); - callCtx - .getDiagServices() - .checkNotNull( - storageIntegration, - "storage_integration_not_exists", - "catalogId={}, entityId={}", - catalogId, - entityId); - - // validate access - PolarisStorageConfigurationInfo storageConfigurationInfo = - BaseMetaStoreManager.extractStorageConfiguration(callCtx, reloadedEntity.getEntity()); - Map validateLocationAccess = - storageIntegration - .validateAccessToLocations(storageConfigurationInfo, actions, locations) - .entrySet() - .stream() - .collect( - Collectors.toMap( - Map.Entry::getKey, - e -> PolarisObjectMapperUtil.serialize(callCtx, e.getValue()))); - - // done, return result - return new ValidateAccessResult(validateLocationAccess); - } - /** * Get the internal property map for an entity * diff --git a/polaris-core/src/main/java/org/apache/polaris/core/storage/PolarisCredentialVendor.java b/polaris-core/src/main/java/org/apache/polaris/core/storage/PolarisCredentialVendor.java index 536311afa1..04022d233c 100644 --- a/polaris-core/src/main/java/org/apache/polaris/core/storage/PolarisCredentialVendor.java +++ b/polaris-core/src/main/java/org/apache/polaris/core/storage/PolarisCredentialVendor.java @@ -23,7 +23,6 @@ import org.apache.polaris.core.PolarisCallContext; import org.apache.polaris.core.entity.PolarisEntityType; import org.apache.polaris.core.persistence.dao.entity.ScopedCredentialsResult; -import org.apache.polaris.core.persistence.dao.entity.ValidateAccessResult; /** Manage credentials for storage locations. */ public interface PolarisCredentialVendor { @@ -49,46 +48,4 @@ ScopedCredentialsResult getSubscopedCredsForEntity( boolean allowListOperation, @Nonnull Set allowedReadLocations, @Nonnull Set allowedWriteLocations); - - /** - * Validate whether the entity has access to the locations with the provided target operations - * - * @param callCtx the polaris call context - * @param catalogId the catalog id - * @param entityId the entity id - * @param actions a set of operation actions: READ/WRITE/LIST/DELETE/ALL - * @param locations a set of locations to verify - * @return a Map of {@code }, a validate result value looks like this - *
-   * {
-   *   "status" : "failure",
-   *   "actions" : {
-   *     "READ" : {
-   *       "message" : "The specified file was not found",
-   *       "status" : "failure"
-   *     },
-   *     "DELETE" : {
-   *       "message" : "One or more objects could not be deleted (Status Code: 200; Error Code: null)",
-   *       "status" : "failure"
-   *     },
-   *     "LIST" : {
-   *       "status" : "success"
-   *     },
-   *     "WRITE" : {
-   *       "message" : "Access Denied (Status Code: 403; Error Code: AccessDenied)",
-   *       "status" : "failure"
-   *     }
-   *   },
-   *   "message" : "Some of the integration checks failed. Check the Polaris documentation for more information."
-   * }
-   * 
- */ - @Nonnull - ValidateAccessResult validateAccessToLocations( - @Nonnull PolarisCallContext callCtx, - long catalogId, - long entityId, - PolarisEntityType entityType, - @Nonnull Set actions, - @Nonnull Set locations); } diff --git a/service/common/src/main/java/org/apache/polaris/service/catalog/iceberg/IcebergCatalog.java b/service/common/src/main/java/org/apache/polaris/service/catalog/iceberg/IcebergCatalog.java index 3fb19a364e..27ef12c3d7 100644 --- a/service/common/src/main/java/org/apache/polaris/service/catalog/iceberg/IcebergCatalog.java +++ b/service/common/src/main/java/org/apache/polaris/service/catalog/iceberg/IcebergCatalog.java @@ -989,25 +989,6 @@ private void validateLocationsForTableLike( identifier); } })); - - // TODO: Consider exposing a property to control whether to use the explicit default - // in-memory PolarisStorageIntegration implementation to perform validation or - // whether to delegate to PolarisMetaStoreManager::validateAccessToLocations. - // Usually the validation is better to perform with local business logic, but if - // there are additional rules to be evaluated by a custom PolarisMetaStoreManager - // implementation, then the validation should go through that API instead as follows: - // - // PolarisMetaStoreManager.ValidateAccessResult validateResult = - // getMetaStoreManager().validateAccessToLocations( - // getCurrentPolarisContext(), - // storageInfoHolderEntity.getCatalogId(), - // storageInfoHolderEntity.getId(), - // Set.of(PolarisStorageActions.ALL), - // Set.of(location)); - // if (!validateResult.isSuccess()) { - // throw new ForbiddenException("Invalid location '%s' for identifier '%s': %s", - // location, identifier, validateResult.getExtraInformation()); - // } }, () -> { List allowedStorageTypes =