Skip to content
Closed
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
6 changes: 5 additions & 1 deletion docs/src/main/sphinx/security/opa-access-control.md
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,7 @@ The `context` object contains all other contextual information about the query:
following two fields:
- `user`: username
- `groups`: list of groups this user belongs to
- `queryId`: query_id
- `softwareStack`: Information about the software stack issuing the request to
OPA. The following information is included:
- `trinoVersion`: Version of Trino used
Expand Down Expand Up @@ -157,7 +158,8 @@ Accessing a table results in a query similar to the following example:
"identity": {
"user": "foo",
"groups": ["some-group"]
},
},
"queryId": "20250718_081710_03427_trino",
"softwareStack": {
"trinoVersion": "434"
}
Expand Down Expand Up @@ -190,6 +192,7 @@ The `targetResource` is used in cases where a new resource, distinct from the on
"user": "foo",
"groups": ["some-group"]
},
"queryId": "20250718_081710_03427_trino",
"softwareStack": {
"trinoVersion": "434"
}
Expand Down Expand Up @@ -373,6 +376,7 @@ A batch column masking request is similar to the following example:
"user": "foo",
"groups": ["some-group"]
},
"queryId": "20250718_081710_03427_trino",
"softwareStack": {
"trinoVersion": "434"
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -802,11 +802,11 @@ private static Map<String, Optional<Object>> convertProperties(Map<String, Objec

OpaQueryContext buildQueryContext(Identity trinoIdentity)
{
return new OpaQueryContext(TrinoIdentity.fromTrinoIdentity(trinoIdentity), pluginContext);
return new OpaQueryContext(TrinoIdentity.fromTrinoIdentity(trinoIdentity), pluginContext, null);
}

OpaQueryContext buildQueryContext(SystemSecurityContext securityContext)
{
return new OpaQueryContext(TrinoIdentity.fromTrinoIdentity(securityContext.getIdentity()), pluginContext);
return new OpaQueryContext(TrinoIdentity.fromTrinoIdentity(securityContext.getIdentity()), pluginContext, securityContext.getQueryId().toString());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@

import static java.util.Objects.requireNonNull;

public record OpaQueryContext(TrinoIdentity identity, OpaPluginContext softwareStack)
public record OpaQueryContext(TrinoIdentity identity, OpaPluginContext softwareStack, String queryId)
Comment thread
ebyhr marked this conversation as resolved.
{
public OpaQueryContext
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
import io.trino.plugin.opa.HttpClientUtils.InstrumentedHttpClient;
import io.trino.plugin.opa.HttpClientUtils.MockResponse;
import io.trino.plugin.opa.schema.OpaViewExpression;
import io.trino.spi.QueryId;
import io.trino.spi.connector.CatalogSchemaName;
import io.trino.spi.connector.CatalogSchemaRoutineName;
import io.trino.spi.connector.CatalogSchemaTableName;
Expand All @@ -37,6 +38,7 @@
import io.trino.spi.type.VarcharType;
import org.junit.jupiter.api.Test;

import java.time.Instant;
import java.util.List;
import java.util.Map;
import java.util.Optional;
Expand Down Expand Up @@ -1015,4 +1017,58 @@ private static void assertAccessControlMethodBehaviour(MethodWrapper method, Set
assertStringRequestsEqual(expectedRequests, permissiveMockClient.getRequests(), "/input/action");
assertAccessControlMethodThrowsForIllegalResponses(method::isAccessAllowed, simpleOpaConfig(), OPA_SERVER_URI);
}

@Test
public void testQueryIdInSystemSecurityContextRequests()
{

String customQueryId = "20250718_081710_03427_trino";

SystemSecurityContext customSecurityContext = new SystemSecurityContext(
TEST_IDENTITY,
new QueryId("20250718_081710_03427_trino"),
Instant.now()
);
Comment thread
harshit2283 marked this conversation as resolved.

FunctionalHelpers.Consumer3<OpaAccessControl, SystemSecurityContext, CatalogSchemaTableName> callable =
OpaAccessControl::checkCanShowCreateTable;
CatalogSchemaTableName tableName = new CatalogSchemaTableName("my_catalog", "my_schema", "my_table");

ThrowingMethodWrapper wrappedMethod = new ThrowingMethodWrapper(
Comment thread
harshit2283 marked this conversation as resolved.
accessControl -> callable.accept(accessControl, customSecurityContext, tableName));

String expectedActionRequest =
"""
{
"operation": "ShowCreateTable",
"resource": {
"table": {
"catalogName": "%s",
"schemaName": "%s",
"tableName": "%s"
}
}
}
""".formatted(
tableName.getCatalogName(),
tableName.getSchemaTableName().getSchemaName(),
tableName.getSchemaTableName().getTableName());

InstrumentedHttpClient mockClient = createMockHttpClient(
OPA_SERVER_URI,
(request) -> {
JsonNode contextNode = request.path("input").path("context");

assertThat(contextNode.path("queryId").asText()).isEqualTo(customQueryId);
assertThat(contextNode.path("identity").path("user").asText()).isEqualTo(TEST_IDENTITY.getUser());
assertThat(contextNode.path("softwareStack").path("trinoVersion").asText()).isEqualTo("trino-version");

return OK_RESPONSE;
});

OpaAccessControl authorizer = createOpaAuthorizer(simpleOpaConfig(), mockClient);

assertThat(wrappedMethod.isAccessAllowed(authorizer)).isTrue();
assertStringRequestsEqual(ImmutableSet.of(expectedActionRequest), mockClient.getRequests(), "/input/action");
}
}
Loading