-
Notifications
You must be signed in to change notification settings - Fork 3.6k
Add more tests for column masking #10437
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -180,7 +180,7 @@ public void testSimpleMask() | |
| } | ||
|
|
||
| @Test | ||
| public void testMultipleMasksOnSameColumn() | ||
| public void testMultipleMasksOnDifferentColumns() | ||
| { | ||
| accessControl.reset(); | ||
| accessControl.columnMask( | ||
|
|
@@ -191,31 +191,134 @@ public void testMultipleMasksOnSameColumn() | |
|
|
||
| accessControl.columnMask( | ||
| new QualifiedObjectName(CATALOG, "tiny", "orders"), | ||
| "custkey", | ||
| "orderstatus", | ||
| USER, | ||
| new ViewExpression(USER, Optional.empty(), Optional.empty(), "custkey * 2")); | ||
| new ViewExpression(USER, Optional.empty(), Optional.empty(), "'X'")); | ||
|
|
||
| assertThat(assertions.query("SELECT custkey FROM orders WHERE orderkey = 1")).matches("VALUES BIGINT '-740'"); | ||
| assertThat(assertions.query("SELECT custkey, orderstatus FROM orders WHERE orderkey = 1")) | ||
| .matches("VALUES (BIGINT '-370', 'X')"); | ||
| } | ||
|
|
||
| @Test | ||
| public void testMultipleMasksOnDifferentColumns() | ||
| public void testMultipleMasksUsingOtherMaskedColumns() | ||
| { | ||
| String query = "SELECT comment, orderstatus, clerk FROM orders WHERE orderkey = 1"; | ||
| String expected = "VALUES (CAST('nstructions sleep furiously among ' as varchar(79)), 'O', 'Clerk#000000951')"; | ||
|
|
||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. it would be worth for the readability of the test scenario to perform the query without any column masking |
||
| accessControl.reset(); | ||
| assertThat(assertions.query(query)).matches(expected); | ||
|
|
||
| // mask "clerk" and "orderstatus" using "comment" ("comment" appears after both in table definition) | ||
| // columns will not be masked since rules are not apply to row values | ||
| accessControl.reset(); | ||
| accessControl.columnMask( | ||
| new QualifiedObjectName(CATALOG, "tiny", "orders"), | ||
| "custkey", | ||
| "comment", | ||
| USER, | ||
| new ViewExpression(USER, Optional.empty(), Optional.empty(), "-custkey")); | ||
| new ViewExpression(USER, Optional.empty(), Optional.empty(), "cast(regexp_replace(comment,'(password: [^ ]+)','password: ****') as varchar(79))")); | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I don't quite get the purpose of this masking.
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I want to mask some values in In a real example there is a json
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
This value doesn't contain a
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I found that issue happens in InlineProjections#inlineProjections
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
You are right. That's why I added the last test (L293:L337)
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I had a look again on the test and I am sorry to say that I still don't quite understand why isn't there any masking in the result of the queries.
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
You are right. I fixed it now. Take a look on the tests with
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
That's right. masking is pointless for this specific row, but I added it to demonstrate the issue when adding the masking on
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I see now. The purpose of the test is currently just to demonstrate that the masking doesn't work properly. Thank you for the patience in trying to explain the purpose of the tests. |
||
|
|
||
| accessControl.columnMask( | ||
| new QualifiedObjectName(CATALOG, "tiny", "orders"), | ||
| "orderstatus", | ||
| USER, | ||
| new ViewExpression(USER, Optional.empty(), Optional.empty(), "'X'")); | ||
| new ViewExpression(USER, Optional.empty(), Optional.empty(), "if(regexp_extract(comment,'(country: [^ ]+)') IN ('country: 1'), '*', orderstatus)")); | ||
|
|
||
| assertThat(assertions.query("SELECT custkey, orderstatus FROM orders WHERE orderkey = 1")) | ||
| .matches("VALUES (BIGINT '-370', 'X')"); | ||
| accessControl.columnMask( | ||
| new QualifiedObjectName(CATALOG, "tiny", "orders"), | ||
| "clerk", | ||
| USER, | ||
| new ViewExpression(USER, Optional.empty(), Optional.empty(), "if(regexp_extract(comment,'(country: [^ ]+)') IN ('country: 1'), '***', clerk)")); | ||
|
|
||
| assertThat(assertions.query(query)).matches(expected); | ||
|
|
||
| // mask "comment" using "clerk" ("clerk" column appears before "comment" in table definition) | ||
| // columns will not be masked since rules are not apply to row values | ||
| accessControl.reset(); | ||
| accessControl.columnMask( | ||
| new QualifiedObjectName(CATALOG, "tiny", "orders"), | ||
| "clerk", | ||
| USER, | ||
| new ViewExpression(USER, Optional.empty(), Optional.empty(), "cast(regexp_replace(clerk,'(password: [^ ]+)','password: ****') as varchar(15))")); | ||
|
|
||
| accessControl.columnMask( | ||
| new QualifiedObjectName(CATALOG, "tiny", "orders"), | ||
| "comment", | ||
| USER, | ||
| new ViewExpression(USER, Optional.empty(), Optional.empty(), "if(regexp_extract(clerk,'(country: [^ ]+)') IN ('country: 1'), '***', comment)")); | ||
|
|
||
| assertThat(assertions.query(query)).matches(expected); | ||
|
|
||
| // now add mask for "orderstatus" using "clerk" | ||
| // columns will not be masked since rules are not apply to row values | ||
| accessControl.reset(); | ||
| accessControl.columnMask( | ||
| new QualifiedObjectName(CATALOG, "tiny", "orders"), | ||
| "clerk", | ||
| USER, | ||
| new ViewExpression(USER, Optional.empty(), Optional.empty(), "cast(regexp_replace(clerk,'(password: [^ ]+)','password: ****') as varchar(15))")); | ||
|
|
||
| accessControl.columnMask( | ||
| new QualifiedObjectName(CATALOG, "tiny", "orders"), | ||
| "orderstatus", | ||
| USER, | ||
| new ViewExpression(USER, Optional.empty(), Optional.empty(), "if(regexp_extract(clerk,'(country: [^ ]+)') IN ('country: 1'), '*', orderstatus)")); | ||
|
|
||
| accessControl.columnMask( | ||
| new QualifiedObjectName(CATALOG, "tiny", "orders"), | ||
| "comment", | ||
| USER, | ||
| new ViewExpression(USER, Optional.empty(), Optional.empty(), "if(regexp_extract(clerk,'(country: [^ ]+)') IN ('country: 1'), '***', comment)")); | ||
|
|
||
| assertThat(assertions.query(query)).matches(expected); | ||
|
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Fails with |
||
|
|
||
| query = "SELECT comment, orderstatus, clerk FROM orders WHERE orderkey = 39"; | ||
|
|
||
| accessControl.reset(); | ||
| assertThat(assertions.query(query)) | ||
| .matches("VALUES (CAST('ole express, ironic requests: ir' as varchar(79)), 'O', 'Clerk#000000659')"); | ||
|
|
||
| // mask "comment" and "orderstatus" using "clerk" ("clerk" appears before "comment" table definition) | ||
| accessControl.reset(); | ||
| accessControl.columnMask( | ||
| new QualifiedObjectName(CATALOG, "tiny", "orders"), | ||
| "clerk", | ||
| USER, | ||
| new ViewExpression(USER, Optional.empty(), Optional.empty(), "cast(regexp_replace(clerk,'(Clerk#)','***#') as varchar(15))")); | ||
|
|
||
| accessControl.columnMask( | ||
| new QualifiedObjectName(CATALOG, "tiny", "orders"), | ||
| "comment", | ||
| USER, | ||
| new ViewExpression(USER, Optional.empty(), Optional.empty(), "if(regexp_extract(clerk,'([1-9]+)') IN ('659'), '***', comment)")); | ||
|
|
||
| assertThat(assertions.query(query)) | ||
| .matches("VALUES (CAST('***' as varchar(79)), 'O', CAST('***#000000659' as varchar(15)))"); | ||
|
|
||
| assertThat(assertions.query("SELECT comment, orderstatus, clerk, length(clerk) FROM orders WHERE orderkey = 39")) | ||
| .matches("VALUES (CAST('***' as varchar(79)), 'O', CAST('***#000000659' as varchar(15)), bigint'13')"); | ||
|
|
||
| // mask "comment" and "orderstatus" using "clerk" ("clerk" appears before "comment" table definition) | ||
| accessControl.reset(); | ||
| accessControl.columnMask( | ||
| new QualifiedObjectName(CATALOG, "tiny", "orders"), | ||
| "clerk", | ||
| USER, | ||
| new ViewExpression(USER, Optional.empty(), Optional.empty(), "cast(regexp_replace(clerk,'(Clerk#)','***#') as varchar(15))")); | ||
|
|
||
| accessControl.columnMask( | ||
| new QualifiedObjectName(CATALOG, "tiny", "orders"), | ||
| "orderstatus", | ||
| USER, | ||
| new ViewExpression(USER, Optional.empty(), Optional.empty(), "if(regexp_extract(clerk,'([1-9]+)') IN ('659'), '*', orderstatus)")); | ||
|
|
||
| accessControl.columnMask( | ||
| new QualifiedObjectName(CATALOG, "tiny", "orders"), | ||
| "comment", | ||
| USER, | ||
| new ViewExpression(USER, Optional.empty(), Optional.empty(), "if(regexp_extract(clerk,'([1-9]+)') IN ('659'), '***', comment)")); | ||
|
|
||
| assertThat(assertions.query(query)) | ||
| .matches("VALUES (CAST('***' as varchar(79)), '*', CAST('***#000000659' as varchar(15)))"); | ||
| } | ||
|
|
||
| @Test | ||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Removing this test, since AC doesn't allow to have more than one masking per column.
trino/lib/trino-plugin-toolkit/src/main/java/io/trino/plugin/base/security/TableAccessControlRule.java
Line 72 in 35986d7