Skip to content

Commit 305bc9d

Browse files
committed
Send view security on view creation to OPA authorizer
1 parent 674d482 commit 305bc9d

File tree

3 files changed

+53
-13
lines changed

3 files changed

+53
-13
lines changed

plugin/trino-opa/src/main/java/io/trino/plugin/opa/OpaAccessControl.java

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -468,7 +468,7 @@ public void checkCanUpdateTableColumns(SystemSecurityContext securityContext, Ca
468468
@Override
469469
public void checkCanCreateView(SystemSecurityContext context, CatalogSchemaTableName view, Optional<ViewSecurity> security)
470470
{
471-
checkTableOperation(context, "CreateView", view, AccessDeniedException::denyCreateView);
471+
checkViewOperation(context, "CreateView", view, security, AccessDeniedException::denyCreateView);
472472
}
473473

474474
@Override
@@ -780,6 +780,17 @@ private void checkTableAndColumnsOperation(SystemSecurityContext context, String
780780
OpaQueryInputResource.builder().table(new TrinoTable(table).withColumns(columns)).build());
781781
}
782782

783+
private void checkViewOperation(SystemSecurityContext context, String actionName, CatalogSchemaTableName view, Optional<ViewSecurity> security, Consumer<String> deny)
784+
{
785+
OpaQueryInputResource.Builder opaQueryInputResourceBuilder = OpaQueryInputResource.builder().table(new TrinoTable(view));
786+
security.ifPresent(opaQueryInputResourceBuilder::security);
787+
opaHighLevelClient.queryAndEnforce(
788+
buildQueryContext(context),
789+
actionName,
790+
() -> deny.accept(view.toString()),
791+
opaQueryInputResourceBuilder.build());
792+
}
793+
783794
private <T> void enforcePermissionManagementOperation(Consumer<T> deny, T arg)
784795
{
785796
if (!allowPermissionManagementOperations) {

plugin/trino-opa/src/main/java/io/trino/plugin/opa/schema/OpaQueryInputResource.java

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
package io.trino.plugin.opa.schema;
1515

1616
import com.fasterxml.jackson.annotation.JsonInclude;
17+
import io.trino.spi.security.ViewSecurity;
1718

1819
import static com.fasterxml.jackson.annotation.JsonInclude.Include.NON_NULL;
1920
import static java.util.Objects.requireNonNull;
@@ -27,7 +28,8 @@ public record OpaQueryInputResource(
2728
NamedEntity catalog,
2829
TrinoSchema schema,
2930
TrinoTable table,
30-
TrinoColumn column)
31+
TrinoColumn column,
32+
ViewSecurity security)
3133
{
3234
public record NamedEntity(String name)
3335
{
@@ -52,6 +54,7 @@ public static class Builder
5254
private TrinoTable table;
5355
private TrinoFunction function;
5456
private TrinoColumn column;
57+
private ViewSecurity security;
5558

5659
private Builder() {}
5760

@@ -109,6 +112,12 @@ public Builder column(TrinoColumn column)
109112
return this;
110113
}
111114

115+
public Builder security(ViewSecurity security)
116+
{
117+
this.security = security;
118+
return this;
119+
}
120+
112121
public OpaQueryInputResource build()
113122
{
114123
return new OpaQueryInputResource(
@@ -119,7 +128,8 @@ public OpaQueryInputResource build()
119128
this.catalog,
120129
this.schema,
121130
this.table,
122-
this.column);
131+
this.column,
132+
this.security);
123133
}
124134
}
125135
}

plugin/trino-opa/src/test/java/io/trino/plugin/opa/TestOpaAccessControl.java

Lines changed: 29 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -211,36 +211,55 @@ private void testTableWithPropertiesActions(
211211
}
212212

213213
@Test
214-
public void testViewResourceActions()
214+
public void testCreateViewWithoutSecurity()
215215
{
216-
testViewResourceActions("CreateView", OpaAccessControl::checkCanCreateView);
216+
CatalogSchemaTableName viewName = new CatalogSchemaTableName("my_catalog", "my_schema", "my_view");
217+
ThrowingMethodWrapper wrappedMethod = new ThrowingMethodWrapper(
218+
accessControl -> accessControl.checkCanCreateView(TEST_SECURITY_CONTEXT, viewName, Optional.empty()));
219+
String expectedRequest =
220+
"""
221+
{
222+
"operation": "CreateView",
223+
"resource": {
224+
"table": {
225+
"catalogName": "%s",
226+
"schemaName": "%s",
227+
"tableName": "%s"
228+
}
229+
}
230+
}
231+
""".formatted(
232+
viewName.getCatalogName(),
233+
viewName.getSchemaTableName().getSchemaName(),
234+
viewName.getSchemaTableName().getTableName());
235+
assertAccessControlMethodBehaviour(wrappedMethod, ImmutableSet.of(expectedRequest));
217236
}
218237

219-
private void testViewResourceActions(
220-
String actionName,
221-
FunctionalHelpers.Consumer4<OpaAccessControl, SystemSecurityContext, CatalogSchemaTableName, Optional<ViewSecurity>> callable)
238+
@Test
239+
public void testCreateViewWithInvokerSecurity()
222240
{
223241
CatalogSchemaTableName viewName = new CatalogSchemaTableName("my_catalog", "my_schema", "my_view");
224242
Optional<ViewSecurity> security = Optional.of(ViewSecurity.INVOKER);
225243
ThrowingMethodWrapper wrappedMethod = new ThrowingMethodWrapper(
226-
accessControl -> callable.accept(accessControl, TEST_SECURITY_CONTEXT, viewName, security));
244+
accessControl -> accessControl.checkCanCreateView(TEST_SECURITY_CONTEXT, viewName, security));
227245
String expectedRequest =
228246
"""
229247
{
230-
"operation": "%s",
248+
"operation": "CreateView",
231249
"resource": {
232250
"table": {
233251
"catalogName": "%s",
234252
"schemaName": "%s",
235253
"tableName": "%s"
236-
}
254+
},
255+
"security": "%s"
237256
}
238257
}
239258
""".formatted(
240-
actionName,
241259
viewName.getCatalogName(),
242260
viewName.getSchemaTableName().getSchemaName(),
243-
viewName.getSchemaTableName().getTableName());
261+
viewName.getSchemaTableName().getTableName(),
262+
security.get());
244263
assertAccessControlMethodBehaviour(wrappedMethod, ImmutableSet.of(expectedRequest));
245264
}
246265

0 commit comments

Comments
 (0)