diff --git a/core/trino-grammar/src/main/antlr4/io/trino/grammar/sql/SqlBase.g4 b/core/trino-grammar/src/main/antlr4/io/trino/grammar/sql/SqlBase.g4 index 3bc36d93c3ad..266f2f759840 100644 --- a/core/trino-grammar/src/main/antlr4/io/trino/grammar/sql/SqlBase.g4 +++ b/core/trino-grammar/src/main/antlr4/io/trino/grammar/sql/SqlBase.g4 @@ -60,7 +60,6 @@ statement (WITH properties)? #createSchema | DROP SCHEMA (IF EXISTS)? qualifiedName (CASCADE | RESTRICT)? #dropSchema | ALTER SCHEMA qualifiedName RENAME TO identifier #renameSchema - | ALTER SCHEMA qualifiedName SET AUTHORIZATION principal #setSchemaAuthorization | CREATE (OR REPLACE)? TABLE (IF NOT EXISTS)? qualifiedName columnAliases? (COMMENT string)? @@ -89,13 +88,13 @@ statement ALTER COLUMN columnName=qualifiedName SET DATA TYPE type #setColumnType | ALTER TABLE (IF EXISTS)? tableName=qualifiedName ALTER COLUMN columnName=identifier DROP NOT NULL #dropNotNullConstraint - | ALTER TABLE tableName=qualifiedName SET AUTHORIZATION principal #setTableAuthorization | ALTER TABLE tableName=qualifiedName SET PROPERTIES propertyAssignments #setTableProperties | ALTER TABLE tableName=qualifiedName EXECUTE procedureName=identifier ('(' (callArgument (',' callArgument)*)? ')')? (WHERE where=booleanExpression)? #tableExecute + | ALTER ownedEntityKind qualifiedName SET AUTHORIZATION principal #setAuthorization | ANALYZE qualifiedName (WITH properties)? #analyze | CREATE (OR REPLACE)? MATERIALIZED VIEW (IF NOT EXISTS)? qualifiedName @@ -114,7 +113,6 @@ statement SET PROPERTIES propertyAssignments #setMaterializedViewProperties | DROP VIEW (IF EXISTS)? qualifiedName #dropView | ALTER VIEW from=qualifiedName RENAME TO to=qualifiedName #renameView - | ALTER VIEW from=qualifiedName SET AUTHORIZATION principal #setViewAuthorization | CALL qualifiedName '(' (callArgument (',' callArgument)*)? ')' #call | CREATE (OR REPLACE)? functionSpecification #createFunction | DROP FUNCTION (IF EXISTS)? functionDeclaration #dropFunction @@ -937,6 +935,14 @@ grantObject : entityKind? qualifiedName ; +ownedEntityKind + : MATERIALIZED? basicEntityKind + ; + +basicEntityKind + : TABLE | SCHEMA | VIEW | identifier + ; + qualifiedName : identifier ('.' identifier)* ; diff --git a/core/trino-main/src/main/java/io/trino/execution/SetAuthorizationTask.java b/core/trino-main/src/main/java/io/trino/execution/SetAuthorizationTask.java new file mode 100644 index 000000000000..c01a0f179944 --- /dev/null +++ b/core/trino-main/src/main/java/io/trino/execution/SetAuthorizationTask.java @@ -0,0 +1,114 @@ +/* + * Licensed 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 io.trino.execution; + +import com.google.common.util.concurrent.ListenableFuture; +import com.google.inject.Inject; +import io.trino.Session; +import io.trino.execution.warnings.WarningCollector; +import io.trino.metadata.Metadata; +import io.trino.metadata.QualifiedObjectName; +import io.trino.metadata.RedirectionAwareTableHandle; +import io.trino.security.AccessControl; +import io.trino.spi.connector.CatalogSchemaName; +import io.trino.spi.security.TrinoPrincipal; +import io.trino.sql.tree.Expression; +import io.trino.sql.tree.SetAuthorizationStatement; + +import java.util.List; +import java.util.Optional; + +import static com.google.common.util.concurrent.Futures.immediateVoidFuture; +import static io.trino.metadata.MetadataUtil.checkRoleExists; +import static io.trino.metadata.MetadataUtil.createCatalogSchemaName; +import static io.trino.metadata.MetadataUtil.createPrincipal; +import static io.trino.metadata.MetadataUtil.fillInNameParts; +import static io.trino.metadata.MetadataUtil.getRequiredCatalogHandle; +import static io.trino.spi.StandardErrorCode.NOT_SUPPORTED; +import static io.trino.spi.StandardErrorCode.SCHEMA_NOT_FOUND; +import static io.trino.spi.StandardErrorCode.TABLE_NOT_FOUND; +import static io.trino.sql.analyzer.SemanticExceptions.semanticException; +import static java.util.Objects.requireNonNull; + +public class SetAuthorizationTask + implements DataDefinitionTask +{ + private final Metadata metadata; + private final AccessControl accessControl; + + @Inject + public SetAuthorizationTask(Metadata metadata, AccessControl accessControl) + { + this.metadata = requireNonNull(metadata, "metadata is null"); + this.accessControl = requireNonNull(accessControl, "accessControl is null"); + } + + @Override + public String getName() + { + return "SET AUTHORIZATION"; + } + + @Override + public ListenableFuture execute( + SetAuthorizationStatement statement, + QueryStateMachine stateMachine, + List parameters, + WarningCollector warningCollector) + { + Session session = stateMachine.getSession(); + setEntityAuthorization(session, statement); + + return immediateVoidFuture(); + } + + private void setEntityAuthorization(Session session, SetAuthorizationStatement statement) + { + List name = fillInNameParts(session, statement, statement.getOwnedEntityKind(), statement.getSource().getParts()); + + // Preprocess SCHEMA, TABLE and VIEW to generate error messages in the order compatible with existing tests + switch (statement.getOwnedEntityKind()) { + case "SCHEMA" -> { + CatalogSchemaName source = createCatalogSchemaName(session, statement, Optional.of(statement.getSource())); + if (!metadata.schemaExists(session, source)) { + throw semanticException(SCHEMA_NOT_FOUND, statement, "Schema '%s' does not exist", source); + } + } + case "TABLE" -> { + QualifiedObjectName tableName = new QualifiedObjectName(name.get(0), name.get(1), name.get(2)); + getRequiredCatalogHandle(metadata, session, statement, name.get(0)); + RedirectionAwareTableHandle redirection = metadata.getRedirectionAwareTableHandle(session, tableName); + if (redirection.tableHandle().isEmpty()) { + throw semanticException(TABLE_NOT_FOUND, statement, "Table '%s' does not exist", tableName); + } + if (redirection.redirectedTableName().isPresent()) { + throw semanticException(NOT_SUPPORTED, statement, "Table %s is redirected to %s and SET TABLE AUTHORIZATION is not supported with table redirections", tableName, redirection.redirectedTableName().get()); + } + } + case "VIEW" -> { + QualifiedObjectName viewName = new QualifiedObjectName(name.get(0), name.get(1), name.get(2)); + getRequiredCatalogHandle(metadata, session, statement, viewName.catalogName()); + if (!metadata.isView(session, viewName)) { + throw semanticException(TABLE_NOT_FOUND, statement, "View '%s' does not exist", viewName); + } + } + } + + TrinoPrincipal principal = createPrincipal(statement.getPrincipal()); + Optional maybeCatalogName = name.size() > 1 ? Optional.of(name.get(0)) : Optional.empty(); + checkRoleExists(session, statement, metadata, principal, maybeCatalogName.filter(catalog -> metadata.isCatalogManagedSecurity(session, catalog))); + accessControl.checkCanSetEntityAuthorization(session.toSecurityContext(), statement.getOwnedEntityKind(), name, principal); + metadata.setEntityAuthorization(session, statement.getOwnedEntityKind(), name, principal); + } +} diff --git a/core/trino-main/src/main/java/io/trino/execution/SetSchemaAuthorizationTask.java b/core/trino-main/src/main/java/io/trino/execution/SetSchemaAuthorizationTask.java deleted file mode 100644 index c1cdd7ba1d66..000000000000 --- a/core/trino-main/src/main/java/io/trino/execution/SetSchemaAuthorizationTask.java +++ /dev/null @@ -1,80 +0,0 @@ -/* - * Licensed 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 io.trino.execution; - -import com.google.common.util.concurrent.ListenableFuture; -import com.google.inject.Inject; -import io.trino.Session; -import io.trino.execution.warnings.WarningCollector; -import io.trino.metadata.Metadata; -import io.trino.security.AccessControl; -import io.trino.spi.connector.CatalogSchemaName; -import io.trino.spi.security.TrinoPrincipal; -import io.trino.sql.tree.Expression; -import io.trino.sql.tree.SetSchemaAuthorization; - -import java.util.List; -import java.util.Optional; - -import static com.google.common.util.concurrent.Futures.immediateVoidFuture; -import static io.trino.metadata.MetadataUtil.checkRoleExists; -import static io.trino.metadata.MetadataUtil.createCatalogSchemaName; -import static io.trino.metadata.MetadataUtil.createPrincipal; -import static io.trino.spi.StandardErrorCode.SCHEMA_NOT_FOUND; -import static io.trino.sql.analyzer.SemanticExceptions.semanticException; -import static java.util.Objects.requireNonNull; - -public class SetSchemaAuthorizationTask - implements DataDefinitionTask -{ - private final Metadata metadata; - private final AccessControl accessControl; - - @Inject - public SetSchemaAuthorizationTask(Metadata metadata, AccessControl accessControl) - { - this.metadata = requireNonNull(metadata, "metadata is null"); - this.accessControl = requireNonNull(accessControl, "accessControl is null"); - } - - @Override - public String getName() - { - return "SET SCHEMA AUTHORIZATION"; - } - - @Override - public ListenableFuture execute( - SetSchemaAuthorization statement, - QueryStateMachine stateMachine, - List parameters, - WarningCollector warningCollector) - { - Session session = stateMachine.getSession(); - - CatalogSchemaName source = createCatalogSchemaName(session, statement, Optional.of(statement.getSource())); - - if (!metadata.schemaExists(session, source)) { - throw semanticException(SCHEMA_NOT_FOUND, statement, "Schema '%s' does not exist", source); - } - TrinoPrincipal principal = createPrincipal(statement.getPrincipal()); - checkRoleExists(session, statement, metadata, principal, Optional.of(source.getCatalogName()).filter(catalog -> metadata.isCatalogManagedSecurity(session, catalog))); - - accessControl.checkCanSetSchemaAuthorization(session.toSecurityContext(), source, principal); - - metadata.setSchemaAuthorization(session, source, principal); - - return immediateVoidFuture(); - } -} diff --git a/core/trino-main/src/main/java/io/trino/execution/SetTableAuthorizationTask.java b/core/trino-main/src/main/java/io/trino/execution/SetTableAuthorizationTask.java deleted file mode 100644 index c8d38986b063..000000000000 --- a/core/trino-main/src/main/java/io/trino/execution/SetTableAuthorizationTask.java +++ /dev/null @@ -1,88 +0,0 @@ -/* - * Licensed 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 io.trino.execution; - -import com.google.common.util.concurrent.ListenableFuture; -import com.google.inject.Inject; -import io.trino.Session; -import io.trino.execution.warnings.WarningCollector; -import io.trino.metadata.Metadata; -import io.trino.metadata.QualifiedObjectName; -import io.trino.metadata.RedirectionAwareTableHandle; -import io.trino.security.AccessControl; -import io.trino.spi.security.TrinoPrincipal; -import io.trino.sql.tree.Expression; -import io.trino.sql.tree.SetTableAuthorization; - -import java.util.List; -import java.util.Optional; - -import static com.google.common.util.concurrent.Futures.immediateVoidFuture; -import static io.trino.metadata.MetadataUtil.checkRoleExists; -import static io.trino.metadata.MetadataUtil.createPrincipal; -import static io.trino.metadata.MetadataUtil.createQualifiedObjectName; -import static io.trino.metadata.MetadataUtil.getRequiredCatalogHandle; -import static io.trino.spi.StandardErrorCode.NOT_SUPPORTED; -import static io.trino.spi.StandardErrorCode.TABLE_NOT_FOUND; -import static io.trino.sql.analyzer.SemanticExceptions.semanticException; -import static java.util.Objects.requireNonNull; - -public class SetTableAuthorizationTask - implements DataDefinitionTask -{ - private final Metadata metadata; - private final AccessControl accessControl; - - @Inject - public SetTableAuthorizationTask(Metadata metadata, AccessControl accessControl) - { - this.metadata = requireNonNull(metadata, "metadata is null"); - this.accessControl = requireNonNull(accessControl, "accessControl is null"); - } - - @Override - public String getName() - { - return "SET TABLE AUTHORIZATION"; - } - - @Override - public ListenableFuture execute( - SetTableAuthorization statement, - QueryStateMachine stateMachine, - List parameters, - WarningCollector warningCollector) - { - Session session = stateMachine.getSession(); - QualifiedObjectName tableName = createQualifiedObjectName(session, statement, statement.getSource()); - - getRequiredCatalogHandle(metadata, session, statement, tableName.catalogName()); - RedirectionAwareTableHandle redirection = metadata.getRedirectionAwareTableHandle(session, tableName); - if (redirection.tableHandle().isEmpty()) { - throw semanticException(TABLE_NOT_FOUND, statement, "Table '%s' does not exist", tableName); - } - if (redirection.redirectedTableName().isPresent()) { - throw semanticException(NOT_SUPPORTED, statement, "Table %s is redirected to %s and SET TABLE AUTHORIZATION is not supported with table redirections", tableName, redirection.redirectedTableName().get()); - } - - TrinoPrincipal principal = createPrincipal(statement.getPrincipal()); - checkRoleExists(session, statement, metadata, principal, Optional.of(tableName.catalogName()).filter(catalog -> metadata.isCatalogManagedSecurity(session, catalog))); - - accessControl.checkCanSetTableAuthorization(session.toSecurityContext(), tableName, principal); - - metadata.setTableAuthorization(session, tableName.asCatalogSchemaTableName(), principal); - - return immediateVoidFuture(); - } -} diff --git a/core/trino-main/src/main/java/io/trino/execution/SetViewAuthorizationTask.java b/core/trino-main/src/main/java/io/trino/execution/SetViewAuthorizationTask.java deleted file mode 100644 index 14d76cb57472..000000000000 --- a/core/trino-main/src/main/java/io/trino/execution/SetViewAuthorizationTask.java +++ /dev/null @@ -1,81 +0,0 @@ -/* - * Licensed 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 io.trino.execution; - -import com.google.common.util.concurrent.ListenableFuture; -import com.google.inject.Inject; -import io.trino.Session; -import io.trino.execution.warnings.WarningCollector; -import io.trino.metadata.Metadata; -import io.trino.metadata.QualifiedObjectName; -import io.trino.security.AccessControl; -import io.trino.spi.security.TrinoPrincipal; -import io.trino.sql.tree.Expression; -import io.trino.sql.tree.SetViewAuthorization; - -import java.util.List; -import java.util.Optional; - -import static com.google.common.util.concurrent.Futures.immediateVoidFuture; -import static io.trino.metadata.MetadataUtil.checkRoleExists; -import static io.trino.metadata.MetadataUtil.createPrincipal; -import static io.trino.metadata.MetadataUtil.createQualifiedObjectName; -import static io.trino.metadata.MetadataUtil.getRequiredCatalogHandle; -import static io.trino.spi.StandardErrorCode.TABLE_NOT_FOUND; -import static io.trino.sql.analyzer.SemanticExceptions.semanticException; -import static java.util.Objects.requireNonNull; - -public class SetViewAuthorizationTask - implements DataDefinitionTask -{ - private final Metadata metadata; - private final AccessControl accessControl; - - @Inject - public SetViewAuthorizationTask(Metadata metadata, AccessControl accessControl) - { - this.metadata = requireNonNull(metadata, "metadata is null"); - this.accessControl = requireNonNull(accessControl, "accessControl is null"); - } - - @Override - public String getName() - { - return "SET VIEW AUTHORIZATION"; - } - - @Override - public ListenableFuture execute( - SetViewAuthorization statement, - QueryStateMachine stateMachine, - List parameters, - WarningCollector warningCollector) - { - Session session = stateMachine.getSession(); - QualifiedObjectName viewName = createQualifiedObjectName(session, statement, statement.getSource()); - getRequiredCatalogHandle(metadata, session, statement, viewName.catalogName()); - if (!metadata.isView(session, viewName)) { - throw semanticException(TABLE_NOT_FOUND, statement, "View '%s' does not exist", viewName); - } - - TrinoPrincipal principal = createPrincipal(statement.getPrincipal()); - checkRoleExists(session, statement, metadata, principal, Optional.of(viewName.catalogName()).filter(catalog -> metadata.isCatalogManagedSecurity(session, catalog))); - - accessControl.checkCanSetViewAuthorization(session.toSecurityContext(), viewName, principal); - - metadata.setViewAuthorization(session, viewName.asCatalogSchemaTableName(), principal); - - return immediateVoidFuture(); - } -} diff --git a/core/trino-main/src/main/java/io/trino/metadata/DisabledSystemSecurityMetadata.java b/core/trino-main/src/main/java/io/trino/metadata/DisabledSystemSecurityMetadata.java index 1ab6ab47e830..f66aa0aab78d 100644 --- a/core/trino-main/src/main/java/io/trino/metadata/DisabledSystemSecurityMetadata.java +++ b/core/trino-main/src/main/java/io/trino/metadata/DisabledSystemSecurityMetadata.java @@ -165,30 +165,12 @@ public Optional getSchemaOwner(Session session, CatalogSchemaNam return Optional.empty(); } - @Override - public void setSchemaOwner(Session session, CatalogSchemaName schema, TrinoPrincipal principal) - { - throw notSupportedException(schema.getCatalogName()); - } - - @Override - public void setTableOwner(Session session, CatalogSchemaTableName table, TrinoPrincipal principal) - { - throw notSupportedException(table.getCatalogName()); - } - @Override public Optional getViewRunAsIdentity(Session session, CatalogSchemaTableName view) { return Optional.empty(); } - @Override - public void setViewOwner(Session session, CatalogSchemaTableName view, TrinoPrincipal principal) - { - throw notSupportedException(view.getCatalogName()); - } - @Override public Optional getFunctionRunAsIdentity(Session session, CatalogSchemaFunctionName functionName) { @@ -228,6 +210,12 @@ public void columnTypeChanged(Session session, CatalogSchemaTableName table, Str @Override public void columnNotNullConstraintDropped(Session session, CatalogSchemaTableName table, String column) {} + @Override + public void setEntityOwner(Session session, String ownedKind, List name, TrinoPrincipal principal) + { + throw notSupportedException(name.get(0)); + } + private static TrinoException notSupportedException(String catalogName) { return new TrinoException(NOT_SUPPORTED, "Catalog does not support permission management: " + catalogName); diff --git a/core/trino-main/src/main/java/io/trino/metadata/Metadata.java b/core/trino-main/src/main/java/io/trino/metadata/Metadata.java index 2c71eb193ab4..3c1c3b832421 100644 --- a/core/trino-main/src/main/java/io/trino/metadata/Metadata.java +++ b/core/trino-main/src/main/java/io/trino/metadata/Metadata.java @@ -221,11 +221,6 @@ Optional getTableHandleForExecute( */ void renameSchema(Session session, CatalogSchemaName source, String target); - /** - * Set the specified schema's user/role. - */ - void setSchemaAuthorization(Session session, CatalogSchemaName source, TrinoPrincipal principal); - /** * Creates a table using the specified table metadata. * @@ -298,11 +293,6 @@ Optional getTableHandleForExecute( */ void dropNotNullConstraint(Session session, TableHandle tableHandle, ColumnHandle column); - /** - * Set the authorization (owner) of specified table's user/role - */ - void setTableAuthorization(Session session, CatalogSchemaTableName table, TrinoPrincipal principal); - /** * Drop the specified column. */ @@ -519,11 +509,6 @@ Optional finishRefreshMaterializedView( */ void renameView(Session session, QualifiedObjectName existingViewName, QualifiedObjectName newViewName); - /** - * Set the authorization (owner) of specified view's user/role - */ - void setViewAuthorization(Session session, CatalogSchemaTableName view, TrinoPrincipal principal); - /** * Drops the specified view. */ @@ -865,4 +850,6 @@ default boolean isMaterializedView(Session session, QualifiedObjectName viewName * Returns writer scaling options for the specified table. */ WriterScalingOptions getInsertWriterScalingOptions(Session session, TableHandle tableHandle); + + void setEntityAuthorization(Session session, String ownedKind, List name, TrinoPrincipal principal); } diff --git a/core/trino-main/src/main/java/io/trino/metadata/MetadataManager.java b/core/trino-main/src/main/java/io/trino/metadata/MetadataManager.java index f437ae0bd5f9..56082526018e 100644 --- a/core/trino-main/src/main/java/io/trino/metadata/MetadataManager.java +++ b/core/trino-main/src/main/java/io/trino/metadata/MetadataManager.java @@ -179,6 +179,7 @@ public final class MetadataManager implements Metadata { + private static final Set ENTITY_KINDS_WITH_CATALOG = ImmutableSet.of("SCHEMA", "TABLE", "VIEW"); private static final Logger log = Logger.get(MetadataManager.class); @VisibleForTesting @@ -850,20 +851,6 @@ public void renameSchema(Session session, CatalogSchemaName source, String targe } } - @Override - public void setSchemaAuthorization(Session session, CatalogSchemaName source, TrinoPrincipal principal) - { - CatalogMetadata catalogMetadata = getCatalogMetadataForWrite(session, source.getCatalogName()); - CatalogHandle catalogHandle = catalogMetadata.getCatalogHandle(); - ConnectorMetadata metadata = catalogMetadata.getMetadata(session); - if (catalogMetadata.getSecurityManagement() == SYSTEM) { - systemSecurityMetadata.setSchemaOwner(session, source, principal); - } - else { - metadata.setSchemaAuthorization(session.toConnectorSession(catalogHandle), source.getSchemaName(), principal); - } - } - @Override public void createTable(Session session, String catalogName, ConnectorTableMetadata tableMetadata, SaveMode saveMode) { @@ -1039,19 +1026,6 @@ public void dropNotNullConstraint(Session session, TableHandle tableHandle, Colu } } - @Override - public void setTableAuthorization(Session session, CatalogSchemaTableName table, TrinoPrincipal principal) - { - CatalogMetadata catalogMetadata = getCatalogMetadataForWrite(session, table.getCatalogName()); - ConnectorMetadata metadata = catalogMetadata.getMetadata(session); - if (catalogMetadata.getSecurityManagement() == SYSTEM) { - systemSecurityMetadata.setTableOwner(session, table, principal); - } - else { - metadata.setTableAuthorization(session.toConnectorSession(catalogMetadata.getCatalogHandle()), table.getSchemaTableName(), principal); - } - } - @Override public void dropTable(Session session, TableHandle tableHandle, CatalogSchemaTableName tableName) { @@ -1633,21 +1607,6 @@ public void renameView(Session session, QualifiedObjectName source, QualifiedObj } } - @Override - public void setViewAuthorization(Session session, CatalogSchemaTableName view, TrinoPrincipal principal) - { - CatalogMetadata catalogMetadata = getCatalogMetadataForWrite(session, view.getCatalogName()); - CatalogHandle catalogHandle = catalogMetadata.getCatalogHandle(); - ConnectorMetadata metadata = catalogMetadata.getMetadata(session); - - if (catalogMetadata.getSecurityManagement() == SYSTEM) { - systemSecurityMetadata.setViewOwner(session, view, principal); - } - else { - metadata.setViewAuthorization(session.toConnectorSession(catalogHandle), view.getSchemaTableName(), principal); - } - } - @Override public void dropView(Session session, QualifiedObjectName viewName) { @@ -2874,6 +2833,27 @@ public WriterScalingOptions getInsertWriterScalingOptions(Session session, Table return metadata.getInsertWriterScalingOptions(session.toConnectorSession(tableHandle.catalogHandle()), tableHandle.connectorHandle()); } + @Override + public void setEntityAuthorization(Session session, String ownedKind, List name, TrinoPrincipal principal) + { + if (ENTITY_KINDS_WITH_CATALOG.contains(ownedKind)) { + CatalogMetadata catalogMetadata = getCatalogMetadataForWrite(session, name.get(0)); + CatalogHandle catalogHandle = catalogMetadata.getCatalogHandle(); + ConnectorMetadata metadata = catalogMetadata.getMetadata(session); + + if (catalogMetadata.getSecurityManagement() != SYSTEM) { + switch (ownedKind) { + case "TABLE" -> metadata.setTableAuthorization(session.toConnectorSession(catalogHandle), new SchemaTableName(name.get(1), name.get(2)), principal); + case "VIEW" -> metadata.setViewAuthorization(session.toConnectorSession(catalogHandle), new SchemaTableName(name.get(1), name.get(2)), principal); + case "SCHEMA" -> metadata.setSchemaAuthorization(session.toConnectorSession(catalogHandle), name.get(1), principal); + default -> throw new IllegalArgumentException("Unsupported owned kind: " + ownedKind); + } + return; + } + } + systemSecurityMetadata.setEntityOwner(session, ownedKind, name, principal); + } + private Optional toConnectorVersion(Optional version) { Optional connectorVersion = Optional.empty(); diff --git a/core/trino-main/src/main/java/io/trino/metadata/MetadataUtil.java b/core/trino-main/src/main/java/io/trino/metadata/MetadataUtil.java index eb7f1b48550d..3c989c932eb9 100644 --- a/core/trino-main/src/main/java/io/trino/metadata/MetadataUtil.java +++ b/core/trino-main/src/main/java/io/trino/metadata/MetadataUtil.java @@ -34,10 +34,13 @@ import java.util.List; import java.util.Optional; +import java.util.stream.Collectors; import static com.google.common.base.Preconditions.checkArgument; import static io.trino.SystemSessionProperties.isLegacyCatalogRoles; import static io.trino.spi.StandardErrorCode.CATALOG_NOT_FOUND; +import static io.trino.spi.StandardErrorCode.GENERIC_USER_ERROR; +import static io.trino.spi.StandardErrorCode.INVALID_ENTITY_KIND; import static io.trino.spi.StandardErrorCode.MISSING_CATALOG_NAME; import static io.trino.spi.StandardErrorCode.MISSING_SCHEMA_NAME; import static io.trino.spi.StandardErrorCode.NOT_SUPPORTED; @@ -110,6 +113,55 @@ public static CatalogHandle getRequiredCatalogHandle(Metadata metadata, Session .orElseThrow(() -> semanticException(CATALOG_NOT_FOUND, node, "Catalog '%s' not found", catalogName)); } + /** + * If necessary, fill in missing catalog and schema names from the session catalog and schema + * in the supplied entity name, and throw an exception if they don't exist. + */ + public static List fillInNameParts(Session session, Node node, String entityKind, List name) + { + switch (entityKind) { + case "SCHEMA": + switch (name.size()) { + case 1: + if (session.getCatalog().isPresent()) { + return ImmutableList.of(session.getCatalog().get(), name.get(0)); + } + throw semanticException(MISSING_CATALOG_NAME, node, "Catalog must be specified when session catalog is not set"); + case 2: + break; + default: + throw new TrinoException(GENERIC_USER_ERROR, "Invalid entity %s for entity kind %s".formatted(joinName(name), entityKind)); + } + break; + case "TABLE", "VIEW": + switch (name.size()) { + case 1: + if (session.getCatalog().isPresent() && session.getSchema().isPresent()) { + return ImmutableList.of(session.getCatalog().get(), session.getSchema().get(), name.get(0)); + } + throw semanticException(MISSING_CATALOG_NAME, node, "Catalog and schema name must be specified when session catalog and schema are not set"); + case 2: + if (session.getCatalog().isPresent()) { + return ImmutableList.of(session.getCatalog().get(), name.get(0), name.get(1)); + } + throw semanticException(MISSING_CATALOG_NAME, node, "Catalog must be specified when session catalog is not set"); + case 3: + break; + default: + throw semanticException(INVALID_ENTITY_KIND, node, "Invalid entity %s for entity kind %s", joinName(name), entityKind); + } + break; + default: + break; + } + return name; + } + + private static String joinName(List name) + { + return name.stream().collect(Collectors.joining(".")); + } + public static CatalogSchemaName createCatalogSchemaName(Session session, Node node, Optional schema) { String catalogName = session.getCatalog().orElse(null); diff --git a/core/trino-main/src/main/java/io/trino/metadata/SystemSecurityMetadata.java b/core/trino-main/src/main/java/io/trino/metadata/SystemSecurityMetadata.java index a462d65f4f5c..9f2e062f9e31 100644 --- a/core/trino-main/src/main/java/io/trino/metadata/SystemSecurityMetadata.java +++ b/core/trino-main/src/main/java/io/trino/metadata/SystemSecurityMetadata.java @@ -25,6 +25,7 @@ import io.trino.spi.security.RoleGrant; import io.trino.spi.security.TrinoPrincipal; +import java.util.List; import java.util.Optional; import java.util.Set; @@ -159,26 +160,11 @@ default void validateEntityKindAndPrivileges(Session session, String entityKind, */ Optional getSchemaOwner(Session session, CatalogSchemaName schema); - /** - * Set the owner of the specified schema - */ - void setSchemaOwner(Session session, CatalogSchemaName schema, TrinoPrincipal principal); - - /** - * Set the owner of the specified table - */ - void setTableOwner(Session session, CatalogSchemaTableName table, TrinoPrincipal principal); - /** * Get the identity to run the view as */ Optional getViewRunAsIdentity(Session session, CatalogSchemaTableName viewName); - /** - * Set the owner of the specified view - */ - void setViewOwner(Session session, CatalogSchemaTableName view, TrinoPrincipal principal); - /** * Get the identity to run the function as */ @@ -238,4 +224,11 @@ default void validateEntityKindAndPrivileges(Session session, String entityKind, * Column's NOT NULL constraint was dropped */ void columnNotNullConstraintDropped(Session session, CatalogSchemaTableName table, String column); + + /** + * Set the owner of the entity of entity kind ownedKind, with dotted name from the components of the name list, + * to the supplied principal. The ownedKind string is guaranteed to be uppercase, and the name is guaranteed + * to be fully qualified, i.e., if the entity is a table, the name is of size three. + */ + void setEntityOwner(Session session, String ownedKind, List name, TrinoPrincipal principal); } diff --git a/core/trino-main/src/main/java/io/trino/security/AccessControl.java b/core/trino-main/src/main/java/io/trino/security/AccessControl.java index 475bfad96c47..2ba99f2a6bfb 100644 --- a/core/trino-main/src/main/java/io/trino/security/AccessControl.java +++ b/core/trino-main/src/main/java/io/trino/security/AccessControl.java @@ -37,8 +37,6 @@ import java.util.Optional; import java.util.Set; -import static io.trino.spi.security.AccessDeniedException.denySetViewAuthorization; - public interface AccessControl { /** @@ -143,13 +141,6 @@ public interface AccessControl */ void checkCanRenameSchema(SecurityContext context, CatalogSchemaName schemaName, String newSchemaName); - /** - * Check if identity is allowed to change the specified schema's user/role. - * - * @throws AccessDeniedException if not allowed - */ - void checkCanSetSchemaAuthorization(SecurityContext context, CatalogSchemaName schemaName, TrinoPrincipal principal); - /** * Check if identity is allowed to execute SHOW SCHEMAS in a catalog. *

@@ -282,13 +273,6 @@ public interface AccessControl */ void checkCanAlterColumn(SecurityContext context, QualifiedObjectName tableName); - /** - * Check if identity is allowed to change the specified table's user/role. - * - * @throws AccessDeniedException if not allowed - */ - void checkCanSetTableAuthorization(SecurityContext context, QualifiedObjectName tableName, TrinoPrincipal principal); - /** * Check if identity is allowed to rename a column in the specified table. * @@ -338,16 +322,6 @@ public interface AccessControl */ void checkCanRenameView(SecurityContext context, QualifiedObjectName viewName, QualifiedObjectName newViewName); - /** - * Check if identity is allowed to change the specified view's user/role. - * - * @throws AccessDeniedException if not allowed - */ - default void checkCanSetViewAuthorization(SecurityContext context, QualifiedObjectName view, TrinoPrincipal principal) - { - denySetViewAuthorization(view.toString(), principal); - } - /** * Check if identity is allowed to drop the specified view. * @@ -620,4 +594,11 @@ default Map getColumnMasks(SecurityContext context { return ImmutableMap.of(); } + + /** + * Check that the principal has the privileges to set the owner of the entity with the give name and ownedKind. + * + * @throws AccessDeniedException if not allowed + */ + void checkCanSetEntityAuthorization(SecurityContext context, String ownedKind, List name, TrinoPrincipal principal); } diff --git a/core/trino-main/src/main/java/io/trino/security/AccessControlManager.java b/core/trino-main/src/main/java/io/trino/security/AccessControlManager.java index 03f448f263fe..837595a1d739 100644 --- a/core/trino-main/src/main/java/io/trino/security/AccessControlManager.java +++ b/core/trino-main/src/main/java/io/trino/security/AccessControlManager.java @@ -82,6 +82,7 @@ import java.util.function.Predicate; import java.util.stream.Collectors; +import static com.google.common.base.Preconditions.checkArgument; import static com.google.common.base.Preconditions.checkState; import static com.google.common.base.Strings.isNullOrEmpty; import static com.google.common.base.Throwables.throwIfUnchecked; @@ -425,19 +426,6 @@ public void checkCanRenameSchema(SecurityContext securityContext, CatalogSchemaN catalogAuthorizationCheck(schemaName.getCatalogName(), securityContext, (control, context) -> control.checkCanRenameSchema(context, schemaName.getSchemaName(), newSchemaName)); } - @Override - public void checkCanSetSchemaAuthorization(SecurityContext securityContext, CatalogSchemaName schemaName, TrinoPrincipal principal) - { - requireNonNull(securityContext, "securityContext is null"); - requireNonNull(schemaName, "schemaName is null"); - - checkCanAccessCatalog(securityContext, schemaName.getCatalogName()); - - systemAuthorizationCheck(control -> control.checkCanSetSchemaAuthorization(securityContext.toSystemSecurityContext(), schemaName, principal)); - - catalogAuthorizationCheck(schemaName.getCatalogName(), securityContext, (control, context) -> control.checkCanSetSchemaAuthorization(context, schemaName.getSchemaName(), principal)); - } - @Override public void checkCanShowSchemas(SecurityContext securityContext, String catalogName) { @@ -730,23 +718,6 @@ public void checkCanRenameColumn(SecurityContext securityContext, QualifiedObjec catalogAuthorizationCheck(tableName.catalogName(), securityContext, (control, context) -> control.checkCanRenameColumn(context, tableName.asSchemaTableName())); } - @Override - public void checkCanSetTableAuthorization(SecurityContext securityContext, QualifiedObjectName tableName, TrinoPrincipal principal) - { - requireNonNull(securityContext, "securityContext is null"); - requireNonNull(tableName, "tableName is null"); - requireNonNull(principal, "principal is null"); - - checkCanAccessCatalog(securityContext, tableName.catalogName()); - - systemAuthorizationCheck(control -> control.checkCanSetTableAuthorization(securityContext.toSystemSecurityContext(), tableName.asCatalogSchemaTableName(), principal)); - - catalogAuthorizationCheck( - tableName.catalogName(), - securityContext, - (control, context) -> control.checkCanSetTableAuthorization(context, tableName.asSchemaTableName(), principal)); - } - @Override public void checkCanInsertIntoTable(SecurityContext securityContext, QualifiedObjectName tableName) { @@ -826,23 +797,6 @@ public void checkCanRenameView(SecurityContext securityContext, QualifiedObjectN catalogAuthorizationCheck(viewName.catalogName(), securityContext, (control, context) -> control.checkCanRenameView(context, viewName.asSchemaTableName(), newViewName.asSchemaTableName())); } - @Override - public void checkCanSetViewAuthorization(SecurityContext securityContext, QualifiedObjectName viewName, TrinoPrincipal principal) - { - requireNonNull(securityContext, "securityContext is null"); - requireNonNull(viewName, "viewName is null"); - requireNonNull(principal, "principal is null"); - - checkCanAccessCatalog(securityContext, viewName.catalogName()); - - systemAuthorizationCheck(control -> control.checkCanSetViewAuthorization(securityContext.toSystemSecurityContext(), viewName.asCatalogSchemaTableName(), principal)); - - catalogAuthorizationCheck( - viewName.catalogName(), - securityContext, - (control, context) -> control.checkCanSetViewAuthorization(context, viewName.asSchemaTableName(), principal)); - } - @Override public void checkCanDropView(SecurityContext securityContext, QualifiedObjectName viewName) { @@ -1442,6 +1396,41 @@ public Map getColumnMasks(SecurityContext context, } } + @Override + public void checkCanSetEntityAuthorization(SecurityContext securityContext, String ownedKind, List name, TrinoPrincipal principal) + { + requireNonNull(securityContext, "securityContext is null"); + requireNonNull(ownedKind, "ownedKind is null"); + requireNonNull(name, "name is null"); + checkArgument(!name.isEmpty(), "name is empty"); + requireNonNull(principal, "principal is null"); + + switch (ownedKind) { + case "SCHEMA" -> { + checkCanAccessCatalog(securityContext, name.get(0)); + catalogAuthorizationCheck( + name.get(0), + securityContext, + (control, context) -> control.checkCanSetSchemaAuthorization(context, name.get(1), principal)); + } + case "TABLE" -> { + checkCanAccessCatalog(securityContext, name.get(0)); + catalogAuthorizationCheck( + name.get(0), + securityContext, + (control, context) -> control.checkCanSetTableAuthorization(context, new SchemaTableName(name.get(1), name.get(2)), principal)); + } + case "VIEW" -> { + checkCanAccessCatalog(securityContext, name.get(0)); + catalogAuthorizationCheck( + name.get(0), + securityContext, + (control, context) -> control.checkCanSetViewAuthorization(context, new SchemaTableName(name.get(1), name.get(2)), principal)); + } + default -> systemAuthorizationCheck(control -> control.checkCanSetEntityAuthorization(securityContext.toSystemSecurityContext(), ownedKind, name, principal)); + } + } + private ConnectorAccessControl getConnectorAccessControl(TransactionId transactionId, String catalogName) { CatalogServiceProvider> connectorAccessControlProvider = this.connectorAccessControlProvider.get(); diff --git a/core/trino-main/src/main/java/io/trino/security/AllowAllAccessControl.java b/core/trino-main/src/main/java/io/trino/security/AllowAllAccessControl.java index a63bd24d4cdc..585bb27f7f36 100644 --- a/core/trino-main/src/main/java/io/trino/security/AllowAllAccessControl.java +++ b/core/trino-main/src/main/java/io/trino/security/AllowAllAccessControl.java @@ -27,6 +27,7 @@ import java.security.Principal; import java.util.Collection; +import java.util.List; import java.util.Map; import java.util.Optional; import java.util.Set; @@ -82,9 +83,6 @@ public void checkCanDropSchema(SecurityContext context, CatalogSchemaName schema @Override public void checkCanRenameSchema(SecurityContext context, CatalogSchemaName schemaName, String newSchemaName) {} - @Override - public void checkCanSetSchemaAuthorization(SecurityContext context, CatalogSchemaName schemaName, TrinoPrincipal principal) {} - @Override public void checkCanShowSchemas(SecurityContext context, String catalogName) {} @@ -148,9 +146,6 @@ public void checkCanAlterColumn(SecurityContext context, QualifiedObjectName tab @Override public void checkCanDropColumn(SecurityContext context, QualifiedObjectName tableName) {} - @Override - public void checkCanSetTableAuthorization(SecurityContext context, QualifiedObjectName tableName, TrinoPrincipal principal) {} - @Override public void checkCanRenameColumn(SecurityContext context, QualifiedObjectName tableName) {} @@ -172,9 +167,6 @@ public void checkCanCreateView(SecurityContext context, QualifiedObjectName view @Override public void checkCanRenameView(SecurityContext context, QualifiedObjectName viewName, QualifiedObjectName newViewName) {} - @Override - public void checkCanSetViewAuthorization(SecurityContext context, QualifiedObjectName view, TrinoPrincipal principal) {} - @Override public void checkCanDropView(SecurityContext context, QualifiedObjectName viewName) {} @@ -291,4 +283,7 @@ public void checkCanDropFunction(SecurityContext context, QualifiedObjectName fu @Override public void checkCanShowCreateFunction(SecurityContext context, QualifiedObjectName functionName) {} + + @Override + public void checkCanSetEntityAuthorization(SecurityContext context, String ownedKind, List name, TrinoPrincipal principal) {} } diff --git a/core/trino-main/src/main/java/io/trino/security/DenyAllAccessControl.java b/core/trino-main/src/main/java/io/trino/security/DenyAllAccessControl.java index b9816afeab12..83ee7519fda0 100644 --- a/core/trino-main/src/main/java/io/trino/security/DenyAllAccessControl.java +++ b/core/trino-main/src/main/java/io/trino/security/DenyAllAccessControl.java @@ -30,6 +30,7 @@ import java.security.Principal; import java.util.Collection; +import java.util.List; import java.util.Map; import java.util.Optional; import java.util.Set; @@ -82,14 +83,12 @@ import static io.trino.spi.security.AccessDeniedException.denyRevokeTablePrivilege; import static io.trino.spi.security.AccessDeniedException.denySelectColumns; import static io.trino.spi.security.AccessDeniedException.denySetCatalogSessionProperty; +import static io.trino.spi.security.AccessDeniedException.denySetEntityAuthorization; import static io.trino.spi.security.AccessDeniedException.denySetMaterializedViewProperties; import static io.trino.spi.security.AccessDeniedException.denySetRole; -import static io.trino.spi.security.AccessDeniedException.denySetSchemaAuthorization; import static io.trino.spi.security.AccessDeniedException.denySetSystemSessionProperty; -import static io.trino.spi.security.AccessDeniedException.denySetTableAuthorization; import static io.trino.spi.security.AccessDeniedException.denySetTableProperties; import static io.trino.spi.security.AccessDeniedException.denySetUser; -import static io.trino.spi.security.AccessDeniedException.denySetViewAuthorization; import static io.trino.spi.security.AccessDeniedException.denyShowColumns; import static io.trino.spi.security.AccessDeniedException.denyShowCreateFunction; import static io.trino.spi.security.AccessDeniedException.denyShowCreateSchema; @@ -204,12 +203,6 @@ public void checkCanShowCreateTable(SecurityContext context, QualifiedObjectName denyShowCreateTable(tableName.toString()); } - @Override - public void checkCanSetSchemaAuthorization(SecurityContext context, CatalogSchemaName schemaName, TrinoPrincipal principal) - { - denySetSchemaAuthorization(schemaName.toString(), principal); - } - @Override public void checkCanCreateTable(SecurityContext context, QualifiedObjectName tableName, Map properties) { @@ -312,12 +305,6 @@ public void checkCanDropColumn(SecurityContext context, QualifiedObjectName tabl denyDropColumn(tableName.toString()); } - @Override - public void checkCanSetTableAuthorization(SecurityContext context, QualifiedObjectName tableName, TrinoPrincipal principal) - { - denySetTableAuthorization(tableName.toString(), principal); - } - @Override public void checkCanInsertIntoTable(SecurityContext context, QualifiedObjectName tableName) { @@ -354,12 +341,6 @@ public void checkCanRenameView(SecurityContext context, QualifiedObjectName view denyRenameView(viewName.toString(), newViewName.toString()); } - @Override - public void checkCanSetViewAuthorization(SecurityContext context, QualifiedObjectName view, TrinoPrincipal principal) - { - denySetViewAuthorization(view.toString(), principal); - } - @Override public void checkCanDropView(SecurityContext context, QualifiedObjectName viewName) { @@ -575,4 +556,10 @@ public void checkCanShowCreateFunction(SecurityContext context, QualifiedObjectN { denyShowCreateFunction(functionName.toString()); } + + @Override + public void checkCanSetEntityAuthorization(SecurityContext context, String ownedKind, List name, TrinoPrincipal principal) + { + denySetEntityAuthorization(ownedKind, name, principal); + } } diff --git a/core/trino-main/src/main/java/io/trino/security/ForwardingAccessControl.java b/core/trino-main/src/main/java/io/trino/security/ForwardingAccessControl.java index 42c89e5d0f43..a396c5b26319 100644 --- a/core/trino-main/src/main/java/io/trino/security/ForwardingAccessControl.java +++ b/core/trino-main/src/main/java/io/trino/security/ForwardingAccessControl.java @@ -140,12 +140,6 @@ public void checkCanRenameSchema(SecurityContext context, CatalogSchemaName sche delegate().checkCanRenameSchema(context, schemaName, newSchemaName); } - @Override - public void checkCanSetSchemaAuthorization(SecurityContext context, CatalogSchemaName schemaName, TrinoPrincipal principal) - { - delegate().checkCanSetSchemaAuthorization(context, schemaName, principal); - } - @Override public void checkCanShowSchemas(SecurityContext context, String catalogName) { @@ -266,12 +260,6 @@ public void checkCanRenameColumn(SecurityContext context, QualifiedObjectName ta delegate().checkCanRenameColumn(context, tableName); } - @Override - public void checkCanSetTableAuthorization(SecurityContext context, QualifiedObjectName tableName, TrinoPrincipal principal) - { - delegate().checkCanSetTableAuthorization(context, tableName, principal); - } - @Override public void checkCanInsertIntoTable(SecurityContext context, QualifiedObjectName tableName) { @@ -302,12 +290,6 @@ public void checkCanRenameView(SecurityContext context, QualifiedObjectName view delegate().checkCanRenameView(context, viewName, newViewName); } - @Override - public void checkCanSetViewAuthorization(SecurityContext context, QualifiedObjectName view, TrinoPrincipal principal) - { - delegate().checkCanSetViewAuthorization(context, view, principal); - } - @Override public void checkCanDropView(SecurityContext context, QualifiedObjectName viewName) { @@ -535,4 +517,10 @@ public Map getColumnMasks(SecurityContext context, { return delegate().getColumnMasks(context, tableName, columns); } + + @Override + public void checkCanSetEntityAuthorization(SecurityContext context, String ownedKind, List name, TrinoPrincipal principal) + { + delegate().checkCanSetEntityAuthorization(context, ownedKind, name, principal); + } } diff --git a/core/trino-main/src/main/java/io/trino/security/InjectedConnectorAccessControl.java b/core/trino-main/src/main/java/io/trino/security/InjectedConnectorAccessControl.java index 9969848871f0..e77593cc5d48 100644 --- a/core/trino-main/src/main/java/io/trino/security/InjectedConnectorAccessControl.java +++ b/core/trino-main/src/main/java/io/trino/security/InjectedConnectorAccessControl.java @@ -78,7 +78,8 @@ public void checkCanRenameSchema(ConnectorSecurityContext context, String schema public void checkCanSetSchemaAuthorization(ConnectorSecurityContext context, String schemaName, TrinoPrincipal principal) { checkArgument(context == null, "context must be null"); - accessControl.checkCanSetSchemaAuthorization(securityContext, getCatalogSchemaName(schemaName), principal); + CatalogSchemaName name = getCatalogSchemaName(schemaName); + accessControl.checkCanSetEntityAuthorization(securityContext, "SCHEMA", List.of(name.getCatalogName(), name.getSchemaName()), principal); } @Override @@ -211,7 +212,7 @@ public void checkCanDropColumn(ConnectorSecurityContext context, SchemaTableName public void checkCanSetTableAuthorization(ConnectorSecurityContext context, SchemaTableName tableName, TrinoPrincipal principal) { checkArgument(context == null, "context must be null"); - accessControl.checkCanSetTableAuthorization(securityContext, getQualifiedObjectName(tableName), principal); + accessControl.checkCanSetEntityAuthorization(securityContext, "TABLE", getQualifiedObjectNameParts(tableName), principal); } @Override @@ -267,7 +268,7 @@ public void checkCanCreateView(ConnectorSecurityContext context, SchemaTableName public void checkCanSetViewAuthorization(ConnectorSecurityContext context, SchemaTableName viewName, TrinoPrincipal principal) { checkArgument(context == null, "context must be null"); - accessControl.checkCanSetViewAuthorization(securityContext, getQualifiedObjectName(viewName), principal); + accessControl.checkCanSetEntityAuthorization(securityContext, "VIEW", getQualifiedObjectNameParts(viewName), principal); } @Override @@ -544,6 +545,11 @@ private QualifiedObjectName getQualifiedObjectName(SchemaRoutineName schemaRouti return new QualifiedObjectName(catalogName, schemaRoutineName.getSchemaName(), schemaRoutineName.getRoutineName()); } + private List getQualifiedObjectNameParts(SchemaTableName schemaTableName) + { + return List.of(catalogName, schemaTableName.getSchemaName(), schemaTableName.getTableName()); + } + private CatalogSchemaName getCatalogSchemaName(String schemaName) { return new CatalogSchemaName(catalogName, schemaName); diff --git a/core/trino-main/src/main/java/io/trino/server/QueryExecutionFactoryModule.java b/core/trino-main/src/main/java/io/trino/server/QueryExecutionFactoryModule.java index 1d50e34dc0e8..6db8b912cf28 100644 --- a/core/trino-main/src/main/java/io/trino/server/QueryExecutionFactoryModule.java +++ b/core/trino-main/src/main/java/io/trino/server/QueryExecutionFactoryModule.java @@ -56,16 +56,14 @@ import io.trino.execution.RevokeRolesTask; import io.trino.execution.RevokeTask; import io.trino.execution.RollbackTask; +import io.trino.execution.SetAuthorizationTask; import io.trino.execution.SetColumnTypeTask; import io.trino.execution.SetPathTask; import io.trino.execution.SetPropertiesTask; import io.trino.execution.SetRoleTask; -import io.trino.execution.SetSchemaAuthorizationTask; import io.trino.execution.SetSessionAuthorizationTask; import io.trino.execution.SetSessionTask; -import io.trino.execution.SetTableAuthorizationTask; import io.trino.execution.SetTimeZoneTask; -import io.trino.execution.SetViewAuthorizationTask; import io.trino.execution.SqlQueryExecution.SqlQueryExecutionFactory; import io.trino.execution.StartTransactionTask; import io.trino.execution.TruncateTableTask; @@ -105,16 +103,14 @@ import io.trino.sql.tree.Revoke; import io.trino.sql.tree.RevokeRoles; import io.trino.sql.tree.Rollback; +import io.trino.sql.tree.SetAuthorizationStatement; import io.trino.sql.tree.SetColumnType; import io.trino.sql.tree.SetPath; import io.trino.sql.tree.SetProperties; import io.trino.sql.tree.SetRole; -import io.trino.sql.tree.SetSchemaAuthorization; import io.trino.sql.tree.SetSession; import io.trino.sql.tree.SetSessionAuthorization; -import io.trino.sql.tree.SetTableAuthorization; import io.trino.sql.tree.SetTimeZone; -import io.trino.sql.tree.SetViewAuthorization; import io.trino.sql.tree.StartTransaction; import io.trino.sql.tree.Statement; import io.trino.sql.tree.TruncateTable; @@ -181,11 +177,9 @@ public void configure(Binder binder) bindDataDefinitionTask(binder, executionBinder, SetProperties.class, SetPropertiesTask.class); bindDataDefinitionTask(binder, executionBinder, SetTimeZone.class, SetTimeZoneTask.class); bindDataDefinitionTask(binder, executionBinder, SetRole.class, SetRoleTask.class); - bindDataDefinitionTask(binder, executionBinder, SetSchemaAuthorization.class, SetSchemaAuthorizationTask.class); + bindDataDefinitionTask(binder, executionBinder, SetAuthorizationStatement.class, SetAuthorizationTask.class); bindDataDefinitionTask(binder, executionBinder, SetSession.class, SetSessionTask.class); bindDataDefinitionTask(binder, executionBinder, SetSessionAuthorization.class, SetSessionAuthorizationTask.class); - bindDataDefinitionTask(binder, executionBinder, SetTableAuthorization.class, SetTableAuthorizationTask.class); - bindDataDefinitionTask(binder, executionBinder, SetViewAuthorization.class, SetViewAuthorizationTask.class); bindDataDefinitionTask(binder, executionBinder, StartTransaction.class, StartTransactionTask.class); bindDataDefinitionTask(binder, executionBinder, Use.class, UseTask.class); } diff --git a/core/trino-main/src/main/java/io/trino/sql/analyzer/StatementAnalyzer.java b/core/trino-main/src/main/java/io/trino/sql/analyzer/StatementAnalyzer.java index 6f7cc0422026..6a28c69707f2 100644 --- a/core/trino-main/src/main/java/io/trino/sql/analyzer/StatementAnalyzer.java +++ b/core/trino-main/src/main/java/io/trino/sql/analyzer/StatementAnalyzer.java @@ -227,15 +227,13 @@ import io.trino.sql.tree.SecurityCharacteristic; import io.trino.sql.tree.Select; import io.trino.sql.tree.SelectItem; +import io.trino.sql.tree.SetAuthorizationStatement; import io.trino.sql.tree.SetColumnType; import io.trino.sql.tree.SetOperation; import io.trino.sql.tree.SetProperties; -import io.trino.sql.tree.SetSchemaAuthorization; import io.trino.sql.tree.SetSession; import io.trino.sql.tree.SetSessionAuthorization; -import io.trino.sql.tree.SetTableAuthorization; import io.trino.sql.tree.SetTimeZone; -import io.trino.sql.tree.SetViewAuthorization; import io.trino.sql.tree.SimpleGroupBy; import io.trino.sql.tree.SingleColumn; import io.trino.sql.tree.SkipTo; @@ -1143,7 +1141,7 @@ protected Scope visitRenameSchema(RenameSchema node, Optional scope) } @Override - protected Scope visitSetSchemaAuthorization(SetSchemaAuthorization node, Optional scope) + protected Scope visitSetAuthorization(SetAuthorizationStatement node, Optional scope) { return createAndAssignScope(node, scope); } @@ -1218,12 +1216,6 @@ protected Scope visitDropColumn(DropColumn node, Optional scope) return createAndAssignScope(node, scope); } - @Override - protected Scope visitSetTableAuthorization(SetTableAuthorization node, Optional scope) - { - return createAndAssignScope(node, scope); - } - @Override protected Scope visitTableExecute(TableExecute node, Optional scope) { @@ -1355,12 +1347,6 @@ protected Scope visitRenameMaterializedView(RenameMaterializedView node, Optiona return createAndAssignScope(node, scope); } - @Override - protected Scope visitSetViewAuthorization(SetViewAuthorization node, Optional scope) - { - return createAndAssignScope(node, scope); - } - @Override protected Scope visitDropView(DropView node, Optional scope) { diff --git a/core/trino-main/src/main/java/io/trino/tracing/TracingAccessControl.java b/core/trino-main/src/main/java/io/trino/tracing/TracingAccessControl.java index 50fb5343ebe9..e300c00bc591 100644 --- a/core/trino-main/src/main/java/io/trino/tracing/TracingAccessControl.java +++ b/core/trino-main/src/main/java/io/trino/tracing/TracingAccessControl.java @@ -188,15 +188,6 @@ public void checkCanRenameSchema(SecurityContext context, CatalogSchemaName sche } } - @Override - public void checkCanSetSchemaAuthorization(SecurityContext context, CatalogSchemaName schemaName, TrinoPrincipal principal) - { - Span span = startSpan("checkCanSetSchemaAuthorization"); - try (var _ = scopedSpan(span)) { - delegate.checkCanSetSchemaAuthorization(context, schemaName, principal); - } - } - @Override public void checkCanShowSchemas(SecurityContext context, String catalogName) { @@ -359,15 +350,6 @@ public void checkCanAlterColumn(SecurityContext context, QualifiedObjectName tab } } - @Override - public void checkCanSetTableAuthorization(SecurityContext context, QualifiedObjectName tableName, TrinoPrincipal principal) - { - Span span = startSpan("checkCanSetTableAuthorization"); - try (var _ = scopedSpan(span)) { - delegate.checkCanSetTableAuthorization(context, tableName, principal); - } - } - @Override public void checkCanRenameColumn(SecurityContext context, QualifiedObjectName tableName) { @@ -431,15 +413,6 @@ public void checkCanRenameView(SecurityContext context, QualifiedObjectName view } } - @Override - public void checkCanSetViewAuthorization(SecurityContext context, QualifiedObjectName view, TrinoPrincipal principal) - { - Span span = startSpan("checkCanSetViewAuthorization"); - try (var _ = scopedSpan(span)) { - delegate.checkCanSetViewAuthorization(context, view, principal); - } - } - @Override public void checkCanDropView(SecurityContext context, QualifiedObjectName viewName) { @@ -782,6 +755,15 @@ public Map getColumnMasks(SecurityContext context, } } + @Override + public void checkCanSetEntityAuthorization(SecurityContext context, String ownedKind, List name, TrinoPrincipal principal) + { + Span span = startSpan("checkCanSetEntityAuthorization"); + try (var ignored = scopedSpan(span)) { + delegate.checkCanSetEntityAuthorization(context, ownedKind, name, principal); + } + } + private Span startSpan(String methodName) { return tracer.spanBuilder("AccessControl." + methodName) diff --git a/core/trino-main/src/main/java/io/trino/tracing/TracingMetadata.java b/core/trino-main/src/main/java/io/trino/tracing/TracingMetadata.java index 04a3f5b443c6..99da9d8ef74b 100644 --- a/core/trino-main/src/main/java/io/trino/tracing/TracingMetadata.java +++ b/core/trino-main/src/main/java/io/trino/tracing/TracingMetadata.java @@ -394,15 +394,6 @@ public void renameSchema(Session session, CatalogSchemaName source, String targe } } - @Override - public void setSchemaAuthorization(Session session, CatalogSchemaName source, TrinoPrincipal principal) - { - Span span = startSpan("setSchemaAuthorization", source); - try (var _ = scopedSpan(span)) { - delegate.setSchemaAuthorization(session, source, principal); - } - } - @Override public void createTable(Session session, String catalogName, ConnectorTableMetadata tableMetadata, SaveMode saveMode) { @@ -529,15 +520,6 @@ public void dropNotNullConstraint(Session session, TableHandle tableHandle, Colu } } - @Override - public void setTableAuthorization(Session session, CatalogSchemaTableName table, TrinoPrincipal principal) - { - Span span = startSpan("setTableAuthorization", table); - try (var _ = scopedSpan(span)) { - delegate.setTableAuthorization(session, table, principal); - } - } - @Override public void dropColumn(Session session, TableHandle tableHandle, CatalogSchemaTableName table, ColumnHandle column) { @@ -942,15 +924,6 @@ public void renameView(Session session, QualifiedObjectName existingViewName, Qu } } - @Override - public void setViewAuthorization(Session session, CatalogSchemaTableName view, TrinoPrincipal principal) - { - Span span = startSpan("setViewAuthorization", view); - try (var _ = scopedSpan(span)) { - delegate.setViewAuthorization(session, view, principal); - } - } - @Override public void dropView(Session session, QualifiedObjectName viewName) { @@ -1550,6 +1523,15 @@ public WriterScalingOptions getInsertWriterScalingOptions(Session session, Table } } + @Override + public void setEntityAuthorization(Session session, String ownedKind, List name, TrinoPrincipal principal) + { + Span span = startSpan("setEntityAuthorization", name.stream().collect(Collectors.joining("."))); + try (var ignored = scopedSpan(span)) { + delegate.setEntityAuthorization(session, ownedKind, name, principal); + } + } + private Span startSpan(String methodName) { return tracer.spanBuilder("Metadata." + methodName) diff --git a/core/trino-main/src/main/java/io/trino/util/StatementUtils.java b/core/trino-main/src/main/java/io/trino/util/StatementUtils.java index c183e7783a4c..a43b7600758e 100644 --- a/core/trino-main/src/main/java/io/trino/util/StatementUtils.java +++ b/core/trino-main/src/main/java/io/trino/util/StatementUtils.java @@ -51,16 +51,14 @@ import io.trino.execution.RevokeRolesTask; import io.trino.execution.RevokeTask; import io.trino.execution.RollbackTask; +import io.trino.execution.SetAuthorizationTask; import io.trino.execution.SetColumnTypeTask; import io.trino.execution.SetPathTask; import io.trino.execution.SetPropertiesTask; import io.trino.execution.SetRoleTask; -import io.trino.execution.SetSchemaAuthorizationTask; import io.trino.execution.SetSessionAuthorizationTask; import io.trino.execution.SetSessionTask; -import io.trino.execution.SetTableAuthorizationTask; import io.trino.execution.SetTimeZoneTask; -import io.trino.execution.SetViewAuthorizationTask; import io.trino.execution.StartTransactionTask; import io.trino.execution.TruncateTableTask; import io.trino.execution.UseTask; @@ -111,16 +109,14 @@ import io.trino.sql.tree.Revoke; import io.trino.sql.tree.RevokeRoles; import io.trino.sql.tree.Rollback; +import io.trino.sql.tree.SetAuthorizationStatement; import io.trino.sql.tree.SetColumnType; import io.trino.sql.tree.SetPath; import io.trino.sql.tree.SetProperties; import io.trino.sql.tree.SetRole; -import io.trino.sql.tree.SetSchemaAuthorization; import io.trino.sql.tree.SetSession; import io.trino.sql.tree.SetSessionAuthorization; -import io.trino.sql.tree.SetTableAuthorization; import io.trino.sql.tree.SetTimeZone; -import io.trino.sql.tree.SetViewAuthorization; import io.trino.sql.tree.ShowCatalogs; import io.trino.sql.tree.ShowColumns; import io.trino.sql.tree.ShowCreate; @@ -236,13 +232,11 @@ private StatementUtils() {} .add(dataDefinitionStatement(DropNotNullConstraint.class, DropNotNullConstraintTask.class)) .add(dataDefinitionStatement(SetPath.class, SetPathTask.class)) .add(dataDefinitionStatement(SetRole.class, SetRoleTask.class)) - .add(dataDefinitionStatement(SetSchemaAuthorization.class, SetSchemaAuthorizationTask.class)) + .add(dataDefinitionStatement(SetAuthorizationStatement.class, SetAuthorizationTask.class)) .add(dataDefinitionStatement(SetSession.class, SetSessionTask.class)) .add(dataDefinitionStatement(SetSessionAuthorization.class, SetSessionAuthorizationTask.class)) .add(dataDefinitionStatement(SetProperties.class, SetPropertiesTask.class)) - .add(dataDefinitionStatement(SetTableAuthorization.class, SetTableAuthorizationTask.class)) .add(dataDefinitionStatement(SetTimeZone.class, SetTimeZoneTask.class)) - .add(dataDefinitionStatement(SetViewAuthorization.class, SetViewAuthorizationTask.class)) .add(dataDefinitionStatement(StartTransaction.class, StartTransactionTask.class)) .add(dataDefinitionStatement(Use.class, UseTask.class)) .build().stream() diff --git a/core/trino-main/src/test/java/io/trino/metadata/AbstractMockMetadata.java b/core/trino-main/src/test/java/io/trino/metadata/AbstractMockMetadata.java index 7edfd163ab0a..2a2abd8b0bad 100644 --- a/core/trino-main/src/test/java/io/trino/metadata/AbstractMockMetadata.java +++ b/core/trino-main/src/test/java/io/trino/metadata/AbstractMockMetadata.java @@ -278,12 +278,6 @@ public void renameSchema(Session session, CatalogSchemaName source, String targe throw new UnsupportedOperationException(); } - @Override - public void setSchemaAuthorization(Session session, CatalogSchemaName source, TrinoPrincipal principal) - { - throw new UnsupportedOperationException(); - } - @Override public void createTable(Session session, String catalogName, ConnectorTableMetadata tableMetadata, SaveMode saveMode) { @@ -380,12 +374,6 @@ public void dropNotNullConstraint(Session session, TableHandle tableHandle, Colu throw new UnsupportedOperationException(); } - @Override - public void setTableAuthorization(Session session, CatalogSchemaTableName table, TrinoPrincipal principal) - { - throw new UnsupportedOperationException(); - } - @Override public void dropTable(Session session, TableHandle tableHandle, CatalogSchemaTableName tableName) { @@ -627,12 +615,6 @@ public void renameView(Session session, QualifiedObjectName source, QualifiedObj throw new UnsupportedOperationException(); } - @Override - public void setViewAuthorization(Session session, CatalogSchemaTableName view, TrinoPrincipal principal) - { - throw new UnsupportedOperationException(); - } - @Override public void dropView(Session session, QualifiedObjectName viewName) { @@ -1037,4 +1019,10 @@ public WriterScalingOptions getInsertWriterScalingOptions(Session session, Table { throw new UnsupportedOperationException(); } + + @Override + public void setEntityAuthorization(Session session, String ownedKind, List name, TrinoPrincipal principal) + { + throw new UnsupportedOperationException(); + } } diff --git a/core/trino-parser/src/main/java/io/trino/sql/SqlFormatter.java b/core/trino-parser/src/main/java/io/trino/sql/SqlFormatter.java index 90f29216f630..de2175b3e150 100644 --- a/core/trino-parser/src/main/java/io/trino/sql/SqlFormatter.java +++ b/core/trino-parser/src/main/java/io/trino/sql/SqlFormatter.java @@ -138,16 +138,14 @@ import io.trino.sql.tree.SecurityCharacteristic; import io.trino.sql.tree.Select; import io.trino.sql.tree.SelectItem; +import io.trino.sql.tree.SetAuthorizationStatement; import io.trino.sql.tree.SetColumnType; import io.trino.sql.tree.SetPath; import io.trino.sql.tree.SetProperties; import io.trino.sql.tree.SetRole; -import io.trino.sql.tree.SetSchemaAuthorization; import io.trino.sql.tree.SetSession; import io.trino.sql.tree.SetSessionAuthorization; -import io.trino.sql.tree.SetTableAuthorization; import io.trino.sql.tree.SetTimeZone; -import io.trino.sql.tree.SetViewAuthorization; import io.trino.sql.tree.ShowCatalogs; import io.trino.sql.tree.ShowColumns; import io.trino.sql.tree.ShowCreate; @@ -1197,9 +1195,11 @@ protected Void visitRenameMaterializedView(RenameMaterializedView node, Integer } @Override - protected Void visitSetViewAuthorization(SetViewAuthorization node, Integer indent) + protected Void visitSetAuthorization(SetAuthorizationStatement node, Integer indent) { - builder.append("ALTER VIEW ") + builder.append("ALTER ") + .append(node.getOwnedEntityKind()) + .append(" ") .append(formatName(node.getSource())) .append(" SET AUTHORIZATION ") .append(formatPrincipal(node.getPrincipal())); @@ -1533,17 +1533,6 @@ protected Void visitRenameSchema(RenameSchema node, Integer indent) return null; } - @Override - protected Void visitSetSchemaAuthorization(SetSchemaAuthorization node, Integer indent) - { - builder.append("ALTER SCHEMA ") - .append(formatName(node.getSource())) - .append(" SET AUTHORIZATION ") - .append(formatPrincipal(node.getPrincipal())); - - return null; - } - @Override protected Void visitCreateTableAsSelect(CreateTableAsSelect node, Integer indent) { @@ -1860,17 +1849,6 @@ protected Void visitDropNotNullConstraint(DropNotNullConstraint node, Integer co return null; } - @Override - protected Void visitSetTableAuthorization(SetTableAuthorization node, Integer indent) - { - builder.append("ALTER TABLE ") - .append(formatName(node.getSource())) - .append(" SET AUTHORIZATION ") - .append(formatPrincipal(node.getPrincipal())); - - return null; - } - @Override protected Void visitInsert(Insert node, Integer indent) { diff --git a/core/trino-parser/src/main/java/io/trino/sql/parser/AstBuilder.java b/core/trino-parser/src/main/java/io/trino/sql/parser/AstBuilder.java index d5afc46d87fe..9357f329d9a2 100644 --- a/core/trino-parser/src/main/java/io/trino/sql/parser/AstBuilder.java +++ b/core/trino-parser/src/main/java/io/trino/sql/parser/AstBuilder.java @@ -239,16 +239,14 @@ import io.trino.sql.tree.SecurityCharacteristic; import io.trino.sql.tree.Select; import io.trino.sql.tree.SelectItem; +import io.trino.sql.tree.SetAuthorizationStatement; import io.trino.sql.tree.SetColumnType; import io.trino.sql.tree.SetPath; import io.trino.sql.tree.SetProperties; import io.trino.sql.tree.SetRole; -import io.trino.sql.tree.SetSchemaAuthorization; import io.trino.sql.tree.SetSession; import io.trino.sql.tree.SetSessionAuthorization; -import io.trino.sql.tree.SetTableAuthorization; import io.trino.sql.tree.SetTimeZone; -import io.trino.sql.tree.SetViewAuthorization; import io.trino.sql.tree.ShowCatalogs; import io.trino.sql.tree.ShowColumns; import io.trino.sql.tree.ShowCreate; @@ -504,10 +502,18 @@ public Node visitRenameSchema(SqlBaseParser.RenameSchemaContext context) } @Override - public Node visitSetSchemaAuthorization(SqlBaseParser.SetSchemaAuthorizationContext context) + public Node visitSetAuthorization(SqlBaseParser.SetAuthorizationContext context) { - return new SetSchemaAuthorization( + boolean materialized = context.ownedEntityKind().MATERIALIZED() != null; + String entityKind = context.ownedEntityKind().basicEntityKind().getText(); + if (materialized && !"VIEW".equalsIgnoreCase(entityKind)) { + throw parseError("Unknown owned entity kind MATERIALIZED " + entityKind, context.ownedEntityKind()); + } + // No special checks are needed for a materialized view owner change. + // It's just a view, identified by name. + return new SetAuthorizationStatement( getLocation(context), + entityKind.toUpperCase(ENGLISH), getQualifiedName(context.qualifiedName()), getPrincipalSpecification(context.principal())); } @@ -847,15 +853,6 @@ public Node visitDropNotNullConstraint(SqlBaseParser.DropNotNullConstraintContex context.EXISTS() != null); } - @Override - public Node visitSetTableAuthorization(SqlBaseParser.SetTableAuthorizationContext context) - { - return new SetTableAuthorization( - getLocation(context), - getQualifiedName(context.qualifiedName()), - getPrincipalSpecification(context.principal())); - } - @Override public Node visitDropColumn(SqlBaseParser.DropColumnContext context) { @@ -925,15 +922,6 @@ public Node visitRenameMaterializedView(SqlBaseParser.RenameMaterializedViewCont return new RenameMaterializedView(getLocation(context), getQualifiedName(context.from), getQualifiedName(context.to), context.EXISTS() != null); } - @Override - public Node visitSetViewAuthorization(SqlBaseParser.SetViewAuthorizationContext context) - { - return new SetViewAuthorization( - getLocation(context), - getQualifiedName(context.qualifiedName()), - getPrincipalSpecification(context.principal())); - } - @Override public Node visitSetMaterializedViewProperties(SqlBaseParser.SetMaterializedViewPropertiesContext context) { diff --git a/core/trino-parser/src/main/java/io/trino/sql/tree/AstVisitor.java b/core/trino-parser/src/main/java/io/trino/sql/tree/AstVisitor.java index 9165b3480b45..b6e2c7c965a4 100644 --- a/core/trino-parser/src/main/java/io/trino/sql/tree/AstVisitor.java +++ b/core/trino-parser/src/main/java/io/trino/sql/tree/AstVisitor.java @@ -627,7 +627,7 @@ protected R visitRenameSchema(RenameSchema node, C context) return visitStatement(node, context); } - protected R visitSetSchemaAuthorization(SetSchemaAuthorization node, C context) + protected R visitSetAuthorization(SetAuthorizationStatement node, C context) { return visitStatement(node, context); } @@ -667,11 +667,6 @@ protected R visitRenameMaterializedView(RenameMaterializedView node, C context) return visitStatement(node, context); } - protected R visitSetViewAuthorization(SetViewAuthorization node, C context) - { - return visitStatement(node, context); - } - protected R visitSetProperties(SetProperties node, C context) { return visitStatement(node, context); @@ -707,11 +702,6 @@ protected R visitDropNotNullConstraint(DropNotNullConstraint node, C context) return visitStatement(node, context); } - protected R visitSetTableAuthorization(SetTableAuthorization node, C context) - { - return visitStatement(node, context); - } - protected R visitTableExecute(TableExecute node, C context) { return visitStatement(node, context); diff --git a/core/trino-parser/src/main/java/io/trino/sql/tree/SetAuthorizationStatement.java b/core/trino-parser/src/main/java/io/trino/sql/tree/SetAuthorizationStatement.java index fc91629d96ae..ecd00f4f1a6a 100644 --- a/core/trino-parser/src/main/java/io/trino/sql/tree/SetAuthorizationStatement.java +++ b/core/trino-parser/src/main/java/io/trino/sql/tree/SetAuthorizationStatement.java @@ -21,19 +21,32 @@ import static com.google.common.base.MoreObjects.toStringHelper; import static java.util.Objects.requireNonNull; -public abstract class SetAuthorizationStatement +public class SetAuthorizationStatement extends Statement { + private final String ownedEntityKind; private final QualifiedName source; private final PrincipalSpecification principal; - public SetAuthorizationStatement(NodeLocation location, QualifiedName source, PrincipalSpecification principal) + public SetAuthorizationStatement(NodeLocation location, String ownedEntityKind, QualifiedName source, PrincipalSpecification principal) { super(location); + this.ownedEntityKind = requireNonNull(ownedEntityKind, "ownedEntityKind is null"); this.source = requireNonNull(source, "source is null"); this.principal = requireNonNull(principal, "principal is null"); } + @Override + public R accept(AstVisitor visitor, C context) + { + return visitor.visitSetAuthorization(this, context); + } + + public String getOwnedEntityKind() + { + return ownedEntityKind; + } + public QualifiedName getSource() { return source; diff --git a/core/trino-parser/src/main/java/io/trino/sql/tree/SetSchemaAuthorization.java b/core/trino-parser/src/main/java/io/trino/sql/tree/SetSchemaAuthorization.java deleted file mode 100644 index d18c2a0baadf..000000000000 --- a/core/trino-parser/src/main/java/io/trino/sql/tree/SetSchemaAuthorization.java +++ /dev/null @@ -1,29 +0,0 @@ -/* - * Licensed 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 io.trino.sql.tree; - -public final class SetSchemaAuthorization - extends SetAuthorizationStatement -{ - public SetSchemaAuthorization(NodeLocation location, QualifiedName source, PrincipalSpecification principal) - { - super(location, source, principal); - } - - @Override - public R accept(AstVisitor visitor, C context) - { - return visitor.visitSetSchemaAuthorization(this, context); - } -} diff --git a/core/trino-parser/src/main/java/io/trino/sql/tree/SetTableAuthorization.java b/core/trino-parser/src/main/java/io/trino/sql/tree/SetTableAuthorization.java deleted file mode 100644 index b0c408789744..000000000000 --- a/core/trino-parser/src/main/java/io/trino/sql/tree/SetTableAuthorization.java +++ /dev/null @@ -1,29 +0,0 @@ -/* - * Licensed 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 io.trino.sql.tree; - -public final class SetTableAuthorization - extends SetAuthorizationStatement -{ - public SetTableAuthorization(NodeLocation location, QualifiedName source, PrincipalSpecification principal) - { - super(location, source, principal); - } - - @Override - public R accept(AstVisitor visitor, C context) - { - return visitor.visitSetTableAuthorization(this, context); - } -} diff --git a/core/trino-parser/src/main/java/io/trino/sql/tree/SetViewAuthorization.java b/core/trino-parser/src/main/java/io/trino/sql/tree/SetViewAuthorization.java deleted file mode 100644 index 554831978adc..000000000000 --- a/core/trino-parser/src/main/java/io/trino/sql/tree/SetViewAuthorization.java +++ /dev/null @@ -1,29 +0,0 @@ -/* - * Licensed 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 io.trino.sql.tree; - -public final class SetViewAuthorization - extends SetAuthorizationStatement -{ - public SetViewAuthorization(NodeLocation location, QualifiedName source, PrincipalSpecification principal) - { - super(location, source, principal); - } - - @Override - public R accept(AstVisitor visitor, C context) - { - return visitor.visitSetViewAuthorization(this, context); - } -} diff --git a/core/trino-parser/src/test/java/io/trino/sql/parser/TestSqlParser.java b/core/trino-parser/src/test/java/io/trino/sql/parser/TestSqlParser.java index dcc7e3f4b927..9021c0bb4292 100644 --- a/core/trino-parser/src/test/java/io/trino/sql/parser/TestSqlParser.java +++ b/core/trino-parser/src/test/java/io/trino/sql/parser/TestSqlParser.java @@ -171,15 +171,14 @@ import io.trino.sql.tree.SearchedCaseExpression; import io.trino.sql.tree.Select; import io.trino.sql.tree.SelectItem; +import io.trino.sql.tree.SetAuthorizationStatement; import io.trino.sql.tree.SetColumnType; import io.trino.sql.tree.SetPath; import io.trino.sql.tree.SetProperties; import io.trino.sql.tree.SetRole; import io.trino.sql.tree.SetSession; import io.trino.sql.tree.SetSessionAuthorization; -import io.trino.sql.tree.SetTableAuthorization; import io.trino.sql.tree.SetTimeZone; -import io.trino.sql.tree.SetViewAuthorization; import io.trino.sql.tree.ShowCatalogs; import io.trino.sql.tree.ShowColumns; import io.trino.sql.tree.ShowFunctions; @@ -3346,20 +3345,29 @@ public void testRenameView() public void testAlterViewSetAuthorization() { assertThat(statement("ALTER VIEW foo.bar.baz SET AUTHORIZATION qux")).isEqualTo( - new SetViewAuthorization( + new SetAuthorizationStatement( location(1, 1), + "VIEW", QualifiedName.of(ImmutableList.of(new Identifier(location(1, 12), "foo", false), new Identifier(location(1, 16), "bar", false), new Identifier(location(1, 20), "baz", false))), new PrincipalSpecification(PrincipalSpecification.Type.UNSPECIFIED, new Identifier(location(1, 42), "qux", false)))); assertThat(statement("ALTER VIEW foo.bar.baz SET AUTHORIZATION USER qux")).isEqualTo( - new SetViewAuthorization( + new SetAuthorizationStatement( location(1, 1), + "VIEW", QualifiedName.of(ImmutableList.of(new Identifier(location(1, 12), "foo", false), new Identifier(location(1, 16), "bar", false), new Identifier(location(1, 20), "baz", false))), new PrincipalSpecification(PrincipalSpecification.Type.USER, new Identifier(location(1, 47), "qux", false)))); assertThat(statement("ALTER VIEW foo.bar.baz SET AUTHORIZATION ROLE qux")).isEqualTo( - new SetViewAuthorization( + new SetAuthorizationStatement( location(1, 1), + "VIEW", QualifiedName.of(ImmutableList.of(new Identifier(location(1, 12), "foo", false), new Identifier(location(1, 16), "bar", false), new Identifier(location(1, 20), "baz", false))), new PrincipalSpecification(PrincipalSpecification.Type.ROLE, new Identifier(location(1, 47), "qux", false)))); + assertThat(statement("ALTER MATERIALIZED VIEW foo.bar.baz SET AUTHORIZATION ROLE qux")).isEqualTo( + new SetAuthorizationStatement( + location(1, 1), + "VIEW", + QualifiedName.of(ImmutableList.of(new Identifier(location(1, 25), "foo", false), new Identifier(location(1, 29), "bar", false), new Identifier(location(1, 33), "baz", false))), + new PrincipalSpecification(PrincipalSpecification.Type.ROLE, new Identifier(location(1, 60), "qux", false)))); } @Test @@ -3678,18 +3686,44 @@ public void testAlterColumnDropNotNullConstraint() public void testAlterTableSetAuthorization() { assertThat(statement("ALTER TABLE foo.bar.baz SET AUTHORIZATION qux")).isEqualTo( - new SetTableAuthorization( + new SetAuthorizationStatement( location(1, 1), + "TABLE", QualifiedName.of(ImmutableList.of(new Identifier(location(1, 13), "foo", false), new Identifier(location(1, 17), "bar", false), new Identifier(location(1, 21), "baz", false))), new PrincipalSpecification(PrincipalSpecification.Type.UNSPECIFIED, new Identifier(location(1, 43), "qux", false)))); assertThat(statement("ALTER TABLE foo.bar.baz SET AUTHORIZATION USER qux")).isEqualTo( - new SetTableAuthorization( + new SetAuthorizationStatement( location(1, 1), + "TABLE", QualifiedName.of(ImmutableList.of(new Identifier(location(1, 13), "foo", false), new Identifier(location(1, 17), "bar", false), new Identifier(location(1, 21), "baz", false))), new PrincipalSpecification(PrincipalSpecification.Type.USER, new Identifier(location(1, 48), "qux", false)))); assertThat(statement("ALTER TABLE foo.bar.baz SET AUTHORIZATION ROLE qux")).isEqualTo( - new SetTableAuthorization( + new SetAuthorizationStatement( + location(1, 1), + "TABLE", + QualifiedName.of(ImmutableList.of(new Identifier(location(1, 13), "foo", false), new Identifier(location(1, 17), "bar", false), new Identifier(location(1, 21), "baz", false))), + new PrincipalSpecification(PrincipalSpecification.Type.ROLE, new Identifier(location(1, 48), "qux", false)))); + } + + @Test + public void testAlterNewEntityKindSetAuthorization() + { + assertThat(statement("ALTER QUARK foo.bar.baz SET AUTHORIZATION qux")).isEqualTo( + new SetAuthorizationStatement( + location(1, 1), + "QUARK", + QualifiedName.of(ImmutableList.of(new Identifier(location(1, 13), "foo", false), new Identifier(location(1, 17), "bar", false), new Identifier(location(1, 21), "baz", false))), + new PrincipalSpecification(PrincipalSpecification.Type.UNSPECIFIED, new Identifier(location(1, 43), "qux", false)))); + assertThat(statement("ALTER QUARK foo.bar.baz SET AUTHORIZATION USER qux")).isEqualTo( + new SetAuthorizationStatement( + location(1, 1), + "QUARK", + QualifiedName.of(ImmutableList.of(new Identifier(location(1, 13), "foo", false), new Identifier(location(1, 17), "bar", false), new Identifier(location(1, 21), "baz", false))), + new PrincipalSpecification(PrincipalSpecification.Type.USER, new Identifier(location(1, 48), "qux", false)))); + assertThat(statement("ALTER QUARK foo.bar.baz SET AUTHORIZATION ROLE qux")).isEqualTo( + new SetAuthorizationStatement( location(1, 1), + "QUARK", QualifiedName.of(ImmutableList.of(new Identifier(location(1, 13), "foo", false), new Identifier(location(1, 17), "bar", false), new Identifier(location(1, 21), "baz", false))), new PrincipalSpecification(PrincipalSpecification.Type.ROLE, new Identifier(location(1, 48), "qux", false)))); } diff --git a/core/trino-spi/src/main/java/io/trino/spi/security/AccessDeniedException.java b/core/trino-spi/src/main/java/io/trino/spi/security/AccessDeniedException.java index 49a9b1f45544..55c01d074834 100644 --- a/core/trino-spi/src/main/java/io/trino/spi/security/AccessDeniedException.java +++ b/core/trino-spi/src/main/java/io/trino/spi/security/AccessDeniedException.java @@ -19,12 +19,15 @@ import java.security.Principal; import java.util.Collection; +import java.util.List; import java.util.Locale; import java.util.Optional; import java.util.Set; import static io.trino.spi.StandardErrorCode.PERMISSION_DENIED; import static java.lang.String.format; +import static java.util.Locale.ENGLISH; +import static java.util.stream.Collectors.joining; public class AccessDeniedException extends TrinoException @@ -171,11 +174,19 @@ public static void denyRenameSchema(String schemaName, String newSchemaName, Str throw new AccessDeniedException(format("Cannot rename schema from %s to %s%s", schemaName, newSchemaName, formatExtraInfo(extraInfo))); } + /** + * @deprecated Use {@link #denySetEntityAuthorization(String, List, TrinoPrincipal)} + */ + @Deprecated public static void denySetSchemaAuthorization(String schemaName, TrinoPrincipal principal) { denySetSchemaAuthorization(schemaName, principal, null); } + /** + * @deprecated Use {@link #denySetEntityAuthorization(String, List, TrinoPrincipal, String)} + */ + @Deprecated public static void denySetSchemaAuthorization(String schemaName, TrinoPrincipal principal, String extraInfo) { throw new AccessDeniedException(format("Cannot set authorization for schema %s to %s%s", schemaName, principal, formatExtraInfo(extraInfo))); @@ -331,11 +342,19 @@ public static void denyAlterColumn(String tableName, String extraInfo) throw new AccessDeniedException(format("Cannot alter a column for table %s%s", tableName, formatExtraInfo(extraInfo))); } + /** + * @deprecated Use {@link #denySetEntityAuthorization(String, List, TrinoPrincipal)} + */ + @Deprecated public static void denySetTableAuthorization(String tableName, TrinoPrincipal principal) { denySetTableAuthorization(tableName, principal, null); } + /** + * @deprecated Use {@link #denySetEntityAuthorization(String, List, TrinoPrincipal, String)} + */ + @Deprecated public static void denySetTableAuthorization(String tableName, TrinoPrincipal principal, String extraInfo) { throw new AccessDeniedException(format("Cannot set authorization for table %s to %s%s", tableName, principal, formatExtraInfo(extraInfo))); @@ -436,11 +455,19 @@ public static void denyRenameView(String viewName, String newViewName, String ex throw new AccessDeniedException(format("Cannot rename view from %s to %s%s", viewName, newViewName, formatExtraInfo(extraInfo))); } + /** + * @deprecated Use {@link #denySetEntityAuthorization(String, List, TrinoPrincipal)} + */ + @Deprecated public static void denySetViewAuthorization(String viewName, TrinoPrincipal principal) { denySetViewAuthorization(viewName, principal, null); } + /** + * @deprecated Use {@link #denySetEntityAuthorization(String, List, TrinoPrincipal, String)} + */ + @Deprecated public static void denySetViewAuthorization(String viewName, TrinoPrincipal principal, String extraInfo) { throw new AccessDeniedException(format("Cannot set authorization for view %s to %s%s", viewName, principal, formatExtraInfo(extraInfo))); @@ -746,6 +773,21 @@ public static void denyShowCreateFunction(String functionName, String extraInfo) throw new AccessDeniedException(format("Cannot show create function for %s%s", functionName, formatExtraInfo(extraInfo))); } + public static void denySetEntityAuthorization(String ownedKind, List name, TrinoPrincipal principal) + { + denySetEntityAuthorization(ownedKind, name, principal, null); + } + + public static void denySetEntityAuthorization(String ownedKind, List name, TrinoPrincipal principal, String extraInfo) + { + throw new AccessDeniedException(format("Cannot set authorization for %s %s to %s%s", ownedKind.toLowerCase(ENGLISH), entityNameString(name), principal, formatExtraInfo(extraInfo))); + } + + private static String entityNameString(List name) + { + return name.stream().collect(joining(".")); + } + private static Object formatExtraInfo(String extraInfo) { if (extraInfo == null || extraInfo.isEmpty()) { diff --git a/core/trino-spi/src/main/java/io/trino/spi/security/SystemAccessControl.java b/core/trino-spi/src/main/java/io/trino/spi/security/SystemAccessControl.java index eb4a2f078411..0ea2c753120f 100644 --- a/core/trino-spi/src/main/java/io/trino/spi/security/SystemAccessControl.java +++ b/core/trino-spi/src/main/java/io/trino/spi/security/SystemAccessControl.java @@ -14,6 +14,8 @@ package io.trino.spi.security; import io.trino.spi.QueryId; +import io.trino.spi.StandardErrorCode; +import io.trino.spi.TrinoException; import io.trino.spi.connector.CatalogSchemaName; import io.trino.spi.connector.CatalogSchemaRoutineName; import io.trino.spi.connector.CatalogSchemaTableName; @@ -28,6 +30,7 @@ import java.security.Principal; import java.util.Collection; import java.util.List; +import java.util.Locale; import java.util.Map; import java.util.Optional; import java.util.Set; @@ -80,13 +83,11 @@ import static io.trino.spi.security.AccessDeniedException.denyRevokeTablePrivilege; import static io.trino.spi.security.AccessDeniedException.denySelectColumns; import static io.trino.spi.security.AccessDeniedException.denySetCatalogSessionProperty; +import static io.trino.spi.security.AccessDeniedException.denySetEntityAuthorization; import static io.trino.spi.security.AccessDeniedException.denySetMaterializedViewProperties; -import static io.trino.spi.security.AccessDeniedException.denySetSchemaAuthorization; import static io.trino.spi.security.AccessDeniedException.denySetSystemSessionProperty; -import static io.trino.spi.security.AccessDeniedException.denySetTableAuthorization; import static io.trino.spi.security.AccessDeniedException.denySetTableProperties; import static io.trino.spi.security.AccessDeniedException.denySetUser; -import static io.trino.spi.security.AccessDeniedException.denySetViewAuthorization; import static io.trino.spi.security.AccessDeniedException.denyShowColumns; import static io.trino.spi.security.AccessDeniedException.denyShowCreateFunction; import static io.trino.spi.security.AccessDeniedException.denyShowCreateSchema; @@ -271,10 +272,13 @@ default void checkCanRenameSchema(SystemSecurityContext context, CatalogSchemaNa * Check if identity is allowed to change the specified schema's user/role. * * @throws AccessDeniedException if not allowed + * + * @deprecated {Use {@link #checkCanSetEntityAuthorization} */ + @Deprecated(forRemoval = true) default void checkCanSetSchemaAuthorization(SystemSecurityContext context, CatalogSchemaName schema, TrinoPrincipal principal) { - denySetSchemaAuthorization(schema.toString(), principal); + denySetEntityAuthorization("SCHEMA", List.of(schema.getCatalogName(), schema.getSchemaName()), principal); } /** @@ -481,10 +485,13 @@ default void checkCanDropColumn(SystemSecurityContext context, CatalogSchemaTabl * Check if identity is allowed to change the specified table's user/role. * * @throws AccessDeniedException if not allowed + * + * @deprecated {Use {@link #checkCanSetEntityAuthorization} */ + @Deprecated(forRemoval = true) default void checkCanSetTableAuthorization(SystemSecurityContext context, CatalogSchemaTableName table, TrinoPrincipal principal) { - denySetTableAuthorization(table.toString(), principal); + denySetEntityAuthorization("TABLE", List.of(table.getCatalogName(), table.getSchemaTableName().getSchemaName(), table.getSchemaTableName().getTableName()), principal); } /** @@ -571,10 +578,13 @@ default void checkCanRenameView(SystemSecurityContext context, CatalogSchemaTabl * Check if identity is allowed to change the specified view's user/role. * * @throws AccessDeniedException if not allowed + * + * @deprecated {Use {@link #checkCanSetEntityAuthorization} */ + @Deprecated(forRemoval = true) default void checkCanSetViewAuthorization(SystemSecurityContext context, CatalogSchemaTableName view, TrinoPrincipal principal) { - denySetViewAuthorization(view.toString(), principal); + denySetEntityAuthorization("VIEW", List.of(view.getCatalogName(), view.getSchemaTableName().getSchemaName(), view.getSchemaTableName().getTableName()), principal); } /** @@ -932,6 +942,33 @@ default Optional getColumnMask(SystemSecurityContext context, Ca return Optional.empty(); } + default void checkCanSetEntityAuthorization(SystemSecurityContext context, String ownedKind, List name, TrinoPrincipal principal) + { + String kind = ownedKind.toUpperCase(Locale.ENGLISH); + switch (kind) { + case "SCHEMA": + if (name.size() != 2) { + throw new TrinoException(StandardErrorCode.INVALID_ARGUMENTS, "The schema name %s must have two elements".formatted(name)); + } + checkCanSetSchemaAuthorization(context, new CatalogSchemaName(name.get(0), name.get(1)), principal); + break; + case "TABLE": + if (name.size() != 3) { + throw new TrinoException(StandardErrorCode.INVALID_ARGUMENTS, "The table name %s must have three elements".formatted(name)); + } + checkCanSetTableAuthorization(context, new CatalogSchemaTableName(name.get(0), name.get(1), name.get(2)), principal); + break; + case "VIEW": + if (name.size() != 3) { + throw new TrinoException(StandardErrorCode.INVALID_ARGUMENTS, "The view name %s must have three elements".formatted(name)); + } + checkCanSetTableAuthorization(context, new CatalogSchemaTableName(name.get(0), name.get(1), name.get(2)), principal); + break; + default: + denySetEntityAuthorization(ownedKind, name, principal); + } + } + /** * Bulk method for getting column masks for a subset of columns in a table. *

diff --git a/core/trino-spi/src/test/java/io/trino/spi/testing/InterfaceTestUtils.java b/core/trino-spi/src/test/java/io/trino/spi/testing/InterfaceTestUtils.java index b3bb9cd432fd..c33c7ec8526f 100644 --- a/core/trino-spi/src/test/java/io/trino/spi/testing/InterfaceTestUtils.java +++ b/core/trino-spi/src/test/java/io/trino/spi/testing/InterfaceTestUtils.java @@ -17,6 +17,7 @@ import java.lang.reflect.Method; import java.lang.reflect.Modifier; +import java.util.Arrays; import java.util.HashSet; import java.util.Set; import java.util.function.Function; @@ -49,6 +50,9 @@ public static void assertAllMethodsOverridden(Class iface, C if (method.getDeclaringClass() == Object.class) { continue; } + if (Arrays.stream(method.getAnnotations()).anyMatch(annotation -> annotation instanceof Deprecated deprecated && deprecated.forRemoval())) { + continue; + } try { Method override = clazz.getDeclaredMethod(method.getName(), method.getParameterTypes()); if (!method.getReturnType().isAssignableFrom(override.getReturnType())) { diff --git a/lib/trino-plugin-toolkit/src/main/java/io/trino/plugin/base/security/AllowAllSystemAccessControl.java b/lib/trino-plugin-toolkit/src/main/java/io/trino/plugin/base/security/AllowAllSystemAccessControl.java index 9d062c183382..f3cc57200199 100644 --- a/lib/trino-plugin-toolkit/src/main/java/io/trino/plugin/base/security/AllowAllSystemAccessControl.java +++ b/lib/trino-plugin-toolkit/src/main/java/io/trino/plugin/base/security/AllowAllSystemAccessControl.java @@ -125,9 +125,6 @@ public void checkCanDropSchema(SystemSecurityContext context, CatalogSchemaName @Override public void checkCanRenameSchema(SystemSecurityContext context, CatalogSchemaName schema, String newSchemaName) {} - @Override - public void checkCanSetSchemaAuthorization(SystemSecurityContext context, CatalogSchemaName schema, TrinoPrincipal principal) {} - @Override public void checkCanShowSchemas(SystemSecurityContext context, String catalogName) {} @@ -200,9 +197,6 @@ public void checkCanRenameColumn(SystemSecurityContext context, CatalogSchemaTab @Override public void checkCanAlterColumn(SystemSecurityContext context, CatalogSchemaTableName table) {} - @Override - public void checkCanSetTableAuthorization(SystemSecurityContext context, CatalogSchemaTableName table, TrinoPrincipal principal) {} - @Override public void checkCanSelectFromColumns(SystemSecurityContext context, CatalogSchemaTableName table, Set columns) {} @@ -224,9 +218,6 @@ public void checkCanCreateView(SystemSecurityContext context, CatalogSchemaTable @Override public void checkCanRenameView(SystemSecurityContext context, CatalogSchemaTableName view, CatalogSchemaTableName newView) {} - @Override - public void checkCanSetViewAuthorization(SystemSecurityContext context, CatalogSchemaTableName view, TrinoPrincipal principal) {} - @Override public void checkCanDropView(SystemSecurityContext context, CatalogSchemaTableName view) {} @@ -359,6 +350,9 @@ public Map getColumnMasks(SystemSecurityContext co return ImmutableMap.of(); } + @Override + public void checkCanSetEntityAuthorization(SystemSecurityContext context, String ownedKind, List name, TrinoPrincipal principal) {} + @Override public void shutdown() {} } diff --git a/lib/trino-plugin-toolkit/src/main/java/io/trino/plugin/base/security/FileBasedSystemAccessControl.java b/lib/trino-plugin-toolkit/src/main/java/io/trino/plugin/base/security/FileBasedSystemAccessControl.java index cb982a5350f8..40eb52fe3496 100644 --- a/lib/trino-plugin-toolkit/src/main/java/io/trino/plugin/base/security/FileBasedSystemAccessControl.java +++ b/lib/trino-plugin-toolkit/src/main/java/io/trino/plugin/base/security/FileBasedSystemAccessControl.java @@ -107,13 +107,11 @@ import static io.trino.spi.security.AccessDeniedException.denyRevokeTablePrivilege; import static io.trino.spi.security.AccessDeniedException.denySelectTable; import static io.trino.spi.security.AccessDeniedException.denySetCatalogSessionProperty; +import static io.trino.spi.security.AccessDeniedException.denySetEntityAuthorization; import static io.trino.spi.security.AccessDeniedException.denySetMaterializedViewProperties; -import static io.trino.spi.security.AccessDeniedException.denySetSchemaAuthorization; import static io.trino.spi.security.AccessDeniedException.denySetSystemSessionProperty; -import static io.trino.spi.security.AccessDeniedException.denySetTableAuthorization; import static io.trino.spi.security.AccessDeniedException.denySetTableProperties; import static io.trino.spi.security.AccessDeniedException.denySetUser; -import static io.trino.spi.security.AccessDeniedException.denySetViewAuthorization; import static io.trino.spi.security.AccessDeniedException.denyShowColumns; import static io.trino.spi.security.AccessDeniedException.denyShowCreateFunction; import static io.trino.spi.security.AccessDeniedException.denyShowCreateSchema; @@ -450,17 +448,6 @@ public void checkCanRenameSchema(SystemSecurityContext context, CatalogSchemaNam } } - @Override - public void checkCanSetSchemaAuthorization(SystemSecurityContext context, CatalogSchemaName schema, TrinoPrincipal principal) - { - if (!isSchemaOwner(context, schema)) { - denySetSchemaAuthorization(schema.toString(), principal); - } - if (!checkCanSetAuthorization(context, principal)) { - denySetSchemaAuthorization(schema.toString(), principal); - } - } - @Override public void checkCanShowSchemas(SystemSecurityContext context, String catalogName) { @@ -654,17 +641,6 @@ public void checkCanAlterColumn(SystemSecurityContext context, CatalogSchemaTabl } } - @Override - public void checkCanSetTableAuthorization(SystemSecurityContext context, CatalogSchemaTableName table, TrinoPrincipal principal) - { - if (!checkTablePermission(context, table, OWNERSHIP)) { - denySetTableAuthorization(table.toString(), principal); - } - if (!checkCanSetAuthorization(context, principal)) { - denySetTableAuthorization(table.toString(), principal); - } - } - @Override public void checkCanSelectFromColumns(SystemSecurityContext context, CatalogSchemaTableName table, Set columns) { @@ -729,17 +705,6 @@ public void checkCanRenameView(SystemSecurityContext context, CatalogSchemaTable } } - @Override - public void checkCanSetViewAuthorization(SystemSecurityContext context, CatalogSchemaTableName view, TrinoPrincipal principal) - { - if (!checkTablePermission(context, view, OWNERSHIP)) { - denySetViewAuthorization(view.toString(), principal); - } - if (!checkCanSetAuthorization(context, principal)) { - denySetViewAuthorization(view.toString(), principal); - } - } - @Override public void checkCanDropView(SystemSecurityContext context, CatalogSchemaTableName view) { @@ -1103,6 +1068,28 @@ public Map getColumnMasks(SystemSecurityContext co } } + @Override + public void checkCanSetEntityAuthorization(SystemSecurityContext context, String ownedKind, List name, TrinoPrincipal principal) + { + boolean denied; + switch (ownedKind) { + case "SCHEMA": + CatalogSchemaName schema = new CatalogSchemaName(name.get(0), name.get(1)); + denied = !isSchemaOwner(context, schema) || !checkCanSetAuthorization(context, principal); + break; + case "TABLE", "VIEW": + CatalogSchemaTableName table = new CatalogSchemaTableName(name.get(0), name.get(1), name.get(2)); + denied = !checkTablePermission(context, table, OWNERSHIP) || !checkCanSetAuthorization(context, principal); + break; + default: + denied = true; + break; + } + if (denied) { + denySetEntityAuthorization(ownedKind, name, principal); + } + } + private boolean checkAnyCatalogAccess(SystemSecurityContext context, String catalogName) { if (canAccessCatalog(context, catalogName, OWNER)) { diff --git a/lib/trino-plugin-toolkit/src/main/java/io/trino/plugin/base/security/ForwardingSystemAccessControl.java b/lib/trino-plugin-toolkit/src/main/java/io/trino/plugin/base/security/ForwardingSystemAccessControl.java index 8370b3b49ca9..ae2141944335 100644 --- a/lib/trino-plugin-toolkit/src/main/java/io/trino/plugin/base/security/ForwardingSystemAccessControl.java +++ b/lib/trino-plugin-toolkit/src/main/java/io/trino/plugin/base/security/ForwardingSystemAccessControl.java @@ -557,6 +557,12 @@ public Map getColumnMasks(SystemSecurityContext co return delegate().getColumnMasks(context, tableName, columns); } + @Override + public void checkCanSetEntityAuthorization(SystemSecurityContext context, String ownedKind, List name, TrinoPrincipal principal) + { + delegate().checkCanSetEntityAuthorization(context, ownedKind, name, principal); + } + @Override public void shutdown() { diff --git a/lib/trino-plugin-toolkit/src/test/java/io/trino/plugin/base/security/BaseFileBasedSystemAccessControlTest.java b/lib/trino-plugin-toolkit/src/test/java/io/trino/plugin/base/security/BaseFileBasedSystemAccessControlTest.java index 293948726768..63ad5f8d64fa 100644 --- a/lib/trino-plugin-toolkit/src/test/java/io/trino/plugin/base/security/BaseFileBasedSystemAccessControlTest.java +++ b/lib/trino-plugin-toolkit/src/test/java/io/trino/plugin/base/security/BaseFileBasedSystemAccessControlTest.java @@ -176,7 +176,7 @@ public void testEmptyFile() accessControl.checkCanDropSchema(UNKNOWN, new CatalogSchemaName("some-catalog", "unknown")); accessControl.checkCanRenameSchema(UNKNOWN, new CatalogSchemaName("some-catalog", "unknown"), "new_unknown"); assertAccessDenied( - () -> accessControl.checkCanSetSchemaAuthorization(UNKNOWN, new CatalogSchemaName("some-catalog", "unknown"), new TrinoPrincipal(ROLE, "some_role")), + () -> accessControl.checkCanSetEntityAuthorization(UNKNOWN, "SCHEMA", List.of("some-catalog", "unknown"), new TrinoPrincipal(ROLE, "some_role")), "Cannot set authorization for schema some-catalog.unknown to ROLE some_role"); accessControl.checkCanShowCreateSchema(UNKNOWN, new CatalogSchemaName("some-catalog", "unknown")); @@ -193,18 +193,18 @@ public void testEmptyFile() new CatalogSchemaTableName("some-catalog", "unknown", "unknown"), new CatalogSchemaTableName("some-catalog", "unknown", "new_unknown")); assertAccessDenied( - () -> accessControl.checkCanSetTableAuthorization(UNKNOWN, new CatalogSchemaTableName("some-catalog", "unknown", "unknown"), new TrinoPrincipal(ROLE, "some_role")), + () -> accessControl.checkCanSetEntityAuthorization(UNKNOWN, "TABLE", List.of("some-catalog", "unknown", "unknown"), new TrinoPrincipal(ROLE, "some_role")), "Cannot set authorization for table some-catalog.unknown.unknown to ROLE some_role"); assertAccessDenied( - () -> accessControl.checkCanSetViewAuthorization(UNKNOWN, new CatalogSchemaTableName("some-catalog", "unknown", "unknown"), new TrinoPrincipal(ROLE, "some_role")), + () -> accessControl.checkCanSetEntityAuthorization(UNKNOWN, "VIEW", List.of("some-catalog", "unknown", "unknown"), new TrinoPrincipal(ROLE, "some_role")), "Cannot set authorization for view some-catalog.unknown.unknown to ROLE some_role"); accessControl.checkCanCreateMaterializedView(UNKNOWN, new CatalogSchemaTableName("some-catalog", "unknown", "unknown"), Map.of()); accessControl.checkCanDropMaterializedView(UNKNOWN, new CatalogSchemaTableName("some-catalog", "unknown", "unknown")); accessControl.checkCanRefreshMaterializedView(UNKNOWN, new CatalogSchemaTableName("some-catalog", "unknown", "unknown")); assertAccessDenied( - () -> accessControl.checkCanSetViewAuthorization(UNKNOWN, new CatalogSchemaTableName("some-catalog", "unknown", "unknown"), new TrinoPrincipal(ROLE, "some_role")), + () -> accessControl.checkCanSetEntityAuthorization(UNKNOWN, "VIEW", List.of("some-catalog", "unknown", "unknown"), new TrinoPrincipal(ROLE, "some_role")), "Cannot set authorization for view some-catalog.unknown.unknown to ROLE some_role"); accessControl.checkCanSetUser(Optional.empty(), "unknown"); @@ -1508,64 +1508,64 @@ public void testSchemaAuthorization() SystemAccessControl accessControl = newFileBasedSystemAccessControl("authorization.json"); CatalogSchemaName schema = new CatalogSchemaName("some-catalog", "test"); - CatalogSchemaName ownedByUser = new CatalogSchemaName("some-catalog", "owned_by_user"); - CatalogSchemaName ownedByGroup = new CatalogSchemaName("some-catalog", "owned_by_group"); - CatalogSchemaName ownedByRole = new CatalogSchemaName("some-catalog", "owned_by_role"); + List ownedByUser = List.of("some-catalog", "owned_by_user"); + List ownedByGroup = List.of("some-catalog", "owned_by_group"); + List ownedByRole = List.of("some-catalog", "owned_by_role"); assertAccessDenied( - () -> accessControl.checkCanSetSchemaAuthorization(user("user", "group", "role"), schema, new TrinoPrincipal(ROLE, "new_role")), + () -> accessControl.checkCanSetEntityAuthorization(user("user", "group", "role"), "SCHEMA", List.of(schema.getCatalogName(), schema.getSchemaName()), new TrinoPrincipal(ROLE, "new_role")), "Cannot set authorization for schema some-catalog.test to ROLE new_role"); // access to schema granted to user - accessControl.checkCanSetSchemaAuthorization(user("owner_authorized", "group", "role"), ownedByUser, new TrinoPrincipal(USER, "new_user")); - accessControl.checkCanSetSchemaAuthorization(user("owner", "authorized", "role"), ownedByUser, new TrinoPrincipal(ROLE, "new_role")); - accessControl.checkCanSetSchemaAuthorization(user("owner", "group", "authorized"), ownedByUser, new TrinoPrincipal(ROLE, "new_role")); + accessControl.checkCanSetEntityAuthorization(user("owner_authorized", "group", "role"), "SCHEMA", ownedByUser, new TrinoPrincipal(USER, "new_user")); + accessControl.checkCanSetEntityAuthorization(user("owner", "authorized", "role"), "SCHEMA", ownedByUser, new TrinoPrincipal(ROLE, "new_role")); + accessControl.checkCanSetEntityAuthorization(user("owner", "group", "authorized"), "SCHEMA", ownedByUser, new TrinoPrincipal(ROLE, "new_role")); assertAccessDenied( - () -> accessControl.checkCanSetSchemaAuthorization(user("owner_without_authorization_access", "group", "role"), ownedByUser, new TrinoPrincipal(ROLE, "new_role")), + () -> accessControl.checkCanSetEntityAuthorization(user("owner_without_authorization_access", "group", "role"), "SCHEMA", ownedByUser, new TrinoPrincipal(ROLE, "new_role")), "Cannot set authorization for schema some-catalog.owned_by_user to ROLE new_role"); assertAccessDenied( - () -> accessControl.checkCanSetSchemaAuthorization(user("owner_DENY_authorized", "group", "role"), ownedByUser, new TrinoPrincipal(USER, "new_user")), + () -> accessControl.checkCanSetEntityAuthorization(user("owner_DENY_authorized", "group", "role"), "SCHEMA", ownedByUser, new TrinoPrincipal(USER, "new_user")), "Cannot set authorization for schema some-catalog.owned_by_user to USER new_user"); assertAccessDenied( - () -> accessControl.checkCanSetSchemaAuthorization(user("owner", "DENY_authorized", "role"), ownedByUser, new TrinoPrincipal(ROLE, "new_role")), + () -> accessControl.checkCanSetEntityAuthorization(user("owner", "DENY_authorized", "role"), "SCHEMA", ownedByUser, new TrinoPrincipal(ROLE, "new_role")), "Cannot set authorization for schema some-catalog.owned_by_user to ROLE new_role"); assertAccessDenied( - () -> accessControl.checkCanSetSchemaAuthorization(user("owner", "group", "DENY_authorized"), ownedByUser, new TrinoPrincipal(ROLE, "new_role")), + () -> accessControl.checkCanSetEntityAuthorization(user("owner", "group", "DENY_authorized"), "SCHEMA", ownedByUser, new TrinoPrincipal(ROLE, "new_role")), "Cannot set authorization for schema some-catalog.owned_by_user to ROLE new_role"); assertAccessDenied( - () -> accessControl.checkCanSetSchemaAuthorization(user("owner", "group", "authorized"), ownedByUser, new TrinoPrincipal(USER, "new_user")), + () -> accessControl.checkCanSetEntityAuthorization(user("owner", "group", "authorized"), "SCHEMA", ownedByUser, new TrinoPrincipal(USER, "new_user")), "Cannot set authorization for schema some-catalog.owned_by_user to USER new_user"); // access to schema granted to group - accessControl.checkCanSetSchemaAuthorization(user("authorized", "owner", "role"), ownedByGroup, new TrinoPrincipal(USER, "new_user")); - accessControl.checkCanSetSchemaAuthorization(user("user", "owner", "authorized"), ownedByGroup, new TrinoPrincipal(ROLE, "new_role")); + accessControl.checkCanSetEntityAuthorization(user("authorized", "owner", "role"), "SCHEMA", ownedByGroup, new TrinoPrincipal(USER, "new_user")); + accessControl.checkCanSetEntityAuthorization(user("user", "owner", "authorized"), "SCHEMA", ownedByGroup, new TrinoPrincipal(ROLE, "new_role")); assertAccessDenied( - () -> accessControl.checkCanSetSchemaAuthorization(user("user", "owner", "role"), ownedByGroup, new TrinoPrincipal(ROLE, "new_role")), + () -> accessControl.checkCanSetEntityAuthorization(user("user", "owner", "role"), "SCHEMA", ownedByGroup, new TrinoPrincipal(ROLE, "new_role")), "Cannot set authorization for schema some-catalog.owned_by_group to ROLE new_role"); assertAccessDenied( - () -> accessControl.checkCanSetSchemaAuthorization(user("DENY_authorized", "owner", "role"), ownedByGroup, new TrinoPrincipal(USER, "new_user")), + () -> accessControl.checkCanSetEntityAuthorization(user("DENY_authorized", "owner", "role"), "SCHEMA", ownedByGroup, new TrinoPrincipal(USER, "new_user")), "Cannot set authorization for schema some-catalog.owned_by_group to USER new_user"); assertAccessDenied( - () -> accessControl.checkCanSetSchemaAuthorization(user("user", "owner", "DENY_authorized"), ownedByGroup, new TrinoPrincipal(ROLE, "new_role")), + () -> accessControl.checkCanSetEntityAuthorization(user("user", "owner", "DENY_authorized"), "SCHEMA", ownedByGroup, new TrinoPrincipal(ROLE, "new_role")), "Cannot set authorization for schema some-catalog.owned_by_group to ROLE new_role"); assertAccessDenied( - () -> accessControl.checkCanSetSchemaAuthorization(user("user", "owner", "authorized"), ownedByGroup, new TrinoPrincipal(USER, "new_user")), + () -> accessControl.checkCanSetEntityAuthorization(user("user", "owner", "authorized"), "SCHEMA", ownedByGroup, new TrinoPrincipal(USER, "new_user")), "Cannot set authorization for schema some-catalog.owned_by_group to USER new_user"); // access to schema granted to role - accessControl.checkCanSetSchemaAuthorization(user("authorized", "group", "owner"), ownedByRole, new TrinoPrincipal(USER, "new_user")); - accessControl.checkCanSetSchemaAuthorization(user("user", "group", "owner_authorized"), ownedByRole, new TrinoPrincipal(ROLE, "new_role")); + accessControl.checkCanSetEntityAuthorization(user("authorized", "group", "owner"), "SCHEMA", ownedByRole, new TrinoPrincipal(USER, "new_user")); + accessControl.checkCanSetEntityAuthorization(user("user", "group", "owner_authorized"), "SCHEMA", ownedByRole, new TrinoPrincipal(ROLE, "new_role")); assertAccessDenied( - () -> accessControl.checkCanSetSchemaAuthorization(user("user", "group", "owner"), ownedByRole, new TrinoPrincipal(ROLE, "new_role")), + () -> accessControl.checkCanSetEntityAuthorization(user("user", "group", "owner"), "SCHEMA", ownedByRole, new TrinoPrincipal(ROLE, "new_role")), "Cannot set authorization for schema some-catalog.owned_by_role to ROLE new_role"); assertAccessDenied( - () -> accessControl.checkCanSetSchemaAuthorization(user("DENY_authorized", "group", "owner"), ownedByRole, new TrinoPrincipal(USER, "new_user")), + () -> accessControl.checkCanSetEntityAuthorization(user("DENY_authorized", "group", "owner"), "SCHEMA", ownedByRole, new TrinoPrincipal(USER, "new_user")), "Cannot set authorization for schema some-catalog.owned_by_role to USER new_user"); assertAccessDenied( - () -> accessControl.checkCanSetSchemaAuthorization(user("user", "group", "owner_DENY_authorized"), ownedByRole, new TrinoPrincipal(ROLE, "new_role")), + () -> accessControl.checkCanSetEntityAuthorization(user("user", "group", "owner_DENY_authorized"), "SCHEMA", ownedByRole, new TrinoPrincipal(ROLE, "new_role")), "Cannot set authorization for schema some-catalog.owned_by_role to ROLE new_role"); assertAccessDenied( - () -> accessControl.checkCanSetSchemaAuthorization(user("user", "group", "owner_authorized"), ownedByRole, new TrinoPrincipal(USER, "new_user")), + () -> accessControl.checkCanSetEntityAuthorization(user("user", "group", "owner_authorized"), "SCHEMA", ownedByRole, new TrinoPrincipal(USER, "new_user")), "Cannot set authorization for schema some-catalog.owned_by_role to USER new_user"); } @@ -1574,61 +1574,61 @@ public void testTableAuthorization() { SystemAccessControl accessControl = newFileBasedSystemAccessControl("authorization.json"); - CatalogSchemaTableName table = new CatalogSchemaTableName("some-catalog", "test", "table"); - CatalogSchemaTableName ownedByUser = new CatalogSchemaTableName("some-catalog", "test", "owned_by_user"); - CatalogSchemaTableName ownedByGroup = new CatalogSchemaTableName("some-catalog", "test", "owned_by_group"); - CatalogSchemaTableName ownedByRole = new CatalogSchemaTableName("some-catalog", "test", "owned_by_role"); + List table = List.of("some-catalog", "test", "table"); + List ownedByUser = List.of("some-catalog", "test", "owned_by_user"); + List ownedByGroup = List.of("some-catalog", "test", "owned_by_group"); + List ownedByRole = List.of("some-catalog", "test", "owned_by_role"); assertAccessDenied( - () -> accessControl.checkCanSetTableAuthorization(user("user", "group", "role"), table, new TrinoPrincipal(ROLE, "new_role")), + () -> accessControl.checkCanSetEntityAuthorization(user("user", "group", "role"), "TABLE", table, new TrinoPrincipal(ROLE, "new_role")), "Cannot set authorization for table some-catalog.test.table to ROLE new_role"); // access to table granted to user - accessControl.checkCanSetTableAuthorization(user("owner_authorized", "group", "role"), ownedByUser, new TrinoPrincipal(USER, "new_user")); - accessControl.checkCanSetTableAuthorization(user("owner", "group", "authorized"), ownedByUser, new TrinoPrincipal(ROLE, "new_role")); + accessControl.checkCanSetEntityAuthorization(user("owner_authorized", "group", "role"), "TABLE", ownedByUser, new TrinoPrincipal(USER, "new_user")); + accessControl.checkCanSetEntityAuthorization(user("owner", "group", "authorized"), "TABLE", ownedByUser, new TrinoPrincipal(ROLE, "new_role")); assertAccessDenied( - () -> accessControl.checkCanSetTableAuthorization(user("owner_without_authorization_access", "group", "role"), ownedByUser, new TrinoPrincipal(ROLE, "new_role")), + () -> accessControl.checkCanSetEntityAuthorization(user("owner_without_authorization_access", "group", "role"), "TABLE", ownedByUser, new TrinoPrincipal(ROLE, "new_role")), "Cannot set authorization for table some-catalog.test.owned_by_user to ROLE new_role"); assertAccessDenied( - () -> accessControl.checkCanSetTableAuthorization(user("owner_DENY_authorized", "group", "role"), ownedByUser, new TrinoPrincipal(USER, "new_user")), + () -> accessControl.checkCanSetEntityAuthorization(user("owner_DENY_authorized", "group", "role"), "TABLE", ownedByUser, new TrinoPrincipal(USER, "new_user")), "Cannot set authorization for table some-catalog.test.owned_by_user to USER new_user"); assertAccessDenied( - () -> accessControl.checkCanSetTableAuthorization(user("owner", "group", "DENY_authorized"), ownedByUser, new TrinoPrincipal(ROLE, "new_role")), + () -> accessControl.checkCanSetEntityAuthorization(user("owner", "group", "DENY_authorized"), "TABLE", ownedByUser, new TrinoPrincipal(ROLE, "new_role")), "Cannot set authorization for table some-catalog.test.owned_by_user to ROLE new_role"); assertAccessDenied( - () -> accessControl.checkCanSetTableAuthorization(user("owner", "group", "authorized"), ownedByUser, new TrinoPrincipal(USER, "new_user")), + () -> accessControl.checkCanSetEntityAuthorization(user("owner", "group", "authorized"), "TABLE", ownedByUser, new TrinoPrincipal(USER, "new_user")), "Cannot set authorization for table some-catalog.test.owned_by_user to USER new_user"); // access to table granted to group - accessControl.checkCanSetTableAuthorization(user("authorized", "owner", "role"), ownedByGroup, new TrinoPrincipal(USER, "new_user")); - accessControl.checkCanSetTableAuthorization(user("user", "owner", "authorized"), ownedByGroup, new TrinoPrincipal(ROLE, "new_role")); + accessControl.checkCanSetEntityAuthorization(user("authorized", "owner", "role"), "TABLE", ownedByGroup, new TrinoPrincipal(USER, "new_user")); + accessControl.checkCanSetEntityAuthorization(user("user", "owner", "authorized"), "TABLE", ownedByGroup, new TrinoPrincipal(ROLE, "new_role")); assertAccessDenied( - () -> accessControl.checkCanSetTableAuthorization(user("user", "owner", "role"), ownedByGroup, new TrinoPrincipal(ROLE, "new_role")), + () -> accessControl.checkCanSetEntityAuthorization(user("user", "owner", "role"), "TABLE", ownedByGroup, new TrinoPrincipal(ROLE, "new_role")), "Cannot set authorization for table some-catalog.test.owned_by_group to ROLE new_role"); assertAccessDenied( - () -> accessControl.checkCanSetTableAuthorization(user("DENY_authorized", "owner", "role"), ownedByGroup, new TrinoPrincipal(USER, "new_user")), + () -> accessControl.checkCanSetEntityAuthorization(user("DENY_authorized", "owner", "role"), "TABLE", ownedByGroup, new TrinoPrincipal(USER, "new_user")), "Cannot set authorization for table some-catalog.test.owned_by_group to USER new_user"); assertAccessDenied( - () -> accessControl.checkCanSetTableAuthorization(user("user", "owner", "DENY_authorized"), ownedByGroup, new TrinoPrincipal(ROLE, "new_role")), + () -> accessControl.checkCanSetEntityAuthorization(user("user", "owner", "DENY_authorized"), "TABLE", ownedByGroup, new TrinoPrincipal(ROLE, "new_role")), "Cannot set authorization for table some-catalog.test.owned_by_group to ROLE new_role"); assertAccessDenied( - () -> accessControl.checkCanSetTableAuthorization(user("user", "owner", "authorized"), ownedByGroup, new TrinoPrincipal(USER, "new_user")), + () -> accessControl.checkCanSetEntityAuthorization(user("user", "owner", "authorized"), "TABLE", ownedByGroup, new TrinoPrincipal(USER, "new_user")), "Cannot set authorization for table some-catalog.test.owned_by_group to USER new_user"); // access to table granted to role - accessControl.checkCanSetTableAuthorization(user("authorized", "group", "owner"), ownedByRole, new TrinoPrincipal(USER, "new_user")); - accessControl.checkCanSetTableAuthorization(user("user", "group", "owner_authorized"), ownedByRole, new TrinoPrincipal(ROLE, "new_role")); + accessControl.checkCanSetEntityAuthorization(user("authorized", "group", "owner"), "TABLE", ownedByRole, new TrinoPrincipal(USER, "new_user")); + accessControl.checkCanSetEntityAuthorization(user("user", "group", "owner_authorized"), "TABLE", ownedByRole, new TrinoPrincipal(ROLE, "new_role")); assertAccessDenied( - () -> accessControl.checkCanSetTableAuthorization(user("user", "group", "owner"), ownedByRole, new TrinoPrincipal(ROLE, "new_role")), + () -> accessControl.checkCanSetEntityAuthorization(user("user", "group", "owner"), "TABLE", ownedByRole, new TrinoPrincipal(ROLE, "new_role")), "Cannot set authorization for table some-catalog.test.owned_by_role to ROLE new_role"); assertAccessDenied( - () -> accessControl.checkCanSetTableAuthorization(user("DENY_authorized", "group", "owner"), ownedByRole, new TrinoPrincipal(USER, "new_user")), + () -> accessControl.checkCanSetEntityAuthorization(user("DENY_authorized", "group", "owner"), "TABLE", ownedByRole, new TrinoPrincipal(USER, "new_user")), "Cannot set authorization for table some-catalog.test.owned_by_role to USER new_user"); assertAccessDenied( - () -> accessControl.checkCanSetTableAuthorization(user("user", "group", "owner_DENY_authorized"), ownedByRole, new TrinoPrincipal(ROLE, "new_role")), + () -> accessControl.checkCanSetEntityAuthorization(user("user", "group", "owner_DENY_authorized"), "TABLE", ownedByRole, new TrinoPrincipal(ROLE, "new_role")), "Cannot set authorization for table some-catalog.test.owned_by_role to ROLE new_role"); assertAccessDenied( - () -> accessControl.checkCanSetTableAuthorization(user("user", "group", "owner_authorized"), ownedByRole, new TrinoPrincipal(USER, "new_user")), + () -> accessControl.checkCanSetEntityAuthorization(user("user", "group", "owner_authorized"), "TABLE", ownedByRole, new TrinoPrincipal(USER, "new_user")), "Cannot set authorization for table some-catalog.test.owned_by_role to USER new_user"); } @@ -1637,61 +1637,61 @@ public void testViewAuthorization() { SystemAccessControl accessControl = newFileBasedSystemAccessControl("authorization.json"); - CatalogSchemaTableName table = new CatalogSchemaTableName("some-catalog", "test", "table"); - CatalogSchemaTableName ownedByUser = new CatalogSchemaTableName("some-catalog", "test", "owned_by_user"); - CatalogSchemaTableName ownedByGroup = new CatalogSchemaTableName("some-catalog", "test", "owned_by_group"); - CatalogSchemaTableName ownedByRole = new CatalogSchemaTableName("some-catalog", "test", "owned_by_role"); + List table = List.of("some-catalog", "test", "table"); + List ownedByUser = List.of("some-catalog", "test", "owned_by_user"); + List ownedByGroup = List.of("some-catalog", "test", "owned_by_group"); + List ownedByRole = List.of("some-catalog", "test", "owned_by_role"); assertAccessDenied( - () -> accessControl.checkCanSetViewAuthorization(user("user", "group", "role"), table, new TrinoPrincipal(ROLE, "new_role")), + () -> accessControl.checkCanSetEntityAuthorization(user("user", "group", "role"), "VIEW", table, new TrinoPrincipal(ROLE, "new_role")), "Cannot set authorization for view some-catalog.test.table to ROLE new_role"); // access to table granted to user - accessControl.checkCanSetViewAuthorization(user("owner_authorized", "group", "role"), ownedByUser, new TrinoPrincipal(USER, "new_user")); - accessControl.checkCanSetViewAuthorization(user("owner", "group", "authorized"), ownedByUser, new TrinoPrincipal(ROLE, "new_role")); + accessControl.checkCanSetEntityAuthorization(user("owner_authorized", "group", "role"), "VIEW", ownedByUser, new TrinoPrincipal(USER, "new_user")); + accessControl.checkCanSetEntityAuthorization(user("owner", "group", "authorized"), "VIEW", ownedByUser, new TrinoPrincipal(ROLE, "new_role")); assertAccessDenied( - () -> accessControl.checkCanSetViewAuthorization(user("owner_without_authorization_access", "group", "role"), ownedByUser, new TrinoPrincipal(ROLE, "new_role")), + () -> accessControl.checkCanSetEntityAuthorization(user("owner_without_authorization_access", "group", "role"), "VIEW", ownedByUser, new TrinoPrincipal(ROLE, "new_role")), "Cannot set authorization for view some-catalog.test.owned_by_user to ROLE new_role"); assertAccessDenied( - () -> accessControl.checkCanSetViewAuthorization(user("owner_DENY_authorized", "group", "role"), ownedByUser, new TrinoPrincipal(USER, "new_user")), + () -> accessControl.checkCanSetEntityAuthorization(user("owner_DENY_authorized", "group", "role"), "VIEW", ownedByUser, new TrinoPrincipal(USER, "new_user")), "Cannot set authorization for view some-catalog.test.owned_by_user to USER new_user"); assertAccessDenied( - () -> accessControl.checkCanSetViewAuthorization(user("owner", "group", "DENY_authorized"), ownedByUser, new TrinoPrincipal(ROLE, "new_role")), + () -> accessControl.checkCanSetEntityAuthorization(user("owner", "group", "DENY_authorized"), "VIEW", ownedByUser, new TrinoPrincipal(ROLE, "new_role")), "Cannot set authorization for view some-catalog.test.owned_by_user to ROLE new_role"); assertAccessDenied( - () -> accessControl.checkCanSetViewAuthorization(user("owner", "group", "authorized"), ownedByUser, new TrinoPrincipal(USER, "new_user")), + () -> accessControl.checkCanSetEntityAuthorization(user("owner", "group", "authorized"), "VIEW", ownedByUser, new TrinoPrincipal(USER, "new_user")), "Cannot set authorization for view some-catalog.test.owned_by_user to USER new_user"); // access to table granted to group - accessControl.checkCanSetViewAuthorization(user("authorized", "owner", "role"), ownedByGroup, new TrinoPrincipal(USER, "new_user")); - accessControl.checkCanSetViewAuthorization(user("user", "owner", "authorized"), ownedByGroup, new TrinoPrincipal(ROLE, "new_role")); + accessControl.checkCanSetEntityAuthorization(user("authorized", "owner", "role"), "VIEW", ownedByGroup, new TrinoPrincipal(USER, "new_user")); + accessControl.checkCanSetEntityAuthorization(user("user", "owner", "authorized"), "VIEW", ownedByGroup, new TrinoPrincipal(ROLE, "new_role")); assertAccessDenied( - () -> accessControl.checkCanSetViewAuthorization(user("user", "owner", "role"), ownedByGroup, new TrinoPrincipal(ROLE, "new_role")), + () -> accessControl.checkCanSetEntityAuthorization(user("user", "owner", "role"), "VIEW", ownedByGroup, new TrinoPrincipal(ROLE, "new_role")), "Cannot set authorization for view some-catalog.test.owned_by_group to ROLE new_role"); assertAccessDenied( - () -> accessControl.checkCanSetViewAuthorization(user("DENY_authorized", "owner", "role"), ownedByGroup, new TrinoPrincipal(USER, "new_user")), + () -> accessControl.checkCanSetEntityAuthorization(user("DENY_authorized", "owner", "role"), "VIEW", ownedByGroup, new TrinoPrincipal(USER, "new_user")), "Cannot set authorization for view some-catalog.test.owned_by_group to USER new_user"); assertAccessDenied( - () -> accessControl.checkCanSetViewAuthorization(user("user", "owner", "DENY_authorized"), ownedByGroup, new TrinoPrincipal(ROLE, "new_role")), + () -> accessControl.checkCanSetEntityAuthorization(user("user", "owner", "DENY_authorized"), "VIEW", ownedByGroup, new TrinoPrincipal(ROLE, "new_role")), "Cannot set authorization for view some-catalog.test.owned_by_group to ROLE new_role"); assertAccessDenied( - () -> accessControl.checkCanSetViewAuthorization(user("user", "owner", "authorized"), ownedByGroup, new TrinoPrincipal(USER, "new_user")), + () -> accessControl.checkCanSetEntityAuthorization(user("user", "owner", "authorized"), "VIEW", ownedByGroup, new TrinoPrincipal(USER, "new_user")), "Cannot set authorization for view some-catalog.test.owned_by_group to USER new_user"); // access to table granted to role - accessControl.checkCanSetViewAuthorization(user("authorized", "group", "owner"), ownedByRole, new TrinoPrincipal(USER, "new_user")); - accessControl.checkCanSetViewAuthorization(user("user", "group", "owner_authorized"), ownedByRole, new TrinoPrincipal(ROLE, "new_role")); + accessControl.checkCanSetEntityAuthorization(user("authorized", "group", "owner"), "VIEW", ownedByRole, new TrinoPrincipal(USER, "new_user")); + accessControl.checkCanSetEntityAuthorization(user("user", "group", "owner_authorized"), "VIEW", ownedByRole, new TrinoPrincipal(ROLE, "new_role")); assertAccessDenied( - () -> accessControl.checkCanSetViewAuthorization(user("user", "group", "owner"), ownedByRole, new TrinoPrincipal(ROLE, "new_role")), + () -> accessControl.checkCanSetEntityAuthorization(user("user", "group", "owner"), "VIEW", ownedByRole, new TrinoPrincipal(ROLE, "new_role")), "Cannot set authorization for view some-catalog.test.owned_by_role to ROLE new_role"); assertAccessDenied( - () -> accessControl.checkCanSetViewAuthorization(user("DENY_authorized", "group", "owner"), ownedByRole, new TrinoPrincipal(USER, "new_user")), + () -> accessControl.checkCanSetEntityAuthorization(user("DENY_authorized", "group", "owner"), "VIEW", ownedByRole, new TrinoPrincipal(USER, "new_user")), "Cannot set authorization for view some-catalog.test.owned_by_role to USER new_user"); assertAccessDenied( - () -> accessControl.checkCanSetViewAuthorization(user("user", "group", "owner_DENY_authorized"), ownedByRole, new TrinoPrincipal(ROLE, "new_role")), + () -> accessControl.checkCanSetEntityAuthorization(user("user", "group", "owner_DENY_authorized"), "VIEW", ownedByRole, new TrinoPrincipal(ROLE, "new_role")), "Cannot set authorization for view some-catalog.test.owned_by_role to ROLE new_role"); assertAccessDenied( - () -> accessControl.checkCanSetViewAuthorization(user("user", "group", "owner_authorized"), ownedByRole, new TrinoPrincipal(USER, "new_user")), + () -> accessControl.checkCanSetEntityAuthorization(user("user", "group", "owner_authorized"), "VIEW", ownedByRole, new TrinoPrincipal(USER, "new_user")), "Cannot set authorization for view some-catalog.test.owned_by_role to USER new_user"); } @@ -1745,22 +1745,22 @@ public void testAuthorizationDocsExample() { File rulesFile = new File("../../docs/src/main/sphinx/security/authorization.json"); SystemAccessControl accessControlManager = newFileBasedSystemAccessControl(rulesFile, ImmutableMap.of()); - CatalogSchemaName schema = new CatalogSchemaName("catalog", "schema"); - CatalogSchemaTableName tableOrView = new CatalogSchemaTableName("catalog", "schema", "table_or_view"); - accessControlManager.checkCanSetSchemaAuthorization(ADMIN, schema, new TrinoPrincipal(USER, "alice")); - accessControlManager.checkCanSetSchemaAuthorization(ADMIN, schema, new TrinoPrincipal(ROLE, "role")); - accessControlManager.checkCanSetTableAuthorization(ADMIN, tableOrView, new TrinoPrincipal(USER, "alice")); - accessControlManager.checkCanSetTableAuthorization(ADMIN, tableOrView, new TrinoPrincipal(ROLE, "role")); - accessControlManager.checkCanSetViewAuthorization(ADMIN, tableOrView, new TrinoPrincipal(USER, "alice")); - accessControlManager.checkCanSetViewAuthorization(ADMIN, tableOrView, new TrinoPrincipal(ROLE, "role")); - assertAccessDenied( - () -> accessControlManager.checkCanSetSchemaAuthorization(ADMIN, schema, new TrinoPrincipal(USER, "bob")), + List schema = List.of("catalog", "schema"); + List tableOrView = List.of("catalog", "schema", "table_or_view"); + accessControlManager.checkCanSetEntityAuthorization(ADMIN, "SCHEMA", schema, new TrinoPrincipal(USER, "alice")); + accessControlManager.checkCanSetEntityAuthorization(ADMIN, "SCHEMA", schema, new TrinoPrincipal(ROLE, "role")); + accessControlManager.checkCanSetEntityAuthorization(ADMIN, "TABLE", tableOrView, new TrinoPrincipal(USER, "alice")); + accessControlManager.checkCanSetEntityAuthorization(ADMIN, "TABLE", tableOrView, new TrinoPrincipal(ROLE, "role")); + accessControlManager.checkCanSetEntityAuthorization(ADMIN, "VIEW", tableOrView, new TrinoPrincipal(USER, "alice")); + accessControlManager.checkCanSetEntityAuthorization(ADMIN, "VIEW", tableOrView, new TrinoPrincipal(ROLE, "role")); + assertAccessDenied( + () -> accessControlManager.checkCanSetEntityAuthorization(ADMIN, "SCHEMA", schema, new TrinoPrincipal(USER, "bob")), "Cannot set authorization for schema catalog.schema to USER bob"); assertAccessDenied( - () -> accessControlManager.checkCanSetTableAuthorization(ADMIN, tableOrView, new TrinoPrincipal(USER, "bob")), + () -> accessControlManager.checkCanSetEntityAuthorization(ADMIN, "TABLE", tableOrView, new TrinoPrincipal(USER, "bob")), "Cannot set authorization for table catalog.schema.table_or_view to USER bob"); assertAccessDenied( - () -> accessControlManager.checkCanSetViewAuthorization(ADMIN, tableOrView, new TrinoPrincipal(USER, "bob")), + () -> accessControlManager.checkCanSetEntityAuthorization(ADMIN, "VIEW", tableOrView, new TrinoPrincipal(USER, "bob")), "Cannot set authorization for view catalog.schema.table_or_view to USER bob"); } diff --git a/testing/trino-tests/src/test/java/io/trino/security/TestAccessControl.java b/testing/trino-tests/src/test/java/io/trino/security/TestAccessControl.java index f413304ec248..67b9c629c3f5 100644 --- a/testing/trino-tests/src/test/java/io/trino/security/TestAccessControl.java +++ b/testing/trino-tests/src/test/java/io/trino/security/TestAccessControl.java @@ -476,9 +476,10 @@ public void testViewOwnersRoleGrants() String viewName = "test_view_column_access_" + randomNameSuffix(); systemSecurityMetadata.grantRoles(getSession(), Set.of("view_owner_role"), Set.of(viewOwnerPrincipal), false, Optional.empty()); - systemSecurityMetadata.setViewOwner( + systemSecurityMetadata.setEntityOwner( getSession(), - new CatalogSchemaTableName("blackhole", "default", viewName), + "VIEW", + List.of("blackhole", "default", viewName), viewOwnerPrincipal); Session viewOwnerSession = TestingSession.testSessionBuilder() @@ -518,9 +519,10 @@ public void testJoinBaseTableWithView() String viewName = "test_join_base_table_with_view_" + randomNameSuffix(); systemSecurityMetadata.grantRoles(getSession(), Set.of("view_owner_role"), Set.of(viewOwnerPrincipal), false, Optional.empty()); - systemSecurityMetadata.setViewOwner( + systemSecurityMetadata.setEntityOwner( getSession(), - new CatalogSchemaTableName("blackhole", "default", viewName), + "VIEW", + List.of("blackhole", "default", viewName), viewOwnerPrincipal); Session viewOwnerSession = TestingSession.testSessionBuilder() diff --git a/testing/trino-tests/src/test/java/io/trino/security/TestAccessControlTableRedirection.java b/testing/trino-tests/src/test/java/io/trino/security/TestAccessControlTableRedirection.java index 9824a7298248..7461d3b75bd9 100644 --- a/testing/trino-tests/src/test/java/io/trino/security/TestAccessControlTableRedirection.java +++ b/testing/trino-tests/src/test/java/io/trino/security/TestAccessControlTableRedirection.java @@ -33,6 +33,7 @@ import io.trino.testing.QueryRunner; import org.junit.jupiter.api.Test; +import java.util.List; import java.util.Map; import java.util.Optional; import java.util.Set; @@ -107,10 +108,10 @@ public boolean roleExists(Session session, String role) } @Override - public void setTableOwner(Session session, CatalogSchemaTableName table, TrinoPrincipal principal) {} + public void denyTablePrivileges(Session session, QualifiedObjectName tableName, Set privileges, TrinoPrincipal grantee) {} @Override - public void denyTablePrivileges(Session session, QualifiedObjectName tableName, Set privileges, TrinoPrincipal grantee) {} + public void setEntityOwner(Session session, String ownedKind, List name, TrinoPrincipal principal) {} }); }) .build(); diff --git a/testing/trino-tests/src/test/java/io/trino/security/TestingSystemSecurityMetadata.java b/testing/trino-tests/src/test/java/io/trino/security/TestingSystemSecurityMetadata.java index 83fe28ca4b5e..866ceaae3b7d 100644 --- a/testing/trino-tests/src/test/java/io/trino/security/TestingSystemSecurityMetadata.java +++ b/testing/trino-tests/src/test/java/io/trino/security/TestingSystemSecurityMetadata.java @@ -30,6 +30,7 @@ import java.util.ArrayDeque; import java.util.HashMap; import java.util.HashSet; +import java.util.List; import java.util.Map; import java.util.Optional; import java.util.Queue; @@ -212,18 +213,6 @@ public Optional getSchemaOwner(Session session, CatalogSchemaNam return Optional.empty(); } - @Override - public void setSchemaOwner(Session session, CatalogSchemaName schema, TrinoPrincipal principal) - { - throw new UnsupportedOperationException(); - } - - @Override - public void setTableOwner(Session session, CatalogSchemaTableName table, TrinoPrincipal principal) - { - throw new UnsupportedOperationException(); - } - @Override public Optional getViewRunAsIdentity(Session session, CatalogSchemaTableName viewName) { @@ -236,13 +225,6 @@ public Optional getViewRunAsIdentity(Session session, CatalogSchemaTab .build()); } - @Override - public void setViewOwner(Session session, CatalogSchemaTableName view, TrinoPrincipal principal) - { - checkArgument(principal.getType() == USER, "Only a user can be a view owner"); - viewOwners.put(view, Identity.ofUser(principal.getName())); - } - @Override public Optional getFunctionRunAsIdentity(Session session, CatalogSchemaFunctionName functionName) { @@ -281,4 +263,16 @@ public void columnTypeChanged(Session session, CatalogSchemaTableName table, Str @Override public void columnNotNullConstraintDropped(Session session, CatalogSchemaTableName table, String column) {} + + @Override + public void setEntityOwner(Session session, String ownedKind, List name, TrinoPrincipal principal) + { + if (ownedKind.equals("VIEW")) { + checkArgument(principal.getType() == USER, "Only a user can be a view owner"); + viewOwners.put(new CatalogSchemaTableName(name.get(0), name.get(1), name.get(2)), Identity.ofUser(principal.getName())); + } + else { + throw new UnsupportedOperationException(); + } + } }