Skip to content

Commit 1a81b69

Browse files
David Strykerkokosing
authored andcommitted
Add generic SET AUTHORIZATION
This commit adds machinery to set the owner of arbitrary entities, by extending the syntax of ALTER (SCHEMA | TABLE | VIEW) qualifiedName SET AUTHORIZATION to support arbitrary owningKinds in place of SCHEMA, TABLE or VIEW. Checks that a specific SET AUTHORIZATION is legal is done by AccessControl.checkCanSetEntityAuthorization, also defined by SystemAccessControl. Setting the owner is done by Metadata.setEntityAuthorization and SystemSecurityMetadata.setEntityAuthorization.
1 parent c6c1469 commit 1a81b69

File tree

40 files changed

+619
-876
lines changed

40 files changed

+619
-876
lines changed

core/trino-grammar/src/main/antlr4/io/trino/grammar/sql/SqlBase.g4

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,6 @@ statement
6060
(WITH properties)? #createSchema
6161
| DROP SCHEMA (IF EXISTS)? qualifiedName (CASCADE | RESTRICT)? #dropSchema
6262
| ALTER SCHEMA qualifiedName RENAME TO identifier #renameSchema
63-
| ALTER SCHEMA qualifiedName SET AUTHORIZATION principal #setSchemaAuthorization
6463
| CREATE (OR REPLACE)? TABLE (IF NOT EXISTS)? qualifiedName
6564
columnAliases?
6665
(COMMENT string)?
@@ -90,13 +89,13 @@ statement
9089
ALTER COLUMN columnName=qualifiedName SET DATA TYPE type #setColumnType
9190
| ALTER TABLE (IF EXISTS)? tableName=qualifiedName
9291
ALTER COLUMN columnName=identifier DROP NOT NULL #dropNotNullConstraint
93-
| ALTER TABLE tableName=qualifiedName SET AUTHORIZATION principal #setTableAuthorization
9492
| ALTER TABLE tableName=qualifiedName
9593
SET PROPERTIES propertyAssignments #setTableProperties
9694
| ALTER TABLE tableName=qualifiedName
9795
EXECUTE procedureName=identifier
9896
('(' (callArgument (',' callArgument)*)? ')')?
9997
(WHERE where=booleanExpression)? #tableExecute
98+
| ALTER ownedEntityKind qualifiedName SET AUTHORIZATION principal #setAuthorization
10099
| ANALYZE qualifiedName (WITH properties)? #analyze
101100
| CREATE (OR REPLACE)? MATERIALIZED VIEW
102101
(IF NOT EXISTS)? qualifiedName
@@ -115,7 +114,6 @@ statement
115114
SET PROPERTIES propertyAssignments #setMaterializedViewProperties
116115
| DROP VIEW (IF EXISTS)? qualifiedName #dropView
117116
| ALTER VIEW from=qualifiedName RENAME TO to=qualifiedName #renameView
118-
| ALTER VIEW from=qualifiedName SET AUTHORIZATION principal #setViewAuthorization
119117
| CALL qualifiedName '(' (callArgument (',' callArgument)*)? ')' #call
120118
| CREATE (OR REPLACE)? functionSpecification #createFunction
121119
| DROP FUNCTION (IF EXISTS)? functionDeclaration #dropFunction
@@ -945,6 +943,10 @@ grantObject
945943
: entityKind? qualifiedName
946944
;
947945

946+
ownedEntityKind
947+
: TABLE | SCHEMA | VIEW | identifier
948+
;
949+
948950
qualifiedName
949951
: identifier ('.' identifier)*
950952
;
Lines changed: 116 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,116 @@
1+
/*
2+
* Licensed under the Apache License, Version 2.0 (the "License");
3+
* you may not use this file except in compliance with the License.
4+
* You may obtain a copy of the License at
5+
*
6+
* http://www.apache.org/licenses/LICENSE-2.0
7+
*
8+
* Unless required by applicable law or agreed to in writing, software
9+
* distributed under the License is distributed on an "AS IS" BASIS,
10+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11+
* See the License for the specific language governing permissions and
12+
* limitations under the License.
13+
*/
14+
package io.trino.execution;
15+
16+
import com.google.common.util.concurrent.ListenableFuture;
17+
import com.google.inject.Inject;
18+
import io.trino.Session;
19+
import io.trino.execution.warnings.WarningCollector;
20+
import io.trino.metadata.Metadata;
21+
import io.trino.metadata.QualifiedObjectName;
22+
import io.trino.metadata.RedirectionAwareTableHandle;
23+
import io.trino.security.AccessControl;
24+
import io.trino.spi.connector.CatalogSchemaName;
25+
import io.trino.spi.connector.EntityKindAndName;
26+
import io.trino.spi.security.TrinoPrincipal;
27+
import io.trino.sql.tree.Expression;
28+
import io.trino.sql.tree.SetAuthorizationStatement;
29+
30+
import java.util.List;
31+
import java.util.Optional;
32+
33+
import static com.google.common.util.concurrent.Futures.immediateVoidFuture;
34+
import static io.trino.metadata.MetadataUtil.checkRoleExists;
35+
import static io.trino.metadata.MetadataUtil.createCatalogSchemaName;
36+
import static io.trino.metadata.MetadataUtil.createPrincipal;
37+
import static io.trino.metadata.MetadataUtil.fillInNameParts;
38+
import static io.trino.metadata.MetadataUtil.getRequiredCatalogHandle;
39+
import static io.trino.spi.StandardErrorCode.NOT_SUPPORTED;
40+
import static io.trino.spi.StandardErrorCode.SCHEMA_NOT_FOUND;
41+
import static io.trino.spi.StandardErrorCode.TABLE_NOT_FOUND;
42+
import static io.trino.sql.analyzer.SemanticExceptions.semanticException;
43+
import static java.util.Objects.requireNonNull;
44+
45+
public class SetAuthorizationTask
46+
implements DataDefinitionTask<SetAuthorizationStatement>
47+
{
48+
private final Metadata metadata;
49+
private final AccessControl accessControl;
50+
51+
@Inject
52+
public SetAuthorizationTask(Metadata metadata, AccessControl accessControl)
53+
{
54+
this.metadata = requireNonNull(metadata, "metadata is null");
55+
this.accessControl = requireNonNull(accessControl, "accessControl is null");
56+
}
57+
58+
@Override
59+
public String getName()
60+
{
61+
return "SET AUTHORIZATION";
62+
}
63+
64+
@Override
65+
public ListenableFuture<Void> execute(
66+
SetAuthorizationStatement statement,
67+
QueryStateMachine stateMachine,
68+
List<Expression> parameters,
69+
WarningCollector warningCollector)
70+
{
71+
Session session = stateMachine.getSession();
72+
setEntityAuthorization(session, statement);
73+
74+
return immediateVoidFuture();
75+
}
76+
77+
private void setEntityAuthorization(Session session, SetAuthorizationStatement statement)
78+
{
79+
List<String> name = fillInNameParts(session, statement, statement.getOwnedEntityKind(), statement.getSource().getParts());
80+
81+
// Preprocess SCHEMA, TABLE and VIEW to generate error messages in the order compatible with existing tests
82+
switch (statement.getOwnedEntityKind()) {
83+
case "SCHEMA" -> {
84+
CatalogSchemaName source = createCatalogSchemaName(session, statement, Optional.of(statement.getSource()));
85+
if (!metadata.schemaExists(session, source)) {
86+
throw semanticException(SCHEMA_NOT_FOUND, statement, "Schema '%s' does not exist", source);
87+
}
88+
}
89+
case "TABLE" -> {
90+
QualifiedObjectName tableName = new QualifiedObjectName(name.get(0), name.get(1), name.get(2));
91+
getRequiredCatalogHandle(metadata, session, statement, name.get(0));
92+
RedirectionAwareTableHandle redirection = metadata.getRedirectionAwareTableHandle(session, tableName);
93+
if (redirection.tableHandle().isEmpty()) {
94+
throw semanticException(TABLE_NOT_FOUND, statement, "Table '%s' does not exist", tableName);
95+
}
96+
if (redirection.redirectedTableName().isPresent()) {
97+
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());
98+
}
99+
}
100+
case "VIEW" -> {
101+
QualifiedObjectName viewName = new QualifiedObjectName(name.get(0), name.get(1), name.get(2));
102+
getRequiredCatalogHandle(metadata, session, statement, viewName.catalogName());
103+
if (!metadata.isView(session, viewName)) {
104+
throw semanticException(TABLE_NOT_FOUND, statement, "View '%s' does not exist", viewName);
105+
}
106+
}
107+
}
108+
109+
TrinoPrincipal principal = createPrincipal(statement.getPrincipal());
110+
Optional<String> maybeCatalogName = name.size() > 1 ? Optional.of(name.get(0)) : Optional.empty();
111+
checkRoleExists(session, statement, metadata, principal, maybeCatalogName.filter(catalog -> metadata.isCatalogManagedSecurity(session, catalog)));
112+
EntityKindAndName entityKindAndName = new EntityKindAndName(statement.getOwnedEntityKind(), name);
113+
accessControl.checkCanSetEntityAuthorization(session.toSecurityContext(), entityKindAndName, principal);
114+
metadata.setEntityAuthorization(session, entityKindAndName, principal);
115+
}
116+
}

core/trino-main/src/main/java/io/trino/execution/SetSchemaAuthorizationTask.java

Lines changed: 0 additions & 80 deletions
This file was deleted.

core/trino-main/src/main/java/io/trino/execution/SetTableAuthorizationTask.java

Lines changed: 0 additions & 88 deletions
This file was deleted.

0 commit comments

Comments
 (0)