Skip to content

Add support for GRANT/DENY/REVOKE on branches #25152

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -948,15 +948,15 @@ sqlStatementList
;

privilege
: CREATE | SELECT | DELETE | INSERT | UPDATE | identifier
: CREATE | SELECT | DELETE | INSERT | UPDATE | identifier | CREATE BRANCH
;

entityKind
: TABLE | SCHEMA | identifier
;

grantObject
: entityKind? qualifiedName
: (BRANCH branch=identifier IN)? entityKind? qualifiedName
;

ownedEntityKind
Expand Down Expand Up @@ -989,7 +989,7 @@ principal
;

privilegeOrRole
: CREATE | SELECT | DELETE | INSERT | UPDATE | identifier
: CREATE | SELECT | DELETE | INSERT | UPDATE | identifier | CREATE BRANCH
;

identifier
Expand Down
22 changes: 18 additions & 4 deletions core/trino-main/src/main/java/io/trino/execution/DenyTask.java
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
import io.trino.spi.security.Privilege;
import io.trino.sql.tree.Deny;
import io.trino.sql.tree.Expression;
import io.trino.sql.tree.Identifier;

import java.util.List;
import java.util.Optional;
Expand Down Expand Up @@ -82,6 +83,10 @@ else if (entityKind.equalsIgnoreCase("SCHEMA")) {

private static void executeDenyOnSchema(Session session, Deny statement, Metadata metadata, AccessControl accessControl)
{
if (statement.getGrantObject().getBranch().isPresent()) {
throw semanticException(NOT_SUPPORTED, statement, "Denying on branch is not supported");
}

CatalogSchemaName schemaName = createCatalogSchemaName(session, statement, Optional.of(statement.getGrantObject().getName()));

if (!metadata.schemaExists(session, schemaName)) {
Expand All @@ -99,6 +104,7 @@ private static void executeDenyOnSchema(Session session, Deny statement, Metadat
private static void executeDenyOnTable(Session session, Deny statement, Metadata metadata, AccessControl accessControl)
{
QualifiedObjectName tableName = createQualifiedObjectName(session, statement, statement.getGrantObject().getName());
Optional<Identifier> branch = statement.getGrantObject().getBranch();

if (!metadata.isMaterializedView(session, tableName) && !metadata.isView(session, tableName)) {
RedirectionAwareTableHandle redirection = metadata.getRedirectionAwareTableHandle(session, tableName);
Expand All @@ -112,15 +118,23 @@ private static void executeDenyOnTable(Session session, Deny statement, Metadata

Set<Privilege> privileges = parseStatementPrivileges(statement, statement.getPrivileges());

for (Privilege privilege : privileges) {
accessControl.checkCanDenyTablePrivilege(session.toSecurityContext(), privilege, tableName, createPrincipal(statement.getGrantee()));
if (branch.isEmpty()) {
privileges.forEach(privilege -> accessControl.checkCanDenyTablePrivilege(session.toSecurityContext(), privilege, tableName, createPrincipal(statement.getGrantee())));
metadata.denyTablePrivileges(session, tableName, privileges, createPrincipal(statement.getGrantee()));
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should go after the loop.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is not inside a loop.

}
else {
String branchName = branch.get().getValue();
privileges.forEach(privilege -> accessControl.checkCanDenyTableBranchPrivilege(session.toSecurityContext(), privilege, tableName, branchName, createPrincipal(statement.getGrantee())));
metadata.denyTableBranchPrivileges(session, tableName, branchName, privileges, createPrincipal(statement.getGrantee()));
}

metadata.denyTablePrivileges(session, tableName, privileges, createPrincipal(statement.getGrantee()));
}

private static void executeDenyOnEntity(Session session, Deny statement, Metadata metadata, String entityKind, AccessControl accessControl)
{
if (statement.getGrantObject().getBranch().isPresent()) {
throw semanticException(NOT_SUPPORTED, statement, "Denying on branch is not supported");
}

EntityKindAndName entity = createEntityKindAndName(entityKind, statement.getGrantObject().getName());
Set<EntityPrivilege> privileges = fetchEntityKindPrivileges(entityKind, metadata, statement.getPrivileges());

Expand Down
22 changes: 18 additions & 4 deletions core/trino-main/src/main/java/io/trino/execution/GrantTask.java
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
import io.trino.spi.security.Privilege;
import io.trino.sql.tree.Expression;
import io.trino.sql.tree.Grant;
import io.trino.sql.tree.Identifier;

import java.util.List;
import java.util.Optional;
Expand Down Expand Up @@ -86,6 +87,10 @@ else if (entityKind.equalsIgnoreCase("SCHEMA")) {

private void executeGrantOnSchema(Session session, Grant statement)
{
if (statement.getGrantObject().getBranch().isPresent()) {
throw semanticException(NOT_SUPPORTED, statement, "Granting on branch is not supported");
}

CatalogSchemaName schemaName = createCatalogSchemaName(session, statement, Optional.of(statement.getGrantObject().getName()));

if (!metadata.schemaExists(session, schemaName)) {
Expand All @@ -103,6 +108,7 @@ private void executeGrantOnSchema(Session session, Grant statement)
private void executeGrantOnTable(Session session, Grant statement)
{
QualifiedObjectName tableName = createQualifiedObjectName(session, statement, statement.getGrantObject().getName());
Optional<Identifier> branch = statement.getGrantObject().getBranch();

if (!metadata.isMaterializedView(session, tableName) && !metadata.isView(session, tableName)) {
RedirectionAwareTableHandle redirection = metadata.getRedirectionAwareTableHandle(session, tableName);
Expand All @@ -116,15 +122,23 @@ private void executeGrantOnTable(Session session, Grant statement)

Set<Privilege> privileges = parseStatementPrivileges(statement, statement.getPrivileges());

for (Privilege privilege : privileges) {
accessControl.checkCanGrantTablePrivilege(session.toSecurityContext(), privilege, tableName, createPrincipal(statement.getGrantee()), statement.isWithGrantOption());
if (branch.isEmpty()) {
privileges.forEach(privilege -> accessControl.checkCanGrantTablePrivilege(session.toSecurityContext(), privilege, tableName, createPrincipal(statement.getGrantee()), statement.isWithGrantOption()));
metadata.grantTablePrivileges(session, tableName, privileges, createPrincipal(statement.getGrantee()), statement.isWithGrantOption());
}
else {
String branchName = branch.get().getValue();
privileges.forEach(privilege -> accessControl.checkCanGrantTableBranchPrivilege(session.toSecurityContext(), privilege, tableName, branchName, createPrincipal(statement.getGrantee()), statement.isWithGrantOption()));
metadata.grantTableBranchPrivileges(session, tableName, branchName, privileges, createPrincipal(statement.getGrantee()), statement.isWithGrantOption());
}

metadata.grantTablePrivileges(session, tableName, privileges, createPrincipal(statement.getGrantee()), statement.isWithGrantOption());
}

private void executeGrantOnEntity(Session session, String entityKind, Metadata metadata, Grant statement)
{
if (statement.getGrantObject().getBranch().isPresent()) {
throw semanticException(NOT_SUPPORTED, statement, "Granting on branch is not supported");
}

EntityKindAndName entity = createEntityKindAndName(entityKind, statement.getGrantObject().getName());
Set<EntityPrivilege> privileges = fetchEntityKindPrivileges(entityKind, metadata, statement.getPrivileges());

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ public static Set<EntityPrivilege> fetchEntityKindPrivileges(String entityKind,
private static Privilege parsePrivilege(Node statement, String privilegeString)
{
for (Privilege privilege : Privilege.values()) {
if (privilege.name().equalsIgnoreCase(privilegeString)) {
if (privilege.toString().equalsIgnoreCase(privilegeString)) {
return privilege;
}
}
Expand Down
22 changes: 18 additions & 4 deletions core/trino-main/src/main/java/io/trino/execution/RevokeTask.java
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
import io.trino.spi.connector.EntityPrivilege;
import io.trino.spi.security.Privilege;
import io.trino.sql.tree.Expression;
import io.trino.sql.tree.Identifier;
import io.trino.sql.tree.Revoke;

import java.util.List;
Expand Down Expand Up @@ -87,6 +88,10 @@ else if (entityKind.equalsIgnoreCase("SCHEMA")) {

private void executeRevokeOnSchema(Session session, Revoke statement)
{
if (statement.getGrantObject().getBranch().isPresent()) {
throw semanticException(NOT_SUPPORTED, statement, "Revoking on branch is not supported");
}

CatalogSchemaName schemaName = createCatalogSchemaName(session, statement, Optional.of(statement.getGrantObject().getName()));

if (!metadata.schemaExists(session, schemaName)) {
Expand All @@ -104,6 +109,7 @@ private void executeRevokeOnSchema(Session session, Revoke statement)
private void executeRevokeOnTable(Session session, Revoke statement)
{
QualifiedObjectName tableName = createQualifiedObjectName(session, statement, statement.getGrantObject().getName());
Optional<Identifier> branch = statement.getGrantObject().getBranch();

if (!metadata.isMaterializedView(session, tableName) && !metadata.isView(session, tableName)) {
RedirectionAwareTableHandle redirection = metadata.getRedirectionAwareTableHandle(session, tableName);
Expand All @@ -116,15 +122,23 @@ private void executeRevokeOnTable(Session session, Revoke statement)
}

Set<Privilege> privileges = parseStatementPrivileges(statement, statement.getPrivileges());
for (Privilege privilege : privileges) {
accessControl.checkCanRevokeTablePrivilege(session.toSecurityContext(), privilege, tableName, createPrincipal(statement.getGrantee()), statement.isGrantOptionFor());
if (branch.isEmpty()) {
privileges.forEach(privilege -> accessControl.checkCanRevokeTablePrivilege(session.toSecurityContext(), privilege, tableName, createPrincipal(statement.getGrantee()), statement.isGrantOptionFor()));
metadata.revokeTablePrivileges(session, tableName, privileges, createPrincipal(statement.getGrantee()), statement.isGrantOptionFor());
}
else {
String branchName = branch.get().getValue();
privileges.forEach(privilege -> accessControl.checkCanRevokeTableBranchPrivilege(session.toSecurityContext(), privilege, tableName, branchName, createPrincipal(statement.getGrantee()), statement.isGrantOptionFor()));
metadata.revokeTableBranchPrivileges(session, tableName, branchName, privileges, createPrincipal(statement.getGrantee()), statement.isGrantOptionFor());
}

metadata.revokeTablePrivileges(session, tableName, privileges, createPrincipal(statement.getGrantee()), statement.isGrantOptionFor());
}

private void executeRevokeOnEntity(Session session, String entityKind, Metadata metadata, Revoke statement)
{
if (statement.getGrantObject().getBranch().isPresent()) {
throw semanticException(NOT_SUPPORTED, statement, "Revoking on branch is not supported");
}

EntityKindAndName entity = createEntityKindAndName(entityKind, statement.getGrantObject().getName());
Set<EntityPrivilege> privileges = fetchEntityKindPrivileges(entityKind, metadata, statement.getPrivileges());

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,24 @@ public Set<GrantInfo> listTablePrivileges(Session session, QualifiedTablePrefix
return ImmutableSet.of();
}

@Override
public void grantTableBranchPrivileges(Session session, QualifiedObjectName tableName, String branchName, Set<Privilege> privileges, TrinoPrincipal grantee, boolean grantOption)
{
throw notSupportedException(tableName.catalogName());
}

@Override
public void denyTableBranchPrivileges(Session session, QualifiedObjectName tableName, String branchName, Set<Privilege> privileges, TrinoPrincipal grantee)
{
throw notSupportedException(tableName.catalogName());
}

@Override
public void revokeTableBranchPrivileges(Session session, QualifiedObjectName tableName, String branchName, Set<Privilege> privileges, TrinoPrincipal grantee, boolean grantOption)
{
throw notSupportedException(tableName.catalogName());
}

@Override
public void grantEntityPrivileges(Session session, EntityKindAndName entity, Set<EntityPrivilege> privileges, TrinoPrincipal grantee, boolean grantOption)
{
Expand Down
15 changes: 15 additions & 0 deletions core/trino-main/src/main/java/io/trino/metadata/Metadata.java
Original file line number Diff line number Diff line change
Expand Up @@ -674,6 +674,21 @@ default void validateScan(Session session, TableHandle table) {}
*/
List<GrantInfo> listTablePrivileges(Session session, QualifiedTablePrefix prefix);

/**
* Grants the specified privilege to the specified user on the specified branch
*/
void grantTableBranchPrivileges(Session session, QualifiedObjectName tableName, String branchName, Set<Privilege> privileges, TrinoPrincipal grantee, boolean grantOption);

/**
* Deny the specified privilege to the specified principal on the specified branch
*/
void denyTableBranchPrivileges(Session session, QualifiedObjectName tableName, String branchName, Set<Privilege> privileges, TrinoPrincipal grantee);

/**
* Revokes the specified privilege on the specified branch from the specified user.
*/
void revokeTableBranchPrivileges(Session session, QualifiedObjectName tableName, String branchName, Set<Privilege> privileges, TrinoPrincipal grantee, boolean grantOption);

/**
* Gets all the EntityPrivileges associated with an entityKind. Defines ALL PRIVILEGES
* for the entityKind
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2365,6 +2365,48 @@ public void revokeTablePrivileges(Session session, QualifiedObjectName tableName
metadata.revokeTablePrivileges(session.toConnectorSession(catalogHandle), tableName.asSchemaTableName(), privileges, grantee, grantOption);
}

@Override
public void grantTableBranchPrivileges(Session session, QualifiedObjectName tableName, String branchName, Set<Privilege> privileges, TrinoPrincipal grantee, boolean grantOption)
{
CatalogMetadata catalogMetadata = getCatalogMetadataForWrite(session, tableName.catalogName());
if (catalogMetadata.getSecurityManagement() == SYSTEM) {
systemSecurityMetadata.grantTableBranchPrivileges(session, tableName, branchName, privileges, grantee, grantOption);
return;
}
CatalogHandle catalogHandle = catalogMetadata.getCatalogHandle();
ConnectorMetadata metadata = catalogMetadata.getMetadata(session);

metadata.grantTableBranchPrivileges(session.toConnectorSession(catalogHandle), tableName.asSchemaTableName(), branchName, privileges, grantee, grantOption);
}

@Override
public void denyTableBranchPrivileges(Session session, QualifiedObjectName tableName, String branchName, Set<Privilege> privileges, TrinoPrincipal grantee)
{
CatalogMetadata catalogMetadata = getCatalogMetadataForWrite(session, tableName.catalogName());
if (catalogMetadata.getSecurityManagement() == SYSTEM) {
systemSecurityMetadata.denyTableBranchPrivileges(session, tableName, branchName, privileges, grantee);
return;
}
CatalogHandle catalogHandle = catalogMetadata.getCatalogHandle();
ConnectorMetadata metadata = catalogMetadata.getMetadata(session);

metadata.denyTableBranchPrivileges(session.toConnectorSession(catalogHandle), tableName.asSchemaTableName(), branchName, privileges, grantee);
}

@Override
public void revokeTableBranchPrivileges(Session session, QualifiedObjectName tableName, String branchName, Set<Privilege> privileges, TrinoPrincipal grantee, boolean grantOption)
{
CatalogMetadata catalogMetadata = getCatalogMetadataForWrite(session, tableName.catalogName());
if (catalogMetadata.getSecurityManagement() == SYSTEM) {
systemSecurityMetadata.revokeTableBranchPrivileges(session, tableName, branchName, privileges, grantee, grantOption);
return;
}
CatalogHandle catalogHandle = catalogMetadata.getCatalogHandle();
ConnectorMetadata metadata = catalogMetadata.getMetadata(session);

metadata.revokeTableBranchPrivileges(session.toConnectorSession(catalogHandle), tableName.asSchemaTableName(), branchName, privileges, grantee, grantOption);
}

@Override
public void grantSchemaPrivileges(Session session, CatalogSchemaName schemaName, Set<Privilege> privileges, TrinoPrincipal grantee, boolean grantOption)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,21 @@ public interface SystemSecurityMetadata
*/
Set<GrantInfo> listTablePrivileges(Session session, QualifiedTablePrefix prefix);

/**
* Grants the specified privilege to the specified user on the specified branch
*/
void grantTableBranchPrivileges(Session session, QualifiedObjectName tableName, String branchName, Set<Privilege> privileges, TrinoPrincipal grantee, boolean grantOption);

/**
* Denys the specified privilege to the specified user on the specified branch
*/
void denyTableBranchPrivileges(Session session, QualifiedObjectName tableName, String branchName, Set<Privilege> privileges, TrinoPrincipal grantee);

/**
* Revokes the specified privilege on the specified branch from the specified user
*/
void revokeTableBranchPrivileges(Session session, QualifiedObjectName tableName, String branchName, Set<Privilege> privileges, TrinoPrincipal grantee, boolean grantOption);

default Set<EntityPrivilege> getAllEntityKindPrivileges(String entityKind)
{
throw new UnsupportedOperationException();
Expand Down
21 changes: 21 additions & 0 deletions core/trino-main/src/main/java/io/trino/security/AccessControl.java
Original file line number Diff line number Diff line change
Expand Up @@ -413,6 +413,27 @@ public interface AccessControl
*/
void checkCanRevokeTablePrivilege(SecurityContext context, Privilege privilege, QualifiedObjectName tableName, TrinoPrincipal revokee, boolean grantOption);

/**
* Check if identity is allowed to grant a privilege to the grantee on the specified branch.
*
* @throws AccessDeniedException if not allowed
*/
void checkCanGrantTableBranchPrivilege(SecurityContext context, Privilege privilege, QualifiedObjectName tableName, String branchName, TrinoPrincipal grantee, boolean grantOption);

/**
* Check if identity is allowed to deny a privilege to the grantee on the specified branch.
*
* @throws AccessDeniedException if not allowed
*/
void checkCanDenyTableBranchPrivilege(SecurityContext context, Privilege privilege, QualifiedObjectName tableName, String branchName, TrinoPrincipal grantee);

/**
* Check if identity is allowed to revoke a privilege from the revokee on the specified branch.
*
* @throws AccessDeniedException if not allowed
*/
void checkCanRevokeTableBranchPrivilege(SecurityContext context, Privilege privilege, QualifiedObjectName tableName, String branchName, TrinoPrincipal revokee, boolean grantOption);

/**
* Check if identity is allowed to grant the specified privilege to the grantee on the specified entity.
*
Expand Down
Loading