Skip to content
Merged
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 @@ -2279,7 +2279,7 @@ private void analyzeFiltersAndMasks(Table table, QualifiedObjectName name, Relat
private void analyzeCheckConstraints(Table table, QualifiedObjectName name, Scope accessControlScope, List<String> constraints)
{
for (String constraint : constraints) {
ViewExpression expression = new ViewExpression(session.getIdentity().getUser(), Optional.of(name.getCatalogName()), Optional.of(name.getSchemaName()), constraint);
ViewExpression expression = new ViewExpression(Optional.empty(), Optional.of(name.getCatalogName()), Optional.of(name.getSchemaName()), constraint);
Comment thread
kokosing marked this conversation as resolved.
Outdated
analyzeCheckConstraint(table, name, accessControlScope, expression);
}
}
Expand Down Expand Up @@ -4663,9 +4663,11 @@ private void analyzeRowFilter(String currentIdentity, Table table, QualifiedObje

ExpressionAnalysis expressionAnalysis;
try {
Identity filterIdentity = Identity.forUser(filter.getIdentity())
.withGroups(groupProvider.getGroups(filter.getIdentity()))
.build();
Identity filterIdentity = filter.getSecurityIdentity()
.map(filterUser -> Identity.forUser(filterUser)
.withGroups(groupProvider.getGroups(filterUser))
.build())
.orElseGet(session::getIdentity);
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Can there be any difference between cases

  • when ViewExpression has empty identity
  • when ViewExpression has identity equal to current session user?

is it worth having a code comment why we don't check equality between them?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

FWIW I tried to make it so that when the expression's identity is the same as the session's user then the latter is re-used, and it was vetoed. But I think making it explicit that it should be reused is a better way to go.

Also, extending the view analogy, with views we do have special handling if the current session's user is the same as the view's owner (some restrictions are relaxed then). So there may be a difference between these two, but I don't think there would be any meaningful difference in semantics.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

I tried to make it so that when the expression's identity is the same as the session's user then the latter is re-used, and it was vetoed. But I think making it explicit that it should be reused is a better way to go.

We used have that for views and it was also causing issues. When session had limited set of roles, so they couldn't select the view because view wanted more roles. It got removed. So now in views the there is no custom logic for when view owner is the same as same user. "Impersonation" works the same way for any user now for views.

This commit is going to make something similar for filters and masks.

Can there be any difference between cases

  • when ViewExpression has empty identity
  • when ViewExpression has identity equal to current session user?

Yes. The former will impersonate the user to itself, and so the information about roles could change.

expressionAnalysis = ExpressionAnalyzer.analyzeExpression(
createViewSession(filter.getCatalog(), filter.getSchema(), filterIdentity, session.getPath()), // TODO: path should be included in row filter
plannerContext,
Expand Down Expand Up @@ -4714,11 +4716,13 @@ private void analyzeCheckConstraint(Table table, QualifiedObjectName name, Scope

ExpressionAnalysis expressionAnalysis;
try {
Identity filterIdentity = Identity.forUser(constraint.getIdentity())
.withGroups(groupProvider.getGroups(constraint.getIdentity()))
.build();
Identity constraintIdentity = constraint.getSecurityIdentity()
.map(user -> Identity.forUser(user)
.withGroups(groupProvider.getGroups(user))
.build())
.orElseGet(session::getIdentity);
expressionAnalysis = ExpressionAnalyzer.analyzeExpression(
createViewSession(constraint.getCatalog(), constraint.getSchema(), filterIdentity, session.getPath()),
createViewSession(constraint.getCatalog(), constraint.getSchema(), constraintIdentity, session.getPath()),
plannerContext,
statementAnalyzerFactory,
accessControl,
Expand Down Expand Up @@ -4777,9 +4781,11 @@ private void analyzeColumnMask(String currentIdentity, Table table, QualifiedObj
verifyNoAggregateWindowOrGroupingFunctions(session, metadata, expression, format("Column mask for '%s.%s'", table.getName(), column));

try {
Identity maskIdentity = Identity.forUser(mask.getIdentity())
.withGroups(groupProvider.getGroups(mask.getIdentity()))
.build();
Identity maskIdentity = mask.getSecurityIdentity()
.map(maskUser -> Identity.forUser(maskUser)
.withGroups(groupProvider.getGroups(maskUser))
.build())
.orElseGet(session::getIdentity);
expressionAnalysis = ExpressionAnalyzer.analyzeExpression(
createViewSession(mask.getCatalog(), mask.getSchema(), maskIdentity, session.getPath()), // TODO: path should be included in row filter
plannerContext,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -839,70 +839,22 @@ public String toString()
}
}

private static class RowFilterKey
private record RowFilterKey(String identity, QualifiedObjectName table)
{
private final String identity;
private final QualifiedObjectName table;

public RowFilterKey(String identity, QualifiedObjectName table)
{
this.identity = requireNonNull(identity, "identity is null");
this.table = requireNonNull(table, "table is null");
}

@Override
public boolean equals(Object o)
{
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
RowFilterKey that = (RowFilterKey) o;
return identity.equals(that.identity) &&
table.equals(that.table);
}

@Override
public int hashCode()
private RowFilterKey
{
return Objects.hash(identity, table);
requireNonNull(identity, "identity is null");
requireNonNull(table, "table is null");
}
}

private static class ColumnMaskKey
private record ColumnMaskKey(String identity, QualifiedObjectName table, String column)
{
private final String identity;
private final QualifiedObjectName table;
private final String column;

public ColumnMaskKey(String identity, QualifiedObjectName table, String column)
{
this.identity = identity;
this.table = table;
this.column = column;
}

@Override
public boolean equals(Object o)
{
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
ColumnMaskKey that = (ColumnMaskKey) o;
return identity.equals(that.identity) &&
table.equals(that.table) &&
column.equals(that.column);
}

@Override
public int hashCode()
private ColumnMaskKey
{
return Objects.hash(identity, table, column);
requireNonNull(identity, "identity is null");
requireNonNull(table, "table is null");
requireNonNull(column, "column is null");
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -231,7 +231,7 @@ public SystemAccessControl create(Map<String, String> config)
@Override
public List<ViewExpression> getColumnMasks(SystemSecurityContext context, CatalogSchemaTableName tableName, String column, Type type)
{
return ImmutableList.of(new ViewExpression("user", Optional.empty(), Optional.empty(), "system mask"));
return ImmutableList.of(new ViewExpression(Optional.of("user"), Optional.empty(), Optional.empty(), "system mask"));
}

@Override
Expand All @@ -249,7 +249,7 @@ public void checkCanSetSystemSessionProperty(SystemSecurityContext context, Stri
@Override
public List<ViewExpression> getColumnMasks(ConnectorSecurityContext context, SchemaTableName tableName, String column, Type type)
{
return ImmutableList.of(new ViewExpression("user", Optional.empty(), Optional.empty(), "connector mask"));
return ImmutableList.of(new ViewExpression(Optional.of("user"), Optional.empty(), Optional.empty(), "connector mask"));
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -236,7 +236,7 @@ public void testMaterializedViewWithCasts()
new QualifiedObjectName(TEST_CATALOG_NAME, SCHEMA, "materialized_view_with_casts"),
"a",
"user",
new ViewExpression("user", Optional.empty(), Optional.empty(), "a + 1"));
new ViewExpression(Optional.empty(), Optional.empty(), Optional.empty(), "a + 1"));
assertPlan("SELECT * FROM materialized_view_with_casts",
anyTree(
project(
Expand Down
Loading