diff --git a/docs/src/main/sphinx/security/opa-access-control.md b/docs/src/main/sphinx/security/opa-access-control.md index 6a16bd9b6ba0..6e3125975f19 100644 --- a/docs/src/main/sphinx/security/opa-access-control.md +++ b/docs/src/main/sphinx/security/opa-access-control.md @@ -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 @@ -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" } @@ -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" } @@ -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" } diff --git a/plugin/trino-opa/src/main/java/io/trino/plugin/opa/OpaAccessControl.java b/plugin/trino-opa/src/main/java/io/trino/plugin/opa/OpaAccessControl.java index a0b92afee640..59673e2bcb3e 100644 --- a/plugin/trino-opa/src/main/java/io/trino/plugin/opa/OpaAccessControl.java +++ b/plugin/trino-opa/src/main/java/io/trino/plugin/opa/OpaAccessControl.java @@ -802,11 +802,11 @@ private static Map> convertProperties(Map callable = + OpaAccessControl::checkCanShowCreateTable; + CatalogSchemaTableName tableName = new CatalogSchemaTableName("my_catalog", "my_schema", "my_table"); + + ThrowingMethodWrapper wrappedMethod = new ThrowingMethodWrapper( + 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"); + } }