This is an automated email from the ASF dual-hosted git repository. emaynard pushed a commit to branch main in repository https://gitbox.apache.org/repos/asf/polaris.git
The following commit(s) were added to refs/heads/main by this push: new dd223c1bd Make entity lookups by id honor the specified entity type (#1401) dd223c1bd is described below commit dd223c1bd9a0ccfe2520d76e388f0e1940958737 Author: Alexandre Dutra <adu...@users.noreply.github.com> AuthorDate: Wed Apr 23 19:25:55 2025 +0200 Make entity lookups by id honor the specified entity type (#1401) * Make entity lookups by id honor the specified entity type All implementations of `TransactionalPersistence.lookupEntityInCurrentTxn()` are currently ignoring the `typeCode` parameter completely and could potentially return an entity of the wrong type. This can become very concerning during authentication, since a principal lookup could return some entity that is not a principal, and that would be considered a successful authentication. * review --- .../PolarisEclipseLinkMetaStoreSessionImpl.java | 6 +- .../impl/eclipselink/PolarisEclipseLinkStore.java | 12 ++-- .../TreeMapTransactionalPersistenceImpl.java | 7 +- .../BasePolarisMetaStoreManagerTest.java | 6 ++ .../persistence/PolarisTestMetaStoreManager.java | 80 ++++++++++++++++++++++ 5 files changed, 103 insertions(+), 8 deletions(-) diff --git a/extension/persistence/eclipselink/src/main/java/org/apache/polaris/extension/persistence/impl/eclipselink/PolarisEclipseLinkMetaStoreSessionImpl.java b/extension/persistence/eclipselink/src/main/java/org/apache/polaris/extension/persistence/impl/eclipselink/PolarisEclipseLinkMetaStoreSessionImpl.java index 14bb01d83..e19b0ef72 100644 --- a/extension/persistence/eclipselink/src/main/java/org/apache/polaris/extension/persistence/impl/eclipselink/PolarisEclipseLinkMetaStoreSessionImpl.java +++ b/extension/persistence/eclipselink/src/main/java/org/apache/polaris/extension/persistence/impl/eclipselink/PolarisEclipseLinkMetaStoreSessionImpl.java @@ -309,7 +309,8 @@ public class PolarisEclipseLinkMetaStoreSessionImpl extends AbstractTransactiona @Nonnull PolarisCallContext callCtx, @Nonnull PolarisEntityCore entity) { // delete it - this.store.deleteFromEntities(localSession.get(), entity.getCatalogId(), entity.getId()); + this.store.deleteFromEntities( + localSession.get(), entity.getCatalogId(), entity.getId(), entity.getTypeCode()); } /** {@inheritDoc} */ @@ -360,7 +361,8 @@ public class PolarisEclipseLinkMetaStoreSessionImpl extends AbstractTransactiona @Override public @Nullable PolarisBaseEntity lookupEntityInCurrentTxn( @Nonnull PolarisCallContext callCtx, long catalogId, long entityId, int typeCode) { - return ModelEntity.toEntity(this.store.lookupEntity(localSession.get(), catalogId, entityId)); + return ModelEntity.toEntity( + this.store.lookupEntity(localSession.get(), catalogId, entityId, typeCode)); } @Override diff --git a/extension/persistence/eclipselink/src/main/java/org/apache/polaris/extension/persistence/impl/eclipselink/PolarisEclipseLinkStore.java b/extension/persistence/eclipselink/src/main/java/org/apache/polaris/extension/persistence/impl/eclipselink/PolarisEclipseLinkStore.java index fc889656b..9ebb4e816 100644 --- a/extension/persistence/eclipselink/src/main/java/org/apache/polaris/extension/persistence/impl/eclipselink/PolarisEclipseLinkStore.java +++ b/extension/persistence/eclipselink/src/main/java/org/apache/polaris/extension/persistence/impl/eclipselink/PolarisEclipseLinkStore.java @@ -84,7 +84,8 @@ public class PolarisEclipseLinkStore { diagnosticServices.check(session != null, "session_is_null"); checkInitialized(); - ModelEntity model = lookupEntity(session, entity.getCatalogId(), entity.getId()); + ModelEntity model = + lookupEntity(session, entity.getCatalogId(), entity.getId(), entity.getTypeCode()); if (model != null) { // Update if the same entity already exists model.update(entity); @@ -129,11 +130,11 @@ public class PolarisEclipseLinkStore { session.persist(ModelGrantRecord.fromGrantRecord(grantRec)); } - void deleteFromEntities(EntityManager session, long catalogId, long entityId) { + void deleteFromEntities(EntityManager session, long catalogId, long entityId, int typeCode) { diagnosticServices.check(session != null, "session_is_null"); checkInitialized(); - ModelEntity model = lookupEntity(session, catalogId, entityId); + ModelEntity model = lookupEntity(session, catalogId, entityId, typeCode); diagnosticServices.check(model != null, "entity_not_found"); session.remove(model); @@ -203,14 +204,15 @@ public class PolarisEclipseLinkStore { LOGGER.debug("All entities deleted."); } - ModelEntity lookupEntity(EntityManager session, long catalogId, long entityId) { + ModelEntity lookupEntity(EntityManager session, long catalogId, long entityId, long typeCode) { diagnosticServices.check(session != null, "session_is_null"); checkInitialized(); return session .createQuery( - "SELECT m from ModelEntity m where m.catalogId=:catalogId and m.id=:id", + "SELECT m from ModelEntity m where m.catalogId=:catalogId and m.id=:id and m.typeCode=:typeCode", ModelEntity.class) + .setParameter("typeCode", typeCode) .setParameter("catalogId", catalogId) .setParameter("id", entityId) .getResultStream() diff --git a/polaris-core/src/main/java/org/apache/polaris/core/persistence/transactional/TreeMapTransactionalPersistenceImpl.java b/polaris-core/src/main/java/org/apache/polaris/core/persistence/transactional/TreeMapTransactionalPersistenceImpl.java index 822045673..e9cbd53f3 100644 --- a/polaris-core/src/main/java/org/apache/polaris/core/persistence/transactional/TreeMapTransactionalPersistenceImpl.java +++ b/polaris-core/src/main/java/org/apache/polaris/core/persistence/transactional/TreeMapTransactionalPersistenceImpl.java @@ -217,7 +217,12 @@ public class TreeMapTransactionalPersistenceImpl extends AbstractTransactionalPe @Override public @Nullable PolarisBaseEntity lookupEntityInCurrentTxn( @Nonnull PolarisCallContext callCtx, long catalogId, long entityId, int typeCode) { - return this.store.getSliceEntities().read(this.store.buildKeyComposite(catalogId, entityId)); + PolarisBaseEntity entity = + this.store.getSliceEntities().read(this.store.buildKeyComposite(catalogId, entityId)); + if (entity != null && entity.getTypeCode() != typeCode) { + return null; + } + return entity; } /** {@inheritDoc} */ diff --git a/polaris-core/src/testFixtures/java/org/apache/polaris/core/persistence/BasePolarisMetaStoreManagerTest.java b/polaris-core/src/testFixtures/java/org/apache/polaris/core/persistence/BasePolarisMetaStoreManagerTest.java index b37a57464..d11bed82d 100644 --- a/polaris-core/src/testFixtures/java/org/apache/polaris/core/persistence/BasePolarisMetaStoreManagerTest.java +++ b/polaris-core/src/testFixtures/java/org/apache/polaris/core/persistence/BasePolarisMetaStoreManagerTest.java @@ -273,6 +273,12 @@ public abstract class BasePolarisMetaStoreManagerTest { polarisTestMetaStoreManager.testRename(); } + /** test entity lookup */ + @Test + protected void testLookup() { + polarisTestMetaStoreManager.testLookup(); + } + /** Test the set of functions for the entity cache */ @Test protected void testEntityCache() { diff --git a/polaris-core/src/testFixtures/java/org/apache/polaris/core/persistence/PolarisTestMetaStoreManager.java b/polaris-core/src/testFixtures/java/org/apache/polaris/core/persistence/PolarisTestMetaStoreManager.java index 81b95ab39..b401d4efb 100644 --- a/polaris-core/src/testFixtures/java/org/apache/polaris/core/persistence/PolarisTestMetaStoreManager.java +++ b/polaris-core/src/testFixtures/java/org/apache/polaris/core/persistence/PolarisTestMetaStoreManager.java @@ -192,6 +192,24 @@ public class PolarisTestMetaStoreManager { return entity; } + /** + * Validate that the specified identity identified by the pair catalogId, entityId does not exist. + * + * @param catalogId catalog id of that entity + * @param entityId the entity id + * @param expectedType its expected type + */ + private void ensureNotExistsById(long catalogId, long entityId, PolarisEntityType expectedType) { + + PolarisBaseEntity entity = + polarisMetaStoreManager + .loadEntity(this.polarisCallContext, catalogId, entityId, expectedType) + .getEntity(); + + // assert entity was not found + Assertions.assertThat(entity).isNull(); + } + /** * Check if the specified grant record exists * @@ -2564,6 +2582,68 @@ public class PolarisTestMetaStoreManager { this.renameEntity(List.of(catalog, N1, N1_N2), N1_N2_T1, List.of(catalog, N5), "T7"); } + /** Play with looking up entities */ + public void testLookup() { + // load all principals + List<EntityNameLookupRecord> principals = + polarisMetaStoreManager + .listEntities( + this.polarisCallContext, + null, + PolarisEntityType.PRINCIPAL, + PolarisEntitySubType.NULL_SUBTYPE) + .getEntities(); + + // ensure not null, one element only + Assertions.assertThat(principals).isNotNull().hasSize(1); + + // get catalog list information + EntityNameLookupRecord principalListInfo = principals.get(0); + + PolarisBaseEntity principal = + this.ensureExistsById( + null, + principalListInfo.getId(), + true, + PolarisEntityConstants.getRootPrincipalName(), + PolarisEntityType.PRINCIPAL, + PolarisEntitySubType.NULL_SUBTYPE); + + this.ensureNotExistsById( + PolarisEntityConstants.getNullId(), principal.getId(), PolarisEntityType.PRINCIPAL_ROLE); + this.ensureNotExistsById( + PolarisEntityConstants.getNullId(), principal.getId(), PolarisEntityType.CATALOG); + this.ensureNotExistsById( + PolarisEntityConstants.getNullId(), principal.getId(), PolarisEntityType.CATALOG_ROLE); + + // create new catalog + PolarisBaseEntity catalog = + new PolarisBaseEntity( + PolarisEntityConstants.getNullId(), + polarisMetaStoreManager.generateNewEntityId(this.polarisCallContext).getId(), + PolarisEntityType.CATALOG, + PolarisEntitySubType.NULL_SUBTYPE, + PolarisEntityConstants.getRootEntityId(), + "test"); + CreateCatalogResult catalogCreated = + polarisMetaStoreManager.createCatalog(this.polarisCallContext, catalog, List.of()); + Assertions.assertThat(catalogCreated).isNotNull(); + catalog = catalogCreated.getCatalog(); + + // now create all objects + PolarisBaseEntity N1 = this.createEntity(List.of(catalog), PolarisEntityType.NAMESPACE, "N1"); + PolarisBaseEntity N1_N2 = + this.createEntity(List.of(catalog, N1), PolarisEntityType.NAMESPACE, "N2"); + PolarisBaseEntity T1 = + this.createEntity( + List.of(catalog, N1, N1_N2), + PolarisEntityType.TABLE_LIKE, + PolarisEntitySubType.ICEBERG_TABLE, + "T1"); + + this.ensureNotExistsById(catalog.getId(), T1.getId(), PolarisEntityType.NAMESPACE); + } + /** Test the set of functions for the entity cache */ public void testEntityCache() { // create test catalog