Skip to content

Commit

Permalink
Add ownership to SystemSecurityMetadata
Browse files Browse the repository at this point in the history
For connectors using system security send ownership calls to
SystemSecurityMetadata
  • Loading branch information
dain committed Nov 16, 2021
1 parent 027a82d commit 44c7be0
Show file tree
Hide file tree
Showing 9 changed files with 210 additions and 23 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
import io.trino.Session;
import io.trino.spi.TrinoException;
import io.trino.spi.connector.CatalogSchemaName;
import io.trino.spi.connector.CatalogSchemaTableName;
import io.trino.spi.security.GrantInfo;
import io.trino.spi.security.Identity;
import io.trino.spi.security.Privilege;
Expand All @@ -28,7 +29,6 @@
import java.util.Set;

import static io.trino.spi.StandardErrorCode.NOT_SUPPORTED;
import static java.lang.String.format;

public class DisabledSystemSecurityMetadata
implements SystemSecurityMetadata
Expand Down Expand Up @@ -100,7 +100,7 @@ public void grantSchemaPrivileges(
Set<Privilege> privileges,
TrinoPrincipal grantee, boolean grantOption)
{
throw new TrinoException(NOT_SUPPORTED, format("Catalog '%s' does not support permission management", schemaName.getCatalogName()));
throw notSupportedException(schemaName.getCatalogName());
}

@Override
Expand All @@ -110,24 +110,59 @@ public void revokeSchemaPrivileges(
Set<Privilege> privileges,
TrinoPrincipal grantee, boolean grantOption)
{
throw new TrinoException(NOT_SUPPORTED, format("Catalog '%s' does not support permission management", schemaName.getCatalogName()));
throw notSupportedException(schemaName.getCatalogName());
}

@Override
public void grantTablePrivileges(Session session, QualifiedObjectName tableName, Set<Privilege> privileges, TrinoPrincipal grantee, boolean grantOption)
{
throw new TrinoException(NOT_SUPPORTED, format("Catalog '%s' does not support permission management", tableName.getCatalogName()));
throw notSupportedException(tableName.getCatalogName());
}

@Override
public void revokeTablePrivileges(Session session, QualifiedObjectName tableName, Set<Privilege> privileges, TrinoPrincipal grantee, boolean grantOption)
{
throw new TrinoException(NOT_SUPPORTED, format("Catalog '%s' does not support permission management", tableName.getCatalogName()));
throw notSupportedException(tableName.getCatalogName());
}

@Override
public Set<GrantInfo> listTablePrivileges(Session session, QualifiedTablePrefix prefix)
{
return ImmutableSet.of();
}

@Override
public Optional<TrinoPrincipal> getSchemaOwner(Session session, CatalogSchemaName schema)
{
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<Identity> getViewRunAsIdentity(Session session, CatalogSchemaTableName view)
{
return Optional.empty();
}

@Override
public void setViewOwner(Session session, CatalogSchemaTableName view, TrinoPrincipal principal)
{
throw notSupportedException(view.getCatalogName());
}

private static TrinoException notSupportedException(String catalogName)
{
return new TrinoException(NOT_SUPPORTED, "Catalog does not support permission management: " + catalogName);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -101,4 +101,18 @@ public String toString()
.add("properties", properties)
.toString();
}

@Override
public MaterializedViewDefinition withOwner(Identity owner)
{
return new MaterializedViewDefinition(
getOriginalSql(),
getCatalog(),
getSchema(),
getColumns(),
getComment(),
owner,
storageTable,
properties);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -805,7 +805,12 @@ public void setSchemaAuthorization(Session session, CatalogSchemaName source, Tr
CatalogMetadata catalogMetadata = getCatalogMetadataForWrite(session, source.getCatalogName());
CatalogName catalogName = catalogMetadata.getCatalogName();
ConnectorMetadata metadata = catalogMetadata.getMetadata();
metadata.setSchemaAuthorization(session.toConnectorSession(catalogName), source.getSchemaName(), principal);
if (catalogMetadata.getSecurityManagement() == SecurityManagement.SYSTEM) {
systemSecurityMetadata.setSchemaOwner(session, source, principal);
}
else {
metadata.setSchemaAuthorization(session.toConnectorSession(catalogName), source.getSchemaName(), principal);
}
}

@Override
Expand Down Expand Up @@ -883,8 +888,14 @@ public void dropColumn(Session session, TableHandle tableHandle, ColumnHandle co
public void setTableAuthorization(Session session, CatalogSchemaTableName table, TrinoPrincipal principal)
{
CatalogName catalogName = new CatalogName(table.getCatalogName());
ConnectorMetadata metadata = getMetadataForWrite(session, catalogName);
metadata.setTableAuthorization(session.toConnectorSession(catalogName), table.getSchemaTableName(), principal);
CatalogMetadata catalogMetadata = getCatalogMetadataForWrite(session, catalogName);
ConnectorMetadata metadata = catalogMetadata.getMetadata();
if (catalogMetadata.getSecurityManagement() == SecurityManagement.SYSTEM) {
systemSecurityMetadata.setTableOwner(session, table, principal);
}
else {
metadata.setTableAuthorization(session.toConnectorSession(catalogName), table.getSchemaTableName(), principal);
}
}

@Override
Expand Down Expand Up @@ -1285,15 +1296,36 @@ public Optional<TrinoPrincipal> getSchemaOwner(Session session, CatalogSchemaNam
throw new TrinoException(SCHEMA_NOT_FOUND, format("Schema '%s' does not exist", schemaName));
}
CatalogMetadata catalogMetadata = getCatalogMetadata(session, new CatalogName(schemaName.getCatalogName()));
if (catalogMetadata.getSecurityManagement() == SecurityManagement.SYSTEM) {
return systemSecurityMetadata.getSchemaOwner(session, schemaName);
}
CatalogName catalogName = catalogMetadata.getConnectorIdForSchema(schemaName);
ConnectorMetadata metadata = catalogMetadata.getMetadataFor(catalogName);

ConnectorSession connectorSession = session.toConnectorSession(catalogName);
return metadata.getSchemaOwner(connectorSession, schemaName);
}

@Override
public boolean isView(Session session, QualifiedObjectName viewName)
{
return getViewInternal(session, viewName).isPresent();
}

@Override
public Optional<ViewDefinition> getView(Session session, QualifiedObjectName viewName)
{
Optional<ViewDefinition> view = getViewInternal(session, viewName);
if (view.isEmpty() || view.get().isRunAsInvoker() || isCatalogManagedSecurity(session, viewName.getCatalogName())) {
return view;
}
Optional<Identity> runAsIdentity = systemSecurityMetadata.getViewRunAsIdentity(session, viewName.asCatalogSchemaTableName());
if (runAsIdentity.isEmpty()) {
return view;
}
return view.map(v -> v.withOwner(runAsIdentity.get()));
}

private Optional<ViewDefinition> getViewInternal(Session session, QualifiedObjectName viewName)
{
if (viewName.getCatalogName().isEmpty() || viewName.getSchemaName().isEmpty() || viewName.getObjectName().isEmpty()) {
// View cannot exist
Expand Down Expand Up @@ -1343,7 +1375,12 @@ public void setViewAuthorization(Session session, CatalogSchemaTableName view, T
CatalogName catalogName = catalogMetadata.getCatalogName();
ConnectorMetadata metadata = catalogMetadata.getMetadata();

metadata.setViewAuthorization(session.toConnectorSession(catalogName), view.getSchemaTableName(), principal);
if (catalogMetadata.getSecurityManagement() == SecurityManagement.SYSTEM) {
systemSecurityMetadata.setViewOwner(session, view, principal);
}
else {
metadata.setViewAuthorization(session.toConnectorSession(catalogName), view.getSchemaTableName(), principal);
}
}

@Override
Expand Down Expand Up @@ -1447,8 +1484,27 @@ public Map<QualifiedObjectName, ViewInfo> getMaterializedViews(Session session,
return ImmutableMap.copyOf(views);
}

@Override
public boolean isMaterializedView(Session session, QualifiedObjectName viewName)
{
return getMaterializedViewInternal(session, viewName).isPresent();
}

@Override
public Optional<MaterializedViewDefinition> getMaterializedView(Session session, QualifiedObjectName viewName)
{
Optional<MaterializedViewDefinition> view = getMaterializedViewInternal(session, viewName);
if (view.isEmpty() || isCatalogManagedSecurity(session, viewName.getCatalogName())) {
return view;
}
Optional<Identity> runAsIdentity = systemSecurityMetadata.getViewRunAsIdentity(session, viewName.asCatalogSchemaTableName());
if (runAsIdentity.isEmpty()) {
return view;
}
return view.map(v -> v.withOwner(runAsIdentity.get()));
}

private Optional<MaterializedViewDefinition> getMaterializedViewInternal(Session session, QualifiedObjectName viewName)
{
if (viewName.getCatalogName().isEmpty() || viewName.getSchemaName().isEmpty() || viewName.getObjectName().isEmpty()) {
// View cannot exist
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@

import io.trino.Session;
import io.trino.spi.connector.CatalogSchemaName;
import io.trino.spi.connector.CatalogSchemaTableName;
import io.trino.spi.security.GrantInfo;
import io.trino.spi.security.Identity;
import io.trino.spi.security.Privilege;
Expand Down Expand Up @@ -108,4 +109,30 @@ public interface SystemSecurityMetadata
* Gets the privileges for the specified table available to the given grantee considering the selected session role
*/
Set<GrantInfo> listTablePrivileges(Session session, QualifiedTablePrefix prefix);

/**
* Set the owner of the specified schema
*/
Optional<TrinoPrincipal> 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
* @return
*/
Optional<Identity> getViewRunAsIdentity(Session session, CatalogSchemaTableName viewName);

/**
* Set the owner of the specified view
*/
void setViewOwner(Session session, CatalogSchemaTableName view, TrinoPrincipal principal);
}
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,11 @@ public Optional<String> getComment()
return comment;
}

public boolean isRunAsInvoker()
{
return runAsIdentity.isEmpty();
}

public Optional<Identity> getRunAsIdentity()
{
return runAsIdentity;
Expand Down Expand Up @@ -126,4 +131,15 @@ public String toString()
.add("runAsIdentity", runAsIdentity.orElse(null))
.toString();
}

public ViewDefinition withOwner(Identity owner)
{
return new ViewDefinition(
originalSql,
catalog,
schema,
columns,
comment,
Optional.of(owner));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -566,7 +566,7 @@ protected Node visitShowCreate(ShowCreate node, Void context)

accessControl.checkCanShowCreateTable(session.toSecurityContext(), new QualifiedObjectName(catalogName.getValue(), schemaName.getValue(), tableName.getValue()));

CreateView.Security security = viewDefinition.get().getRunAsIdentity().isEmpty() ? INVOKER : DEFINER;
CreateView.Security security = viewDefinition.get().isRunAsInvoker() ? INVOKER : DEFINER;
String sql = formatSql(new CreateView(
QualifiedName.of(ImmutableList.of(catalogName, schemaName, tableName)),
query,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
import io.trino.spi.connector.ColumnHandle;
import io.trino.spi.connector.ColumnMetadata;
import io.trino.spi.connector.Connector;
import io.trino.spi.connector.ConnectorAccessControl;
import io.trino.spi.connector.ConnectorInsertTableHandle;
import io.trino.spi.connector.ConnectorMaterializedViewDefinition;
import io.trino.spi.connector.ConnectorMetadata;
Expand Down Expand Up @@ -119,7 +120,7 @@ public class MockConnector
private final BiFunction<ConnectorSession, ConnectorTableHandle, ConnectorTableProperties> getTableProperties;
private final Supplier<Iterable<EventListener>> eventListeners;
private final MockConnectorFactory.ListRoleGrants roleGrants;
private final Optional<MockConnectorAccessControl> accessControl;
private final ConnectorAccessControl accessControl;
private final Function<SchemaTableName, List<List<?>>> data;
private final Set<Procedure> procedures;

Expand All @@ -145,7 +146,7 @@ public class MockConnector
BiFunction<ConnectorSession, ConnectorTableHandle, ConnectorTableProperties> getTableProperties,
Supplier<Iterable<EventListener>> eventListeners,
MockConnectorFactory.ListRoleGrants roleGrants,
Optional<MockConnectorAccessControl> accessControl,
ConnectorAccessControl accessControl,
Function<SchemaTableName, List<List<?>>> data,
Set<Procedure> procedures)
{
Expand Down Expand Up @@ -219,9 +220,9 @@ public Iterable<EventListener> getEventListeners()
}

@Override
public MockConnectorAccessControl getAccessControl()
public ConnectorAccessControl getAccessControl()
{
return accessControl.orElseThrow(() -> new UnsupportedOperationException("Access control for mock connector is not set"));
return accessControl;
}

@Override
Expand Down Expand Up @@ -596,25 +597,30 @@ public Set<String> listEnabledRoles(ConnectorSession session)
@Override
public void grantSchemaPrivileges(ConnectorSession session, String schemaName, Set<Privilege> privileges, TrinoPrincipal grantee, boolean grantOption)
{
getAccessControl().grantSchemaPrivileges(schemaName, privileges, grantee, grantOption);
getMockAccessControl().grantSchemaPrivileges(schemaName, privileges, grantee, grantOption);
}

@Override
public void revokeSchemaPrivileges(ConnectorSession session, String schemaName, Set<Privilege> privileges, TrinoPrincipal revokee, boolean grantOption)
{
getAccessControl().revokeSchemaPrivileges(schemaName, privileges, revokee, grantOption);
getMockAccessControl().revokeSchemaPrivileges(schemaName, privileges, revokee, grantOption);
}

@Override
public void grantTablePrivileges(ConnectorSession session, SchemaTableName tableName, Set<Privilege> privileges, TrinoPrincipal grantee, boolean grantOption)
{
getAccessControl().grantTablePrivileges(tableName, privileges, grantee, grantOption);
getMockAccessControl().grantTablePrivileges(tableName, privileges, grantee, grantOption);
}

@Override
public void revokeTablePrivileges(ConnectorSession session, SchemaTableName tableName, Set<Privilege> privileges, TrinoPrincipal revokee, boolean grantOption)
{
getAccessControl().revokeTablePrivileges(tableName, privileges, revokee, grantOption);
getMockAccessControl().revokeTablePrivileges(tableName, privileges, revokee, grantOption);
}

private MockConnectorAccessControl getMockAccessControl()
{
return (MockConnectorAccessControl) accessControl;
}
}

Expand Down
Loading

0 comments on commit 44c7be0

Please sign in to comment.