Skip to content

[#12594] feat(authz): Add Semantic Model ownership and privilege support - #12867

Open
laserninja wants to merge 1 commit into
apache:mainfrom
laserninja:semantic-model-ownership-privilege
Open

[#12594] feat(authz): Add Semantic Model ownership and privilege support#12867
laserninja wants to merge 1 commit into
apache:mainfrom
laserninja:semantic-model-ownership-privilege

Conversation

@laserninja

Copy link
Copy Markdown
Collaborator

What changes were proposed in this pull request?

Adds the authorization layer for Semantic Models, following the "Authorization and Governance" section of design-docs/gravitino-semantic-model-design.md.

Privileges (api)

  • CREATE_SEMANTIC_MODEL, SELECT_SEMANTIC_MODEL, and MODIFY_SEMANTIC_MODEL in Privilege.Name, plus the matching Privileges classes and allow/deny resolution.
  • Binding rules: CREATE_SEMANTIC_MODEL binds to METALAKE, CATALOG, and SCHEMA (the scope it creates into); SELECT_SEMANTIC_MODEL and MODIFY_SEMANTIC_MODEL additionally bind to SEMANTIC_MODEL.
  • SecurableObjects.ofSemanticModel(...), and SEMANTIC_MODEL added to ManageGrants bindings so grant management can be delegated per Semantic Model, as it already can for every other schema-level object.
  • AuthorizationUtils.checkPrivilege rejects the new privileges on non-relational catalogs, matching SemanticModelOperationDispatcher, which only serves relational catalogs.

Ownership (core)

  • New SemanticModelHookDispatcher sets the creator as owner after a successful create.
  • The dispatcher chain becomes SemanticModelHookDispatcher -> SemanticModelNormalizeDispatcher -> SemanticModelOperationDispatcher, with a TODO marking where [Subtask] Add event listener support for Semantic Model operations #12595's event dispatcher belongs.
  • The hook rebuilds the stored identifier as normalized-namespace plus the created model's own name. SemanticModelNormalizeDispatcher case-folds only the parent namespace against the catalog capability and applies Gravitino-owned naming to the model name, so reusing applyCapabilities(ident, scope, catalogManager) the way ModelHookDispatcher does would attach the owner to a case-folded name the store never used.
  • SEMANTIC_MODEL added to AuthorizationUtils.SKIP_APPLY_TYPES: Semantic Models exist only in Gravitino, so there is nothing for a catalog authorization plugin to grant, revoke, or rename.

Authorization plumbing

  • LOAD, CREATE, MODIFY, DROP, and FILTER expressions in AuthorizationExpressionConstants. Drop deliberately requires ownership rather than MODIFY_SEMANTIC_MODEL, per the design doc.
  • ANY_CREATE_SEMANTIC_MODEL, ANY_SELECT_SEMANTIC_MODEL, and ANY_MODIFY_SEMANTIC_MODEL token expansion in AuthorizationExpressionConverter, with deny taking precedence at every scope.
  • SEMANTIC_MODEL in CAN_ACCESS_METADATA, so the owner API accepts Semantic Model objects.
  • MetadataObjectUtil.checkMetadataObject, EntityClassMapper, MetadataIdConverter case-sensitivity scope, and JcasbinAuthorizationCacheKeys all handle SEMANTIC_MODEL.

Docs

  • docs/security/access-control.md: object tree, privilege table, and required-privileges table.

Why are the changes needed?

Semantic Models are new securable metadata objects. Without privileges and an ownership hook they would be created with no owner and no way to grant access, so the REST APIs in #12607 and #12608 have nothing to enforce.

Fix: #12594

Does this PR introduce any user-facing change?

Yes, additive only:

  • Three new privilege names usable in role grants: CREATE_SEMANTIC_MODEL, SELECT_SEMANTIC_MODEL, MODIFY_SEMANTIC_MODEL.
  • SecurableObjects.ofSemanticModel(...) in the public API.
  • SEMANTIC_MODEL accepted by the owner API and as a MANAGE_GRANTS target.

No existing privilege, wire format, or config default changes.

Follow-up

Two items in the issue's checklist depend on SemanticModelMetaMapper and SemanticModelPO, which land in #12602/#12603, and are deferred to a follow-up PR:

  • MetadataObjectService.TYPE_TO_FULLNAME_FUNCTION_MAP needs a getSemanticModelObjectsFullName entry to resolve a Semantic Model ID back to a full name when listing owned objects.
  • OrphanedMetadataObjectRelationService.ENTITY_TABLES needs a Semantic Model entry so owner relation rows are cleaned up after a hard delete.

Neither is reachable on main today: JDBCBackend still stubs Semantic Model persistence, so no Semantic Model, and therefore no owner relation, can exist yet.

How was this patch tested?

New tests:

  • TestSemanticModelHookDispatcher: owner assignment, namespace normalization versus Gravitino-owned naming, pass-through when the owner dispatcher is disabled, propagation when setOwner fails, and no owner interaction on list/load/alter/drop.
  • TestSemanticModelAuthorizationExpression: create, load, filter, alter, and drop expressions, covering owner paths, the USE_CATALOG + USE_SCHEMA chain, deny precedence, and the two negative cases that matter, namely SELECT_SEMANTIC_MODEL not permitting alter and MODIFY_SEMANTIC_MODEL not permitting drop.

Extended: TestSecurableObjects (binding matrix, allow/deny resolution, name-length validation), TestAuthorizationUtils (plugin is not notified for Semantic Models), TestMetadataIdConverter, TestJcasbinAuthorizationCacheKeys.

Local verification with JDK 17:

./gradlew :api:test :server-common:test :core:test --tests "org.apache.gravitino.hook.*" --tests "org.apache.gravitino.authorization.*" --tests "org.apache.gravitino.utils.*" :server:test --tests "org.apache.gravitino.server.web.rest.authorization.*" -PskipITs

All green, plus spotlessCheck and javadoc clean on :api, :core, :server-common, and :server.

…e support

Introduce the CREATE_SEMANTIC_MODEL, SELECT_SEMANTIC_MODEL, and
MODIFY_SEMANTIC_MODEL privileges together with their schema-level and
object-level binding rules, and add SemanticModelHookDispatcher so the
creator becomes the owner of a newly created Semantic Model.

Semantic Models are managed entirely by Gravitino, so their privileges are
not pushed down to catalog authorization plugins.
@github-actions

github-actions Bot commented Sep 3, 2026

Copy link
Copy Markdown

Code Coverage Report

Overall Project 68.94% -0.11% 🟢
Files changed 62.42% 🟢

Module Coverage
aliyun 19.74% 🔴
api 51.91% +1.71% 🟢
authorization-common 85.96% 🟢
authorization-ranger 4.38% 🔴
aws 53.54% 🟢
azure 32.1% 🔴
catalog-common 20.87% 🔴
catalog-fileset 82.17% 🟢
catalog-glue 69.24% 🟢
catalog-hive 82.96% 🟢
catalog-jdbc-common 45.69% 🟢
catalog-jdbc-doris 82.69% 🟢
catalog-jdbc-mysql 79.33% 🟢
catalog-jdbc-postgresql 83.39% 🟢
catalog-jdbc-starrocks 79.16% 🟢
catalog-kafka 76.99% 🟢
catalog-lakehouse-generic 60.55% 🟢
catalog-lakehouse-hudi 79.1% 🟢
catalog-lakehouse-iceberg 85.86% 🟢
catalog-lakehouse-paimon 84.29% 🟢
catalog-model 77.99% 🟢
cli 44.51% 🟢
client-java 77.37% 🟢
common 56.34% 🟢
core 83.82% -0.8% 🟢
filesystem-hadoop3 76.48% 🟢
flink 0.0% 🔴
flink-common 52.1% 🟢
flink-runtime 0.0% 🔴
gcp 32.2% 🔴
hadoop-auth 68.0% 🟢
hadoop-common 17.84% 🔴
hive-metastore-common 53.4% 🟢
iceberg-aliyun-bundle 0.0% 🔴
iceberg-common 64.75% 🟢
iceberg-rest-server 75.96% -1.26% 🟢
idp-basic 86.42% 🟢
integration-test-common 0.0% 🔴
jobs 62.92% 🟢
lance-common 32.52% 🔴
lance-rest-server 65.69% 🟢
lineage 53.02% 🟢
optimizer 83.17% 🟢
optimizer-api 21.95% 🔴
server 88.47% -0.43% 🟢
server-common 80.71% +0.89% 🟢
spark 28.57% 🔴
spark-common 52.04% 🟢
tencent 81.78% 🟢
trino-connector 51.26% 🟢
Files
Module File Coverage
api Privilege.java 96.0% 🟢
Privileges.java 64.84% 🟢
SecurableObjects.java 62.3% 🟢
core SemanticModelHookDispatcher.java 100.0% 🟢
AuthorizationUtils.java 63.67% 🟢
MetadataObjectUtil.java 57.35% 🔴
GravitinoEnv.java 29.55% 🔴
EntityClassMapper.java 0.0% 🔴
iceberg-rest-server RenameViewAuthzHandler.java 0.0% 🔴
server ViewOperations.java 100.0% 🟢
GravitinoInterceptionService.java 70.4% 🟢
server-common AuthorizationExpressionConverter.java 98.25% 🟢
JcasbinAuthorizationCacheKeys.java 95.74% 🟢
MetadataIdConverter.java 75.86% 🟢
AuthorizationExpressionConstants.java 0.0% 🔴

@laserninja

Copy link
Copy Markdown
Collaborator Author

CI is green except FrontendIT, which failed on two Selenium tests in CatalogsPageTest:

  • testClickCatalogLink - org.awaitility.core.ConditionTimeoutException after 5 seconds
  • testCreateFileset - expected: <true> but was: <false>

Both look unrelated to this PR:

  • The diff touches only api, core, server-common, server tests, and docs. Nothing under web-v2, and no catalog or fileset code path.
  • CatalogsPageTest is unstable across unrelated PRs in the same window - for example run 33735997908 on trino-479-support failed with CatalogsPageTest > initializationError.
  • Every other integration suite passed here, including access-control-IT, all three BackendIT variants (h2 embedded, MySQL deploy, PostgreSQL deploy), TrinoIT, IcebergRestTrinoIT, SparkIT, FlinkIT, PythonIT, and MaintenanceIT. If the new dispatcher wiring broke server startup, those would have failed too.

I do not have rights to re-run the single failed job. Happy to push a rebase to re-trigger the matrix if a committer prefers a clean run.

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.

[Subtask] Add Semantic Model ownership and privilege support

1 participant